summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAndre de la Rocha <andre.rocha@qt.io>2019-02-04 19:25:31 +0100
committerAndre de la Rocha <andre.rocha@qt.io>2019-02-12 22:17:54 +0000
commit38504041148f2d1cffea6520ea448dd4171adb0b (patch)
tree77d60e06d5f2381783ab44001a0b4d3395eff67d /src
parent80bcfa776f9243641484181a18090b34147e8e30 (diff)
Windows QPA: Handle mouse input using legacy messages
This change reverts to using legacy mouse messages when handling mouse and touchpad input, while using pointer messages to handle touchscreen and pen input. The use of pointer messages to handle everything, added in 5.12.0, caused issues in some particular cases, due mainly to differences in behavior or bugs in the pointer messages, which required workarounds in the Windows QPA, which didn't work well in all cases and led to additional issues. For instance, DoDragDrop() does not work when called by pointer (or touch/pen) handlers, but only after OS-synthesized legacy mouse messages are generated. Also, in some cases pointer messages for mouse movement are generated as non-client for client area events. Modal loops like the ones in window resize/move and menu handling caused some issues with pointer messages, as well. Also, we have to handle the OS-synthesized legacy mouse message generated for touch and pen. Ignoring them while letting the gui layer synthesize mouse events for touch/pen may break Drag and Drop by triggering DoDragDrop() before legacy messages, which can result in a hang inside the DoDragDrop() modal loop. This change should fix most regressions related to pointer messages, while keeping the enhancements in pen and touch input. Fixes: QTBUG-73389 Fixes: QTBUG-72624 Fixes: QTBUG-72801 Fixes: QTBUG-73290 Fixes: QTBUG-72458 Fixes: QTBUG-73358 Fixes: QTBUG-72992 Change-Id: I919f78930d3965270ef2094401e827ab87174979 Reviewed-by: Friedemann Kleint <Friedemann.Kleint@qt.io>
Diffstat (limited to 'src')
-rw-r--r--src/plugins/platforms/windows/qwindowscontext.cpp20
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.cpp483
-rw-r--r--src/plugins/platforms/windows/qwindowspointerhandler.h6
3 files changed, 165 insertions, 344 deletions
diff --git a/src/plugins/platforms/windows/qwindowscontext.cpp b/src/plugins/platforms/windows/qwindowscontext.cpp
index 2b96fb3a5e..41655dbd57 100644
--- a/src/plugins/platforms/windows/qwindowscontext.cpp
+++ b/src/plugins/platforms/windows/qwindowscontext.cpp
@@ -334,12 +334,8 @@ bool QWindowsContext::initTouch(unsigned integrationOptions)
if (!touchDevice)
return false;
- if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer) {
- QWindowSystemInterfacePrivate::TabletEvent::setPlatformSynthesizesMouse(false);
- } else {
- if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
- touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
- }
+ if (!(integrationOptions & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch))
+ touchDevice->setCapabilities(touchDevice->capabilities() | QTouchDevice::MouseEmulation);
QWindowSystemInterface::registerTouchDevice(touchDevice);
@@ -376,7 +372,6 @@ bool QWindowsContext::initPointer(unsigned integrationOptions)
if (!QWindowsContext::user32dll.supportsPointerApi())
return false;
- QWindowsContext::user32dll.enableMouseInPointer(TRUE);
d->m_systemInfo |= QWindowsContext::SI_SupportsPointer;
return true;
}
@@ -1218,9 +1213,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
case QtWindows::ExposeEvent:
return platformWindow->handleWmPaint(hwnd, message, wParam, lParam);
case QtWindows::NonClientMouseEvent:
- if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
+ if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
+ return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
+ else
return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(platformWindow->window(), hwnd, et, msg, result);
- break;
case QtWindows::NonClientPointerEvent:
if ((d->m_systemInfo & QWindowsContext::SI_SupportsPointer) && platformWindow->frameStrutEventsEnabled())
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translatePointerEvent(platformWindow->window(), hwnd, et, msg, result);
@@ -1246,10 +1242,10 @@ bool QWindowsContext::windowsProc(HWND hwnd, UINT message,
window = window->parent();
if (!window)
return false;
- if (!(d->m_systemInfo & QWindowsContext::SI_SupportsPointer))
- return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
- else
+ if (d->m_systemInfo & QWindowsContext::SI_SupportsPointer)
return sessionManagerInteractionBlocked() || d->m_pointerHandler.translateMouseEvent(window, hwnd, et, msg, result);
+ else
+ return sessionManagerInteractionBlocked() || d->m_mouseHandler.translateMouseEvent(window, hwnd, et, msg, result);
}
break;
case QtWindows::TouchEvent:
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.cpp b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
index 203d803a1b..f1960f1585 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.cpp
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.cpp
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -50,9 +50,6 @@
#include "qwindowswindow.h"
#include "qwindowsintegration.h"
#include "qwindowsscreen.h"
-#if QT_CONFIG(draganddrop)
-# include "qwindowsdrag.h"
-#endif
#include <QtGui/qguiapplication.h>
#include <QtGui/qscreen.h>
@@ -78,111 +75,9 @@ enum {
QT_PT_TOUCHPAD = 5, // MinGW is missing PT_TOUCHPAD
};
-struct PointerTouchEventInfo {
- QPointer<QWindow> window;
- QList<QWindowSystemInterface::TouchPoint> points;
- Qt::KeyboardModifiers modifiers;
-};
-
-struct PointerTabletEventInfo {
- QPointer<QWindow> window;
- QPointF local;
- QPointF global;
- int device;
- int pointerType;
- Qt::MouseButtons buttons;
- qreal pressure;
- int xTilt;
- int yTilt;
- qreal tangentialPressure;
- qreal rotation;
- int z;
- qint64 uid;
- Qt::KeyboardModifiers modifiers;
-};
-
-static QQueue<PointerTouchEventInfo> touchEventQueue;
-static QQueue<PointerTabletEventInfo> tabletEventQueue;
-
-static void enqueueTouchEvent(QWindow *window,
- const QList<QWindowSystemInterface::TouchPoint> &points,
- Qt::KeyboardModifiers modifiers)
-{
- PointerTouchEventInfo eventInfo;
- eventInfo.window = window;
- eventInfo.points = points;
- eventInfo.modifiers = modifiers;
- touchEventQueue.enqueue(eventInfo);
-}
-
-static void enqueueTabletEvent(QWindow *window, const QPointF &local, const QPointF &global,
- int device, int pointerType, Qt::MouseButtons buttons, qreal pressure,
- int xTilt, int yTilt, qreal tangentialPressure, qreal rotation,
- int z, qint64 uid, Qt::KeyboardModifiers modifiers)
-{
- PointerTabletEventInfo eventInfo;
- eventInfo.window = window;
- eventInfo.local = local;
- eventInfo.global = global;
- eventInfo.device = device;
- eventInfo.pointerType = pointerType;
- eventInfo.buttons = buttons;
- eventInfo.pressure = pressure;
- eventInfo.xTilt = xTilt;
- eventInfo.yTilt = yTilt;
- eventInfo.tangentialPressure = tangentialPressure;
- eventInfo.rotation = rotation;
- eventInfo.z = z;
- eventInfo.uid = uid;
- eventInfo.modifiers = modifiers;
- tabletEventQueue.enqueue(eventInfo);
-}
-
-static void flushTouchEvents(QTouchDevice *touchDevice)
-{
- while (!touchEventQueue.isEmpty()) {
- PointerTouchEventInfo eventInfo = touchEventQueue.dequeue();
- if (eventInfo.window) {
- QWindowSystemInterface::handleTouchEvent(eventInfo.window,
- touchDevice,
- eventInfo.points,
- eventInfo.modifiers);
- }
- }
-}
-
-static void flushTabletEvents()
-{
- while (!tabletEventQueue.isEmpty()) {
- PointerTabletEventInfo eventInfo = tabletEventQueue.dequeue();
- if (eventInfo.window) {
- QWindowSystemInterface::handleTabletEvent(eventInfo.window,
- eventInfo.local,
- eventInfo.global,
- eventInfo.device,
- eventInfo.pointerType,
- eventInfo.buttons,
- eventInfo.pressure,
- eventInfo.xTilt,
- eventInfo.yTilt,
- eventInfo.tangentialPressure,
- eventInfo.rotation,
- eventInfo.z,
- eventInfo.uid,
- eventInfo.modifiers);
- }
- }
-}
-
bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
{
*result = 0;
-
- // If we are inside the move/resize modal loop, let DefWindowProc() handle it (but process NC button release).
- QWindowsWindow *platformWindow = static_cast<QWindowsWindow *>(window->handle());
- if (msg.message != WM_NCPOINTERUP && platformWindow->testFlag(QWindowsWindow::ResizeMoveActive))
- return false;
-
const quint32 pointerId = GET_POINTERID_WPARAM(msg.wParam);
POINTER_INPUT_TYPE pointerType;
@@ -191,30 +86,12 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
return false;
}
- m_lastPointerType = pointerType;
-
- // Handle non-client pen/touch as generic mouse events for compatibility with QDockWindow.
- if ((pointerType == QT_PT_TOUCH || pointerType == QT_PT_PEN) && (et & QtWindows::NonClientEventFlag)) {
- POINTER_INFO pointerInfo;
- if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) {
- qWarning() << "GetPointerInfo() failed:" << qt_error_string();
- return false;
- }
- if (pointerInfo.pointerFlags & (POINTER_FLAG_UP | POINTER_FLAG_DOWN))
- return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo);
- return false;
- }
-
switch (pointerType) {
case QT_PT_POINTER:
case QT_PT_MOUSE:
case QT_PT_TOUCHPAD: {
- POINTER_INFO pointerInfo;
- if (!QWindowsContext::user32dll.getPointerInfo(pointerId, &pointerInfo)) {
- qWarning() << "GetPointerInfo() failed:" << qt_error_string();
- return false;
- }
- return translateMouseTouchPadEvent(window, hwnd, et, msg, &pointerInfo);
+ // Let Mouse/TouchPad be handled using legacy messages.
+ return false;
}
case QT_PT_TOUCH: {
quint32 pointerCount = 0;
@@ -290,76 +167,71 @@ bool QWindowsPointerHandler::translatePointerEvent(QWindow *window, HWND hwnd, Q
return false;
}
-static void getMouseEventInfo(UINT message, POINTER_BUTTON_CHANGE_TYPE changeType, QEvent::Type *eventType, Qt::MouseButton *mouseButton)
-{
- static const QHash<POINTER_BUTTON_CHANGE_TYPE, Qt::MouseButton> buttonMapping {
- {POINTER_CHANGE_FIRSTBUTTON_DOWN, Qt::LeftButton},
- {POINTER_CHANGE_FIRSTBUTTON_UP, Qt::LeftButton},
- {POINTER_CHANGE_SECONDBUTTON_DOWN, Qt::RightButton},
- {POINTER_CHANGE_SECONDBUTTON_UP, Qt::RightButton},
- {POINTER_CHANGE_THIRDBUTTON_DOWN, Qt::MiddleButton},
- {POINTER_CHANGE_THIRDBUTTON_UP, Qt::MiddleButton},
- {POINTER_CHANGE_FOURTHBUTTON_DOWN, Qt::XButton1},
- {POINTER_CHANGE_FOURTHBUTTON_UP, Qt::XButton1},
- {POINTER_CHANGE_FIFTHBUTTON_DOWN, Qt::XButton2},
- {POINTER_CHANGE_FIFTHBUTTON_UP, Qt::XButton2},
- };
-
- static const POINTER_BUTTON_CHANGE_TYPE downChanges[] = {
- POINTER_CHANGE_FIRSTBUTTON_DOWN,
- POINTER_CHANGE_SECONDBUTTON_DOWN,
- POINTER_CHANGE_THIRDBUTTON_DOWN,
- POINTER_CHANGE_FOURTHBUTTON_DOWN,
- POINTER_CHANGE_FIFTHBUTTON_DOWN,
- };
-
- static const POINTER_BUTTON_CHANGE_TYPE upChanges[] = {
- POINTER_CHANGE_FIRSTBUTTON_UP,
- POINTER_CHANGE_SECONDBUTTON_UP,
- POINTER_CHANGE_THIRDBUTTON_UP,
- POINTER_CHANGE_FOURTHBUTTON_UP,
- POINTER_CHANGE_FIFTHBUTTON_UP,
- };
-
- if (!eventType || !mouseButton)
- return;
-
- const bool nonClient = message == WM_NCPOINTERUPDATE ||
- message == WM_NCPOINTERDOWN ||
- message == WM_NCPOINTERUP;
-
- if (std::find(std::begin(downChanges),
- std::end(downChanges), changeType) < std::end(downChanges)) {
- *eventType = nonClient ? QEvent::NonClientAreaMouseButtonPress :
- QEvent::MouseButtonPress;
- } else if (std::find(std::begin(upChanges),
- std::end(upChanges), changeType) < std::end(upChanges)) {
- *eventType = nonClient ? QEvent::NonClientAreaMouseButtonRelease :
- QEvent::MouseButtonRelease;
- } else if (message == WM_POINTERWHEEL || message == WM_POINTERHWHEEL) {
- *eventType = QEvent::Wheel;
- } else {
- *eventType = nonClient ? QEvent::NonClientAreaMouseMove :
- QEvent::MouseMove;
- }
+namespace {
+struct MouseEvent {
+ QEvent::Type type;
+ Qt::MouseButton button;
+};
+} // namespace
- *mouseButton = buttonMapping.value(changeType, Qt::NoButton);
+static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON...
+{
+ return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton;
}
-static Qt::MouseButtons mouseButtonsFromPointerFlags(POINTER_FLAGS pointerFlags)
+static inline MouseEvent eventFromMsg(const MSG &msg)
{
- Qt::MouseButtons result = Qt::NoButton;
- if (pointerFlags & POINTER_FLAG_FIRSTBUTTON)
- result |= Qt::LeftButton;
- if (pointerFlags & POINTER_FLAG_SECONDBUTTON)
- result |= Qt::RightButton;
- if (pointerFlags & POINTER_FLAG_THIRDBUTTON)
- result |= Qt::MiddleButton;
- if (pointerFlags & POINTER_FLAG_FOURTHBUTTON)
- result |= Qt::XButton1;
- if (pointerFlags & POINTER_FLAG_FIFTHBUTTON)
- result |= Qt::XButton2;
- return result;
+ switch (msg.message) {
+ case WM_MOUSEMOVE:
+ return {QEvent::MouseMove, Qt::NoButton};
+ case WM_LBUTTONDOWN:
+ return {QEvent::MouseButtonPress, Qt::LeftButton};
+ case WM_LBUTTONUP:
+ return {QEvent::MouseButtonRelease, Qt::LeftButton};
+ case WM_LBUTTONDBLCLK: // Qt QPA does not handle double clicks, send as press
+ return {QEvent::MouseButtonPress, Qt::LeftButton};
+ case WM_MBUTTONDOWN:
+ return {QEvent::MouseButtonPress, Qt::MidButton};
+ case WM_MBUTTONUP:
+ return {QEvent::MouseButtonRelease, Qt::MidButton};
+ case WM_MBUTTONDBLCLK:
+ return {QEvent::MouseButtonPress, Qt::MidButton};
+ case WM_RBUTTONDOWN:
+ return {QEvent::MouseButtonPress, Qt::RightButton};
+ case WM_RBUTTONUP:
+ return {QEvent::MouseButtonRelease, Qt::RightButton};
+ case WM_RBUTTONDBLCLK:
+ return {QEvent::MouseButtonPress, Qt::RightButton};
+ case WM_XBUTTONDOWN:
+ return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
+ case WM_XBUTTONUP:
+ return {QEvent::MouseButtonRelease, extraButton(msg.wParam)};
+ case WM_XBUTTONDBLCLK:
+ return {QEvent::MouseButtonPress, extraButton(msg.wParam)};
+ case WM_NCMOUSEMOVE:
+ return {QEvent::NonClientAreaMouseMove, Qt::NoButton};
+ case WM_NCLBUTTONDOWN:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
+ case WM_NCLBUTTONUP:
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::LeftButton};
+ case WM_NCLBUTTONDBLCLK:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::LeftButton};
+ case WM_NCMBUTTONDOWN:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
+ case WM_NCMBUTTONUP:
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton};
+ case WM_NCMBUTTONDBLCLK:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton};
+ case WM_NCRBUTTONDOWN:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
+ case WM_NCRBUTTONUP:
+ return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton};
+ case WM_NCRBUTTONDBLCLK:
+ return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton};
+ default: // WM_MOUSELEAVE
+ break;
+ }
+ return {QEvent::None, Qt::NoButton};
}
static Qt::MouseButtons mouseButtonsFromKeyState(WPARAM keyState)
@@ -419,15 +291,6 @@ static bool isValidWheelReceiver(QWindow *candidate)
return false;
}
-static bool isMenuWindow(QWindow *window)
-{
- if (window)
- if (QObject *fo = window->focusObject())
- if (fo->inherits("QMenu"))
- return true;
- return false;
-}
-
static QTouchDevice *createTouchDevice()
{
const int digitizers = GetSystemMetrics(SM_DIGITIZER);
@@ -553,71 +416,6 @@ void QWindowsPointerHandler::handleEnterLeave(QWindow *window,
m_previousCaptureWindow = hasCapture ? window : nullptr;
}
-bool QWindowsPointerHandler::translateMouseTouchPadEvent(QWindow *window, HWND hwnd,
- QtWindows::WindowsEventType et,
- MSG msg, PVOID vPointerInfo)
-{
- POINTER_INFO *pointerInfo = static_cast<POINTER_INFO *>(vPointerInfo);
- const QPoint globalPos = QPoint(pointerInfo->ptPixelLocation.x, pointerInfo->ptPixelLocation.y);
- const QPoint localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPos);
- const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
- const Qt::MouseButtons mouseButtons = mouseButtonsFromPointerFlags(pointerInfo->pointerFlags);
- QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
-
- switch (msg.message) {
- case WM_NCPOINTERDOWN:
- case WM_NCPOINTERUP:
- case WM_NCPOINTERUPDATE:
- case WM_POINTERDOWN:
- case WM_POINTERUP:
- case WM_POINTERUPDATE: {
-
- QEvent::Type eventType;
- Qt::MouseButton button;
- getMouseEventInfo(msg.message, pointerInfo->ButtonChangeType, &eventType, &button);
-
- if (et & QtWindows::NonClientEventFlag) {
- QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
- keyModifiers, Qt::MouseEventNotSynthesized);
- return false; // To allow window dragging, etc.
- } else {
-
- handleCaptureRelease(window, currentWindowUnderPointer, hwnd, eventType, mouseButtons);
- handleEnterLeave(window, currentWindowUnderPointer, globalPos);
-
- QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, button, eventType,
- keyModifiers, Qt::MouseEventNotSynthesized);
-
- // The initial down click over the QSizeGrip area, which posts a resize WM_SYSCOMMAND
- // has go to through DefWindowProc() for resizing to work, so we return false here,
- // unless the click was on a menu, as it would mess with menu processing.
- return msg.message != WM_POINTERDOWN || isMenuWindow(window);
- }
- }
- case WM_POINTERHWHEEL:
- case WM_POINTERWHEEL: {
-
- if (!isValidWheelReceiver(window))
- return true;
-
- int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
-
- // Qt horizontal wheel rotation orientation is opposite to the one in WM_POINTERHWHEEL
- if (msg.message == WM_POINTERHWHEEL)
- delta = -delta;
-
- const QPoint angleDelta = (msg.message == WM_POINTERHWHEEL || (keyModifiers & Qt::AltModifier)) ?
- QPoint(delta, 0) : QPoint(0, delta);
-
- QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
- return true;
- }
- case WM_POINTERLEAVE:
- return true;
- }
- return false;
-}
-
bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
QtWindows::WindowsEventType et,
MSG msg, PVOID vTouchInfo, quint32 count)
@@ -653,15 +451,14 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
QList<QWindowSystemInterface::TouchPoint> touchPoints;
- bool primaryPointer = false;
- bool pressRelease = false;
-
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaEvents).noquote().nospace() << showbase
<< __FUNCTION__
<< " message=" << hex << msg.message
<< " count=" << dec << count;
+ Qt::TouchPointStates allStates = 0;
+
for (quint32 i = 0; i < count; ++i) {
if (QWindowsContext::verbose > 1)
qCDebug(lcQpaEvents).noquote().nospace() << showbase
@@ -670,7 +467,13 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
<< " flags=" << hex << touchInfo[i].pointerInfo.pointerFlags;
QWindowSystemInterface::TouchPoint touchPoint;
- touchPoint.id = touchInfo[i].pointerInfo.pointerId;
+ const quint32 pointerId = touchInfo[i].pointerInfo.pointerId;
+ int id = m_touchInputIDToTouchPointID.value(pointerId, -1);
+ if (id == -1) {
+ id = m_touchInputIDToTouchPointID.size();
+ m_touchInputIDToTouchPointID.insert(pointerId, id);
+ }
+ touchPoint.id = id;
touchPoint.pressure = (touchInfo[i].touchMask & TOUCH_MASK_PRESSURE) ?
touchInfo[i].pressure / 1024.0 : 1.0;
if (m_lastTouchPositions.contains(touchPoint.id))
@@ -691,32 +494,27 @@ bool QWindowsPointerHandler::translateTouchEvent(QWindow *window, HWND hwnd,
if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_DOWN) {
touchPoint.state = Qt::TouchPointPressed;
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
- pressRelease = true;
} else if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_UP) {
touchPoint.state = Qt::TouchPointReleased;
m_lastTouchPositions.remove(touchPoint.id);
- pressRelease = true;
} else {
touchPoint.state = stationaryTouchPoint ? Qt::TouchPointStationary : Qt::TouchPointMoved;
m_lastTouchPositions.insert(touchPoint.id, touchPoint.normalPosition);
}
- if (touchInfo[i].pointerInfo.pointerFlags & POINTER_FLAG_PRIMARY)
- primaryPointer = true;
+ allStates |= touchPoint.state;
touchPoints.append(touchPoint);
// Avoid getting repeated messages for this frame if there are multiple pointerIds
QWindowsContext::user32dll.skipPointerFrameMessages(touchInfo[i].pointerInfo.pointerId);
}
- if (primaryPointer && !pressRelease) {
- // Postpone event delivery to avoid hanging inside DoDragDrop().
- // Only the primary pointer will generate mouse messages.
- enqueueTouchEvent(window, touchPoints, QWindowsKeyMapper::queryKeyboardModifiers());
- } else {
- flushTouchEvents(m_touchDevice);
- QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints,
- QWindowsKeyMapper::queryKeyboardModifiers());
- }
+
+ // all touch points released, forget the ids we've seen.
+ if (allStates == Qt::TouchPointReleased)
+ m_touchInputIDToTouchPointID.clear();
+
+ QWindowSystemInterface::handleTouchEvent(window, m_touchDevice, touchPoints,
+ QWindowsKeyMapper::queryKeyboardModifiers());
return false; // Allow mouse messages to be generated.
}
@@ -807,10 +605,9 @@ bool QWindowsPointerHandler::translatePenEvent(QWindow *window, HWND hwnd, QtWin
}
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
- // Postpone event delivery to avoid hanging inside DoDragDrop().
- enqueueTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
- pressure, xTilt, yTilt, tangentialPressure, rotation, z,
- pointerId, keyModifiers);
+ QWindowSystemInterface::handleTabletEvent(target, localPos, hiResGlobalPos, device, type, mouseButtons,
+ pressure, xTilt, yTilt, tangentialPressure, rotation, z,
+ pointerId, keyModifiers);
return false; // Allow mouse messages to be generated.
}
}
@@ -835,18 +632,46 @@ static inline bool isMouseEventSynthesizedFromPenOrTouch()
return ((::GetMessageExtraInfo() & SIGNATURE_MASK) == MI_WP_SIGNATURE);
}
-// Process old-style mouse messages here.
-bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result)
+bool QWindowsPointerHandler::translateMouseWheelEvent(QWindow *window,
+ QWindow *currentWindowUnderPointer,
+ MSG msg,
+ QPoint globalPos,
+ Qt::KeyboardModifiers keyModifiers)
{
- // Generate enqueued events.
- flushTouchEvents(m_touchDevice);
- flushTabletEvents();
+ QWindow *receiver = currentWindowUnderPointer;
+ if (!isValidWheelReceiver(receiver))
+ receiver = window;
+ if (!isValidWheelReceiver(receiver))
+ return true;
+
+ int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
+ // Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL
+ if (msg.message == WM_MOUSEHWHEEL)
+ delta = -delta;
+
+ const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ?
+ QPoint(delta, 0) : QPoint(0, delta);
+
+ QPoint localPos = QWindowsGeometryHint::mapFromGlobal(receiver, globalPos);
+
+ QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
+ return true;
+}
+
+// Process legacy mouse messages here.
+bool QWindowsPointerHandler::translateMouseEvent(QWindow *window,
+ HWND hwnd,
+ QtWindows::WindowsEventType et,
+ MSG msg,
+ LRESULT *result)
+{
*result = 0;
const QPoint eventPos(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam));
QPoint localPos;
QPoint globalPos;
+
if ((et == QtWindows::MouseWheelEvent) || (et & QtWindows::NonClientEventFlag)) {
globalPos = eventPos;
localPos = QWindowsGeometryHint::mapFromGlobal(hwnd, eventPos);
@@ -857,46 +682,39 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW
const Qt::KeyboardModifiers keyModifiers = QWindowsKeyMapper::queryKeyboardModifiers();
const Qt::MouseButtons mouseButtons = mouseButtonsFromKeyState(msg.wParam);
+ QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
- // Handle "press and hold for right-clicking".
- // We have to synthesize it here as it only comes from Windows as a fake RMB.
- // MS docs say we could use bit 7 from extraInfo to distinguish pen from touch,
- // but on the Surface it is set for both. So we use the last pointer type.
- if (isMouseEventSynthesizedFromPenOrTouch()) {
- if ((msg.message == WM_RBUTTONDOWN || msg.message == WM_RBUTTONUP)
- && (((m_lastPointerType == QT_PT_PEN)
- && QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTabletEvents))
- || ((m_lastPointerType == QT_PT_TOUCH)
- && QCoreApplication::testAttribute(Qt::AA_SynthesizeMouseForUnhandledTouchEvents)))) {
- QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons, Qt::RightButton,
- (msg.message == WM_RBUTTONDOWN) ? QEvent::MouseButtonPress
- : QEvent::MouseButtonRelease,
- keyModifiers, Qt::MouseEventSynthesizedBySystem);
- }
- // Messages synthesized from touch/pen are only used for flushing queues and press&hold.
- return false;
+ if (et == QtWindows::MouseWheelEvent)
+ return translateMouseWheelEvent(window, currentWindowUnderPointer, msg, globalPos, keyModifiers);
+
+ // Windows sends a mouse move with no buttons pressed to signal "Enter"
+ // when a window is shown over the cursor. Discard the event and only use
+ // it for generating QEvent::Enter to be consistent with other platforms -
+ // X11 and macOS.
+ bool discardEvent = false;
+ if (msg.message == WM_MOUSEMOVE) {
+ static QPoint lastMouseMovePos;
+ if (msg.wParam == 0 && (m_windowUnderPointer.isNull() || globalPos == lastMouseMovePos))
+ discardEvent = true;
+ lastMouseMovePos = globalPos;
}
- if (et == QtWindows::MouseWheelEvent) {
-
- if (!isValidWheelReceiver(window))
- return true;
-
- int delta = GET_WHEEL_DELTA_WPARAM(msg.wParam);
-
- // Qt horizontal wheel rotation orientation is opposite to the one in WM_MOUSEHWHEEL
- if (msg.message == WM_MOUSEHWHEEL)
- delta = -delta;
+ Qt::MouseEventSource source = Qt::MouseEventNotSynthesized;
+ if (isMouseEventSynthesizedFromPenOrTouch()) {
+ if (QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch)
+ return false;
+ source = Qt::MouseEventSynthesizedBySystem;
+ }
- const QPoint angleDelta = (msg.message == WM_MOUSEHWHEEL || (keyModifiers & Qt::AltModifier)) ?
- QPoint(delta, 0) : QPoint(0, delta);
+ const MouseEvent mouseEvent = eventFromMsg(msg);
- QWindowSystemInterface::handleWheelEvent(window, localPos, globalPos, QPoint(), angleDelta, keyModifiers);
- return true;
+ if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) {
+ QWindowSystemInterface::handleFrameStrutMouseEvent(window, localPos, globalPos, mouseButtons,
+ mouseEvent.button, mouseEvent.type, keyModifiers, source);
+ return false; // Allow further event processing
}
if (msg.message == WM_MOUSELEAVE) {
-
if (window == m_currentWindow) {
QWindow *leaveTarget = m_windowUnderPointer ? m_windowUnderPointer : m_currentWindow;
qCDebug(lcQpaEvents) << "Leaving window " << leaveTarget;
@@ -904,14 +722,21 @@ bool QWindowsPointerHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtW
m_windowUnderPointer = nullptr;
m_currentWindow = nullptr;
}
+ return true;
+ }
- } else if (msg.message == WM_MOUSEMOVE) {
+ handleCaptureRelease(window, currentWindowUnderPointer, hwnd, mouseEvent.type, mouseButtons);
+ handleEnterLeave(window, currentWindowUnderPointer, globalPos);
- QWindow *currentWindowUnderPointer = getWindowUnderPointer(window, globalPos);
- handleCaptureRelease(window, currentWindowUnderPointer, hwnd, QEvent::MouseMove, mouseButtons);
- handleEnterLeave(window, currentWindowUnderPointer, globalPos);
+ if (!discardEvent && mouseEvent.type != QEvent::None) {
+ QWindowSystemInterface::handleMouseEvent(window, localPos, globalPos, mouseButtons,
+ mouseEvent.button, mouseEvent.type, keyModifiers, source);
}
- return false;
+
+ // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND
+ // is sent for unhandled WM_XBUTTONDOWN.
+ return (msg.message != WM_XBUTTONUP && msg.message != WM_XBUTTONDOWN && msg.message != WM_XBUTTONDBLCLK)
+ || QWindowSystemInterface::flushWindowSystemEvents();
}
QT_END_NAMESPACE
diff --git a/src/plugins/platforms/windows/qwindowspointerhandler.h b/src/plugins/platforms/windows/qwindowspointerhandler.h
index ec3179e821..aebef062bc 100644
--- a/src/plugins/platforms/windows/qwindowspointerhandler.h
+++ b/src/plugins/platforms/windows/qwindowspointerhandler.h
@@ -1,6 +1,6 @@
/****************************************************************************
**
-** Copyright (C) 2018 The Qt Company Ltd.
+** Copyright (C) 2019 The Qt Company Ltd.
** Contact: https://www.qt.io/licensing/
**
** This file is part of the plugins of the Qt Toolkit.
@@ -66,19 +66,19 @@ public:
void clearWindowUnderMouse() { m_windowUnderPointer = nullptr; }
private:
- bool translateMouseTouchPadEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPointerInfo);
bool translateTouchEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vTouchInfo, unsigned int count);
bool translatePenEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, PVOID vPenInfo);
+ bool translateMouseWheelEvent(QWindow *window, QWindow *currentWindowUnderPointer, MSG msg, QPoint globalPos, Qt::KeyboardModifiers keyModifiers);
void handleCaptureRelease(QWindow *window, QWindow *currentWindowUnderPointer, HWND hwnd, QEvent::Type eventType, Qt::MouseButtons mouseButtons);
void handleEnterLeave(QWindow *window, QWindow *currentWindowUnderPointer, QPoint globalPos);
QTouchDevice *m_touchDevice = nullptr;
QHash<int, QPointF> m_lastTouchPositions;
+ QHash<DWORD, int> m_touchInputIDToTouchPointID;
QPointer<QWindow> m_windowUnderPointer;
QPointer<QWindow> m_currentWindow;
QWindow *m_previousCaptureWindow = nullptr;
bool m_needsEnterOnPointerUpdate = false;
- DWORD m_lastPointerType = 0;
};
QT_END_NAMESPACE