1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef mozilla_widget_WinMouseScrollHandler_h__
8 #define mozilla_widget_WinMouseScrollHandler_h__
12 #include "mozilla/Assertions.h"
13 #include "mozilla/EventForwards.h"
14 #include "mozilla/TimeStamp.h"
23 class ModifierKeyState
;
27 class MouseScrollHandler
{
29 static MouseScrollHandler
* GetInstance();
31 static void Initialize();
32 static void Shutdown();
34 static bool NeedsMessage(UINT aMsg
);
35 static bool ProcessMessage(nsWindowBase
* aWidget
,
42 * See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
45 static nsresult
SynthesizeNativeMouseScrollEvent(nsWindowBase
* aWidget
,
46 const nsIntPoint
& aPoint
,
47 uint32_t aNativeMessage
,
49 uint32_t aModifierFlags
,
50 uint32_t aAdditionalFlags
);
53 * IsWaitingInternalMessage() returns true if MouseScrollHandler posted
54 * an internal message for a native mouse wheel message and has not
55 * received it. Otherwise, false.
57 static bool IsWaitingInternalMessage()
59 return sInstance
&& sInstance
->mIsWaitingInternalMessage
;
64 ~MouseScrollHandler();
66 bool mIsWaitingInternalMessage
;
68 static MouseScrollHandler
* sInstance
;
71 * DispatchEvent() dispatches aEvent on aWidget.
73 * @return TRUE if the event was consumed. Otherwise, FALSE.
75 static bool DispatchEvent(nsWindowBase
* aWidget
, WidgetGUIEvent
& aEvent
);
78 * InitEvent() initializes the aEvent. If aPoint is null, the result of
79 * GetCurrentMessagePos() will be used.
81 static void InitEvent(nsWindowBase
* aWidget
,
82 WidgetGUIEvent
& aEvent
,
83 nsIntPoint
* aPoint
= nullptr);
86 * GetModifierKeyState() returns current modifier key state.
87 * Note that some devices need some hack for the modifier key state.
88 * This method does it automatically.
90 * @param aMessage Handling message.
92 static ModifierKeyState
GetModifierKeyState(UINT aMessage
);
95 * MozGetMessagePos() returns the mouse cursor position when GetMessage()
96 * was called last time. However, if we're sending a native message,
97 * this returns the specified cursor position by
98 * SynthesizeNativeMouseScrollEvent().
100 static POINTS
GetCurrentMessagePos();
103 * ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and
104 * WM_MOUSEHWHEEL. Additionally, processes WM_VSCROLL and WM_HSCROLL if they
105 * should be processed as mouse wheel message.
106 * This method posts MOZ_WM_MOUSEVWHEEL, MOZ_WM_MOUSEHWHEEL,
107 * MOZ_WM_VSCROLL or MOZ_WM_HSCROLL if we need to dispatch mouse scroll
108 * events. That avoids deadlock with plugin process.
110 * @param aWidget A window which receives the message.
111 * @param aMessage WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or
113 * @param aWParam The wParam value of the message.
114 * @param aLParam The lParam value of the message.
116 void ProcessNativeMouseWheelMessage(nsWindowBase
* aWidget
,
122 * ProcessNativeScrollMessage() processes WM_VSCROLL and WM_HSCROLL.
123 * This method just call ProcessMouseWheelMessage() if the message should be
124 * processed as mouse wheel message. Otherwise, dispatches a content
127 * @param aWidget A window which receives the message.
128 * @param aMessage WM_VSCROLL or WM_HSCROLL.
129 * @param aWParam The wParam value of the message.
130 * @param aLParam The lParam value of the message.
131 * @return TRUE if the message is processed. Otherwise, FALSE.
133 bool ProcessNativeScrollMessage(nsWindowBase
* aWidget
,
139 * HandleMouseWheelMessage() processes MOZ_WM_MOUSEVWHEEL and
140 * MOZ_WM_MOUSEHWHEEL which are posted when one of our windows received
141 * WM_MOUSEWHEEL or WM_MOUSEHWHEEL for avoiding deadlock with OOPP.
143 * @param aWidget A window which receives the wheel message.
144 * @param aMessage MOZ_WM_MOUSEWHEEL or MOZ_WM_MOUSEHWHEEL.
145 * @param aWParam The wParam value of the original message.
146 * @param aLParam The lParam value of the original message.
148 void HandleMouseWheelMessage(nsWindowBase
* aWidget
,
154 * HandleScrollMessageAsMouseWheelMessage() processes the MOZ_WM_VSCROLL and
155 * MOZ_WM_HSCROLL which are posted when one of mouse windows received
156 * WM_VSCROLL or WM_HSCROLL and user wants them to emulate mouse wheel
157 * message's behavior.
159 * @param aWidget A window which receives the scroll message.
160 * @param aMessage MOZ_WM_VSCROLL or MOZ_WM_HSCROLL.
161 * @param aWParam The wParam value of the original message.
162 * @param aLParam The lParam value of the original message.
164 void HandleScrollMessageAsMouseWheelMessage(nsWindowBase
* aWidget
,
170 * ComputeMessagePos() computes the cursor position when the message was
171 * added to the queue.
173 * @param aMessage Handling message.
174 * @param aWParam Handling message's wParam.
175 * @param aLParam Handling message's lParam.
176 * @return Mouse cursor position when the message is added to
177 * the queue or current cursor position if the result of
178 * ::GetMessagePos() is broken.
180 POINT
ComputeMessagePos(UINT aMessage
,
187 * @param aWidget An nsWindow which is handling the event.
188 * @param aMessage Must be WM_MOUSEWHEEL or WM_MOUSEHWHEEL.
190 EventInfo(nsWindowBase
* aWidget
, UINT aMessage
, WPARAM aWParam
, LPARAM aLParam
);
192 bool CanDispatchWheelEvent() const;
194 int32_t GetNativeDelta() const { return mDelta
; }
195 HWND
GetWindowHandle() const { return mWnd
; }
196 const TimeStamp
& GetTimeStamp() const { return mTimeStamp
; }
197 bool IsVertical() const { return mIsVertical
; }
198 bool IsPositive() const { return (mDelta
> 0); }
199 bool IsPage() const { return mIsPage
; }
202 * @return Number of lines or pages scrolled per WHEEL_DELTA.
204 int32_t GetScrollAmount() const;
208 mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr)
212 // TRUE if event is for vertical scroll. Otherwise, FALSE.
214 // TRUE if event scrolls per page, otherwise, FALSE.
216 // The native delta value.
218 // The window handle which is handling the event.
220 // Timestamp of the event.
221 TimeStamp mTimeStamp
;
224 class LastEventInfo
: public EventInfo
{
227 EventInfo(), mAccumulatedDelta(0)
232 * CanContinueTransaction() checks whether the new event can continue the
233 * last transaction or not. Note that if there is no transaction, this
236 bool CanContinueTransaction(const EventInfo
& aNewEvent
);
239 * ResetTransaction() resets the transaction, i.e., the instance forgets
240 * the last event information.
242 void ResetTransaction();
245 * RecordEvent() saves the information of new event.
247 void RecordEvent(const EventInfo
& aEvent
);
250 * InitWheelEvent() initializes NS_WHEEL_WHEEL event and
251 * recomputes the remaning detla for the event.
252 * This must be called only once during handling a message and after
253 * RecordEvent() is called.
255 * @param aWidget A window which will dispatch the event.
256 * @param aWheelEvent An NS_WHEEL_WHEEL event, this will be
258 * @param aModKeyState Current modifier key state.
259 * @return TRUE if the event is ready to dispatch.
262 bool InitWheelEvent(nsWindowBase
* aWidget
,
263 WidgetWheelEvent
& aWheelEvent
,
264 const ModifierKeyState
& aModKeyState
);
267 static int32_t RoundDelta(double aDelta
);
269 int32_t mAccumulatedDelta
;
272 LastEventInfo mLastEventInfo
;
274 class SystemSettings
{
276 SystemSettings() : mInitialized(false) {}
280 void NotifyUserPrefsMayOverrideSystemSettings();
282 int32_t GetScrollAmount(bool aForVertical
) const
284 MOZ_ASSERT(mInitialized
, "SystemSettings must be initialized");
285 return aForVertical
? mScrollLines
: mScrollChars
;
288 bool IsPageScroll(bool aForVertical
) const
290 MOZ_ASSERT(mInitialized
, "SystemSettings must be initialized");
291 return aForVertical
? (mScrollLines
== WHEEL_PAGESCROLL
) :
292 (mScrollChars
== WHEEL_PAGESCROLL
);
297 int32_t mScrollLines
;
298 int32_t mScrollChars
;
301 SystemSettings mSystemSettings
;
310 bool IsScrollMessageHandledAsWheelMessage()
313 return mScrollMessageHandledAsWheelMessage
;
316 int32_t GetOverriddenVerticalScrollAmout()
319 return mOverriddenVerticalScrollAmount
;
322 int32_t GetOverriddenHorizontalScrollAmout()
325 return mOverriddenHorizontalScrollAmount
;
328 int32_t GetMouseScrollTransactionTimeout()
331 return mMouseScrollTransactionTimeout
;
337 static void OnChange(const char* aPrefName
, void* aClosure
)
339 static_cast<UserPrefs
*>(aClosure
)->MarkDirty();
343 bool mScrollMessageHandledAsWheelMessage
;
344 int32_t mOverriddenVerticalScrollAmount
;
345 int32_t mOverriddenHorizontalScrollAmount
;
346 int32_t mMouseScrollTransactionTimeout
;
349 UserPrefs mUserPrefs
;
351 class SynthesizingEvent
{
353 SynthesizingEvent() :
354 mWnd(nullptr), mMessage(0), mWParam(0), mLParam(0),
355 mStatus(NOT_SYNTHESIZING
)
359 ~SynthesizingEvent() {}
361 static bool IsSynthesizing();
363 nsresult
Synthesize(const POINTS
& aCursorPoint
, HWND aWnd
,
364 UINT aMessage
, WPARAM aWParam
, LPARAM aLParam
,
365 const BYTE (&aKeyStates
)[256]);
367 void NativeMessageReceived(nsWindowBase
* aWidget
, UINT aMessage
,
368 WPARAM aWParam
, LPARAM aLParam
);
370 void NotifyNativeMessageHandlingFinished();
371 void NotifyInternalMessageHandlingFinished();
373 const POINTS
& GetCursorPoint() const { return mCursorPoint
; }
382 BYTE mOriginalKeyState
[256];
387 NATIVE_MESSAGE_RECEIVED
,
388 INTERNAL_MESSAGE_POSTED
,
393 const char* GetStatusName()
396 case NOT_SYNTHESIZING
:
397 return "NOT_SYNTHESIZING";
398 case SENDING_MESSAGE
:
399 return "SENDING_MESSAGE";
400 case NATIVE_MESSAGE_RECEIVED
:
401 return "NATIVE_MESSAGE_RECEIVED";
402 case INTERNAL_MESSAGE_POSTED
:
403 return "INTERNAL_MESSAGE_POSTED";
411 }; // SynthesizingEvent
413 SynthesizingEvent
* mSynthesizingEvent
;
422 * GetDriverMajorVersion() returns the installed driver's major version.
423 * If Elantech's driver was installed, returns 0.
425 static int32_t GetDriverMajorVersion();
428 * IsHelperWindow() checks whether aWnd is a helper window of Elantech's
429 * touchpad. Returns TRUE if so. Otherwise, FALSE.
431 static bool IsHelperWindow(HWND aWnd
);
434 * Key message handler for Elantech's hack. Returns TRUE if the message
435 * is consumed by this handler. Otherwise, FALSE.
437 static bool HandleKeyMessage(nsWindowBase
* aWidget
,
441 static void UpdateZoomUntil();
442 static bool IsZooming();
446 static bool IsPinchHackNeeded() { return sUsePinchHack
; }
450 // Whether to enable the Elantech swipe gesture hack.
451 static bool sUseSwipeHack
;
452 // Whether to enable the Elantech pinch-to-zoom gesture hack.
453 static bool sUsePinchHack
;
454 static DWORD sZoomUntil
;
460 * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
461 * Otherwise, returns FALSE.
463 static bool IsDriverInstalled();
464 }; // class TrackPoint
469 * IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
470 * is installed on the environment.
471 * Returns TRUE if it was installed. Otherwise, FALSE.
473 static bool IsObsoleteDriverInstalled();
479 * SetPoint, Logitech's mouse driver, may report wrong cursor position
480 * for WM_MOUSEHWHEEL message. See comment in the implementation for
483 static bool IsGetMessagePosResponseValid(UINT aMessage
,
487 static bool sMightBeUsing
;
492 static bool IsFakeScrollableWindowNeeded()
494 return sFakeScrollableWindowNeeded
;
499 * Gets the bool value of aPrefName used to enable or disable an input
500 * workaround (like the Trackpoint hack). The pref can take values 0 (for
501 * disabled), 1 (for enabled) or -1 (to automatically detect whether to
502 * enable the workaround).
504 * @param aPrefName The name of the pref.
505 * @param aValueIfAutomatic Whether the given input workaround should be
506 * enabled by default.
508 static bool GetWorkaroundPref(const char* aPrefName
,
509 bool aValueIfAutomatic
);
511 static bool sFakeScrollableWindowNeeded
;
515 } // namespace widget
516 } // namespace mozilla
518 #endif // mozilla_widget_WinMouseScrollHandler_h__