Source code

Revision control

Other Tools

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/. */
6
7
#ifndef mozilla_widget_WinMouseScrollHandler_h__
8
#define mozilla_widget_WinMouseScrollHandler_h__
9
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"
18
19
class nsWindowBase;
20
21
namespace mozilla {
22
namespace widget {
23
24
class ModifierKeyState;
25
26
struct MSGResult;
27
28
class MouseScrollHandler {
29
public:
30
static MouseScrollHandler* GetInstance();
31
32
static void Initialize();
33
static void Shutdown();
34
35
static bool NeedsMessage(UINT aMsg);
36
static bool ProcessMessage(nsWindowBase* aWidget, UINT msg, WPARAM wParam,
37
LPARAM lParam, MSGResult& aResult);
38
39
/**
40
* See nsIWidget::SynthesizeNativeMouseScrollEvent() for the detail about
41
* this method.
42
*/
43
static nsresult SynthesizeNativeMouseScrollEvent(
44
nsWindowBase* aWidget, const LayoutDeviceIntPoint& aPoint,
45
uint32_t aNativeMessage, int32_t aDelta, uint32_t aModifierFlags,
46
uint32_t aAdditionalFlags);
47
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.
52
*/
53
static bool IsWaitingInternalMessage() {
54
return sInstance && sInstance->mIsWaitingInternalMessage;
55
}
56
57
private:
58
MouseScrollHandler();
59
~MouseScrollHandler();
60
61
bool mIsWaitingInternalMessage;
62
63
static void MaybeLogKeyState();
64
65
static MouseScrollHandler* sInstance;
66
67
/**
68
* InitEvent() initializes the aEvent. If aPoint is null, the result of
69
* GetCurrentMessagePos() will be used.
70
*/
71
static void InitEvent(nsWindowBase* aWidget, WidgetGUIEvent& aEvent,
72
LayoutDeviceIntPoint* aPoint = nullptr);
73
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.
78
*
79
* @param aMessage Handling message.
80
*/
81
static ModifierKeyState GetModifierKeyState(UINT aMessage);
82
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().
88
*/
89
static POINTS GetCurrentMessagePos();
90
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.
98
*
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.
104
*/
105
void ProcessNativeMouseWheelMessage(nsWindowBase* aWidget, UINT aMessage,
106
WPARAM aWParam, LPARAM aLParam);
107
108
/**
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.
113
*
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.
119
*/
120
bool ProcessNativeScrollMessage(nsWindowBase* aWidget, UINT aMessage,
121
WPARAM aWParam, LPARAM aLParam);
122
123
/**
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.
127
*
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.
132
*/
133
void HandleMouseWheelMessage(nsWindowBase* aWidget, UINT aMessage,
134
WPARAM aWParam, LPARAM aLParam);
135
136
/**
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.
141
*
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.
146
*/
147
void HandleScrollMessageAsMouseWheelMessage(nsWindowBase* aWidget,
148
UINT aMessage, WPARAM aWParam,
149
LPARAM aLParam);
150
151
/**
152
* ComputeMessagePos() computes the cursor position when the message was
153
* added to the queue.
154
*
155
* @param aMessage Handling message.
156
* @param aWParam Handling message's wParam.
157
* @param aLParam Handling message's lParam.
158
* @return Mouse cursor position when the message is added to
159
* the queue or current cursor position if the result of
160
* ::GetMessagePos() is broken.
161
*/
162
POINT ComputeMessagePos(UINT aMessage, WPARAM aWParam, LPARAM aLParam);
163
164
class EventInfo {
165
public:
166
/**
167
* @param aWidget An nsWindow which is handling the event.
168
* @param aMessage Must be WM_MOUSEWHEEL or WM_MOUSEHWHEEL.
169
*/
170
EventInfo(nsWindowBase* aWidget, UINT aMessage, WPARAM aWParam,
171
LPARAM aLParam);
172
173
bool CanDispatchWheelEvent() const;
174
175
int32_t GetNativeDelta() const { return mDelta; }
176
HWND GetWindowHandle() const { return mWnd; }
177
const TimeStamp& GetTimeStamp() const { return mTimeStamp; }
178
bool IsVertical() const { return mIsVertical; }
179
bool IsPositive() const { return (mDelta > 0); }
180
bool IsPage() const { return mIsPage; }
181
182
/**
183
* @return Number of lines or pages scrolled per WHEEL_DELTA.
184
*/
185
int32_t GetScrollAmount() const;
186
187
protected:
188
EventInfo()
189
: mIsVertical(false), mIsPage(false), mDelta(0), mWnd(nullptr) {}
190
191
// TRUE if event is for vertical scroll. Otherwise, FALSE.
192
bool mIsVertical;
193
// TRUE if event scrolls per page, otherwise, FALSE.
194
bool mIsPage;
195
// The native delta value.
196
int32_t mDelta;
197
// The window handle which is handling the event.
198
HWND mWnd;
199
// Timestamp of the event.
200
TimeStamp mTimeStamp;
201
};
202
203
class LastEventInfo : public EventInfo {
204
public:
205
LastEventInfo() : EventInfo(), mAccumulatedDelta(0) {}
206
207
/**
208
* CanContinueTransaction() checks whether the new event can continue the
209
* last transaction or not. Note that if there is no transaction, this
210
* returns true.
211
*/
212
bool CanContinueTransaction(const EventInfo& aNewEvent);
213
214
/**
215
* ResetTransaction() resets the transaction, i.e., the instance forgets
216
* the last event information.
217
*/
218
void ResetTransaction();
219
220
/**
221
* RecordEvent() saves the information of new event.
222
*/
223
void RecordEvent(const EventInfo& aEvent);
224
225
/**
226
* InitWheelEvent() initializes NS_WHEEL_WHEEL event and
227
* recomputes the remaning detla for the event.
228
* This must be called only once during handling a message and after
229
* RecordEvent() is called.
230
*
231
* @param aWidget A window which will dispatch the event.
232
* @param aWheelEvent An NS_WHEEL_WHEEL event, this will be
233
* initialized.
234
* @param aModKeyState Current modifier key state.
235
* @return TRUE if the event is ready to dispatch.
236
* Otherwise, FALSE.
237
*/
238
bool InitWheelEvent(nsWindowBase* aWidget, WidgetWheelEvent& aWheelEvent,
239
const ModifierKeyState& aModKeyState);
240
241
private:
242
static int32_t RoundDelta(double aDelta);
243
244
int32_t mAccumulatedDelta;
245
};
246
247
LastEventInfo mLastEventInfo;
248
249
class SystemSettings {
250
public:
251
SystemSettings() : mInitialized(false) {}
252
253
void Init();
254
void MarkDirty();
255
void NotifyUserPrefsMayOverrideSystemSettings();
256
257
// On some environments, SystemParametersInfo() may be hooked by touchpad
258
// utility or something. In such case, when user changes active pointing
259
// device to another one, the result of SystemParametersInfo() may be
260
// changed without WM_SETTINGCHANGE message. For avoiding this trouble,
261
// we need to modify cache of system settings at every wheel message
262
// handling if we meet known device whose utility may hook the API.
263
void TrustedScrollSettingsDriver();
264
265
// Returns true if the system scroll may be overridden for faster scroll.
266
// Otherwise, false. For example, if the user maybe uses an expensive
267
// mouse which supports acceleration of scroll speed, faster scroll makes
268
// the user inconvenient.
269
bool IsOverridingSystemScrollSpeedAllowed();
270
271
int32_t GetScrollAmount(bool aForVertical) const {
272
MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
273
return aForVertical ? mScrollLines : mScrollChars;
274
}
275
276
bool IsPageScroll(bool aForVertical) const {
277
MOZ_ASSERT(mInitialized, "SystemSettings must be initialized");
278
return aForVertical ? (uint32_t(mScrollLines) == WHEEL_PAGESCROLL)
279
: (uint32_t(mScrollChars) == WHEEL_PAGESCROLL);
280
}
281
282
// The default vertical and horizontal scrolling speed is 3, this is defined
283
// on the document of SystemParametersInfo in MSDN.
284
static int32_t DefaultScrollLines() { return 3; }
285
static int32_t DefaultScrollChars() { return 3; }
286
287
private:
288
bool mInitialized;
289
// The result of SystemParametersInfo() may not be reliable since it may
290
// be hooked. So, if the values are initialized with prefs, we can trust
291
// the value. Following mIsReliableScroll* are set true when mScroll* are
292
// initialized with prefs.
293
bool mIsReliableScrollLines;
294
bool mIsReliableScrollChars;
295
296
int32_t mScrollLines;
297
int32_t mScrollChars;
298
299
// Returns true if cached value is changed.
300
bool InitScrollLines();
301
bool InitScrollChars();
302
303
void RefreshCache();
304
};
305
306
SystemSettings mSystemSettings;
307
308
class UserPrefs {
309
public:
310
UserPrefs();
311
~UserPrefs();
312
313
void MarkDirty();
314
315
bool IsScrollMessageHandledAsWheelMessage() {
316
Init();
317
return mScrollMessageHandledAsWheelMessage;
318
}
319
320
bool IsSystemSettingCacheEnabled() {
321
Init();
322
return mEnableSystemSettingCache;
323
}
324
325
bool IsSystemSettingCacheForciblyEnabled() {
326
Init();
327
return mForceEnableSystemSettingCache;
328
}
329
330
bool ShouldEmulateToMakeWindowUnderCursorForeground() {
331
Init();
332
return mEmulateToMakeWindowUnderCursorForeground;
333
}
334
335
int32_t GetOverriddenVerticalScrollAmout() {
336
Init();
337
return mOverriddenVerticalScrollAmount;
338
}
339
340
int32_t GetOverriddenHorizontalScrollAmout() {
341
Init();
342
return mOverriddenHorizontalScrollAmount;
343
}
344
345
int32_t GetMouseScrollTransactionTimeout() {
346
Init();
347
return mMouseScrollTransactionTimeout;
348
}
349
350
private:
351
void Init();
352
353
static void OnChange(const char* aPrefName, UserPrefs* aClosure) {
354
aClosure->MarkDirty();
355
}
356
357
bool mInitialized;
358
bool mScrollMessageHandledAsWheelMessage;
359
bool mEnableSystemSettingCache;
360
bool mForceEnableSystemSettingCache;
361
bool mEmulateToMakeWindowUnderCursorForeground;
362
int32_t mOverriddenVerticalScrollAmount;
363
int32_t mOverriddenHorizontalScrollAmount;
364
int32_t mMouseScrollTransactionTimeout;
365
};
366
367
UserPrefs mUserPrefs;
368
369
class SynthesizingEvent {
370
public:
371
SynthesizingEvent()
372
: mWnd(nullptr),
373
mMessage(0),
374
mWParam(0),
375
mLParam(0),
376
mStatus(NOT_SYNTHESIZING) {}
377
378
~SynthesizingEvent() {}
379
380
static bool IsSynthesizing();
381
382
nsresult Synthesize(const POINTS& aCursorPoint, HWND aWnd, UINT aMessage,
383
WPARAM aWParam, LPARAM aLParam,
384
const BYTE (&aKeyStates)[256]);
385
386
void NativeMessageReceived(nsWindowBase* aWidget, UINT aMessage,
387
WPARAM aWParam, LPARAM aLParam);
388
389
void NotifyNativeMessageHandlingFinished();
390
void NotifyInternalMessageHandlingFinished();
391
392
const POINTS& GetCursorPoint() const { return mCursorPoint; }
393
394
private:
395
POINTS mCursorPoint;
396
HWND mWnd;
397
UINT mMessage;
398
WPARAM mWParam;
399
LPARAM mLParam;
400
BYTE mKeyState[256];
401
BYTE mOriginalKeyState[256];
402
403
enum Status {
404
NOT_SYNTHESIZING,
405
SENDING_MESSAGE,
406
NATIVE_MESSAGE_RECEIVED,
407
INTERNAL_MESSAGE_POSTED,
408
};
409
Status mStatus;
410
411
const char* GetStatusName() {
412
switch (mStatus) {
413
case NOT_SYNTHESIZING:
414
return "NOT_SYNTHESIZING";
415
case SENDING_MESSAGE:
416
return "SENDING_MESSAGE";
417
case NATIVE_MESSAGE_RECEIVED:
418
return "NATIVE_MESSAGE_RECEIVED";
419
case INTERNAL_MESSAGE_POSTED:
420
return "INTERNAL_MESSAGE_POSTED";
421
default:
422
return "Unknown";
423
}
424
}
425
426
void Finish();
427
}; // SynthesizingEvent
428
429
SynthesizingEvent* mSynthesizingEvent;
430
431
public:
432
class Device {
433
public:
434
// SynTP is a touchpad driver of Synaptics.
435
class SynTP {
436
public:
437
static bool IsDriverInstalled() { return sMajorVersion != 0; }
438
/**
439
* GetDriverMajorVersion() returns the installed driver's major version.
440
* If SynTP driver isn't installed, this returns 0.
441
*/
442
static int32_t GetDriverMajorVersion() { return sMajorVersion; }
443
/**
444
* GetDriverMinorVersion() returns the installed driver's minor version.
445
* If SynTP driver isn't installed, this returns -1.
446
*/
447
static int32_t GetDriverMinorVersion() { return sMinorVersion; }
448
449
static void Init();
450
451
private:
452
static bool sInitialized;
453
static int32_t sMajorVersion;
454
static int32_t sMinorVersion;
455
};
456
457
class Elantech {
458
public:
459
/**
460
* GetDriverMajorVersion() returns the installed driver's major version.
461
* If Elantech's driver was installed, returns 0.
462
*/
463
static int32_t GetDriverMajorVersion();
464
465
/**
466
* IsHelperWindow() checks whether aWnd is a helper window of Elantech's
467
* touchpad. Returns TRUE if so. Otherwise, FALSE.
468
*/
469
static bool IsHelperWindow(HWND aWnd);
470
471
/**
472
* Key message handler for Elantech's hack. Returns TRUE if the message
473
* is consumed by this handler. Otherwise, FALSE.
474
*/
475
static bool HandleKeyMessage(nsWindowBase* aWidget, UINT aMsg,
476
WPARAM aWParam, LPARAM aLParam);
477
478
static void UpdateZoomUntil();
479
static bool IsZooming();
480
481
static void Init();
482
483
static bool IsPinchHackNeeded() { return sUsePinchHack; }
484
485
private:
486
// Whether to enable the Elantech swipe gesture hack.
487
static bool sUseSwipeHack;
488
// Whether to enable the Elantech pinch-to-zoom gesture hack.
489
static bool sUsePinchHack;
490
static DWORD sZoomUntil;
491
}; // class Elantech
492
493
// Apoint is a touchpad driver of Alps.
494
class Apoint {
495
public:
496
static bool IsDriverInstalled() { return sMajorVersion != 0; }
497
/**
498
* GetDriverMajorVersion() returns the installed driver's major version.
499
* If Apoint driver isn't installed, this returns 0.
500
*/
501
static int32_t GetDriverMajorVersion() { return sMajorVersion; }
502
/**
503
* GetDriverMinorVersion() returns the installed driver's minor version.
504
* If Apoint driver isn't installed, this returns -1.
505
*/
506
static int32_t GetDriverMinorVersion() { return sMinorVersion; }
507
508
static void Init();
509
510
private:
511
static bool sInitialized;
512
static int32_t sMajorVersion;
513
static int32_t sMinorVersion;
514
};
515
516
class TrackPoint {
517
public:
518
/**
519
* IsDriverInstalled() returns TRUE if TrackPoint's driver is installed.
520
* Otherwise, returns FALSE.
521
*/
522
static bool IsDriverInstalled();
523
}; // class TrackPoint
524
525
class UltraNav {
526
public:
527
/**
528
* IsObsoleteDriverInstalled() checks whether obsoleted UltraNav
529
* is installed on the environment.
530
* Returns TRUE if it was installed. Otherwise, FALSE.
531
*/
532
static bool IsObsoleteDriverInstalled();
533
}; // class UltraNav
534
535
class SetPoint {
536
public:
537
/**
538
* SetPoint, Logitech's mouse driver, may report wrong cursor position
539
* for WM_MOUSEHWHEEL message. See comment in the implementation for
540
* the detail.
541
*/
542
static bool IsGetMessagePosResponseValid(UINT aMessage, WPARAM aWParam,
543
LPARAM aLParam);
544
545
private:
546
static bool sMightBeUsing;
547
};
548
549
static void Init();
550
551
static bool IsFakeScrollableWindowNeeded() {
552
return sFakeScrollableWindowNeeded;
553
}
554
555
private:
556
/**
557
* Gets the bool value of aPrefName used to enable or disable an input
558
* workaround (like the Trackpoint hack). The pref can take values 0 (for
559
* disabled), 1 (for enabled) or -1 (to automatically detect whether to
560
* enable the workaround).
561
*
562
* @param aPrefName The name of the pref.
563
* @param aValueIfAutomatic Whether the given input workaround should be
564
* enabled by default.
565
*/
566
static bool GetWorkaroundPref(const char* aPrefName,
567
bool aValueIfAutomatic);
568
569
static bool sFakeScrollableWindowNeeded;
570
}; // class Device
571
};
572
573
} // namespace widget
574
} // namespace mozilla
575
576
#endif // mozilla_widget_WinMouseScrollHandler_h__