diff options
-rw-r--r-- | src/plugins/platforms/windows/qwindowscontext.cpp | 20 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowspointerhandler.cpp | 483 | ||||
-rw-r--r-- | src/plugins/platforms/windows/qwindowspointerhandler.h | 6 |
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 |