diff options
Diffstat (limited to 'src/plugins/platforms/windows')
3 files changed, 142 insertions, 42 deletions
diff --git a/src/plugins/platforms/windows/qwindowsmousehandler.cpp b/src/plugins/platforms/windows/qwindowsmousehandler.cpp index 814291c54a..0dd1f40b71 100644 --- a/src/plugins/platforms/windows/qwindowsmousehandler.cpp +++ b/src/plugins/platforms/windows/qwindowsmousehandler.cpp @@ -178,6 +178,85 @@ Qt::MouseButtons QWindowsMouseHandler::queryMouseButtons() return result; } +static QPoint lastMouseMovePos; + +namespace { +struct MouseEvent { + QEvent::Type type; + Qt::MouseButton button; +}; + +#ifndef QT_NO_DEBUG_STREAM +QDebug operator<<(QDebug d, const MouseEvent &e) +{ + QDebugStateSaver saver(d); + d.nospace(); + d << "MouseEvent(" << e.type << ", " << e.button << ')'; + return d; +} +#endif // QT_NO_DEBUG_STREAM +} // namespace + +static inline Qt::MouseButton extraButton(WPARAM wParam) // for WM_XBUTTON... +{ + return GET_XBUTTON_WPARAM(wParam) == XBUTTON1 ? Qt::BackButton : Qt::ForwardButton; +} + +static inline MouseEvent eventFromMsg(const MSG &msg) +{ + 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: + return {QEvent::MouseButtonDblClick, Qt::LeftButton}; + case WM_MBUTTONDOWN: + return {QEvent::MouseButtonPress, Qt::MidButton}; + case WM_MBUTTONUP: + return {QEvent::MouseButtonRelease, Qt::MidButton}; + case WM_MBUTTONDBLCLK: + return {QEvent::MouseButtonDblClick, Qt::MidButton}; + case WM_RBUTTONDOWN: + return {QEvent::MouseButtonPress, Qt::RightButton}; + case WM_RBUTTONUP: + return {QEvent::MouseButtonRelease, Qt::RightButton}; + case WM_RBUTTONDBLCLK: + return {QEvent::MouseButtonDblClick, 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::MouseButtonDblClick, 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::NonClientAreaMouseButtonDblClick, Qt::LeftButton}; + case WM_NCMBUTTONDOWN: + return {QEvent::NonClientAreaMouseButtonPress, Qt::MidButton}; + case WM_NCMBUTTONUP: + return {QEvent::NonClientAreaMouseButtonRelease, Qt::MidButton}; + case WM_NCMBUTTONDBLCLK: + return {QEvent::NonClientAreaMouseButtonDblClick, Qt::MidButton}; + case WM_NCRBUTTONDOWN: + return {QEvent::NonClientAreaMouseButtonPress, Qt::RightButton}; + case WM_NCRBUTTONUP: + return {QEvent::NonClientAreaMouseButtonRelease, Qt::RightButton}; + case WM_NCRBUTTONDBLCLK: + return {QEvent::NonClientAreaMouseButtonDblClick, Qt::RightButton}; + default: // WM_MOUSELEAVE + break; + } + return {QEvent::None, Qt::NoButton}; +} + bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, QtWindows::WindowsEventType et, MSG msg, LRESULT *result) @@ -192,8 +271,33 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, if (et == QtWindows::MouseWheelEvent) return translateMouseWheelEvent(window, hwnd, msg, result); + const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); + QPoint clientPosition; + QPoint globalPosition; + if (et & QtWindows::NonClientEventFlag) { + globalPosition = winEventPosition; + clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition); + } else { + clientPosition = winEventPosition; + globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition); + } + + // 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) { + const bool samePosition = globalPosition == lastMouseMovePos; + lastMouseMovePos = globalPosition; + if (msg.wParam == 0 && (m_windowUnderMouse.isNull() || samePosition)) + discardEvent = true; + } + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized; + const MouseEvent mouseEvent = eventFromMsg(msg); + // Check for events synthesized from touch. Lower byte is touch index, 0 means pen. static const bool passSynthesizedMouseEvents = !(QWindowsIntegration::instance()->options() & QWindowsIntegration::DontPassOsMouseEventsSynthesizedFromTouch); @@ -210,13 +314,11 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } } - const QPoint winEventPosition(GET_X_LPARAM(msg.lParam), GET_Y_LPARAM(msg.lParam)); - if (et & QtWindows::NonClientEventFlag) { - const QPoint globalPosition = winEventPosition; - const QPoint clientPosition = QWindowsGeometryHint::mapFromGlobal(hwnd, globalPosition); + if (mouseEvent.type >= QEvent::NonClientAreaMouseMove && mouseEvent.type <= QEvent::NonClientAreaMouseButtonDblClick) { const Qt::MouseButtons buttons = QWindowsMouseHandler::queryMouseButtons(); QWindowSystemInterface::handleFrameStrutMouseEvent(window, clientPosition, globalPosition, buttons, + mouseEvent.button, mouseEvent.type, QWindowsKeyMapper::queryKeyboardModifiers(), source); return false; // Allow further event processing (dragging of windows). @@ -224,7 +326,8 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, *result = 0; if (msg.message == WM_MOUSELEAVE) { - qCDebug(lcQpaEvents) << "WM_MOUSELEAVE for " << window << " previous window under mouse = " << m_windowUnderMouse << " tracked window =" << m_trackedWindow; + qCDebug(lcQpaEvents) << mouseEvent << "for" << window << "previous window under mouse=" + << m_windowUnderMouse << "tracked window=" << m_trackedWindow; // When moving out of a window, WM_MOUSEMOVE within the moved-to window is received first, // so if m_trackedWindow is not the window here, it means the cursor has left the @@ -269,7 +372,6 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, } } - const QPoint globalPosition = QWindowsGeometryHint::mapToGlobal(hwnd, winEventPosition); // In this context, neither an invisible nor a transparent window (transparent regarding mouse // events, "click-through") can be considered as the window under mouse. QWindow *currentWindowUnderMouse = platformWindow->hasMouseCapture() ? @@ -290,10 +392,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, // Qt expects the platform plugin to capture the mouse on // any button press until release. if (!platformWindow->hasMouseCapture() - && (msg.message == WM_LBUTTONDOWN || msg.message == WM_MBUTTONDOWN - || msg.message == WM_RBUTTONDOWN || msg.message == WM_XBUTTONDOWN - || msg.message == WM_LBUTTONDBLCLK || msg.message == WM_MBUTTONDBLCLK - || msg.message == WM_RBUTTONDBLCLK || msg.message == WM_XBUTTONDBLCLK)) { + && (mouseEvent.type == QEvent::MouseButtonPress || mouseEvent.type == QEvent::MouseButtonDblClick)) { platformWindow->setMouseGrabEnabled(true); platformWindow->setFlag(QWindowsWindow::AutoMouseCapture); qCDebug(lcQpaEvents) << "Automatic mouse capture " << window; @@ -302,8 +401,7 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, window->requestActivate(); } else if (platformWindow->hasMouseCapture() && platformWindow->testFlag(QWindowsWindow::AutoMouseCapture) - && (msg.message == WM_LBUTTONUP || msg.message == WM_MBUTTONUP - || msg.message == WM_RBUTTONUP || msg.message == WM_XBUTTONUP) + && mouseEvent.type == QEvent::MouseButtonRelease && !buttons) { platformWindow->setMouseGrabEnabled(false); qCDebug(lcQpaEvents) << "Releasing automatic mouse capture " << window; @@ -369,9 +467,12 @@ bool QWindowsMouseHandler::translateMouseEvent(QWindow *window, HWND hwnd, m_windowUnderMouse = currentWindowUnderMouse; } - QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, - QWindowsKeyMapper::queryKeyboardModifiers(), - source); + if (!discardEvent && mouseEvent.type != QEvent::None) { + QWindowSystemInterface::handleMouseEvent(window, winEventPosition, globalPosition, buttons, + mouseEvent.button, mouseEvent.type, + QWindowsKeyMapper::queryKeyboardModifiers(), + source); + } m_previousCaptureWindow = hasCapture ? window : 0; // QTBUG-48117, force synchronous handling for the extra buttons so that WM_APPCOMMAND // is sent for unhandled WM_XBUTTONDOWN. @@ -397,9 +498,10 @@ static void redirectWheelEvent(QWindow *window, const QPoint &globalPos, int del { // If a window is blocked by modality, it can't get the event. if (isValidWheelReceiver(window)) { + const QPoint point = (orientation == Qt::Vertical) ? QPoint(0, delta) : QPoint(delta, 0); QWindowSystemInterface::handleWheelEvent(window, QWindowsGeometryHint::mapFromGlobal(window, globalPos), - globalPos, delta, orientation, mods); + globalPos, QPoint(), point, mods); } } diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.cpp b/src/plugins/platforms/windows/qwindowstabletsupport.cpp index 280519d39d..00561c9fa1 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.cpp +++ b/src/plugins/platforms/windows/qwindowstabletsupport.cpp @@ -135,9 +135,9 @@ QDebug operator<<(QDebug d, const QWindowsTabletDeviceData &t) d.nospace(); d << "TabletDevice id:" << t.uniqueId << " pressure: " << t.minPressure << ".." << t.maxPressure << " tan pressure: " << t.minTanPressure << ".." - << t.maxTanPressure << " area:" << t.minX << t.minY <<t.minZ - << ".." << t.maxX << t.maxY << t.maxZ << " device " << t.currentDevice - << " pointer " << t.currentPointerType; + << t.maxTanPressure << " area: (" << t.minX << ',' << t.minY << ',' << t.minZ + << ")..(" << t.maxX << ',' << t.maxY << ',' << t.maxZ << ") device " + << t.currentDevice << " pointer " << t.currentPointerType; return d; } @@ -211,9 +211,6 @@ bool QWindowsWinTab32DLL::init() QWindowsTabletSupport::QWindowsTabletSupport(HWND window, HCTX context) : m_window(window) , m_context(context) - , m_absoluteRange(20) - , m_tiltSupport(false) - , m_currentDevice(-1) { AXIS orientation[3]; // Some tablets don't support tilt, check if it is possible, @@ -230,13 +227,13 @@ QWindowsTabletSupport::~QWindowsTabletSupport() QWindowsTabletSupport *QWindowsTabletSupport::create() { if (!m_winTab32DLL.init()) - return 0; + return nullptr; const HWND window = QWindowsContext::instance()->createDummyWindow(QStringLiteral("TabletDummyWindow"), L"TabletDummyWindow", qWindowsTabletSupportWndProc); if (!window) { qCWarning(lcQpaTablet) << __FUNCTION__ << "Unable to create window for tablet."; - return 0; + return nullptr; } LOGCONTEXT lcMine; // build our context from the default context @@ -255,7 +252,7 @@ QWindowsTabletSupport *QWindowsTabletSupport::create() if (!context) { qCDebug(lcQpaTablet) << __FUNCTION__ << "Unable to open tablet."; DestroyWindow(window); - return 0; + return nullptr; } // Set the size of the Packet Queue to the correct size @@ -266,7 +263,7 @@ QWindowsTabletSupport *QWindowsTabletSupport::create() qWarning("Unable to set queue size on tablet. The tablet will not work."); QWindowsTabletSupport::m_winTab32DLL.wTClose(context); DestroyWindow(window); - return 0; + return nullptr; } // cannot restore old size } // cannot set } // mismatch @@ -285,7 +282,7 @@ unsigned QWindowsTabletSupport::options() const QString QWindowsTabletSupport::description() const { - const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, 0); + const unsigned size = m_winTab32DLL.wTInfo(WTI_INTERFACE, IFC_WINTABID, nullptr); if (!size) return QString(); QVarLengthArray<TCHAR> winTabId(size + 1); diff --git a/src/plugins/platforms/windows/qwindowstabletsupport.h b/src/plugins/platforms/windows/qwindowstabletsupport.h index 340818c3f7..0075216d8e 100644 --- a/src/plugins/platforms/windows/qwindowstabletsupport.h +++ b/src/plugins/platforms/windows/qwindowstabletsupport.h @@ -83,22 +83,23 @@ struct QWindowsWinTab32DLL struct QWindowsTabletDeviceData { - QWindowsTabletDeviceData() : minPressure(0), maxPressure(0), minTanPressure(0), - maxTanPressure(0), minX(0), maxX(0), minY(0), maxY(0), minZ(0), maxZ(0), - uniqueId(0), currentDevice(0), currentPointerType(0) {} - QPointF scaleCoordinates(int coordX, int coordY,const QRect &targetArea) const; qreal scalePressure(qreal p) const { return p / qreal(maxPressure - minPressure); } qreal scaleTangentialPressure(qreal p) const { return p / qreal(maxTanPressure - minTanPressure); } - int minPressure; - int maxPressure; - int minTanPressure; - int maxTanPressure; - int minX, maxX, minY, maxY, minZ, maxZ; - qint64 uniqueId; - int currentDevice; - int currentPointerType; + int minPressure = 0; + int maxPressure = 0; + int minTanPressure = 0; + int maxTanPressure = 0; + int minX = 0; + int maxX = 0; + int minY = 0; + int maxY = 0; + int minZ = 0; + int maxZ = 0; + qint64 uniqueId = 0; + int currentDevice = 0; + int currentPointerType = 0; }; #ifndef QT_NO_DEBUG_STREAM @@ -145,10 +146,10 @@ private: static QWindowsWinTab32DLL m_winTab32DLL; const HWND m_window; const HCTX m_context; - int m_absoluteRange; - bool m_tiltSupport; + int m_absoluteRange = 20; + bool m_tiltSupport = false; QVector<QWindowsTabletDeviceData> m_devices; - int m_currentDevice; + int m_currentDevice = -1; QPointF m_oldGlobalPosF; Mode m_mode = PenMode; State m_state = PenUp; |