Bug 1648104 - Consume WM_POINTER with PT_TOUCH r=win-reviewers,rkraesig
Using WM_POINTER prevents touch and mouse pointer interfering each other, which is good for users who use both touchscreen and touchpad e.g. on Surface Pro. Differential Revision: https://phabricator.services.mozilla.com/D236227
This commit is contained in:
@@ -5043,6 +5043,13 @@
|
|||||||
value: true
|
value: true
|
||||||
mirror: always
|
mirror: always
|
||||||
|
|
||||||
|
# Control consuming WM_POINTER for touch pointers instead of WM_TOUCH
|
||||||
|
- name: dom.w3c_pointer_events.dispatch_by_pointer_messages.touch
|
||||||
|
type: bool
|
||||||
|
value: @IS_NIGHTLY_BUILD@
|
||||||
|
mirror: always
|
||||||
|
|
||||||
|
# Control whether to fire WidgetTouchEvent from pen pointers for APZ to handle scrolling.
|
||||||
- name: dom.w3c_pointer_events.scroll_by_pen.enabled
|
- name: dom.w3c_pointer_events.scroll_by_pen.enabled
|
||||||
type: bool
|
type: bool
|
||||||
value: true
|
value: true
|
||||||
|
|||||||
@@ -105,6 +105,21 @@ bool WinPointerEvents::GetPointerPenInfo(uint32_t aPointerId,
|
|||||||
return getPointerPenInfo(aPointerId, aPenInfo);
|
return getPointerPenInfo(aPointerId, aPenInfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void WinPointerEvents::GetPointerFrameTouchInfo(
|
||||||
|
uint32_t pointerId, nsTArray<POINTER_TOUCH_INFO>& aTouchInfoArray) {
|
||||||
|
uint32_t pointerCount = 0;
|
||||||
|
if (!::GetPointerFrameTouchInfo(pointerId, &pointerCount, nullptr)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!pointerCount) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
aTouchInfoArray.SetLength(pointerCount);
|
||||||
|
::GetPointerFrameTouchInfo(pointerId, &pointerCount,
|
||||||
|
aTouchInfoArray.Elements());
|
||||||
|
}
|
||||||
|
|
||||||
bool WinPointerEvents::ShouldRollupOnPointerEvent(UINT aMsg, WPARAM aWParam) {
|
bool WinPointerEvents::ShouldRollupOnPointerEvent(UINT aMsg, WPARAM aWParam) {
|
||||||
MOZ_ASSERT(aMsg == WM_POINTERDOWN);
|
MOZ_ASSERT(aMsg == WM_POINTERDOWN);
|
||||||
// Only roll up popups when we handling WM_POINTER* to fire Gecko
|
// Only roll up popups when we handling WM_POINTER* to fire Gecko
|
||||||
|
|||||||
@@ -44,6 +44,8 @@ class WinPointerEvents final {
|
|||||||
POINTER_INPUT_TYPE GetPointerType(uint32_t aPointerId);
|
POINTER_INPUT_TYPE GetPointerType(uint32_t aPointerId);
|
||||||
bool GetPointerInfo(uint32_t aPointerId, POINTER_INFO* aPointerInfo);
|
bool GetPointerInfo(uint32_t aPointerId, POINTER_INFO* aPointerInfo);
|
||||||
bool GetPointerPenInfo(uint32_t aPointerId, POINTER_PEN_INFO* aPenInfo);
|
bool GetPointerPenInfo(uint32_t aPointerId, POINTER_PEN_INFO* aPenInfo);
|
||||||
|
void GetPointerFrameTouchInfo(uint32_t pointerId,
|
||||||
|
nsTArray<POINTER_TOUCH_INFO>& aTouchInfoArray);
|
||||||
bool ShouldRollupOnPointerEvent(UINT aMsg, WPARAM aWParam);
|
bool ShouldRollupOnPointerEvent(UINT aMsg, WPARAM aWParam);
|
||||||
bool ShouldFirePointerEventByWinPointerMessages();
|
bool ShouldFirePointerEventByWinPointerMessages();
|
||||||
WinPointerInfo* GetCachedPointerInfo(UINT aMsg, WPARAM aWParam);
|
WinPointerInfo* GetCachedPointerInfo(UINT aMsg, WPARAM aWParam);
|
||||||
|
|||||||
@@ -8035,22 +8035,43 @@ bool nsWindow::OnPointerEvents(UINT msg, WPARAM aWParam, LPARAM aLParam) {
|
|||||||
// which fallbacks to WM_LBUTTON* and WM_GESTURE, to keep consistency.
|
// which fallbacks to WM_LBUTTON* and WM_GESTURE, to keep consistency.
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (!mPointerEvents.ShouldHandleWinPointerMessages(msg, aWParam)) {
|
|
||||||
|
uint32_t pointerId = mPointerEvents.GetPointerId(aWParam);
|
||||||
|
POINTER_INPUT_TYPE pointerType = PT_POINTER;
|
||||||
|
if (!GetPointerType(pointerId, &pointerType)) {
|
||||||
|
MOZ_ASSERT(false, "cannot find PointerType");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (pointerType == PT_TOUCH) {
|
||||||
|
if (!StaticPrefs::
|
||||||
|
dom_w3c_pointer_events_dispatch_by_pointer_messages_touch()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return OnTouchPointerEvents(pointerId, msg, aWParam, aLParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pointerType == PT_PEN) {
|
||||||
|
return OnPenPointerEvents(pointerId, msg, aWParam, aLParam);
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool nsWindow::OnPenPointerEvents(uint32_t aPointerId, UINT aMsg,
|
||||||
|
WPARAM aWParam, LPARAM aLParam) {
|
||||||
if (!mPointerEvents.ShouldFirePointerEventByWinPointerMessages()) {
|
if (!mPointerEvents.ShouldFirePointerEventByWinPointerMessages()) {
|
||||||
// We have to handle WM_POINTER* to fetch and cache pen related information
|
// We have to handle WM_POINTER* to fetch and cache pen related information
|
||||||
// and fire WidgetMouseEvent with the cached information the WM_*BUTTONDOWN
|
// and fire WidgetMouseEvent with the cached information the WM_*BUTTONDOWN
|
||||||
// handler. This is because Windows doesn't support ::DoDragDrop in the
|
// handler. This is because Windows doesn't support ::DoDragDrop in the
|
||||||
// touch or pen message handlers.
|
// touch or pen message handlers.
|
||||||
mPointerEvents.ConvertAndCachePointerInfo(msg, aWParam);
|
mPointerEvents.ConvertAndCachePointerInfo(aMsg, aWParam);
|
||||||
// Don't consume the Windows WM_POINTER* messages
|
// Don't consume the Windows WM_POINTER* messages
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32_t pointerId = mPointerEvents.GetPointerId(aWParam);
|
|
||||||
POINTER_PEN_INFO penInfo{};
|
POINTER_PEN_INFO penInfo{};
|
||||||
if (!mPointerEvents.GetPointerPenInfo(pointerId, &penInfo)) {
|
if (!mPointerEvents.GetPointerPenInfo(aPointerId, &penInfo)) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8070,7 +8091,7 @@ bool nsWindow::OnPointerEvents(UINT msg, WPARAM aWParam, LPARAM aLParam) {
|
|||||||
|
|
||||||
EventMessage message;
|
EventMessage message;
|
||||||
mozilla::MouseButton button = MouseButton::ePrimary;
|
mozilla::MouseButton button = MouseButton::ePrimary;
|
||||||
switch (msg) {
|
switch (aMsg) {
|
||||||
case WM_POINTERDOWN: {
|
case WM_POINTERDOWN: {
|
||||||
LayoutDeviceIntPoint eventPoint(GET_X_LPARAM(aLParam),
|
LayoutDeviceIntPoint eventPoint(GET_X_LPARAM(aLParam),
|
||||||
GET_Y_LPARAM(aLParam));
|
GET_Y_LPARAM(aLParam));
|
||||||
@@ -8122,8 +8143,8 @@ bool nsWindow::OnPointerEvents(UINT msg, WPARAM aWParam, LPARAM aLParam) {
|
|||||||
float pressure = penInfo.pressure ? (float)penInfo.pressure / 1024 : 0;
|
float pressure = penInfo.pressure ? (float)penInfo.pressure / 1024 : 0;
|
||||||
int16_t buttons = sPointerDown
|
int16_t buttons = sPointerDown
|
||||||
? nsContentUtils::GetButtonsFlagForButton(button)
|
? nsContentUtils::GetButtonsFlagForButton(button)
|
||||||
: MouseButtonsFlag::eNoButtons;
|
: static_cast<int16_t>(MouseButtonsFlag::eNoButtons);
|
||||||
WinPointerInfo pointerInfo(pointerId, penInfo.tiltX, penInfo.tiltY, pressure,
|
WinPointerInfo pointerInfo(aPointerId, penInfo.tiltX, penInfo.tiltY, pressure,
|
||||||
buttons);
|
buttons);
|
||||||
// Per
|
// Per
|
||||||
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-pointer_pen_info,
|
// https://learn.microsoft.com/en-us/windows/win32/api/winuser/ns-winuser-pointer_pen_info,
|
||||||
@@ -8134,7 +8155,7 @@ bool nsWindow::OnPointerEvents(UINT msg, WPARAM aWParam, LPARAM aLParam) {
|
|||||||
// Fire touch events but not when the barrel button is pressed.
|
// Fire touch events but not when the barrel button is pressed.
|
||||||
if (button != MouseButton::eSecondary &&
|
if (button != MouseButton::eSecondary &&
|
||||||
StaticPrefs::dom_w3c_pointer_events_scroll_by_pen_enabled() &&
|
StaticPrefs::dom_w3c_pointer_events_scroll_by_pen_enabled() &&
|
||||||
DispatchTouchEventFromWMPointer(msg, aLParam, pointerInfo, button)) {
|
DispatchTouchEventFromWMPointer(aMsg, aLParam, pointerInfo, button)) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -8155,6 +8176,71 @@ bool nsWindow::OnPointerEvents(UINT msg, WPARAM aWParam, LPARAM aLParam) {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool nsWindow::OnTouchPointerEvents(uint32_t aPointerId, UINT aMsg,
|
||||||
|
WPARAM aWParam, LPARAM aLParam) {
|
||||||
|
MultiTouchInput::MultiTouchType touchType;
|
||||||
|
switch (aMsg) {
|
||||||
|
case WM_POINTERDOWN:
|
||||||
|
touchType = MultiTouchInput::MULTITOUCH_START;
|
||||||
|
break;
|
||||||
|
case WM_POINTERUPDATE:
|
||||||
|
touchType = MultiTouchInput::MULTITOUCH_MOVE;
|
||||||
|
break;
|
||||||
|
case WM_POINTERUP:
|
||||||
|
touchType = MultiTouchInput::MULTITOUCH_END;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
nsTArray<POINTER_TOUCH_INFO> touchInfoArray{};
|
||||||
|
mPointerEvents.GetPointerFrameTouchInfo(aPointerId, touchInfoArray);
|
||||||
|
if (touchInfoArray.IsEmpty()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
MultiTouchInput inputToDispatch;
|
||||||
|
inputToDispatch.mInputType = MULTITOUCH_INPUT;
|
||||||
|
inputToDispatch.mType = touchType;
|
||||||
|
inputToDispatch.mTimeStamp = GetMessageTimeStamp(::GetMessageTime());
|
||||||
|
|
||||||
|
for (const POINTER_TOUCH_INFO& touchInfo : touchInfoArray) {
|
||||||
|
ScreenSize size(static_cast<float>(touchInfo.rcContact.right -
|
||||||
|
touchInfo.rcContact.left),
|
||||||
|
static_cast<float>(touchInfo.rcContact.bottom -
|
||||||
|
touchInfo.rcContact.top));
|
||||||
|
|
||||||
|
nsPointWin touchPoint;
|
||||||
|
touchPoint.x = touchInfo.pointerInfo.ptPixelLocation.x;
|
||||||
|
touchPoint.y = touchInfo.pointerInfo.ptPixelLocation.y;
|
||||||
|
touchPoint.ScreenToClient(mWnd);
|
||||||
|
|
||||||
|
// Windows provides orientation info, but the behavior differs from
|
||||||
|
// TouchEvent because TouchEvent's angle rotates the elliptic contact region
|
||||||
|
// while the Windows provided orientation is independent from touch point
|
||||||
|
// rect.
|
||||||
|
//
|
||||||
|
// e.g. For a vertically long touch pointer, Windows would give vertically
|
||||||
|
// long rect and also give a 90 degree orientation, and passing both would
|
||||||
|
// incorrectly represent a horizontal ellipse.
|
||||||
|
//
|
||||||
|
// See also: https://w3c.github.io/touch-events/#dom-touch-rotationangle
|
||||||
|
// "The angle (in degrees) that the ellipse described by radiusX and radiusY
|
||||||
|
// is rotated clockwise about its center; 0 if no value is known."
|
||||||
|
float angle = 0.0f;
|
||||||
|
|
||||||
|
bool hasPressure = !!(touchInfo.touchMask & TOUCH_MASK_PRESSURE);
|
||||||
|
float pressure = hasPressure ? (float)touchInfo.pressure / 1024 : 0;
|
||||||
|
inputToDispatch.mTouches.AppendElement(
|
||||||
|
SingleTouchData(static_cast<int32_t>(touchInfo.pointerInfo.pointerId),
|
||||||
|
ScreenIntPoint::FromUnknownPoint(touchPoint), size / 2,
|
||||||
|
angle, pressure));
|
||||||
|
}
|
||||||
|
|
||||||
|
DispatchTouchInput(inputToDispatch);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void nsWindow::GetCompositorWidgetInitData(
|
void nsWindow::GetCompositorWidgetInitData(
|
||||||
mozilla::widget::CompositorWidgetInitData* aInitData) {
|
mozilla::widget::CompositorWidgetInitData* aInitData) {
|
||||||
*aInitData = WinCompositorWidgetInitData(
|
*aInitData = WinCompositorWidgetInitData(
|
||||||
|
|||||||
@@ -609,6 +609,10 @@ class nsWindow final : public nsBaseWidget {
|
|||||||
void OnSysColorChanged();
|
void OnSysColorChanged();
|
||||||
void OnDPIChanged(int32_t x, int32_t y, int32_t width, int32_t height);
|
void OnDPIChanged(int32_t x, int32_t y, int32_t width, int32_t height);
|
||||||
bool OnPointerEvents(UINT msg, WPARAM wParam, LPARAM lParam);
|
bool OnPointerEvents(UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
bool OnPenPointerEvents(uint32_t aPointerId, UINT aMsg, WPARAM aWParam,
|
||||||
|
LPARAM aLParam);
|
||||||
|
bool OnTouchPointerEvents(uint32_t aPointerId, UINT aMsg, WPARAM aWParam,
|
||||||
|
LPARAM aLParam);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Function that registers when the user has been active (used for detecting
|
* Function that registers when the user has been active (used for detecting
|
||||||
|
|||||||
Reference in New Issue
Block a user