From 5728a9d8a7f8b64099cf369d9d307a00b5fce29c Mon Sep 17 00:00:00 2001 From: Romain Pokrzywka Date: Wed, 22 Aug 2018 22:43:29 -0500 Subject: Windows QPA: Dispatch skipped touch/pen events if compression is off If the hardware produces events faster than the app can consume between two updates, Windows automatically coalesces them into a single message with the latest touch/pen pointer state and coordinates, effectively compressing those events. But the pointer API also supports querying and retrieving the skipped individual touch and pen frames. There are cases where keeping all the events generated by the hardware is desired, especially for pen events where having the most sampled points available is critical to precisely rendering curves. Qt already defines application attributes to control event compression for general high frequency events and for tablet events in particular. Use them on Windows also to control whether to retrieve skipped frames. [ChangeLog][Windows] The application attributes AA_CompressTabletEvents and AA_CompressHighFrequencyEvents are now supported on Windows 8 and above for touch/pen input, with the same defaults as on X11 (compress touch events, don't compress tablet events) Task-number: QTBUG-44964 Task-number: QTBUG-60437 Change-Id: I1b11a043e2d71ee502895971fafb3a46306a89d8 Reviewed-by: Andre de la Rocha Reviewed-by: Friedemann Kleint --- src/plugins/platforms/windows/qwindowscontext.cpp | 6 ++- src/plugins/platforms/windows/qwindowscontext.h | 4 ++ .../platforms/windows/qwindowsintegration.cpp | 4 +- .../platforms/windows/qwindowspointerhandler.cpp | 49 ++++++++++++++++++++++ 4 files changed, 60 insertions(+), 3 deletions(-) (limited to 'src/plugins/platforms') diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp index 03bb1bee48..373758b49e 100644 --- a/src/plugins/platforms/windows/qwindowscontext.cpp +++ b/src/plugins/platforms/windows/qwindowscontext.cpp @@ -201,7 +201,9 @@ void QWindowsUser32DLL::init() getPointerDeviceRects = (GetPointerDeviceRects)library.resolve("GetPointerDeviceRects"); getPointerTouchInfo = (GetPointerTouchInfo)library.resolve("GetPointerTouchInfo"); getPointerFrameTouchInfo = (GetPointerFrameTouchInfo)library.resolve("GetPointerFrameTouchInfo"); + getPointerFrameTouchInfoHistory = (GetPointerFrameTouchInfoHistory)library.resolve("GetPointerFrameTouchInfoHistory"); getPointerPenInfo = (GetPointerPenInfo)library.resolve("GetPointerPenInfo"); + getPointerPenInfoHistory = (GetPointerPenInfoHistory)library.resolve("GetPointerPenInfoHistory"); skipPointerFrameMessages = (SkipPointerFrameMessages)library.resolve("SkipPointerFrameMessages"); } @@ -216,8 +218,8 @@ void QWindowsUser32DLL::init() bool QWindowsUser32DLL::supportsPointerApi() { return enableMouseInPointer && getPointerType && getPointerInfo && getPointerDeviceRects - && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerPenInfo - && skipPointerFrameMessages; + && getPointerTouchInfo && getPointerFrameTouchInfo && getPointerFrameTouchInfoHistory + && getPointerPenInfo && getPointerPenInfoHistory && skipPointerFrameMessages; } void QWindowsShcoreDLL::init() diff --git a/src/plugins/platforms/windows/qwindowscontext.h b/src/plugins/platforms/windows/qwindowscontext.h index 8102e0bf19..622c729a10 100644 --- a/src/plugins/platforms/windows/qwindowscontext.h +++ b/src/plugins/platforms/windows/qwindowscontext.h @@ -92,7 +92,9 @@ struct QWindowsUser32DLL typedef BOOL (WINAPI *GetPointerDeviceRects)(HANDLE, RECT *, RECT *); typedef BOOL (WINAPI *GetPointerTouchInfo)(UINT32, PVOID); typedef BOOL (WINAPI *GetPointerFrameTouchInfo)(UINT32, UINT32 *, PVOID); + typedef BOOL (WINAPI *GetPointerFrameTouchInfoHistory)(UINT32, UINT32 *, UINT32 *, PVOID); typedef BOOL (WINAPI *GetPointerPenInfo)(UINT32, PVOID); + typedef BOOL (WINAPI *GetPointerPenInfoHistory)(UINT32, UINT32 *, PVOID); typedef BOOL (WINAPI *SkipPointerFrameMessages)(UINT32); typedef BOOL (WINAPI *SetProcessDPIAware)(); typedef BOOL (WINAPI *AddClipboardFormatListener)(HWND); @@ -110,7 +112,9 @@ struct QWindowsUser32DLL GetPointerDeviceRects getPointerDeviceRects = nullptr; GetPointerTouchInfo getPointerTouchInfo = nullptr; GetPointerFrameTouchInfo getPointerFrameTouchInfo = nullptr; + GetPointerFrameTouchInfoHistory getPointerFrameTouchInfoHistory = nullptr; GetPointerPenInfo getPointerPenInfo = nullptr; + GetPointerPenInfoHistory getPointerPenInfoHistory = nullptr; SkipPointerFrameMessages skipPointerFrameMessages = nullptr; // Windows Vista onwards diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp index 0694435427..7d621126b9 100644 --- a/src/plugins/platforms/windows/qwindowsintegration.cpp +++ b/src/plugins/platforms/windows/qwindowsintegration.cpp @@ -236,7 +236,9 @@ QWindowsIntegrationPrivate::QWindowsIntegrationPrivate(const QStringList ¶mL m_options = parseOptions(paramList, &tabletAbsoluteRange, &dpiAwareness); QWindowsFontDatabase::setFontOptions(m_options); - if (!m_context.initPointer(m_options)) { + if (m_context.initPointer(m_options)) { + QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents); + } else { m_context.initTablet(m_options); if (tabletAbsoluteRange >= 0) m_context.setTabletAbsoluteRange(tabletAbsoluteRange); diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp index d8918d1b3d..7ead14822a 100644 --- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp +++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp @@ -106,6 +106,32 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q qWarning() << "GetPointerFrameTouchInfo() failed:" << qt_error_string(); return false; } + + if (!pointerCount) + return false; + + // The history count is the same for all the touchpoints in touchInfo + quint32 historyCount = touchInfo[0].pointerInfo.historyCount; + // dispatch any skipped frames if event compression is disabled by the app + if (historyCount > 1 && !QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents)) { + touchInfo.resize(pointerCount * historyCount); + if (!QWindowsContext::user32dll.getPointerFrameTouchInfoHistory(pointerId, + &historyCount, + &pointerCount, + touchInfo.data())) { + qWarning() << "GetPointerFrameTouchInfoHistory() failed:" << qt_error_string(); + return false; + } + + // history frames are returned with the most recent frame first so we iterate backwards + bool result = true; + for (auto it = touchInfo.rbegin(), end = touchInfo.rend(); it != end; it += pointerCount) { + result &= translateTouchEvent(window, hwnd, et, msg, + &(*(it + (pointerCount - 1))), pointerCount); + } + return result; + } + return translateTouchEvent(window, hwnd, et, msg, touchInfo.data(), pointerCount); } case QT_PT_PEN: { @@ -114,6 +140,29 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q qWarning() << "GetPointerPenInfo() failed:" << qt_error_string(); return false; } + + quint32 historyCount = penInfo.pointerInfo.historyCount; + // dispatch any skipped frames if generic or tablet event compression is disabled by the app + if (historyCount > 1 + && (!QCoreApplication::testAttribute(Qt::AA_CompressHighFrequencyEvents) + || !QCoreApplication::testAttribute(Qt::AA_CompressTabletEvents))) { + QVarLengthArray penInfoHistory(historyCount); + + if (!QWindowsContext::user32dll.getPointerPenInfoHistory(pointerId, + &historyCount, + penInfoHistory.data())) { + qWarning() << "GetPointerPenInfoHistory() failed:" << qt_error_string(); + return false; + } + + // history frames are returned with the most recent frame first so we iterate backwards + bool result = true; + for (auto it = penInfoHistory.rbegin(), end = penInfoHistory.rend(); it != end; ++it) { + result &= translatePenEvent(window, hwnd, et, msg, &(*(it))); + } + return result; + } + return translatePenEvent(window, hwnd, et, msg, &penInfo); } } -- cgit v1.2.3