summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndré de la Rocha <andre.rocha@qt.io>2022-10-13 20:10:13 +0200
committerShawn Rutledge <shawn.rutledge@qt.io>2022-10-28 10:27:11 +0000
commit31e7790102b260344893eaa8bf8b7b1a0f95e3b7 (patch)
tree962a127358b2b39f4ad4e7dc41a4b85b089bdedb
parent32774f13d961c138f82dc50c085c1d66d0a91dd1 (diff)
Windows QPA: Remove tablet->mouse synth and fix Drag&Drop with touch/pen
This patch avoids synthesizing mouse messages in the QPA for touch/pen input, and lets the GUI do mouse event synthesis for unhandled touch/pen events, if required, like in other platforms. This requires a workaround to avoid breaking drag and drop with touch/pen (or making it worse). DnD on Windows is based on the DoDragDrop() Win32 API, which does not work with touch/pen input, which in some cases cause a DnD operation started with touch/pen to hang until the mouse is moved. To avoid it we process pointer messages for touch/pen and generate mouse input through SendInput() to trigger DoDragDrop(), which then seems to work as expected. So now we inform QtGui that the Windows platform no longer sends synth-mouse events after tablet events (unsetting the flag added in f931e5e72d4617023bbea46cba2c0d61bb1efa4f); this completes what was attempted in 8ada0633cd58e0608df2e16880f1293286025504. Fixes: QTBUG-106368 Fixes: QTBUG-57577 Fixes: QTBUG-100788 Task-number: QTBUG-77414 Task-number: QTBUG-104594 Pick-to: 6.4 6.3 6.2 Change-Id: I46db3c74be2a95cf2d94ba930398e58dc930d2db Reviewed-by: Shawn Rutledge <shawn.rutledge@qt.io>
-rw-r--r--src/plugins/platforms/windows/qwindowsdrag.cpp80
-rw-r--r--src/plugins/platforms/windows/qwindowsintegration.cpp1
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp4
3 files changed, 82 insertions, 3 deletions
diff --git a/src/plugins/platforms/windows/qwindowsdrag.cpp b/src/plugins/platforms/windows/qwindowsdrag.cpp
index 33b1cf2abd..93205259f8 100644
--- a/src/plugins/platforms/windows/qwindowsdrag.cpp
+++ b/src/plugins/platforms/windows/qwindowsdrag.cpp
@@ -644,6 +644,84 @@ IDropTargetHelper* QWindowsDrag::dropHelper() {
return m_cachedDropTargetHelper;
}
+// Workaround for DoDragDrop() not working with touch/pen input, causing DnD to hang until the mouse is moved.
+// We process pointer messages for touch/pen and generate mouse input through SendInput() to trigger DoDragDrop()
+static HRESULT startDoDragDrop(LPDATAOBJECT pDataObj, LPDROPSOURCE pDropSource, DWORD dwOKEffects, LPDWORD pdwEffect)
+{
+ HWND hwnd = ::GetFocus();
+ bool starting = false;
+
+ for (;;) {
+ MSG msg{};
+ if (::GetMessage(&msg, hwnd, 0, 0) > 0) {
+
+ if (msg.message == WM_MOUSEMOVE) {
+
+ // Only consider the first simulated event, or actual mouse messages.
+ if (!starting && (msg.wParam & (MK_LBUTTON | MK_MBUTTON | MK_RBUTTON | MK_XBUTTON1 | MK_XBUTTON2)) == 0)
+ return E_FAIL;
+
+ return ::DoDragDrop(pDataObj, pDropSource, dwOKEffects, pdwEffect);
+ }
+
+ if (msg.message == WM_POINTERUPDATE) {
+
+ const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
+
+ POINTER_INFO pointerInfo{};
+ if (!GetPointerInfo(pointerId, &pointerInfo))
+ return E_FAIL;
+
+ if (pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY) {
+
+ DWORD flags = MOUSEEVENTF_ABSOLUTE | MOUSEEVENTF_VIRTUALDESK | MOUSEEVENTF_MOVE;
+ if (IS_POINTER_FIRSTBUTTON_WPARAM(msg.wParam))
+ flags |= MOUSEEVENTF_LEFTDOWN;
+ if (IS_POINTER_SECONDBUTTON_WPARAM(msg.wParam))
+ flags |= MOUSEEVENTF_RIGHTDOWN;
+ if (IS_POINTER_THIRDBUTTON_WPARAM(msg.wParam))
+ flags |= MOUSEEVENTF_MIDDLEDOWN;
+
+ if (!starting) {
+ POINT pt{};
+ if (::GetCursorPos(&pt)) {
+
+ // Send mouse input that can generate a WM_MOUSEMOVE message.
+ if ((flags & MOUSEEVENTF_LEFTDOWN || flags & MOUSEEVENTF_RIGHTDOWN || flags & MOUSEEVENTF_MIDDLEDOWN)
+ && (pt.x != pointerInfo.ptPixelLocation.x || pt.y != pointerInfo.ptPixelLocation.y)) {
+
+ const int origin_x = ::GetSystemMetrics(SM_XVIRTUALSCREEN);
+ const int origin_y = ::GetSystemMetrics(SM_YVIRTUALSCREEN);
+ const int virt_w = ::GetSystemMetrics(SM_CXVIRTUALSCREEN);
+ const int virt_h = ::GetSystemMetrics(SM_CYVIRTUALSCREEN);
+ const int virt_x = pointerInfo.ptPixelLocation.x - origin_x;
+ const int virt_y = pointerInfo.ptPixelLocation.y - origin_y;
+
+ INPUT input{};
+ input.type = INPUT_MOUSE;
+ input.mi.dx = static_cast<DWORD>(virt_x * (65535.0 / virt_w));
+ input.mi.dy = static_cast<DWORD>(virt_y * (65535.0 / virt_h));
+ input.mi.dwFlags = flags;
+
+ ::SendInput(1, &input, sizeof(input));
+ starting = true;
+ }
+ }
+ }
+ }
+ } else {
+ // Handle other messages.
+ qWindowsWndProc(msg.hwnd, msg.message, msg.wParam, msg.lParam);
+
+ if (msg.message == WM_POINTERLEAVE)
+ return E_FAIL;
+ }
+ } else {
+ return E_FAIL;
+ }
+ }
+}
+
Qt::DropAction QWindowsDrag::drag(QDrag *drag)
{
// TODO: Accessibility handling?
@@ -661,7 +739,7 @@ Qt::DropAction QWindowsDrag::drag(QDrag *drag)
<< Qt::hex << int(possibleActions) << "effects=0x" << allowedEffects << Qt::dec;
// Indicate message handlers we are in DoDragDrop() event loop.
QWindowsDrag::m_dragging = true;
- const HRESULT r = DoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
+ const HRESULT r = startDoDragDrop(dropDataObject, windowDropSource, allowedEffects, &resultEffect);
QWindowsDrag::m_dragging = false;
const DWORD reportedPerformedEffect = dropDataObject->reportedPerformedEffect();
if (r == DRAGDROP_S_DROP) {
diff --git a/src/plugins/platforms/windows/qwindowsintegration.cpp b/src/plugins/platforms/windows/qwindowsintegration.cpp
index 2faeb7456b..dfbf5609fb 100644
--- a/src/plugins/platforms/windows/qwindowsintegration.cpp
+++ b/src/plugins/platforms/windows/qwindowsintegration.cpp
@@ -223,6 +223,7 @@ void QWindowsIntegrationPrivate::parseOptions(QWindowsIntegration *q, const QStr
QCoreApplication::setAttribute(Qt::AA_CompressHighFrequencyEvents);
else
m_context.initTablet();
+ QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
if (!dpiAwarenessSet) { // Set only once in case of repeated instantiations of QGuiApplication.
if (!QCoreApplication::testAttribute(Qt::AA_PluginApplication)) {
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
index 89f236b8ee..88f02347b3 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -796,8 +796,8 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
break;
case QT_PT_PEN:
#if QT_CONFIG(tabletevent)
- if (!m_activeTabletDevice.isNull())
- device = m_activeTabletDevice.data();
+ qCDebug(lcQpaTablet) << "ignoring synth-mouse event for tablet event from" << device;
+ return false;
#endif
break;
}