From d02f888417c144963c929512f5cb3a0178af9fb4 Mon Sep 17 00:00:00 2001 From: Romain Pokrzywka Date: Wed, 22 Aug 2018 11:31:34 -0500 Subject: Windows QPA: Fix duplicate Pointer Touch events and missing TouchCancel translateTouchEvent needs to filter events based on the message type passed in msg, as Windows sends more than just down/up/update events, it also sends enter/leave for each touch and occasionally a few more. One of them is WM_POINTERCAPTURECHANGED which indicates a general loss of touch input, which needs to be translated to a touch cancel event. Ignore WM_POINTERENTER/WM_POINTERLEAVE events as they result in sending duplicate Qt::TouchPointPressed/Qt::TouchPointReleased events otherwise. Also avoid sending duplicate events for each additional touchpoint: Windows already bundles all available touchpoints for a touch event when calling GetPointerFrameTouchInfo, so we get all points at once, but we'll still receive other events for each additional touchpoint, resulting in reading the same bundled data again for each one and sending duplicate events to QWindowSystemInterface. Use SkipPointerFrameMessages() to avoid receiving the additional events for the frame we just processed. Finally, add raw event logging when the platform verbose level is >1. Change-Id: I55d840285f642a00f6ffcda4a3efd7ae3985310b Reviewed-by: Andre de la Rocha --- src/plugins/platforms/windows/qtwindowsglobal.h | 1 + src/plugins/platforms/windows/qwindowscontext.cpp | 4 +++- src/plugins/platforms/windows/qwindowscontext.h | 2 ++ .../platforms/windows/qwindowspointerhandler.cpp | 25 ++++++++++++++++++++++ 4 files changed, 31 insertions(+), 1 deletion(-) (limited to 'src/plugins/platforms/windows') diff --git a/src/plugins/platforms/windows/qtwindowsglobal.h b/src/plugins/platforms/windows/qtwindowsglobal.h index ef22a4451a..985f13bdc5 100644 --- a/src/plugins/platforms/windows/qtwindowsglobal.h +++ b/src/plugins/platforms/windows/qtwindowsglobal.h @@ -71,6 +71,7 @@ # define WM_POINTERENTER 0x0249 # define WM_POINTERLEAVE 0x024A # define WM_POINTERACTIVATE 0x024B +# define WM_POINTERCAPTURECHANGED 0x024C # define WM_POINTERWHEEL 0x024E # define WM_POINTERHWHEEL 0x024F #endif // WM_POINTERUPDATE diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 0df6264bcb..aa85b2edbe 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -201,6 +201,7 @@ void QWindowsUser32DLL::init() getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo"); getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo"); getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo"); + skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages"); } if (QOperatingSystemVersion::current() @@ -214,7 +215,8 @@ void QWindowsUser32DLL::init() bool QWindowsUser32DLL::supportsPointerApi() { return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects - && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerPenInfo; + && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerPenInfo + && skipPointerFrameMessages; } void QWindowsShcoreDLL::init() diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 33bd42a669..8102e0bf19 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -93,6 +93,7 @@ struct QWindowsUser32DLL typedef BOOL (WINAPI *GetPointerTouchInfo)(UINT32, PVOID); typedef BOOL (WINAPI *GetPointerFrameTouchInfo)(UINT32, UINT32 *, PVOID); typedef BOOL (WINAPI *GetPointerPenInfo)(UINT32, PVOID); + typedef BOOL (WINAPI *SkipPointerFrameMessages)(UINT32); typedef BOOL (WINAPI *SetProcessDPIAware)(); typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND); typedef BOOL (WINAPI *RemoveClipboardFormatListener)(HWND); @@ -110,6 +111,7 @@ struct QWindowsUser32DLL GetPointerTouchInfo getPointerTouchInfo = nullptr; GetPointerFrameTouchInfo getPointerFrameTouchInfo = nullptr; GetPointerPenInfo getPointerPenInfo = nullptr; + SkipPointerFrameMessages skipPointerFrameMessages = nullptr; // Windows Vista onwards SetProcessDPIAware setProcessDPIAware = nullptr; diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index abd4d56da0..af9048828f 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -354,6 +354,17 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, if (count < 1) return false; + if (msg.message == WM_POINTERCAPTURECHANGED) { + QWindowSystemInterface::handleTouchCancelEvent(window, m_touchDevice, + QWindowsKeyMapper::queryKeyboardModifiers()); + m_lastTouchPositions.clear(); + return true; + } + + // Only handle down/up/update, ignore others like WM_POINTERENTER, WM_POINTERLEAVE, etc. + if (msg.message > WM_POINTERUP) + return false; + const QScreen *screen = window->screen(); if (!screen) screen = QGuiApplication::primaryScreen(); @@ -366,7 +377,18 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, QList touchPoints; + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaEvents).noquote().nospace() << showbase + << __FUNCTION__ + << " message=" << hex << msg.message + << " count=" << dec << count; + for (quint32 i = 0; i < count; ++i) { + if (QWindowsContext::verbose > 1) + qCDebug(lcQpaEvents).noquote().nospace() << showbase + << " TouchPoint id=" << touchInfo[i].pointerInfo.pointerId + << " frame=" << touchInfo[i].pointerInfo.frameId + << " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags; QWindowSystemInterface::TouchPoint touchPoint; touchPoint.id = touchInfo[i].pointerInfo.pointerId; @@ -398,6 +420,9 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd, m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition); } touchPoints.append(touchPoint); + + // Avoid getting repeated messages for this frame if there are multiple pointerIds + QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId); } QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints, -- cgit v1.2.3