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 int OnChange(const char* aPrefName
, void* aClosure
)
339 static_cast<UserPrefs
*>(aClosure
)->MarkDirty();
344 bool mScrollMessageHandledAsWheelMessage
;
345 int32_t mOverriddenVerticalScrollAmount
;
346 int32_t mOverriddenHorizontalScrollAmount
;
347 int32_t mMouseScrollTransactionTimeout
;
350 UserPrefs mUserPrefs
;
352 class SynthesizingEvent
{
354 SynthesizingEvent() :
355 mWnd(nullptr), mMessage(0), mWParam(0), mLParam(0),
356 mStatus(NOT_SYNTHESIZING
)
360 ~SynthesizingEvent() {}
362 static bool IsSynthesizing();
364 nsresult
Synthesize(const POINTS
& aCursorPoint
, HWND aWnd
,
365 UINT aMessage
, WPARAM aWParam
, LPARAM aLParam
,
366 const BYTE (&aKeyStates
)[256]);
368 void NativeMessageReceived(nsWindowBase
* aWidget
, UINT aMessage
,
369 WPARAM aWParam
, LPARAM aLParam
);
371 void NotifyNativeMessageHandlingFinished();
372 void NotifyInternalMessageHandlingFinished();
374 const POINTS
& GetCursorPoint() const { return mCursorPoint
; }
383 BYTE mOriginalKeyState
[256];
388 NATIVE_MESSAGE_RECEIVED
,
389 INTERNAL_MESSAGE_POSTED
,
394 const char* GetStatusName()
397 case NOT_SYNTHESIZING
:
398 return "NOT_SYNTHESIZING";
399 case SENDING_MESSAGE
:
400 return "SENDING_MESSAGE";
401 case NATIVE_MESSAGE_RECEIVED
:
402 return "NATIVE_MESSAGE_RECEIVED";
403 case INTERNAL_MESSAGE_POSTED
:
404 return "INTERNAL_MESSAGE_POSTED";
412 }; // SynthesizingEvent
414 SynthesizingEvent
* mSynthesizingEvent
;
423 * GetDriverMajorVersion() returns the installed driver's major version.
424 * If Elantech's driver was installed, returns 0.
426 static int32_t GetDriverMajorVersion();
429 * IsHelperWindow() checks whether aWnd is a helper window of Elantech's
430 * touchpad. Returns TRUE if so. Otherwise, FALSE.
432 static bool IsHelperWindow(HWND aWnd
);
435 * Key message handler for Elantech's hack. Returns TRUE if the message
436 * is consumed by this handler. Otherwise, FALSE.
438 static bool HandleKeyMessage(nsWindowBase
* aWidget
,
442 static void UpdateZoomUntil();
443 static bool IsZooming();
447 static bool IsPinchHackNeeded() { return sUsePinchHack
; }
451 // Whether to enable the Elantech swipe gesture hack.
452 static bool sUseSwipeHack
;
453 // Whether to enable the Elantech pinch-to-zoom gesture hack.
454 static bool sUsePinchHack
;
455 static DWORD sZoomUntil
;
461 * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
462 * Otherwise, returns FALSE.
464 static bool IsDriverInstalled();
465 }; // class TrackPoint
470 * IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
471 * is installed on the environment.
472 * Returns TRUE if it was installed. Otherwise, FALSE.
474 static bool IsObsoleteDriverInstalled();
480 * SetPoint, Logitech's mouse driver, may report wrong cursor position
481 * for WM_MOUSEHWHEEL message. See comment in the implementation for
484 static bool IsGetMessagePosResponseValid(UINT aMessage
,
488 static bool sMightBeUsing
;
493 static bool IsFakeScrollableWindowNeeded()
495 return sFakeScrollableWindowNeeded
;
500 * Gets the bool value of aPrefName used to enable or disable an input
501 * workaround (like the Trackpoint hack). The pref can take values 0 (for
502 * disabled), 1 (for enabled) or -1 (to automatically detect whether to
503 * enable the workaround).
505 * @param aPrefName The name of the pref.
506 * @param aValueIfAutomatic Whether the given input workaround should be
507 * enabled by default.
509 static bool GetWorkaroundPref(const char* aPrefName
,
510 bool aValueIfAutomatic
);
512 static bool sFakeScrollableWindowNeeded
;
516 } // namespace widget
517 } // namespace mozilla
519 #endif // mozilla_widget_WinMouseScrollHandler_h__