widget/windows/nsWindowBase.cpp

Thu, 22 Jan 2015 13:21:57 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Thu, 22 Jan 2015 13:21:57 +0100
branch
TOR_BUG_9701
changeset 15
b8a032363ba2
permissions
-rw-r--r--

Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6

michael@0 1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 3 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 5
michael@0 6 #include "nsWindowBase.h"
michael@0 7
michael@0 8 #include "mozilla/MiscEvents.h"
michael@0 9 #include "nsGkAtoms.h"
michael@0 10 #include "WinUtils.h"
michael@0 11 #include "npapi.h"
michael@0 12
michael@0 13 using namespace mozilla;
michael@0 14 using namespace mozilla::widget;
michael@0 15
michael@0 16 static const wchar_t kUser32LibName[] = L"user32.dll";
michael@0 17 bool nsWindowBase::sTouchInjectInitialized = false;
michael@0 18 InjectTouchInputPtr nsWindowBase::sInjectTouchFuncPtr;
michael@0 19
michael@0 20 bool
michael@0 21 nsWindowBase::DispatchPluginEvent(const MSG& aMsg)
michael@0 22 {
michael@0 23 if (!PluginHasFocus()) {
michael@0 24 return false;
michael@0 25 }
michael@0 26 WidgetPluginEvent pluginEvent(true, NS_PLUGIN_INPUT_EVENT, this);
michael@0 27 nsIntPoint point(0, 0);
michael@0 28 InitEvent(pluginEvent, &point);
michael@0 29 NPEvent npEvent;
michael@0 30 npEvent.event = aMsg.message;
michael@0 31 npEvent.wParam = aMsg.wParam;
michael@0 32 npEvent.lParam = aMsg.lParam;
michael@0 33 pluginEvent.pluginEvent = &npEvent;
michael@0 34 pluginEvent.retargetToFocusedDocument = true;
michael@0 35 return DispatchWindowEvent(&pluginEvent);
michael@0 36 }
michael@0 37
michael@0 38 // static
michael@0 39 bool
michael@0 40 nsWindowBase::InitTouchInjection()
michael@0 41 {
michael@0 42 if (!sTouchInjectInitialized) {
michael@0 43 // Initialize touch injection on the first call
michael@0 44 HMODULE hMod = LoadLibraryW(kUser32LibName);
michael@0 45 if (!hMod) {
michael@0 46 return false;
michael@0 47 }
michael@0 48
michael@0 49 InitializeTouchInjectionPtr func =
michael@0 50 (InitializeTouchInjectionPtr)GetProcAddress(hMod, "InitializeTouchInjection");
michael@0 51 if (!func) {
michael@0 52 WinUtils::Log("InitializeTouchInjection not available.");
michael@0 53 return false;
michael@0 54 }
michael@0 55
michael@0 56 if (!func(TOUCH_INJECT_MAX_POINTS, TOUCH_FEEDBACK_DEFAULT)) {
michael@0 57 WinUtils::Log("InitializeTouchInjection failure. GetLastError=%d", GetLastError());
michael@0 58 return false;
michael@0 59 }
michael@0 60
michael@0 61 sInjectTouchFuncPtr =
michael@0 62 (InjectTouchInputPtr)GetProcAddress(hMod, "InjectTouchInput");
michael@0 63 if (!sInjectTouchFuncPtr) {
michael@0 64 WinUtils::Log("InjectTouchInput not available.");
michael@0 65 return false;
michael@0 66 }
michael@0 67 sTouchInjectInitialized = true;
michael@0 68 }
michael@0 69 return true;
michael@0 70 }
michael@0 71
michael@0 72 bool
michael@0 73 nsWindowBase::InjectTouchPoint(uint32_t aId, nsIntPoint& aPointerScreenPoint,
michael@0 74 POINTER_FLAGS aFlags, uint32_t aPressure,
michael@0 75 uint32_t aOrientation)
michael@0 76 {
michael@0 77 if (aId > TOUCH_INJECT_MAX_POINTS) {
michael@0 78 WinUtils::Log("Pointer ID exceeds maximum. See TOUCH_INJECT_MAX_POINTS.");
michael@0 79 return false;
michael@0 80 }
michael@0 81
michael@0 82 POINTER_TOUCH_INFO info;
michael@0 83 memset(&info, 0, sizeof(POINTER_TOUCH_INFO));
michael@0 84
michael@0 85 info.touchFlags = TOUCH_FLAG_NONE;
michael@0 86 info.touchMask = TOUCH_MASK_CONTACTAREA|TOUCH_MASK_ORIENTATION|TOUCH_MASK_PRESSURE;
michael@0 87 info.pressure = aPressure;
michael@0 88 info.orientation = aOrientation;
michael@0 89
michael@0 90 info.pointerInfo.pointerFlags = aFlags;
michael@0 91 info.pointerInfo.pointerType = PT_TOUCH;
michael@0 92 info.pointerInfo.pointerId = aId;
michael@0 93 info.pointerInfo.ptPixelLocation.x = WinUtils::LogToPhys(aPointerScreenPoint.x);
michael@0 94 info.pointerInfo.ptPixelLocation.y = WinUtils::LogToPhys(aPointerScreenPoint.y);
michael@0 95
michael@0 96 info.rcContact.top = info.pointerInfo.ptPixelLocation.y - 2;
michael@0 97 info.rcContact.bottom = info.pointerInfo.ptPixelLocation.y + 2;
michael@0 98 info.rcContact.left = info.pointerInfo.ptPixelLocation.x - 2;
michael@0 99 info.rcContact.right = info.pointerInfo.ptPixelLocation.x + 2;
michael@0 100
michael@0 101 if (!sInjectTouchFuncPtr(1, &info)) {
michael@0 102 WinUtils::Log("InjectTouchInput failure. GetLastError=%d", GetLastError());
michael@0 103 return false;
michael@0 104 }
michael@0 105 return true;
michael@0 106 }
michael@0 107
michael@0 108 nsresult
michael@0 109 nsWindowBase::SynthesizeNativeTouchPoint(uint32_t aPointerId,
michael@0 110 nsIWidget::TouchPointerState aPointerState,
michael@0 111 nsIntPoint aPointerScreenPoint,
michael@0 112 double aPointerPressure,
michael@0 113 uint32_t aPointerOrientation)
michael@0 114 {
michael@0 115 if (!InitTouchInjection()) {
michael@0 116 return NS_ERROR_NOT_IMPLEMENTED;
michael@0 117 }
michael@0 118
michael@0 119 bool hover = aPointerState & TOUCH_HOVER;
michael@0 120 bool contact = aPointerState & TOUCH_CONTACT;
michael@0 121 bool remove = aPointerState & TOUCH_REMOVE;
michael@0 122 bool cancel = aPointerState & TOUCH_CANCEL;
michael@0 123
michael@0 124 // win api expects a value from 0 to 1024. aPointerPressure is a value
michael@0 125 // from 0.0 to 1.0.
michael@0 126 uint32_t pressure = (uint32_t)ceil(aPointerPressure * 1024);
michael@0 127
michael@0 128 // If we already know about this pointer id get it's record
michael@0 129 PointerInfo* info = mActivePointers.Get(aPointerId);
michael@0 130
michael@0 131 // We know about this pointer, send an update
michael@0 132 if (info) {
michael@0 133 POINTER_FLAGS flags = POINTER_FLAG_UPDATE;
michael@0 134 if (hover) {
michael@0 135 flags |= POINTER_FLAG_INRANGE;
michael@0 136 } else if (contact) {
michael@0 137 flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_INRANGE;
michael@0 138 } else if (remove) {
michael@0 139 flags = POINTER_FLAG_UP;
michael@0 140 // Remove the pointer from our tracking list. This is nsAutPtr wrapped,
michael@0 141 // so shouldn't leak.
michael@0 142 mActivePointers.Remove(aPointerId);
michael@0 143 }
michael@0 144
michael@0 145 if (cancel) {
michael@0 146 flags |= POINTER_FLAG_CANCELED;
michael@0 147 }
michael@0 148
michael@0 149 return !InjectTouchPoint(aPointerId, aPointerScreenPoint, flags,
michael@0 150 pressure, aPointerOrientation) ?
michael@0 151 NS_ERROR_UNEXPECTED : NS_OK;
michael@0 152 }
michael@0 153
michael@0 154 // Missing init state, error out
michael@0 155 if (remove || cancel) {
michael@0 156 return NS_ERROR_INVALID_ARG;
michael@0 157 }
michael@0 158
michael@0 159 // Create a new pointer
michael@0 160 info = new PointerInfo(aPointerId, aPointerScreenPoint);
michael@0 161
michael@0 162 POINTER_FLAGS flags = POINTER_FLAG_INRANGE;
michael@0 163 if (contact) {
michael@0 164 flags |= POINTER_FLAG_INCONTACT|POINTER_FLAG_DOWN;
michael@0 165 }
michael@0 166
michael@0 167 mActivePointers.Put(aPointerId, info);
michael@0 168 return !InjectTouchPoint(aPointerId, aPointerScreenPoint, flags,
michael@0 169 pressure, aPointerOrientation) ?
michael@0 170 NS_ERROR_UNEXPECTED : NS_OK;
michael@0 171 }
michael@0 172
michael@0 173 // static
michael@0 174 PLDHashOperator
michael@0 175 nsWindowBase::CancelTouchPoints(const unsigned int& aPointerId, nsAutoPtr<PointerInfo>& aInfo, void* aUserArg)
michael@0 176 {
michael@0 177 nsWindowBase* self = static_cast<nsWindowBase*>(aUserArg);
michael@0 178 self->InjectTouchPoint(aInfo.get()->mPointerId, aInfo.get()->mPosition, POINTER_FLAG_CANCELED);
michael@0 179 return (PLDHashOperator)(PL_DHASH_NEXT|PL_DHASH_REMOVE);
michael@0 180 }
michael@0 181
michael@0 182 nsresult
michael@0 183 nsWindowBase::ClearNativeTouchSequence()
michael@0 184 {
michael@0 185 if (!sTouchInjectInitialized) {
michael@0 186 return NS_OK;
michael@0 187 }
michael@0 188
michael@0 189 // cancel all input points
michael@0 190 mActivePointers.Enumerate(CancelTouchPoints, (void*)this);
michael@0 191
michael@0 192 nsBaseWidget::ClearNativeTouchSequence();
michael@0 193
michael@0 194 return NS_OK;
michael@0 195 }
michael@0 196
michael@0 197 bool
michael@0 198 nsWindowBase::DispatchCommandEvent(uint32_t aEventCommand)
michael@0 199 {
michael@0 200 nsCOMPtr<nsIAtom> command;
michael@0 201 switch (aEventCommand) {
michael@0 202 case APPCOMMAND_BROWSER_BACKWARD:
michael@0 203 command = nsGkAtoms::Back;
michael@0 204 break;
michael@0 205 case APPCOMMAND_BROWSER_FORWARD:
michael@0 206 command = nsGkAtoms::Forward;
michael@0 207 break;
michael@0 208 case APPCOMMAND_BROWSER_REFRESH:
michael@0 209 command = nsGkAtoms::Reload;
michael@0 210 break;
michael@0 211 case APPCOMMAND_BROWSER_STOP:
michael@0 212 command = nsGkAtoms::Stop;
michael@0 213 break;
michael@0 214 case APPCOMMAND_BROWSER_SEARCH:
michael@0 215 command = nsGkAtoms::Search;
michael@0 216 break;
michael@0 217 case APPCOMMAND_BROWSER_FAVORITES:
michael@0 218 command = nsGkAtoms::Bookmarks;
michael@0 219 break;
michael@0 220 case APPCOMMAND_BROWSER_HOME:
michael@0 221 command = nsGkAtoms::Home;
michael@0 222 break;
michael@0 223 case APPCOMMAND_CLOSE:
michael@0 224 command = nsGkAtoms::Close;
michael@0 225 break;
michael@0 226 case APPCOMMAND_FIND:
michael@0 227 command = nsGkAtoms::Find;
michael@0 228 break;
michael@0 229 case APPCOMMAND_HELP:
michael@0 230 command = nsGkAtoms::Help;
michael@0 231 break;
michael@0 232 case APPCOMMAND_NEW:
michael@0 233 command = nsGkAtoms::New;
michael@0 234 break;
michael@0 235 case APPCOMMAND_OPEN:
michael@0 236 command = nsGkAtoms::Open;
michael@0 237 break;
michael@0 238 case APPCOMMAND_PRINT:
michael@0 239 command = nsGkAtoms::Print;
michael@0 240 break;
michael@0 241 case APPCOMMAND_SAVE:
michael@0 242 command = nsGkAtoms::Save;
michael@0 243 break;
michael@0 244 case APPCOMMAND_FORWARD_MAIL:
michael@0 245 command = nsGkAtoms::ForwardMail;
michael@0 246 break;
michael@0 247 case APPCOMMAND_REPLY_TO_MAIL:
michael@0 248 command = nsGkAtoms::ReplyToMail;
michael@0 249 break;
michael@0 250 case APPCOMMAND_SEND_MAIL:
michael@0 251 command = nsGkAtoms::SendMail;
michael@0 252 break;
michael@0 253 default:
michael@0 254 return false;
michael@0 255 }
michael@0 256 WidgetCommandEvent event(true, nsGkAtoms::onAppCommand, command, this);
michael@0 257
michael@0 258 InitEvent(event);
michael@0 259 return DispatchWindowEvent(&event);
michael@0 260 }
michael@0 261
michael@0 262 bool
michael@0 263 nsWindowBase::HandleAppCommandMsg(WPARAM aWParam,
michael@0 264 LPARAM aLParam,
michael@0 265 LRESULT *aRetValue)
michael@0 266 {
michael@0 267 uint32_t appCommand = GET_APPCOMMAND_LPARAM(aLParam);
michael@0 268 uint32_t contentCommandMessage = NS_EVENT_NULL;
michael@0 269 // XXX After we implement KeyboardEvent.key, we should dispatch the
michael@0 270 // key event if (GET_DEVICE_LPARAM(lParam) == FAPPCOMMAND_KEY) is.
michael@0 271 switch (appCommand)
michael@0 272 {
michael@0 273 case APPCOMMAND_BROWSER_BACKWARD:
michael@0 274 case APPCOMMAND_BROWSER_FORWARD:
michael@0 275 case APPCOMMAND_BROWSER_REFRESH:
michael@0 276 case APPCOMMAND_BROWSER_STOP:
michael@0 277 case APPCOMMAND_BROWSER_SEARCH:
michael@0 278 case APPCOMMAND_BROWSER_FAVORITES:
michael@0 279 case APPCOMMAND_BROWSER_HOME:
michael@0 280 case APPCOMMAND_CLOSE:
michael@0 281 case APPCOMMAND_FIND:
michael@0 282 case APPCOMMAND_HELP:
michael@0 283 case APPCOMMAND_NEW:
michael@0 284 case APPCOMMAND_OPEN:
michael@0 285 case APPCOMMAND_PRINT:
michael@0 286 case APPCOMMAND_SAVE:
michael@0 287 case APPCOMMAND_FORWARD_MAIL:
michael@0 288 case APPCOMMAND_REPLY_TO_MAIL:
michael@0 289 case APPCOMMAND_SEND_MAIL:
michael@0 290 // We shouldn't consume the message always because if we don't handle
michael@0 291 // the message, the sender (typically, utility of keyboard or mouse)
michael@0 292 // may send other key messages which indicate well known shortcut key.
michael@0 293 if (DispatchCommandEvent(appCommand)) {
michael@0 294 // tell the driver that we handled the event
michael@0 295 *aRetValue = 1;
michael@0 296 return true;
michael@0 297 }
michael@0 298 break;
michael@0 299
michael@0 300 // Use content command for following commands:
michael@0 301 case APPCOMMAND_COPY:
michael@0 302 contentCommandMessage = NS_CONTENT_COMMAND_COPY;
michael@0 303 break;
michael@0 304 case APPCOMMAND_CUT:
michael@0 305 contentCommandMessage = NS_CONTENT_COMMAND_CUT;
michael@0 306 break;
michael@0 307 case APPCOMMAND_PASTE:
michael@0 308 contentCommandMessage = NS_CONTENT_COMMAND_PASTE;
michael@0 309 break;
michael@0 310 case APPCOMMAND_REDO:
michael@0 311 contentCommandMessage = NS_CONTENT_COMMAND_REDO;
michael@0 312 break;
michael@0 313 case APPCOMMAND_UNDO:
michael@0 314 contentCommandMessage = NS_CONTENT_COMMAND_UNDO;
michael@0 315 break;
michael@0 316 }
michael@0 317
michael@0 318 if (contentCommandMessage) {
michael@0 319 WidgetContentCommandEvent contentCommand(true, contentCommandMessage,
michael@0 320 this);
michael@0 321 DispatchWindowEvent(&contentCommand);
michael@0 322 // tell the driver that we handled the event
michael@0 323 *aRetValue = 1;
michael@0 324 return true;
michael@0 325 }
michael@0 326
michael@0 327 // default = false - tell the driver that the event was not handled
michael@0 328 return false;
michael@0 329 }

mercurial