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"
24 class ModifierKeyState
;
28 class MouseScrollHandler
{
30 static MouseScrollHandler
* GetInstance();
32 static void Initialize();
33 static void Shutdown();
35 static bool NeedsMessage(UINT aMsg
);
36 static bool ProcessMessage(nsWindow
* aWidget
, UINT msg
, WPARAM wParam
,
37 LPARAM lParam
, MSGResult
& aResult
);
39 static bool SkipScrollWheelHack();
42 * See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
45 static nsresult
SynthesizeNativeMouseScrollEvent(
46 nsWindow
* aWidget
, const LayoutDeviceIntPoint
& aPoint
,
47 uint32_t aNativeMessage
, int32_t aDelta
, uint32_t aModifierFlags
,
48 uint32_t aAdditionalFlags
);
51 * IsWaitingInternalMessage() returns true if MouseScrollHandler posted
52 * an internal message for a native mouse wheel message and has not
53 * received it. Otherwise, false.
55 static bool IsWaitingInternalMessage() {
56 return sInstance
&& sInstance
->mIsWaitingInternalMessage
;
61 ~MouseScrollHandler();
63 bool mIsWaitingInternalMessage
;
65 static void MaybeLogKeyState();
67 static MouseScrollHandler
* sInstance
;
70 * InitEvent() initializes the aEvent. If aPoint is null, the result of
71 * GetCurrentMessagePos() will be used.
73 static void InitEvent(nsWindow
* aWidget
, WidgetGUIEvent
& aEvent
,
77 * GetModifierKeyState() returns current modifier key state.
78 * Note that some devices need some hack for the modifier key state.
79 * This method does it automatically.
81 * @param aMessage Handling message.
83 static ModifierKeyState
GetModifierKeyState(UINT aMessage
);
86 * MozGetMessagePos() returns the mouse cursor position when GetMessage()
87 * was called last time. However, if we're sending a native message,
88 * this returns the specified cursor position by
89 * SynthesizeNativeMouseScrollEvent().
91 static POINTS
GetCurrentMessagePos();
94 * ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and
95 * WM_MOUSEHWHEEL. Additionally, processes WM_VSCROLL and WM_HSCROLL if they
96 * should be processed as mouse wheel message.
97 * This method posts MOZ_WM_MOUSEVWHEEL, MOZ_WM_MOUSEHWHEEL,
98 * MOZ_WM_VSCROLL or MOZ_WM_HSCROLL if we need to dispatch mouse scroll
99 * events. That avoids deadlock with plugin process.
101 * @param aWidget A window which receives the message.
102 * @param aMessage WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or
104 * @param aWParam The wParam value of the message.
105 * @param aLParam The lParam value of the message.
107 void ProcessNativeMouseWheelMessage(nsWindow
* aWidget
, UINT aMessage
,
108 WPARAM aWParam
, LPARAM aLParam
);
111 * ProcessMessageDirectly() processes WM_MOUSEWHEEL, WM_MOUSEHWHEEL,
112 * WM_VSCROLL, and WM_HSCROLL without posting a MOZ_WM_* message.
114 * @param aMessage WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or WM_HSCROLL.
115 * @param aWParam The wParam value of the message.
116 * @param aLParam The lParam value of the message.
118 bool ProcessMessageDirectly(UINT msg
, WPARAM wParam
, LPARAM lParam
,
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(nsWindow
* aWidget
, UINT aMessage
,
134 WPARAM aWParam
, LPARAM aLParam
);
137 * HandleMouseWheelMessage() processes MOZ_WM_MOUSEVWHEEL and
138 * MOZ_WM_MOUSEHWHEEL which are posted when one of our windows received
139 * WM_MOUSEWHEEL or WM_MOUSEHWHEEL for avoiding deadlock with OOPP.
141 * @param aWidget A window which receives the wheel message.
142 * @param aMessage MOZ_WM_MOUSEWHEEL or MOZ_WM_MOUSEHWHEEL.
143 * @param aWParam The wParam value of the original message.
144 * @param aLParam The lParam value of the original message.
145 * @return TRUE if the message is processed. Otherwise, FALSE.
147 bool HandleMouseWheelMessage(nsWindow
* aWidget
, UINT aMessage
, WPARAM aWParam
,
151 * HandleScrollMessageAsMouseWheelMessage() processes the MOZ_WM_VSCROLL and
152 * MOZ_WM_HSCROLL which are posted when one of mouse windows received
153 * WM_VSCROLL or WM_HSCROLL and user wants them to emulate mouse wheel
154 * message's behavior.
156 * @param aWidget A window which receives the scroll message.
157 * @param aMessage MOZ_WM_VSCROLL or MOZ_WM_HSCROLL.
158 * @param aWParam The wParam value of the original message.
159 * @param aLParam The lParam value of the original message.
160 * @return TRUE if the message is processed. Otherwise, FALSE.
162 bool HandleScrollMessageAsMouseWheelMessage(nsWindow
* aWidget
, UINT aMessage
,
163 WPARAM aWParam
, LPARAM aLParam
);
166 * HandleScrollMessageAsScrollMessage() processes the MOZ_WM_VSCROLL and
167 * MOZ_WM_HSCROLL which are posted when one of mouse windows received
168 * WM_VSCROLL or WM_HSCROLL and user does _not_ want them to emulate mouse
169 * wheel message's behavior.
171 bool HandleScrollMessageAsItself(nsWindow
* aWidget
, UINT aMessage
,
172 WPARAM aWParam
, LPARAM aLParam
);
175 * ComputeMessagePos() computes the cursor position when the message was
176 * added to the queue.
178 * @param aMessage Current message.
179 * @param aWParam Current message's wParam.
180 * @param aLParam Current message's lParam.
181 * @return Mouse cursor position when the message is added to
182 * the queue or current cursor position if the result of
183 * ::GetMessagePos() is broken.
185 POINT
ComputeMessagePos(UINT aMessage
, WPARAM aWParam
, LPARAM aLParam
);
188 * FindTargetWindow() finds the nsWindow which needs to process the current
189 * scroll event. (This is the window underneath the cursor -- which is not
190 * necessarily the window whose event queue it came in on!)
192 * @param aMessage Current message.
193 * @param aWParam Current message's wParam.
194 * @param aLParam Current message's lParam.
195 * @return The relevant nsWindow, or nullptr if no appropriate
196 * window could be identified.
198 nsWindow
* FindTargetWindow(UINT aMessage
, WPARAM aWParam
, LPARAM aLParam
);
203 * @param aWidget An nsWindow which is handling the event.
204 * @param aMessage Must be WM_MOUSEWHEEL or WM_MOUSEHWHEEL.
206 EventInfo(nsWindow
* aWidget
, UINT aMessage
, WPARAM aWParam
, LPARAM aLParam
);
208 bool CanDispatchWheelEvent() const;
210 int32_t GetNativeDelta() const { return mDelta
; }
211 HWND
GetWindowHandle() const { return mWnd
; }
212 const TimeStamp
& GetTimeStamp() const { return mTimeStamp
; }
213 bool IsVertical() const { return mIsVertical
; }
214 bool IsPositive() const { return (mDelta
> 0); }
215 bool IsPage() const { return mIsPage
; }
218 * @return Number of lines or pages scrolled per WHEEL_DELTA.
220 int32_t GetScrollAmount() const;
224 : mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr) {}
226 // TRUE if event is for vertical scroll. Otherwise, FALSE.
228 // TRUE if event scrolls per page, otherwise, FALSE.
230 // The native delta value.
232 // The window handle which is handling the event.
234 // Timestamp of the event.
235 TimeStamp mTimeStamp
;
238 class LastEventInfo
: public EventInfo
{
240 LastEventInfo() : EventInfo(), mAccumulatedDelta(0) {}
243 * CanContinueTransaction() checks whether the new event can continue the
244 * last transaction or not. Note that if there is no transaction, this
247 bool CanContinueTransaction(const EventInfo
& aNewEvent
);
250 * ResetTransaction() resets the transaction, i.e., the instance forgets
251 * the last event information.
253 void ResetTransaction();
256 * RecordEvent() saves the information of new event.
258 void RecordEvent(const EventInfo
& aEvent
);
261 * InitWheelEvent() initializes NS_WHEEL_WHEEL event and
262 * recomputes the remaning detla for the event.
263 * This must be called only once during handling a message and after
264 * RecordEvent() is called.
266 * @param aWidget A window which will dispatch the event.
267 * @param aWheelEvent An NS_WHEEL_WHEEL event, this will be
269 * @param aModKeyState Current modifier key state.
270 * @return TRUE if the event is ready to dispatch.
273 bool InitWheelEvent(nsWindow
* aWidget
, WidgetWheelEvent
& aWheelEvent
,
274 const ModifierKeyState
& aModKeyState
, LPARAM aLParam
);
277 static int32_t RoundDelta(double aDelta
);
279 int32_t mAccumulatedDelta
;
282 LastEventInfo mLastEventInfo
;
284 class SystemSettings
{
286 SystemSettings() : mInitialized(false) {}
290 void NotifyUserPrefsMayOverrideSystemSettings();
292 // On some environments, SystemParametersInfo() may be hooked by touchpad
293 // utility or something. In such case, when user changes active pointing
294 // device to another one, the result of SystemParametersInfo() may be
295 // changed without WM_SETTINGCHANGE message. For avoiding this trouble,
296 // we need to modify cache of system settings at every wheel message
297 // handling if we meet known device whose utility may hook the API.
298 void TrustedScrollSettingsDriver();
300 int32_t GetScrollAmount(bool aForVertical
) const {
301 MOZ_ASSERT(mInitialized
, "SystemSettings must be initialized");
302 return aForVertical
? mScrollLines
: mScrollChars
;
305 bool IsPageScroll(bool aForVertical
) const {
306 MOZ_ASSERT(mInitialized
, "SystemSettings must be initialized");
307 return aForVertical
? (uint32_t(mScrollLines
) == WHEEL_PAGESCROLL
)
308 : (uint32_t(mScrollChars
) == WHEEL_PAGESCROLL
);
311 // The default vertical and horizontal scrolling speed is 3, this is defined
312 // on the document of SystemParametersInfo in MSDN.
313 static int32_t DefaultScrollLines() { return 3; }
317 // The result of SystemParametersInfo() may not be reliable since it may
318 // be hooked. So, if the values are initialized with prefs, we can trust
319 // the value. Following mIsReliableScroll* are set true when mScroll* are
320 // initialized with prefs.
321 bool mIsReliableScrollLines
;
322 bool mIsReliableScrollChars
;
324 int32_t mScrollLines
;
325 int32_t mScrollChars
;
327 // Returns true if cached value is changed.
328 bool InitScrollLines();
329 bool InitScrollChars();
334 SystemSettings mSystemSettings
;
343 bool IsScrollMessageHandledAsWheelMessage() {
345 return mScrollMessageHandledAsWheelMessage
;
348 bool IsSystemSettingCacheEnabled() {
350 return mEnableSystemSettingCache
;
353 bool IsSystemSettingCacheForciblyEnabled() {
355 return mForceEnableSystemSettingCache
;
358 bool ShouldEmulateToMakeWindowUnderCursorForeground() {
360 return mEmulateToMakeWindowUnderCursorForeground
;
363 int32_t GetOverriddenVerticalScrollAmout() {
365 return mOverriddenVerticalScrollAmount
;
368 int32_t GetOverriddenHorizontalScrollAmout() {
370 return mOverriddenHorizontalScrollAmount
;
373 int32_t GetMouseScrollTransactionTimeout() {
375 return mMouseScrollTransactionTimeout
;
381 static void OnChange(const char* aPrefName
, void* aSelf
) {
382 static_cast<UserPrefs
*>(aSelf
)->MarkDirty();
386 bool mScrollMessageHandledAsWheelMessage
;
387 bool mEnableSystemSettingCache
;
388 bool mForceEnableSystemSettingCache
;
389 bool mEmulateToMakeWindowUnderCursorForeground
;
390 int32_t mOverriddenVerticalScrollAmount
;
391 int32_t mOverriddenHorizontalScrollAmount
;
392 int32_t mMouseScrollTransactionTimeout
;
395 UserPrefs mUserPrefs
;
397 // only used in tests
398 class SynthesizingEvent
;
399 UniquePtr
<SynthesizingEvent
> mSynthesizingEvent
;
400 static SynthesizingEvent
* GetActiveSynthEvent();
405 // SynTP is a touchpad driver of Synaptics.
408 static bool IsDriverInstalled() { return sMajorVersion
!= 0; }
410 * GetDriverMajorVersion() returns the installed driver's major version.
411 * If SynTP driver isn't installed, this returns 0.
413 static int32_t GetDriverMajorVersion() { return sMajorVersion
; }
415 * GetDriverMinorVersion() returns the installed driver's minor version.
416 * If SynTP driver isn't installed, this returns -1.
418 static int32_t GetDriverMinorVersion() { return sMinorVersion
; }
423 static bool sInitialized
;
424 static int32_t sMajorVersion
;
425 static int32_t sMinorVersion
;
431 * GetDriverMajorVersion() returns the installed driver's major version.
432 * If Elantech's driver was installed, returns 0.
434 static int32_t GetDriverMajorVersion();
437 * IsHelperWindow() checks whether aWnd is a helper window of Elantech's
438 * touchpad. Returns TRUE if so. Otherwise, FALSE.
440 static bool IsHelperWindow(HWND aWnd
);
443 * Key message handler for Elantech's hack. Returns TRUE if the message
444 * is consumed by this handler. Otherwise, FALSE.
446 static bool HandleKeyMessage(nsWindow
* aWidget
, UINT aMsg
, WPARAM aWParam
,
449 static void UpdateZoomUntil();
450 static bool IsZooming();
454 static bool IsPinchHackNeeded() { return sUsePinchHack
; }
457 // Whether to enable the Elantech swipe gesture hack.
458 static bool sUseSwipeHack
;
459 // Whether to enable the Elantech pinch-to-zoom gesture hack.
460 static bool sUsePinchHack
;
461 static DWORD sZoomUntil
;
464 // Apoint is a touchpad driver of Alps.
467 static bool IsDriverInstalled() { return sMajorVersion
!= 0; }
469 * GetDriverMajorVersion() returns the installed driver's major version.
470 * If Apoint driver isn't installed, this returns 0.
472 static int32_t GetDriverMajorVersion() { return sMajorVersion
; }
474 * GetDriverMinorVersion() returns the installed driver's minor version.
475 * If Apoint driver isn't installed, this returns -1.
477 static int32_t GetDriverMinorVersion() { return sMinorVersion
; }
482 static bool sInitialized
;
483 static int32_t sMajorVersion
;
484 static int32_t sMinorVersion
;
490 * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
491 * Otherwise, returns FALSE.
493 static bool IsDriverInstalled();
494 }; // class TrackPoint
499 * IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
500 * is installed on the environment.
501 * Returns TRUE if it was installed. Otherwise, FALSE.
503 static bool IsObsoleteDriverInstalled();
509 * SetPoint, Logitech's mouse driver, may report wrong cursor position
510 * for WM_MOUSEHWHEEL message. See comment in the implementation for
513 static bool IsGetMessagePosResponseValid(UINT aMessage
, WPARAM aWParam
,
517 static bool sMightBeUsing
;
522 static bool IsFakeScrollableWindowNeeded() {
523 return sFakeScrollableWindowNeeded
;
528 * Gets the bool value of aPrefName used to enable or disable an input
529 * workaround (like the Trackpoint hack). The pref can take values 0 (for
530 * disabled), 1 (for enabled) or -1 (to automatically detect whether to
531 * enable the workaround).
533 * @param aPrefName The name of the pref.
534 * @param aValueIfAutomatic Whether the given input workaround should be
535 * enabled by default.
537 static bool GetWorkaroundPref(const char* aPrefName
,
538 bool aValueIfAutomatic
);
540 static bool sFakeScrollableWindowNeeded
;
544 } // namespace widget
545 } // namespace mozilla
547 #endif // mozilla_widget_WinMouseScrollHandler_h__