Bug 1931425 - Limit how often moz-label's #setStyles runs r=reusable-components-revie...
[gecko.git] / widget / windows / WinMouseScrollHandler.h
blob6cd499edb54e35f4be66cf5f2db36d9cf03bbad7
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__
10 #include "nscore.h"
11 #include "nsDebug.h"
12 #include "mozilla/Assertions.h"
13 #include "mozilla/EventForwards.h"
14 #include "mozilla/TimeStamp.h"
15 #include "Units.h"
16 #include <windows.h>
17 #include "nsPoint.h"
19 class nsWindow;
21 namespace mozilla {
22 namespace widget {
24 class ModifierKeyState;
26 struct MSGResult;
28 class MouseScrollHandler {
29 public:
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();
41 /**
42 * See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
43 * this method.
45 static nsresult SynthesizeNativeMouseScrollEvent(
46 nsWindow* aWidget, const LayoutDeviceIntPoint& aPoint,
47 uint32_t aNativeMessage, int32_t aDelta, uint32_t aModifierFlags,
48 uint32_t aAdditionalFlags);
50 /**
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;
59 private:
60 MouseScrollHandler();
61 ~MouseScrollHandler();
63 bool mIsWaitingInternalMessage;
65 static void MaybeLogKeyState();
67 static MouseScrollHandler* sInstance;
69 /**
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,
74 LPARAM* aPoint);
76 /**
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);
85 /**
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();
93 /**
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
103 * WM_HSCROLL.
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,
119 MSGResult& aResult);
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
125 * command event.
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,
148 LPARAM aLParam);
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);
200 class EventInfo {
201 public:
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;
222 protected:
223 EventInfo()
224 : mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr) {}
226 // TRUE if event is for vertical scroll. Otherwise, FALSE.
227 bool mIsVertical;
228 // TRUE if event scrolls per page, otherwise, FALSE.
229 bool mIsPage;
230 // The native delta value.
231 int32_t mDelta;
232 // The window handle which is handling the event.
233 HWND mWnd;
234 // Timestamp of the event.
235 TimeStamp mTimeStamp;
238 class LastEventInfo : public EventInfo {
239 public:
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
245 * returns true.
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
268 * initialized.
269 * @param aModKeyState Current modifier key state.
270 * @return TRUE if the event is ready to dispatch.
271 * Otherwise, FALSE.
273 bool InitWheelEvent(nsWindow* aWidget, WidgetWheelEvent& aWheelEvent,
274 const ModifierKeyState& aModKeyState, LPARAM aLParam);
276 private:
277 static int32_t RoundDelta(double aDelta);
279 int32_t mAccumulatedDelta;
282 LastEventInfo mLastEventInfo;
284 class SystemSettings {
285 public:
286 SystemSettings() : mInitialized(false) {}
288 void Init();
289 void MarkDirty();
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; }
315 private:
316 bool mInitialized;
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();
331 void RefreshCache();
334 SystemSettings mSystemSettings;
336 class UserPrefs {
337 public:
338 UserPrefs();
339 ~UserPrefs();
341 void MarkDirty();
343 bool IsScrollMessageHandledAsWheelMessage() {
344 Init();
345 return mScrollMessageHandledAsWheelMessage;
348 bool IsSystemSettingCacheEnabled() {
349 Init();
350 return mEnableSystemSettingCache;
353 bool IsSystemSettingCacheForciblyEnabled() {
354 Init();
355 return mForceEnableSystemSettingCache;
358 bool ShouldEmulateToMakeWindowUnderCursorForeground() {
359 Init();
360 return mEmulateToMakeWindowUnderCursorForeground;
363 int32_t GetOverriddenVerticalScrollAmout() {
364 Init();
365 return mOverriddenVerticalScrollAmount;
368 int32_t GetOverriddenHorizontalScrollAmout() {
369 Init();
370 return mOverriddenHorizontalScrollAmount;
373 int32_t GetMouseScrollTransactionTimeout() {
374 Init();
375 return mMouseScrollTransactionTimeout;
378 private:
379 void Init();
381 static void OnChange(const char* aPrefName, void* aSelf) {
382 static_cast<UserPrefs*>(aSelf)->MarkDirty();
385 bool mInitialized;
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();
402 public:
403 class Device {
404 public:
405 // SynTP is a touchpad driver of Synaptics.
406 class SynTP {
407 public:
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; }
420 static void Init();
422 private:
423 static bool sInitialized;
424 static int32_t sMajorVersion;
425 static int32_t sMinorVersion;
428 class Elantech {
429 public:
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,
447 LPARAM aLParam);
449 static void UpdateZoomUntil();
450 static bool IsZooming();
452 static void Init();
454 static bool IsPinchHackNeeded() { return sUsePinchHack; }
456 private:
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;
462 }; // class Elantech
464 // Apoint is a touchpad driver of Alps.
465 class Apoint {
466 public:
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; }
479 static void Init();
481 private:
482 static bool sInitialized;
483 static int32_t sMajorVersion;
484 static int32_t sMinorVersion;
487 class TrackPoint {
488 public:
490 * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
491 * Otherwise, returns FALSE.
493 static bool IsDriverInstalled();
494 }; // class TrackPoint
496 class UltraNav {
497 public:
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();
504 }; // class UltraNav
506 class SetPoint {
507 public:
509 * SetPoint, Logitech's mouse driver, may report wrong cursor position
510 * for WM_MOUSEHWHEEL message. See comment in the implementation for
511 * the detail.
513 static bool IsGetMessagePosResponseValid(UINT aMessage, WPARAM aWParam,
514 LPARAM aLParam);
516 private:
517 static bool sMightBeUsing;
520 static void Init();
522 static bool IsFakeScrollableWindowNeeded() {
523 return sFakeScrollableWindowNeeded;
526 private:
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;
541 }; // class Device
544 } // namespace widget
545 } // namespace mozilla
547 #endif // mozilla_widget_WinMouseScrollHandler_h__