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 int32_t GetScrollAmount(bool aForVertical
) const {
264 MOZ_ASSERT(mInitialized
, "SystemSettings must be initialized");
265 return aForVertical
? mScrollLines
: mScrollChars
;
268 bool IsPageScroll(bool aForVertical
) const {
269 MOZ_ASSERT(mInitialized
, "SystemSettings must be initialized");
270 return aForVertical
? (uint32_t(mScrollLines
) == WHEEL_PAGESCROLL
)
271 : (uint32_t(mScrollChars
) == WHEEL_PAGESCROLL
);
274 // The default vertical and horizontal scrolling speed is 3, this is defined
275 // on the document of SystemParametersInfo in MSDN.
276 static int32_t DefaultScrollLines() { return 3; }
280 // The result of SystemParametersInfo() may not be reliable since it may
281 // be hooked. So, if the values are initialized with prefs, we can trust
282 // the value. Following mIsReliableScroll* are set true when mScroll* are
283 // initialized with prefs.
284 bool mIsReliableScrollLines
;
285 bool mIsReliableScrollChars
;
287 int32_t mScrollLines
;
288 int32_t mScrollChars
;
290 // Returns true if cached value is changed.
291 bool InitScrollLines();
292 bool InitScrollChars();
297 SystemSettings mSystemSettings
;
306 bool IsScrollMessageHandledAsWheelMessage() {
308 return mScrollMessageHandledAsWheelMessage
;
311 bool IsSystemSettingCacheEnabled() {
313 return mEnableSystemSettingCache
;
316 bool IsSystemSettingCacheForciblyEnabled() {
318 return mForceEnableSystemSettingCache
;
321 bool ShouldEmulateToMakeWindowUnderCursorForeground() {
323 return mEmulateToMakeWindowUnderCursorForeground
;
326 int32_t GetOverriddenVerticalScrollAmout() {
328 return mOverriddenVerticalScrollAmount
;
331 int32_t GetOverriddenHorizontalScrollAmout() {
333 return mOverriddenHorizontalScrollAmount
;
336 int32_t GetMouseScrollTransactionTimeout() {
338 return mMouseScrollTransactionTimeout
;
344 static void OnChange(const char* aPrefName
, void* aSelf
) {
345 static_cast<UserPrefs
*>(aSelf
)->MarkDirty();
349 bool mScrollMessageHandledAsWheelMessage
;
350 bool mEnableSystemSettingCache
;
351 bool mForceEnableSystemSettingCache
;
352 bool mEmulateToMakeWindowUnderCursorForeground
;
353 int32_t mOverriddenVerticalScrollAmount
;
354 int32_t mOverriddenHorizontalScrollAmount
;
355 int32_t mMouseScrollTransactionTimeout
;
358 UserPrefs mUserPrefs
;
360 class SynthesizingEvent
{
367 mStatus(NOT_SYNTHESIZING
) {}
369 ~SynthesizingEvent() {}
371 static bool IsSynthesizing();
373 nsresult
Synthesize(const POINTS
& aCursorPoint
, HWND aWnd
, UINT aMessage
,
374 WPARAM aWParam
, LPARAM aLParam
,
375 const BYTE (&aKeyStates
)[256]);
377 void NativeMessageReceived(nsWindow
* aWidget
, UINT aMessage
, WPARAM aWParam
,
380 void NotifyNativeMessageHandlingFinished();
381 void NotifyInternalMessageHandlingFinished();
383 const POINTS
& GetCursorPoint() const { return mCursorPoint
; }
392 BYTE mOriginalKeyState
[256];
397 NATIVE_MESSAGE_RECEIVED
,
398 INTERNAL_MESSAGE_POSTED
,
402 const char* GetStatusName() {
404 case NOT_SYNTHESIZING
:
405 return "NOT_SYNTHESIZING";
406 case SENDING_MESSAGE
:
407 return "SENDING_MESSAGE";
408 case NATIVE_MESSAGE_RECEIVED
:
409 return "NATIVE_MESSAGE_RECEIVED";
410 case INTERNAL_MESSAGE_POSTED
:
411 return "INTERNAL_MESSAGE_POSTED";
418 }; // SynthesizingEvent
420 SynthesizingEvent
* mSynthesizingEvent
;
425 // SynTP is a touchpad driver of Synaptics.
428 static bool IsDriverInstalled() { return sMajorVersion
!= 0; }
430 * GetDriverMajorVersion() returns the installed driver's major version.
431 * If SynTP driver isn't installed, this returns 0.
433 static int32_t GetDriverMajorVersion() { return sMajorVersion
; }
435 * GetDriverMinorVersion() returns the installed driver's minor version.
436 * If SynTP driver isn't installed, this returns -1.
438 static int32_t GetDriverMinorVersion() { return sMinorVersion
; }
443 static bool sInitialized
;
444 static int32_t sMajorVersion
;
445 static int32_t sMinorVersion
;
451 * GetDriverMajorVersion() returns the installed driver's major version.
452 * If Elantech's driver was installed, returns 0.
454 static int32_t GetDriverMajorVersion();
457 * IsHelperWindow() checks whether aWnd is a helper window of Elantech's
458 * touchpad. Returns TRUE if so. Otherwise, FALSE.
460 static bool IsHelperWindow(HWND aWnd
);
463 * Key message handler for Elantech's hack. Returns TRUE if the message
464 * is consumed by this handler. Otherwise, FALSE.
466 static bool HandleKeyMessage(nsWindow
* aWidget
, UINT aMsg
, WPARAM aWParam
,
469 static void UpdateZoomUntil();
470 static bool IsZooming();
474 static bool IsPinchHackNeeded() { return sUsePinchHack
; }
477 // Whether to enable the Elantech swipe gesture hack.
478 static bool sUseSwipeHack
;
479 // Whether to enable the Elantech pinch-to-zoom gesture hack.
480 static bool sUsePinchHack
;
481 static DWORD sZoomUntil
;
484 // Apoint is a touchpad driver of Alps.
487 static bool IsDriverInstalled() { return sMajorVersion
!= 0; }
489 * GetDriverMajorVersion() returns the installed driver's major version.
490 * If Apoint driver isn't installed, this returns 0.
492 static int32_t GetDriverMajorVersion() { return sMajorVersion
; }
494 * GetDriverMinorVersion() returns the installed driver's minor version.
495 * If Apoint driver isn't installed, this returns -1.
497 static int32_t GetDriverMinorVersion() { return sMinorVersion
; }
502 static bool sInitialized
;
503 static int32_t sMajorVersion
;
504 static int32_t sMinorVersion
;
510 * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
511 * Otherwise, returns FALSE.
513 static bool IsDriverInstalled();
514 }; // class TrackPoint
519 * IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
520 * is installed on the environment.
521 * Returns TRUE if it was installed. Otherwise, FALSE.
523 static bool IsObsoleteDriverInstalled();
529 * SetPoint, Logitech's mouse driver, may report wrong cursor position
530 * for WM_MOUSEHWHEEL message. See comment in the implementation for
533 static bool IsGetMessagePosResponseValid(UINT aMessage
, WPARAM aWParam
,
537 static bool sMightBeUsing
;
542 static bool IsFakeScrollableWindowNeeded() {
543 return sFakeScrollableWindowNeeded
;
548 * Gets the bool value of aPrefName used to enable or disable an input
549 * workaround (like the Trackpoint hack). The pref can take values 0 (for
550 * disabled), 1 (for enabled) or -1 (to automatically detect whether to
551 * enable the workaround).
553 * @param aPrefName The name of the pref.
554 * @param aValueIfAutomatic Whether the given input workaround should be
555 * enabled by default.
557 static bool GetWorkaroundPref(const char* aPrefName
,
558 bool aValueIfAutomatic
);
560 static bool sFakeScrollableWindowNeeded
;
564 } // namespace widget
565 } // namespace mozilla
567 #endif // mozilla_widget_WinMouseScrollHandler_h__