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
);
40 * See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
43 static nsresult
SynthesizeNativeMouseScrollEvent(
44 nsWindow
* aWidget
, const LayoutDeviceIntPoint
& aPoint
,
45 uint32_t aNativeMessage
, int32_t aDelta
, uint32_t aModifierFlags
,
46 uint32_t aAdditionalFlags
);
49 * IsWaitingInternalMessage() returns true if MouseScrollHandler posted
50 * an internal message for a native mouse wheel message and has not
51 * received it. Otherwise, false.
53 static bool IsWaitingInternalMessage() {
54 return sInstance
&& sInstance
->mIsWaitingInternalMessage
;
59 ~MouseScrollHandler();
61 bool mIsWaitingInternalMessage
;
63 static void MaybeLogKeyState();
65 static MouseScrollHandler
* sInstance
;
68 * InitEvent() initializes the aEvent. If aPoint is null, the result of
69 * GetCurrentMessagePos() will be used.
71 static void InitEvent(nsWindow
* aWidget
, WidgetGUIEvent
& aEvent
,
75 * GetModifierKeyState() returns current modifier key state.
76 * Note that some devices need some hack for the modifier key state.
77 * This method does it automatically.
79 * @param aMessage Handling message.
81 static ModifierKeyState
GetModifierKeyState(UINT aMessage
);
84 * MozGetMessagePos() returns the mouse cursor position when GetMessage()
85 * was called last time. However, if we're sending a native message,
86 * this returns the specified cursor position by
87 * SynthesizeNativeMouseScrollEvent().
89 static POINTS
GetCurrentMessagePos();
92 * ProcessNativeMouseWheelMessage() processes WM_MOUSEWHEEL and
93 * WM_MOUSEHWHEEL. Additionally, processes WM_VSCROLL and WM_HSCROLL if they
94 * should be processed as mouse wheel message.
95 * This method posts MOZ_WM_MOUSEVWHEEL, MOZ_WM_MOUSEHWHEEL,
96 * MOZ_WM_VSCROLL or MOZ_WM_HSCROLL if we need to dispatch mouse scroll
97 * events. That avoids deadlock with plugin process.
99 * @param aWidget A window which receives the message.
100 * @param aMessage WM_MOUSEWHEEL, WM_MOUSEHWHEEL, WM_VSCROLL or
102 * @param aWParam The wParam value of the message.
103 * @param aLParam The lParam value of the message.
105 void ProcessNativeMouseWheelMessage(nsWindow
* aWidget
, UINT aMessage
,
106 WPARAM aWParam
, LPARAM aLParam
);
109 * ProcessNativeScrollMessage() processes WM_VSCROLL and WM_HSCROLL.
110 * This method just call ProcessMouseWheelMessage() if the message should be
111 * processed as mouse wheel message. Otherwise, dispatches a content
114 * @param aWidget A window which receives the message.
115 * @param aMessage WM_VSCROLL or WM_HSCROLL.
116 * @param aWParam The wParam value of the message.
117 * @param aLParam The lParam value of the message.
118 * @return TRUE if the message is processed. Otherwise, FALSE.
120 bool ProcessNativeScrollMessage(nsWindow
* aWidget
, UINT aMessage
,
121 WPARAM aWParam
, LPARAM aLParam
);
124 * HandleMouseWheelMessage() processes MOZ_WM_MOUSEVWHEEL and
125 * MOZ_WM_MOUSEHWHEEL which are posted when one of our windows received
126 * WM_MOUSEWHEEL or WM_MOUSEHWHEEL for avoiding deadlock with OOPP.
128 * @param aWidget A window which receives the wheel message.
129 * @param aMessage MOZ_WM_MOUSEWHEEL or MOZ_WM_MOUSEHWHEEL.
130 * @param aWParam The wParam value of the original message.
131 * @param aLParam The lParam value of the original message.
133 void HandleMouseWheelMessage(nsWindow
* aWidget
, UINT aMessage
, WPARAM aWParam
,
137 * HandleScrollMessageAsMouseWheelMessage() processes the MOZ_WM_VSCROLL and
138 * MOZ_WM_HSCROLL which are posted when one of mouse windows received
139 * WM_VSCROLL or WM_HSCROLL and user wants them to emulate mouse wheel
140 * message's behavior.
142 * @param aWidget A window which receives the scroll message.
143 * @param aMessage MOZ_WM_VSCROLL or MOZ_WM_HSCROLL.
144 * @param aWParam The wParam value of the original message.
145 * @param aLParam The lParam value of the original message.
147 void HandleScrollMessageAsMouseWheelMessage(nsWindow
* aWidget
, UINT aMessage
,
148 WPARAM aWParam
, LPARAM aLParam
);
151 * ComputeMessagePos() computes the cursor position when the message was
152 * added to the queue.
154 * @param aMessage Handling message.
155 * @param aWParam Handling message's wParam.
156 * @param aLParam Handling message's lParam.
157 * @return Mouse cursor position when the message is added to
158 * the queue or current cursor position if the result of
159 * ::GetMessagePos() is broken.
161 POINT
ComputeMessagePos(UINT aMessage
, WPARAM aWParam
, LPARAM aLParam
);
166 * @param aWidget An nsWindow which is handling the event.
167 * @param aMessage Must be WM_MOUSEWHEEL or WM_MOUSEHWHEEL.
169 EventInfo(nsWindow
* aWidget
, UINT aMessage
, WPARAM aWParam
, LPARAM aLParam
);
171 bool CanDispatchWheelEvent() const;
173 int32_t GetNativeDelta() const { return mDelta
; }
174 HWND
GetWindowHandle() const { return mWnd
; }
175 const TimeStamp
& GetTimeStamp() const { return mTimeStamp
; }
176 bool IsVertical() const { return mIsVertical
; }
177 bool IsPositive() const { return (mDelta
> 0); }
178 bool IsPage() const { return mIsPage
; }
181 * @return Number of lines or pages scrolled per WHEEL_DELTA.
183 int32_t GetScrollAmount() const;
187 : mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr) {}
189 // TRUE if event is for vertical scroll. Otherwise, FALSE.
191 // TRUE if event scrolls per page, otherwise, FALSE.
193 // The native delta value.
195 // The window handle which is handling the event.
197 // Timestamp of the event.
198 TimeStamp mTimeStamp
;
201 class LastEventInfo
: public EventInfo
{
203 LastEventInfo() : EventInfo(), mAccumulatedDelta(0) {}
206 * CanContinueTransaction() checks whether the new event can continue the
207 * last transaction or not. Note that if there is no transaction, this
210 bool CanContinueTransaction(const EventInfo
& aNewEvent
);
213 * ResetTransaction() resets the transaction, i.e., the instance forgets
214 * the last event information.
216 void ResetTransaction();
219 * RecordEvent() saves the information of new event.
221 void RecordEvent(const EventInfo
& aEvent
);
224 * InitWheelEvent() initializes NS_WHEEL_WHEEL event and
225 * recomputes the remaning detla for the event.
226 * This must be called only once during handling a message and after
227 * RecordEvent() is called.
229 * @param aWidget A window which will dispatch the event.
230 * @param aWheelEvent An NS_WHEEL_WHEEL event, this will be
232 * @param aModKeyState Current modifier key state.
233 * @return TRUE if the event is ready to dispatch.
236 bool InitWheelEvent(nsWindow
* aWidget
, WidgetWheelEvent
& aWheelEvent
,
237 const ModifierKeyState
& aModKeyState
, LPARAM aLParam
);
240 static int32_t RoundDelta(double aDelta
);
242 int32_t mAccumulatedDelta
;
245 LastEventInfo mLastEventInfo
;
247 class SystemSettings
{
249 SystemSettings() : mInitialized(false) {}
253 void NotifyUserPrefsMayOverrideSystemSettings();
255 // On some environments, SystemParametersInfo() may be hooked by touchpad
256 // utility or something. In such case, when user changes active pointing
257 // device to another one, the result of SystemParametersInfo() may be
258 // changed without WM_SETTINGCHANGE message. For avoiding this trouble,
259 // we need to modify cache of system settings at every wheel message
260 // handling if we meet known device whose utility may hook the API.
261 void TrustedScrollSettingsDriver();
263 // Returns true if the system scroll may be overridden for faster scroll.
264 // Otherwise, false. For example, if the user maybe uses an expensive
265 // mouse which supports acceleration of scroll speed, faster scroll makes
266 // the user inconvenient.
267 bool IsOverridingSystemScrollSpeedAllowed();
269 int32_t GetScrollAmount(bool aForVertical
) const {
270 MOZ_ASSERT(mInitialized
, "SystemSettings must be initialized");
271 return aForVertical
? mScrollLines
: mScrollChars
;
274 bool IsPageScroll(bool aForVertical
) const {
275 MOZ_ASSERT(mInitialized
, "SystemSettings must be initialized");
276 return aForVertical
? (uint32_t(mScrollLines
) == WHEEL_PAGESCROLL
)
277 : (uint32_t(mScrollChars
) == WHEEL_PAGESCROLL
);
280 // The default vertical and horizontal scrolling speed is 3, this is defined
281 // on the document of SystemParametersInfo in MSDN.
282 static int32_t DefaultScrollLines() { return 3; }
283 static int32_t DefaultScrollChars() { return 3; }
287 // The result of SystemParametersInfo() may not be reliable since it may
288 // be hooked. So, if the values are initialized with prefs, we can trust
289 // the value. Following mIsReliableScroll* are set true when mScroll* are
290 // initialized with prefs.
291 bool mIsReliableScrollLines
;
292 bool mIsReliableScrollChars
;
294 int32_t mScrollLines
;
295 int32_t mScrollChars
;
297 // Returns true if cached value is changed.
298 bool InitScrollLines();
299 bool InitScrollChars();
304 SystemSettings mSystemSettings
;
313 bool IsScrollMessageHandledAsWheelMessage() {
315 return mScrollMessageHandledAsWheelMessage
;
318 bool IsSystemSettingCacheEnabled() {
320 return mEnableSystemSettingCache
;
323 bool IsSystemSettingCacheForciblyEnabled() {
325 return mForceEnableSystemSettingCache
;
328 bool ShouldEmulateToMakeWindowUnderCursorForeground() {
330 return mEmulateToMakeWindowUnderCursorForeground
;
333 int32_t GetOverriddenVerticalScrollAmout() {
335 return mOverriddenVerticalScrollAmount
;
338 int32_t GetOverriddenHorizontalScrollAmout() {
340 return mOverriddenHorizontalScrollAmount
;
343 int32_t GetMouseScrollTransactionTimeout() {
345 return mMouseScrollTransactionTimeout
;
351 static void OnChange(const char* aPrefName
, void* aSelf
) {
352 static_cast<UserPrefs
*>(aSelf
)->MarkDirty();
356 bool mScrollMessageHandledAsWheelMessage
;
357 bool mEnableSystemSettingCache
;
358 bool mForceEnableSystemSettingCache
;
359 bool mEmulateToMakeWindowUnderCursorForeground
;
360 int32_t mOverriddenVerticalScrollAmount
;
361 int32_t mOverriddenHorizontalScrollAmount
;
362 int32_t mMouseScrollTransactionTimeout
;
365 UserPrefs mUserPrefs
;
367 class SynthesizingEvent
{
374 mStatus(NOT_SYNTHESIZING
) {}
376 ~SynthesizingEvent() {}
378 static bool IsSynthesizing();
380 nsresult
Synthesize(const POINTS
& aCursorPoint
, HWND aWnd
, UINT aMessage
,
381 WPARAM aWParam
, LPARAM aLParam
,
382 const BYTE (&aKeyStates
)[256]);
384 void NativeMessageReceived(nsWindow
* aWidget
, UINT aMessage
, WPARAM aWParam
,
387 void NotifyNativeMessageHandlingFinished();
388 void NotifyInternalMessageHandlingFinished();
390 const POINTS
& GetCursorPoint() const { return mCursorPoint
; }
399 BYTE mOriginalKeyState
[256];
404 NATIVE_MESSAGE_RECEIVED
,
405 INTERNAL_MESSAGE_POSTED
,
409 const char* GetStatusName() {
411 case NOT_SYNTHESIZING
:
412 return "NOT_SYNTHESIZING";
413 case SENDING_MESSAGE
:
414 return "SENDING_MESSAGE";
415 case NATIVE_MESSAGE_RECEIVED
:
416 return "NATIVE_MESSAGE_RECEIVED";
417 case INTERNAL_MESSAGE_POSTED
:
418 return "INTERNAL_MESSAGE_POSTED";
425 }; // SynthesizingEvent
427 SynthesizingEvent
* mSynthesizingEvent
;
432 // SynTP is a touchpad driver of Synaptics.
435 static bool IsDriverInstalled() { return sMajorVersion
!= 0; }
437 * GetDriverMajorVersion() returns the installed driver's major version.
438 * If SynTP driver isn't installed, this returns 0.
440 static int32_t GetDriverMajorVersion() { return sMajorVersion
; }
442 * GetDriverMinorVersion() returns the installed driver's minor version.
443 * If SynTP driver isn't installed, this returns -1.
445 static int32_t GetDriverMinorVersion() { return sMinorVersion
; }
450 static bool sInitialized
;
451 static int32_t sMajorVersion
;
452 static int32_t sMinorVersion
;
458 * GetDriverMajorVersion() returns the installed driver's major version.
459 * If Elantech's driver was installed, returns 0.
461 static int32_t GetDriverMajorVersion();
464 * IsHelperWindow() checks whether aWnd is a helper window of Elantech's
465 * touchpad. Returns TRUE if so. Otherwise, FALSE.
467 static bool IsHelperWindow(HWND aWnd
);
470 * Key message handler for Elantech's hack. Returns TRUE if the message
471 * is consumed by this handler. Otherwise, FALSE.
473 static bool HandleKeyMessage(nsWindow
* aWidget
, UINT aMsg
, WPARAM aWParam
,
476 static void UpdateZoomUntil();
477 static bool IsZooming();
481 static bool IsPinchHackNeeded() { return sUsePinchHack
; }
484 // Whether to enable the Elantech swipe gesture hack.
485 static bool sUseSwipeHack
;
486 // Whether to enable the Elantech pinch-to-zoom gesture hack.
487 static bool sUsePinchHack
;
488 static DWORD sZoomUntil
;
491 // Apoint is a touchpad driver of Alps.
494 static bool IsDriverInstalled() { return sMajorVersion
!= 0; }
496 * GetDriverMajorVersion() returns the installed driver's major version.
497 * If Apoint driver isn't installed, this returns 0.
499 static int32_t GetDriverMajorVersion() { return sMajorVersion
; }
501 * GetDriverMinorVersion() returns the installed driver's minor version.
502 * If Apoint driver isn't installed, this returns -1.
504 static int32_t GetDriverMinorVersion() { return sMinorVersion
; }
509 static bool sInitialized
;
510 static int32_t sMajorVersion
;
511 static int32_t sMinorVersion
;
517 * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
518 * Otherwise, returns FALSE.
520 static bool IsDriverInstalled();
521 }; // class TrackPoint
526 * IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
527 * is installed on the environment.
528 * Returns TRUE if it was installed. Otherwise, FALSE.
530 static bool IsObsoleteDriverInstalled();
536 * SetPoint, Logitech's mouse driver, may report wrong cursor position
537 * for WM_MOUSEHWHEEL message. See comment in the implementation for
540 static bool IsGetMessagePosResponseValid(UINT aMessage
, WPARAM aWParam
,
544 static bool sMightBeUsing
;
549 static bool IsFakeScrollableWindowNeeded() {
550 return sFakeScrollableWindowNeeded
;
555 * Gets the bool value of aPrefName used to enable or disable an input
556 * workaround (like the Trackpoint hack). The pref can take values 0 (for
557 * disabled), 1 (for enabled) or -1 (to automatically detect whether to
558 * enable the workaround).
560 * @param aPrefName The name of the pref.
561 * @param aValueIfAutomatic Whether the given input workaround should be
562 * enabled by default.
564 static bool GetWorkaroundPref(const char* aPrefName
,
565 bool aValueIfAutomatic
);
567 static bool sFakeScrollableWindowNeeded
;
571 } // namespace widget
572 } // namespace mozilla
574 #endif // mozilla_widget_WinMouseScrollHandler_h__