widget/windows/WinMouseScrollHandler.h

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: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
michael@0 2 /* vim: set ts=2 et sw=2 tw=80: */
michael@0 3 /* This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
michael@0 5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef mozilla_widget_WinMouseScrollHandler_h__
michael@0 8 #define mozilla_widget_WinMouseScrollHandler_h__
michael@0 9
michael@0 10 #include "nscore.h"
michael@0 11 #include "nsDebug.h"
michael@0 12 #include "mozilla/Assertions.h"
michael@0 13 #include "mozilla/EventForwards.h"
michael@0 14 #include "mozilla/TimeStamp.h"
michael@0 15 #include <windows.h>
michael@0 16
michael@0 17 class nsWindowBase;
michael@0 18 struct nsIntPoint;
michael@0 19
michael@0 20 namespace mozilla {
michael@0 21 namespace widget {
michael@0 22
michael@0 23 class ModifierKeyState;
michael@0 24
michael@0 25 struct MSGResult;
michael@0 26
michael@0 27 class MouseScrollHandler {
michael@0 28 public:
michael@0 29 static MouseScrollHandler* GetInstance();
michael@0 30
michael@0 31 static void Initialize();
michael@0 32 static void Shutdown();
michael@0 33
michael@0 34 static bool NeedsMessage(UINT aMsg);
michael@0 35 static bool ProcessMessage(nsWindowBase* aWidget,
michael@0 36 UINT msg,
michael@0 37 WPARAM wParam,
michael@0 38 LPARAM lParam,
michael@0 39 MSGResult& aResult);
michael@0 40
michael@0 41 /**
michael@0 42 * See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
michael@0 43 * this method.
michael@0 44 */
michael@0 45 static nsresult SynthesizeNativeMouseScrollEvent(nsWindowBase* aWidget,
michael@0 46 const nsIntPoint& aPoint,
michael@0 47 uint32_t aNativeMessage,
michael@0 48 int32_t aDelta,
michael@0 49 uint32_t aModifierFlags,
michael@0 50 uint32_t aAdditionalFlags);
michael@0 51
michael@0 52 /**
michael@0 53 * IsWaitingInternalMessage() returns true if MouseScrollHandler posted
michael@0 54 * an internal message for a native mouse wheel message and has not
michael@0 55 * received it. Otherwise, false.
michael@0 56 */
michael@0 57 static bool IsWaitingInternalMessage()
michael@0 58 {
michael@0 59 return sInstance && sInstance->mIsWaitingInternalMessage;
michael@0 60 }
michael@0 61
michael@0 62 private:
michael@0 63 MouseScrollHandler();
michael@0 64 ~MouseScrollHandler();
michael@0 65
michael@0 66 bool mIsWaitingInternalMessage;
michael@0 67
michael@0 68 static MouseScrollHandler* sInstance;
michael@0 69
michael@0 70 /**
michael@0 71 * DispatchEvent() dispatches aEvent on aWidget.
michael@0 72 *
michael@0 73 * @return TRUE if the event was consumed. Otherwise, FALSE.
michael@0 74 */
michael@0 75 static bool DispatchEvent(nsWindowBase* aWidget, WidgetGUIEvent& aEvent);
michael@0 76
michael@0 77 /**
michael@0 78 * InitEvent() initializes the aEvent. If aPoint is null, the result of
michael@0 79 * GetCurrentMessagePos() will be used.
michael@0 80 */
michael@0 81 static void InitEvent(nsWindowBase* aWidget,
michael@0 82 WidgetGUIEvent& aEvent,
michael@0 83 nsIntPoint* aPoint = nullptr);
michael@0 84
michael@0 85 /**
michael@0 86 * GetModifierKeyState() returns current modifier key state.
michael@0 87 * Note that some devices need some hack for the modifier key state.
michael@0 88 * This method does it automatically.
michael@0 89 *
michael@0 90 * @param aMessage Handling message.
michael@0 91 */
michael@0 92 static ModifierKeyState GetModifierKeyState(UINT aMessage);
michael@0 93
michael@0 94 /**
michael@0 95 * MozGetMessagePos() returns the mouse cursor position when GetMessage()
michael@0 96 * was called last time. However, if we're sending a native message,
michael@0 97 * this returns the specified cursor position by
michael@0 98 * SynthesizeNativeMouseScrollEvent().
michael@0 99 */
michael@0 100 static POINTS GetCurrentMessagePos();
michael@0 101
michael@0 102 /**
michael@0 103 * ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and
michael@0 104 * WM_MOUSEHWHEEL. Additionally, processes WM_VSCROLL and WM_HSCROLL if they
michael@0 105 * should be processed as mouse wheel message.
michael@0 106 * This method posts MOZ_WM_MOUSEVWHEEL, MOZ_WM_MOUSEHWHEEL,
michael@0 107 * MOZ_WM_VSCROLL or MOZ_WM_HSCROLL if we need to dispatch mouse scroll
michael@0 108 * events. That avoids deadlock with plugin process.
michael@0 109 *
michael@0 110 * @param aWidget A window which receives the message.
michael@0 111 * @param aMessage WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or
michael@0 112 * WM_HSCROLL.
michael@0 113 * @param aWParam The wParam value of the message.
michael@0 114 * @param aLParam The lParam value of the message.
michael@0 115 */
michael@0 116 void ProcessNativeMouseWheelMessage(nsWindowBase* aWidget,
michael@0 117 UINT aMessage,
michael@0 118 WPARAM aWParam,
michael@0 119 LPARAM aLParam);
michael@0 120
michael@0 121 /**
michael@0 122 * ProcessNativeScrollMessage() processes WM_VSCROLL and WM_HSCROLL.
michael@0 123 * This method just call ProcessMouseWheelMessage() if the message should be
michael@0 124 * processed as mouse wheel message. Otherwise, dispatches a content
michael@0 125 * command event.
michael@0 126 *
michael@0 127 * @param aWidget A window which receives the message.
michael@0 128 * @param aMessage WM_VSCROLL or WM_HSCROLL.
michael@0 129 * @param aWParam The wParam value of the message.
michael@0 130 * @param aLParam The lParam value of the message.
michael@0 131 * @return TRUE if the message is processed. Otherwise, FALSE.
michael@0 132 */
michael@0 133 bool ProcessNativeScrollMessage(nsWindowBase* aWidget,
michael@0 134 UINT aMessage,
michael@0 135 WPARAM aWParam,
michael@0 136 LPARAM aLParam);
michael@0 137
michael@0 138 /**
michael@0 139 * HandleMouseWheelMessage() processes MOZ_WM_MOUSEVWHEEL and
michael@0 140 * MOZ_WM_MOUSEHWHEEL which are posted when one of our windows received
michael@0 141 * WM_MOUSEWHEEL or WM_MOUSEHWHEEL for avoiding deadlock with OOPP.
michael@0 142 *
michael@0 143 * @param aWidget A window which receives the wheel message.
michael@0 144 * @param aMessage MOZ_WM_MOUSEWHEEL or MOZ_WM_MOUSEHWHEEL.
michael@0 145 * @param aWParam The wParam value of the original message.
michael@0 146 * @param aLParam The lParam value of the original message.
michael@0 147 */
michael@0 148 void HandleMouseWheelMessage(nsWindowBase* aWidget,
michael@0 149 UINT aMessage,
michael@0 150 WPARAM aWParam,
michael@0 151 LPARAM aLParam);
michael@0 152
michael@0 153 /**
michael@0 154 * HandleScrollMessageAsMouseWheelMessage() processes the MOZ_WM_VSCROLL and
michael@0 155 * MOZ_WM_HSCROLL which are posted when one of mouse windows received
michael@0 156 * WM_VSCROLL or WM_HSCROLL and user wants them to emulate mouse wheel
michael@0 157 * message's behavior.
michael@0 158 *
michael@0 159 * @param aWidget A window which receives the scroll message.
michael@0 160 * @param aMessage MOZ_WM_VSCROLL or MOZ_WM_HSCROLL.
michael@0 161 * @param aWParam The wParam value of the original message.
michael@0 162 * @param aLParam The lParam value of the original message.
michael@0 163 */
michael@0 164 void HandleScrollMessageAsMouseWheelMessage(nsWindowBase* aWidget,
michael@0 165 UINT aMessage,
michael@0 166 WPARAM aWParam,
michael@0 167 LPARAM aLParam);
michael@0 168
michael@0 169 /**
michael@0 170 * ComputeMessagePos() computes the cursor position when the message was
michael@0 171 * added to the queue.
michael@0 172 *
michael@0 173 * @param aMessage Handling message.
michael@0 174 * @param aWParam Handling message's wParam.
michael@0 175 * @param aLParam Handling message's lParam.
michael@0 176 * @return Mouse cursor position when the message is added to
michael@0 177 * the queue or current cursor position if the result of
michael@0 178 * ::GetMessagePos() is broken.
michael@0 179 */
michael@0 180 POINT ComputeMessagePos(UINT aMessage,
michael@0 181 WPARAM aWParam,
michael@0 182 LPARAM aLParam);
michael@0 183
michael@0 184 class EventInfo {
michael@0 185 public:
michael@0 186 /**
michael@0 187 * @param aWidget An nsWindow which is handling the event.
michael@0 188 * @param aMessage Must be WM_MOUSEWHEEL or WM_MOUSEHWHEEL.
michael@0 189 */
michael@0 190 EventInfo(nsWindowBase* aWidget, UINT aMessage, WPARAM aWParam, LPARAM aLParam);
michael@0 191
michael@0 192 bool CanDispatchWheelEvent() const;
michael@0 193
michael@0 194 int32_t GetNativeDelta() const { return mDelta; }
michael@0 195 HWND GetWindowHandle() const { return mWnd; }
michael@0 196 const TimeStamp& GetTimeStamp() const { return mTimeStamp; }
michael@0 197 bool IsVertical() const { return mIsVertical; }
michael@0 198 bool IsPositive() const { return (mDelta > 0); }
michael@0 199 bool IsPage() const { return mIsPage; }
michael@0 200
michael@0 201 /**
michael@0 202 * @return Number of lines or pages scrolled per WHEEL_DELTA.
michael@0 203 */
michael@0 204 int32_t GetScrollAmount() const;
michael@0 205
michael@0 206 protected:
michael@0 207 EventInfo() :
michael@0 208 mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr)
michael@0 209 {
michael@0 210 }
michael@0 211
michael@0 212 // TRUE if event is for vertical scroll. Otherwise, FALSE.
michael@0 213 bool mIsVertical;
michael@0 214 // TRUE if event scrolls per page, otherwise, FALSE.
michael@0 215 bool mIsPage;
michael@0 216 // The native delta value.
michael@0 217 int32_t mDelta;
michael@0 218 // The window handle which is handling the event.
michael@0 219 HWND mWnd;
michael@0 220 // Timestamp of the event.
michael@0 221 TimeStamp mTimeStamp;
michael@0 222 };
michael@0 223
michael@0 224 class LastEventInfo : public EventInfo {
michael@0 225 public:
michael@0 226 LastEventInfo() :
michael@0 227 EventInfo(), mAccumulatedDelta(0)
michael@0 228 {
michael@0 229 }
michael@0 230
michael@0 231 /**
michael@0 232 * CanContinueTransaction() checks whether the new event can continue the
michael@0 233 * last transaction or not. Note that if there is no transaction, this
michael@0 234 * returns true.
michael@0 235 */
michael@0 236 bool CanContinueTransaction(const EventInfo& aNewEvent);
michael@0 237
michael@0 238 /**
michael@0 239 * ResetTransaction() resets the transaction, i.e., the instance forgets
michael@0 240 * the last event information.
michael@0 241 */
michael@0 242 void ResetTransaction();
michael@0 243
michael@0 244 /**
michael@0 245 * RecordEvent() saves the information of new event.
michael@0 246 */
michael@0 247 void RecordEvent(const EventInfo& aEvent);
michael@0 248
michael@0 249 /**
michael@0 250 * InitWheelEvent() initializes NS_WHEEL_WHEEL event and
michael@0 251 * recomputes the remaning detla for the event.
michael@0 252 * This must be called only once during handling a message and after
michael@0 253 * RecordEvent() is called.
michael@0 254 *
michael@0 255 * @param aWidget A window which will dispatch the event.
michael@0 256 * @param aWheelEvent An NS_WHEEL_WHEEL event, this will be
michael@0 257 * initialized.
michael@0 258 * @param aModKeyState Current modifier key state.
michael@0 259 * @return TRUE if the event is ready to dispatch.
michael@0 260 * Otherwise, FALSE.
michael@0 261 */
michael@0 262 bool InitWheelEvent(nsWindowBase* aWidget,
michael@0 263 WidgetWheelEvent& aWheelEvent,
michael@0 264 const ModifierKeyState& aModKeyState);
michael@0 265
michael@0 266 private:
michael@0 267 static int32_t RoundDelta(double aDelta);
michael@0 268
michael@0 269 int32_t mAccumulatedDelta;
michael@0 270 };
michael@0 271
michael@0 272 LastEventInfo mLastEventInfo;
michael@0 273
michael@0 274 class SystemSettings {
michael@0 275 public:
michael@0 276 SystemSettings() : mInitialized(false) {}
michael@0 277
michael@0 278 void Init();
michael@0 279 void MarkDirty();
michael@0 280 void NotifyUserPrefsMayOverrideSystemSettings();
michael@0 281
michael@0 282 int32_t GetScrollAmount(bool aForVertical) const
michael@0 283 {
michael@0 284 MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
michael@0 285 return aForVertical ? mScrollLines : mScrollChars;
michael@0 286 }
michael@0 287
michael@0 288 bool IsPageScroll(bool aForVertical) const
michael@0 289 {
michael@0 290 MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
michael@0 291 return aForVertical ? (mScrollLines == WHEEL_PAGESCROLL) :
michael@0 292 (mScrollChars == WHEEL_PAGESCROLL);
michael@0 293 }
michael@0 294
michael@0 295 private:
michael@0 296 bool mInitialized;
michael@0 297 int32_t mScrollLines;
michael@0 298 int32_t mScrollChars;
michael@0 299 };
michael@0 300
michael@0 301 SystemSettings mSystemSettings;
michael@0 302
michael@0 303 class UserPrefs {
michael@0 304 public:
michael@0 305 UserPrefs();
michael@0 306 ~UserPrefs();
michael@0 307
michael@0 308 void MarkDirty();
michael@0 309
michael@0 310 bool IsScrollMessageHandledAsWheelMessage()
michael@0 311 {
michael@0 312 Init();
michael@0 313 return mScrollMessageHandledAsWheelMessage;
michael@0 314 }
michael@0 315
michael@0 316 int32_t GetOverriddenVerticalScrollAmout()
michael@0 317 {
michael@0 318 Init();
michael@0 319 return mOverriddenVerticalScrollAmount;
michael@0 320 }
michael@0 321
michael@0 322 int32_t GetOverriddenHorizontalScrollAmout()
michael@0 323 {
michael@0 324 Init();
michael@0 325 return mOverriddenHorizontalScrollAmount;
michael@0 326 }
michael@0 327
michael@0 328 int32_t GetMouseScrollTransactionTimeout()
michael@0 329 {
michael@0 330 Init();
michael@0 331 return mMouseScrollTransactionTimeout;
michael@0 332 }
michael@0 333
michael@0 334 private:
michael@0 335 void Init();
michael@0 336
michael@0 337 static void OnChange(const char* aPrefName, void* aClosure)
michael@0 338 {
michael@0 339 static_cast<UserPrefs*>(aClosure)->MarkDirty();
michael@0 340 }
michael@0 341
michael@0 342 bool mInitialized;
michael@0 343 bool mScrollMessageHandledAsWheelMessage;
michael@0 344 int32_t mOverriddenVerticalScrollAmount;
michael@0 345 int32_t mOverriddenHorizontalScrollAmount;
michael@0 346 int32_t mMouseScrollTransactionTimeout;
michael@0 347 };
michael@0 348
michael@0 349 UserPrefs mUserPrefs;
michael@0 350
michael@0 351 class SynthesizingEvent {
michael@0 352 public:
michael@0 353 SynthesizingEvent() :
michael@0 354 mWnd(nullptr), mMessage(0), mWParam(0), mLParam(0),
michael@0 355 mStatus(NOT_SYNTHESIZING)
michael@0 356 {
michael@0 357 }
michael@0 358
michael@0 359 ~SynthesizingEvent() {}
michael@0 360
michael@0 361 static bool IsSynthesizing();
michael@0 362
michael@0 363 nsresult Synthesize(const POINTS& aCursorPoint, HWND aWnd,
michael@0 364 UINT aMessage, WPARAM aWParam, LPARAM aLParam,
michael@0 365 const BYTE (&aKeyStates)[256]);
michael@0 366
michael@0 367 void NativeMessageReceived(nsWindowBase* aWidget, UINT aMessage,
michael@0 368 WPARAM aWParam, LPARAM aLParam);
michael@0 369
michael@0 370 void NotifyNativeMessageHandlingFinished();
michael@0 371 void NotifyInternalMessageHandlingFinished();
michael@0 372
michael@0 373 const POINTS& GetCursorPoint() const { return mCursorPoint; }
michael@0 374
michael@0 375 private:
michael@0 376 POINTS mCursorPoint;
michael@0 377 HWND mWnd;
michael@0 378 UINT mMessage;
michael@0 379 WPARAM mWParam;
michael@0 380 LPARAM mLParam;
michael@0 381 BYTE mKeyState[256];
michael@0 382 BYTE mOriginalKeyState[256];
michael@0 383
michael@0 384 enum Status {
michael@0 385 NOT_SYNTHESIZING,
michael@0 386 SENDING_MESSAGE,
michael@0 387 NATIVE_MESSAGE_RECEIVED,
michael@0 388 INTERNAL_MESSAGE_POSTED,
michael@0 389 };
michael@0 390 Status mStatus;
michael@0 391
michael@0 392 #ifdef PR_LOGGING
michael@0 393 const char* GetStatusName()
michael@0 394 {
michael@0 395 switch (mStatus) {
michael@0 396 case NOT_SYNTHESIZING:
michael@0 397 return "NOT_SYNTHESIZING";
michael@0 398 case SENDING_MESSAGE:
michael@0 399 return "SENDING_MESSAGE";
michael@0 400 case NATIVE_MESSAGE_RECEIVED:
michael@0 401 return "NATIVE_MESSAGE_RECEIVED";
michael@0 402 case INTERNAL_MESSAGE_POSTED:
michael@0 403 return "INTERNAL_MESSAGE_POSTED";
michael@0 404 default:
michael@0 405 return "Unknown";
michael@0 406 }
michael@0 407 }
michael@0 408 #endif
michael@0 409
michael@0 410 void Finish();
michael@0 411 }; // SynthesizingEvent
michael@0 412
michael@0 413 SynthesizingEvent* mSynthesizingEvent;
michael@0 414
michael@0 415 public:
michael@0 416
michael@0 417 class Device {
michael@0 418 public:
michael@0 419 class Elantech {
michael@0 420 public:
michael@0 421 /**
michael@0 422 * GetDriverMajorVersion() returns the installed driver's major version.
michael@0 423 * If Elantech's driver was installed, returns 0.
michael@0 424 */
michael@0 425 static int32_t GetDriverMajorVersion();
michael@0 426
michael@0 427 /**
michael@0 428 * IsHelperWindow() checks whether aWnd is a helper window of Elantech's
michael@0 429 * touchpad. Returns TRUE if so. Otherwise, FALSE.
michael@0 430 */
michael@0 431 static bool IsHelperWindow(HWND aWnd);
michael@0 432
michael@0 433 /**
michael@0 434 * Key message handler for Elantech's hack. Returns TRUE if the message
michael@0 435 * is consumed by this handler. Otherwise, FALSE.
michael@0 436 */
michael@0 437 static bool HandleKeyMessage(nsWindowBase* aWidget,
michael@0 438 UINT aMsg,
michael@0 439 WPARAM aWParam);
michael@0 440
michael@0 441 static void UpdateZoomUntil();
michael@0 442 static bool IsZooming();
michael@0 443
michael@0 444 static void Init();
michael@0 445
michael@0 446 static bool IsPinchHackNeeded() { return sUsePinchHack; }
michael@0 447
michael@0 448
michael@0 449 private:
michael@0 450 // Whether to enable the Elantech swipe gesture hack.
michael@0 451 static bool sUseSwipeHack;
michael@0 452 // Whether to enable the Elantech pinch-to-zoom gesture hack.
michael@0 453 static bool sUsePinchHack;
michael@0 454 static DWORD sZoomUntil;
michael@0 455 }; // class Elantech
michael@0 456
michael@0 457 class TrackPoint {
michael@0 458 public:
michael@0 459 /**
michael@0 460 * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
michael@0 461 * Otherwise, returns FALSE.
michael@0 462 */
michael@0 463 static bool IsDriverInstalled();
michael@0 464 }; // class TrackPoint
michael@0 465
michael@0 466 class UltraNav {
michael@0 467 public:
michael@0 468 /**
michael@0 469 * IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
michael@0 470 * is installed on the environment.
michael@0 471 * Returns TRUE if it was installed. Otherwise, FALSE.
michael@0 472 */
michael@0 473 static bool IsObsoleteDriverInstalled();
michael@0 474 }; // class UltraNav
michael@0 475
michael@0 476 class SetPoint {
michael@0 477 public:
michael@0 478 /**
michael@0 479 * SetPoint, Logitech's mouse driver, may report wrong cursor position
michael@0 480 * for WM_MOUSEHWHEEL message. See comment in the implementation for
michael@0 481 * the detail.
michael@0 482 */
michael@0 483 static bool IsGetMessagePosResponseValid(UINT aMessage,
michael@0 484 WPARAM aWParam,
michael@0 485 LPARAM aLParam);
michael@0 486 private:
michael@0 487 static bool sMightBeUsing;
michael@0 488 };
michael@0 489
michael@0 490 static void Init();
michael@0 491
michael@0 492 static bool IsFakeScrollableWindowNeeded()
michael@0 493 {
michael@0 494 return sFakeScrollableWindowNeeded;
michael@0 495 }
michael@0 496
michael@0 497 private:
michael@0 498 /**
michael@0 499 * Gets the bool value of aPrefName used to enable or disable an input
michael@0 500 * workaround (like the Trackpoint hack). The pref can take values 0 (for
michael@0 501 * disabled), 1 (for enabled) or -1 (to automatically detect whether to
michael@0 502 * enable the workaround).
michael@0 503 *
michael@0 504 * @param aPrefName The name of the pref.
michael@0 505 * @param aValueIfAutomatic Whether the given input workaround should be
michael@0 506 * enabled by default.
michael@0 507 */
michael@0 508 static bool GetWorkaroundPref(const char* aPrefName,
michael@0 509 bool aValueIfAutomatic);
michael@0 510
michael@0 511 static bool sFakeScrollableWindowNeeded;
michael@0 512 }; // class Device
michael@0 513 };
michael@0 514
michael@0 515 } // namespace widget
michael@0 516 } // namespace mozilla
michael@0 517
michael@0 518 #endif // mozilla_widget_WinMouseScrollHandler_h__

mercurial