Bug 1882714 [wpt PR 44850] - Update wpt metadata, a=testonly
[gecko.git] / widget / windows / WinMouseScrollHandler.h
blobecf6c3df44a82816640b49d2967a9f5e7337841e
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 /**
40 * See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
41 * this method.
43 static nsresult SynthesizeNativeMouseScrollEvent(
44 nsWindow* aWidget, const LayoutDeviceIntPoint& aPoint,
45 uint32_t aNativeMessage, int32_t aDelta, uint32_t aModifierFlags,
46 uint32_t aAdditionalFlags);
48 /**
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;
57 private:
58 MouseScrollHandler();
59 ~MouseScrollHandler();
61 bool mIsWaitingInternalMessage;
63 static void MaybeLogKeyState();
65 static MouseScrollHandler* sInstance;
67 /**
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,
72 LPARAM* aPoint);
74 /**
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);
83 /**
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();
91 /**
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
101 * WM_HSCROLL.
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
112 * command event.
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,
134 LPARAM aLParam);
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);
163 class EventInfo {
164 public:
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;
185 protected:
186 EventInfo()
187 : mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr) {}
189 // TRUE if event is for vertical scroll. Otherwise, FALSE.
190 bool mIsVertical;
191 // TRUE if event scrolls per page, otherwise, FALSE.
192 bool mIsPage;
193 // The native delta value.
194 int32_t mDelta;
195 // The window handle which is handling the event.
196 HWND mWnd;
197 // Timestamp of the event.
198 TimeStamp mTimeStamp;
201 class LastEventInfo : public EventInfo {
202 public:
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
208 * returns true.
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
231 * initialized.
232 * @param aModKeyState Current modifier key state.
233 * @return TRUE if the event is ready to dispatch.
234 * Otherwise, FALSE.
236 bool InitWheelEvent(nsWindow* aWidget, WidgetWheelEvent& aWheelEvent,
237 const ModifierKeyState& aModKeyState, LPARAM aLParam);
239 private:
240 static int32_t RoundDelta(double aDelta);
242 int32_t mAccumulatedDelta;
245 LastEventInfo mLastEventInfo;
247 class SystemSettings {
248 public:
249 SystemSettings() : mInitialized(false) {}
251 void Init();
252 void MarkDirty();
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; }
278 private:
279 bool mInitialized;
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();
294 void RefreshCache();
297 SystemSettings mSystemSettings;
299 class UserPrefs {
300 public:
301 UserPrefs();
302 ~UserPrefs();
304 void MarkDirty();
306 bool IsScrollMessageHandledAsWheelMessage() {
307 Init();
308 return mScrollMessageHandledAsWheelMessage;
311 bool IsSystemSettingCacheEnabled() {
312 Init();
313 return mEnableSystemSettingCache;
316 bool IsSystemSettingCacheForciblyEnabled() {
317 Init();
318 return mForceEnableSystemSettingCache;
321 bool ShouldEmulateToMakeWindowUnderCursorForeground() {
322 Init();
323 return mEmulateToMakeWindowUnderCursorForeground;
326 int32_t GetOverriddenVerticalScrollAmout() {
327 Init();
328 return mOverriddenVerticalScrollAmount;
331 int32_t GetOverriddenHorizontalScrollAmout() {
332 Init();
333 return mOverriddenHorizontalScrollAmount;
336 int32_t GetMouseScrollTransactionTimeout() {
337 Init();
338 return mMouseScrollTransactionTimeout;
341 private:
342 void Init();
344 static void OnChange(const char* aPrefName, void* aSelf) {
345 static_cast<UserPrefs*>(aSelf)->MarkDirty();
348 bool mInitialized;
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 {
361 public:
362 SynthesizingEvent()
363 : mWnd(nullptr),
364 mMessage(0),
365 mWParam(0),
366 mLParam(0),
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,
378 LPARAM aLParam);
380 void NotifyNativeMessageHandlingFinished();
381 void NotifyInternalMessageHandlingFinished();
383 const POINTS& GetCursorPoint() const { return mCursorPoint; }
385 private:
386 POINTS mCursorPoint;
387 HWND mWnd;
388 UINT mMessage;
389 WPARAM mWParam;
390 LPARAM mLParam;
391 BYTE mKeyState[256];
392 BYTE mOriginalKeyState[256];
394 enum Status {
395 NOT_SYNTHESIZING,
396 SENDING_MESSAGE,
397 NATIVE_MESSAGE_RECEIVED,
398 INTERNAL_MESSAGE_POSTED,
400 Status mStatus;
402 const char* GetStatusName() {
403 switch (mStatus) {
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";
412 default:
413 return "Unknown";
417 void Finish();
418 }; // SynthesizingEvent
420 SynthesizingEvent* mSynthesizingEvent;
422 public:
423 class Device {
424 public:
425 // SynTP is a touchpad driver of Synaptics.
426 class SynTP {
427 public:
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; }
440 static void Init();
442 private:
443 static bool sInitialized;
444 static int32_t sMajorVersion;
445 static int32_t sMinorVersion;
448 class Elantech {
449 public:
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,
467 LPARAM aLParam);
469 static void UpdateZoomUntil();
470 static bool IsZooming();
472 static void Init();
474 static bool IsPinchHackNeeded() { return sUsePinchHack; }
476 private:
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;
482 }; // class Elantech
484 // Apoint is a touchpad driver of Alps.
485 class Apoint {
486 public:
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; }
499 static void Init();
501 private:
502 static bool sInitialized;
503 static int32_t sMajorVersion;
504 static int32_t sMinorVersion;
507 class TrackPoint {
508 public:
510 * IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
511 * Otherwise, returns FALSE.
513 static bool IsDriverInstalled();
514 }; // class TrackPoint
516 class UltraNav {
517 public:
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();
524 }; // class UltraNav
526 class SetPoint {
527 public:
529 * SetPoint, Logitech's mouse driver, may report wrong cursor position
530 * for WM_MOUSEHWHEEL message. See comment in the implementation for
531 * the detail.
533 static bool IsGetMessagePosResponseValid(UINT aMessage, WPARAM aWParam,
534 LPARAM aLParam);
536 private:
537 static bool sMightBeUsing;
540 static void Init();
542 static bool IsFakeScrollableWindowNeeded() {
543 return sFakeScrollableWindowNeeded;
546 private:
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;
561 }; // class Device
564 } // namespace widget
565 } // namespace mozilla
567 #endif // mozilla_widget_WinMouseScrollHandler_h__