diff options
-rw-r--r-- | src/gui/kernel/qguiapplication.cpp | 151 | ||||
-rw-r--r-- | src/gui/kernel/qplatformcursor.cpp | 2 | ||||
-rw-r--r-- | src/gui/kernel/qwindowsysteminterface.cpp | 86 | ||||
-rw-r--r-- | src/gui/kernel/qwindowsysteminterface.h | 35 | ||||
-rw-r--r-- | src/gui/kernel/qwindowsysteminterface_p.h | 20 | ||||
-rw-r--r-- | src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp | 5 | ||||
-rw-r--r-- | src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h | 6 | ||||
-rw-r--r-- | src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp | 6 | ||||
-rw-r--r-- | src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h | 3 | ||||
-rw-r--r-- | src/platformsupport/input/libinput/qlibinputpointer.cpp | 11 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.cpp | 10 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbconnection.h | 4 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.cpp | 35 | ||||
-rw-r--r-- | src/plugins/platforms/xcb/qxcbwindow.h | 11 | ||||
-rw-r--r-- | src/testlib/qtestmouse.h | 19 |
15 files changed, 297 insertions, 107 deletions
diff --git a/src/gui/kernel/qguiapplication.cpp b/src/gui/kernel/qguiapplication.cpp index 77897e9e57..80a6a9c1e4 100644 --- a/src/gui/kernel/qguiapplication.cpp +++ b/src/gui/kernel/qguiapplication.cpp @@ -1842,29 +1842,111 @@ void QGuiApplicationPrivate::processWindowSystemEvent(QWindowSystemInterfacePriv } } +/*! \internal + + History is silent on why Qt splits mouse events that change position and + button state at the same time. We believe that this was done to emulate mouse + behavior on touch screens. If mouse tracking is enabled, we will get move + events before the button is pressed. A touch panel does not generally give + move events when not pressed, so without event splitting code path we would + only see a press in a new location without any intervening moves. This could + confuse code that is written for a real mouse. The same is true for mouse + release events that change position, see tst_QWidget::touchEventSynthesizedMouseEvent() + auto test. +*/ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::MouseEvent *e) { - QEvent::Type type; - Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons; - if (e->globalPos != QGuiApplicationPrivate::lastCursorPosition && (stateChange != Qt::NoButton)) { - // A mouse event should not change both position and buttons at the same time. Instead we - // should first send a move event followed by a button changed event. Since this is not the case - // with the current event, we split it in two. - QWindowSystemInterfacePrivate::MouseEvent mouseButtonEvent(e->window.data(), e->timestamp, - e->localPos, e->globalPos, e->buttons, e->modifiers, e->source, e->nonClientArea); - if (e->flags & QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic) - mouseButtonEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; - e->buttons = mouse_buttons; - processMouseEvent(e); - processMouseEvent(&mouseButtonEvent); - return; + QEvent::Type type = QEvent::None; + Qt::MouseButton button = Qt::NoButton; + QWindow *window = e->window.data(); + bool positionChanged = QGuiApplicationPrivate::lastCursorPosition != e->globalPos; + bool mouseMove = false; + bool mousePress = false; + + if (e->enhancedMouseEvent()) { + type = e->buttonType; + button = e->button; + + if (type == QEvent::NonClientAreaMouseMove || type == QEvent::MouseMove) + mouseMove = true; + else if (type == QEvent::NonClientAreaMouseButtonPress || type == QEvent::MouseButtonPress) + mousePress = true; + + if (!mouseMove && positionChanged) { + QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, + e->localPos, e->globalPos, e->buttons & ~button, e->modifiers, Qt::NoButton, + e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove, + e->source, e->nonClientArea); + if (e->synthetic()) + moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; + processMouseEvent(&moveEvent); // mouse move excluding state change + processMouseEvent(e); // the original mouse event + return; + } + } else { + Qt::MouseButtons stateChange = e->buttons ^ mouse_buttons; + if (positionChanged && (stateChange != Qt::NoButton)) { + QWindowSystemInterfacePrivate::MouseEvent moveEvent(window, e->timestamp, e->localPos, + e->globalPos, mouse_buttons, e->modifiers, Qt::NoButton, QEvent::None, e->source, + e->nonClientArea); + if (e->synthetic()) + moveEvent.flags |= QWindowSystemInterfacePrivate::WindowSystemEvent::Synthetic; + processMouseEvent(&moveEvent); // mouse move excluding state change + processMouseEvent(e); // the original mouse event + return; + } + + // In the compatibility path we deduce event type and button that caused the event + if (positionChanged) { + mouseMove = true; + type = e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove; + } else { + // Check to see if a new button has been pressed/released. + for (uint mask = Qt::LeftButton; mask <= Qt::MaxMouseButton; mask <<= 1) { + if (stateChange & mask) { + button = Qt::MouseButton(mask); + break; + } + } + if (button == Qt::NoButton) { + // Ignore mouse events that don't change the current state. This shouldn't + // really happen, getting here can only mean that the stored button state + // is out of sync with the actual physical button state. + return; + } + if (button & e->buttons) { + mousePress = true; + type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonPress + : QEvent::MouseButtonPress; + } else { + type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonRelease + : QEvent::MouseButtonRelease; + } + } } - QWindow *window = e->window.data(); modifier_buttons = e->modifiers; - QPointF localPoint = e->localPos; QPointF globalPoint = e->globalPos; + bool doubleClick = false; + + if (mouseMove) { + QGuiApplicationPrivate::lastCursorPosition = globalPoint; + if (qAbs(globalPoint.x() - mousePressX) > mouse_double_click_distance|| + qAbs(globalPoint.y() - mousePressY) > mouse_double_click_distance) + mousePressButton = Qt::NoButton; + } else { + mouse_buttons = e->buttons; + if (mousePress) { + ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval()); + doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton; + mousePressTime = e->timestamp; + mousePressButton = button; + const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint(); + mousePressX = point.x(); + mousePressY = point.y(); + } + } if (e->nullWindow()) { window = QGuiApplication::topLevelAt(globalPoint.toPoint()); @@ -1885,43 +1967,6 @@ void QGuiApplicationPrivate::processMouseEvent(QWindowSystemInterfacePrivate::Mo } } - Qt::MouseButton button = Qt::NoButton; - bool doubleClick = false; - - if (QGuiApplicationPrivate::lastCursorPosition != globalPoint) { - type = e->nonClientArea ? QEvent::NonClientAreaMouseMove : QEvent::MouseMove; - QGuiApplicationPrivate::lastCursorPosition = globalPoint; - if (qAbs(globalPoint.x() - mousePressX) > mouse_double_click_distance|| - qAbs(globalPoint.y() - mousePressY) > mouse_double_click_distance) - mousePressButton = Qt::NoButton; - } else { // Check to see if a new button has been pressed/released. - for (int check = Qt::LeftButton; - check <= int(Qt::MaxMouseButton); - check = check << 1) { - if (check & stateChange) { - button = Qt::MouseButton(check); - break; - } - } - if (button == Qt::NoButton) { - // Ignore mouse events that don't change the current state. - return; - } - mouse_buttons = e->buttons; - if (button & e->buttons) { - ulong doubleClickInterval = static_cast<ulong>(QGuiApplication::styleHints()->mouseDoubleClickInterval()); - doubleClick = e->timestamp - mousePressTime < doubleClickInterval && button == mousePressButton; - type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonPress : QEvent::MouseButtonPress; - mousePressTime = e->timestamp; - mousePressButton = button; - const QPoint point = QGuiApplicationPrivate::lastCursorPosition.toPoint(); - mousePressX = point.x(); - mousePressY = point.y(); - } else { - type = e->nonClientArea ? QEvent::NonClientAreaMouseButtonRelease : QEvent::MouseButtonRelease; - } - } - if (!window) return; diff --git a/src/gui/kernel/qplatformcursor.cpp b/src/gui/kernel/qplatformcursor.cpp index e6cf6a8216..df78e7d896 100644 --- a/src/gui/kernel/qplatformcursor.cpp +++ b/src/gui/kernel/qplatformcursor.cpp @@ -128,7 +128,7 @@ void QPlatformCursor::setPos(const QPoint &pos) qWarning("This plugin does not support QCursor::setPos()" "; emulating movement within the application."); } - QWindowSystemInterface::handleMouseEvent(0, pos, pos, Qt::NoButton); + QWindowSystemInterface::handleMouseEvent(0, pos, pos, Qt::NoButton, Qt::NoButton, QEvent::MouseMove); } // End of display and pointer event handling code diff --git a/src/gui/kernel/qwindowsysteminterface.cpp b/src/gui/kernel/qwindowsysteminterface.cpp index 53653f94d8..a065e254df 100644 --- a/src/gui/kernel/qwindowsysteminterface.cpp +++ b/src/gui/kernel/qwindowsysteminterface.cpp @@ -341,36 +341,79 @@ void QWindowSystemInterface::handleCloseEvent(QWindow *window, bool *accepted) \a w == 0 means that the event is in global coords only, \a local will be ignored in this case */ +#if QT_DEPRECATED_SINCE(5, 11) QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { - unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleMouseEvent<Delivery>(window, time, local, global, b, mods, source); + handleMouseEvent<Delivery>(window, local, global, b, Qt::NoButton, QEvent::None, mods, source); } QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { - QWindowSystemInterfacePrivate::MouseEvent * e = - new QWindowSystemInterfacePrivate::MouseEvent(window, timestamp, QHighDpi::fromNativeLocalPosition(local, window), QHighDpi::fromNativePixels(global, window), b, mods, source); - QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e); + handleMouseEvent<Delivery>(window, timestamp, local, global, b, Qt::NoButton, QEvent::None, mods, source); } void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { - const unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); - handleFrameStrutMouseEvent(window, time, local, global, b, mods, source); + handleFrameStrutMouseEvent(window, local, global, b, Qt::NoButton, QEvent::None, mods, source); } void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, Qt::MouseEventSource source) { - QWindowSystemInterfacePrivate::MouseEvent * e = - new QWindowSystemInterfacePrivate::MouseEvent(window, timestamp, - QHighDpi::fromNativeLocalPosition(local, window), - QHighDpi::fromNativePixels(global, window), - b, mods, source, true); + handleFrameStrutMouseEvent(window, timestamp, local, global, b, Qt::NoButton, QEvent::None, mods, source); +} +#endif // QT_DEPRECATED_SINCE(5, 11) + +QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *window, + const QPointF &local, const QPointF &global, Qt::MouseButtons state, + Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods, + Qt::MouseEventSource source) +{ + unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); + handleMouseEvent<Delivery>(window, time, local, global, state, button, type, mods, source); +} + +QT_DEFINE_QPA_EVENT_HANDLER(void, handleMouseEvent, QWindow *window, ulong timestamp, + const QPointF &local, const QPointF &global, Qt::MouseButtons state, + Qt::MouseButton button, QEvent::Type type, Qt::KeyboardModifiers mods, + Qt::MouseEventSource source) +{ + auto localPos = QHighDpi::fromNativeLocalPosition(local, window); + auto globalPos = QHighDpi::fromNativePixels(global, window); + + QWindowSystemInterfacePrivate::MouseEvent *e = + new QWindowSystemInterfacePrivate::MouseEvent(window, timestamp, localPos, globalPos, + state, mods, button, type, source); + QWindowSystemInterfacePrivate::handleWindowSystemEvent<Delivery>(e); +} + +void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, + const QPointF &local, const QPointF &global, + Qt::MouseButtons state, + Qt::MouseButton button, QEvent::Type type, + Qt::KeyboardModifiers mods, + Qt::MouseEventSource source) +{ + const unsigned long time = QWindowSystemInterfacePrivate::eventTime.elapsed(); + handleFrameStrutMouseEvent(window, time, local, global, state, button, type, mods, source); +} + +void QWindowSystemInterface::handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, + const QPointF &local, const QPointF &global, + Qt::MouseButtons state, + Qt::MouseButton button, QEvent::Type type, + Qt::KeyboardModifiers mods, + Qt::MouseEventSource source) +{ + auto localPos = QHighDpi::fromNativeLocalPosition(local, window); + auto globalPos = QHighDpi::fromNativePixels(global, window); + + QWindowSystemInterfacePrivate::MouseEvent *e = + new QWindowSystemInterfacePrivate::MouseEvent(window, timestamp, localPos, globalPos, + state, mods, button, type, source, true); QWindowSystemInterfacePrivate::handleWindowSystemEvent(e); } @@ -1008,11 +1051,26 @@ bool QWindowSystemInterface::nonUserInputEventsQueued() // The following functions are used by testlib, and need to be synchronous to avoid // race conditions with plugins delivering native events from secondary threads. +// FIXME: It seems unnecessary to export these wrapper functions, when qtestlib could access +// QWindowSystemInterface directly (by adding dependency to gui-private), see QTBUG-63146. + +Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, + Qt::MouseButtons state, Qt::MouseButton button, + QEvent::Type type, Qt::KeyboardModifiers mods, int timestamp) +{ + const qreal factor = QHighDpiScaling::factor(window); + QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(window, + timestamp, local * factor, global * factor, state, button, type, mods); +} -Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp) +// Wrapper for compatibility with Qt < 5.11 +// ### Qt6: Remove +Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, + Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp) { const qreal factor = QHighDpiScaling::factor(window); - QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(window, timestamp, local * factor, global * factor, b, mods); + QWindowSystemInterface::handleMouseEvent<QWindowSystemInterface::SynchronousDelivery>(window, + timestamp, local * factor, global * factor, b, Qt::NoButton, QEvent::None, mods); } // Wrapper for compatibility with Qt < 5.6 diff --git a/src/gui/kernel/qwindowsysteminterface.h b/src/gui/kernel/qwindowsysteminterface.h index b9d8200c43..e027157fac 100644 --- a/src/gui/kernel/qwindowsysteminterface.h +++ b/src/gui/kernel/qwindowsysteminterface.h @@ -76,20 +76,47 @@ public: struct AsynchronousDelivery {}; struct DefaultDelivery {}; +#if QT_DEPRECATED_SINCE(5, 11) template<typename Delivery = QWindowSystemInterface::DefaultDelivery> - static void handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b, + QT_DEPRECATED static void handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); template<typename Delivery = QWindowSystemInterface::DefaultDelivery> - static void handleMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, + QT_DEPRECATED static void handleMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); - static void handleFrameStrutMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b, + + QT_DEPRECATED static void handleFrameStrutMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); - static void handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, + QT_DEPRECATED static void handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods = Qt::NoModifier, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); +#endif + template<typename Delivery = QWindowSystemInterface::DefaultDelivery> + static void handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, + Qt::MouseButtons state, Qt::MouseButton button, QEvent::Type type, + Qt::KeyboardModifiers mods = Qt::NoModifier, + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + template<typename Delivery = QWindowSystemInterface::DefaultDelivery> + static void handleMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, + const QPointF &global, Qt::MouseButtons state, + Qt::MouseButton button, QEvent::Type type, + Qt::KeyboardModifiers mods = Qt::NoModifier, + Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + + static void handleFrameStrutMouseEvent(QWindow *window, const QPointF &local, + const QPointF &global, Qt::MouseButtons state, + Qt::MouseButton button, QEvent::Type type, + Qt::KeyboardModifiers mods = Qt::NoModifier, + Qt::MouseEventSource source = + Qt::MouseEventNotSynthesized); + static void handleFrameStrutMouseEvent(QWindow *window, ulong timestamp, const QPointF &local, + const QPointF &global, Qt::MouseButtons state, + Qt::MouseButton button, QEvent::Type type, + Qt::KeyboardModifiers mods = Qt::NoModifier, + Qt::MouseEventSource source = + Qt::MouseEventNotSynthesized); static bool handleShortcutEvent(QWindow *window, ulong timestamp, int k, Qt::KeyboardModifiers mods, quint32 nativeScanCode, quint32 nativeVirtualKey, quint32 nativeModifiers, const QString & text = QString(), bool autorep = false, ushort count = 1); diff --git a/src/gui/kernel/qwindowsysteminterface_p.h b/src/gui/kernel/qwindowsysteminterface_p.h index ee2780bf91..4fdf34c7b3 100644 --- a/src/gui/kernel/qwindowsysteminterface_p.h +++ b/src/gui/kernel/qwindowsysteminterface_p.h @@ -225,16 +225,34 @@ public: class MouseEvent : public InputEvent { public: + // TODO - remove this ctor when all usages of it in QGuiApplication are cleaned out MouseEvent(QWindow * w, ulong time, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, Qt::MouseEventSource src = Qt::MouseEventNotSynthesized, bool frame = false) : InputEvent(w, time, Mouse, mods), localPos(local), globalPos(global), buttons(b), - source(src), nonClientArea(frame) { } + source(src), nonClientArea(frame), button(Qt::NoButton), buttonType(QEvent::None) { } + + MouseEvent(QWindow *w, ulong time, const QPointF &local, const QPointF &global, + Qt::MouseButtons state, Qt::KeyboardModifiers mods, + Qt::MouseButton b, QEvent::Type type, + Qt::MouseEventSource src = Qt::MouseEventNotSynthesized, bool frame = false) + : InputEvent(w, time, Mouse, mods), localPos(local), globalPos(global), buttons(state), + source(src), nonClientArea(frame), button(b), buttonType(type) { } + + // ### In Qt6 this method can be removed as there won't be need for compatibility code path + bool enhancedMouseEvent() const + { + static const bool disableEnhanced = qEnvironmentVariableIsSet("QT_QPA_DISABLE_ENHANCED_MOUSE"); + return !disableEnhanced && buttonType != QEvent::None; + } + QPointF localPos; QPointF globalPos; Qt::MouseButtons buttons; Qt::MouseEventSource source; bool nonClientArea; + Qt::MouseButton button; + QEvent::Type buttonType; }; class WheelEvent : public InputEvent { diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp index cd7eec3861..04372ae4d9 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler.cpp @@ -184,7 +184,7 @@ void QEvdevMouseHandler::sendMouseEvent() m_prevInvalid = false; } - emit handleMouseEvent(x, y, m_abs, m_buttons); + emit handleMouseEvent(x, y, m_abs, m_buttons, m_button, m_eventType); m_prevx = m_x; m_prevy = m_y; @@ -286,6 +286,8 @@ void QEvdevMouseHandler::readMouseData() case 0x11f: button = Qt::ExtraButton13; break; } m_buttons.setFlag(button, data->value); + m_button = button; + m_eventType = data->value == 0 ? QEvent::MouseButtonRelease : QEvent::MouseButtonPress; btnChanged = true; } else if (data->type == EV_SYN && data->code == SYN_REPORT) { if (btnChanged) { @@ -293,6 +295,7 @@ void QEvdevMouseHandler::readMouseData() sendMouseEvent(); pendingMouseEvent = false; } else if (posChanged) { + m_eventType = QEvent::MouseMove; posChanged = false; if (m_compression) { pendingMouseEvent = true; diff --git a/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h b/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h index 6cad4b9173..c7f2b04eb2 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h +++ b/src/platformsupport/input/evdevmouse/qevdevmousehandler_p.h @@ -54,6 +54,7 @@ #include <QObject> #include <QString> #include <QPoint> +#include <QEvent> QT_BEGIN_NAMESPACE @@ -69,7 +70,8 @@ public: void readMouseData(); signals: - void handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons); + void handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons, + Qt::MouseButton button, QEvent::Type type); void handleWheelEvent(QPoint delta); private: @@ -86,6 +88,8 @@ private: bool m_abs; bool m_compression; Qt::MouseButtons m_buttons; + Qt::MouseButton m_button; + QEvent::Type m_eventType; int m_jitterLimitSquared; bool m_prevInvalid; int m_hardwareWidth; diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp index ba94bcd460..5264736dd6 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager.cpp @@ -131,7 +131,8 @@ void QEvdevMouseManager::clampPosition() m_y = g.bottom() - m_yoffset; } -void QEvdevMouseManager::handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons) +void QEvdevMouseManager::handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons, + Qt::MouseButton button, QEvent::Type type) { // update current absolute coordinates if (!abs) { @@ -147,7 +148,8 @@ void QEvdevMouseManager::handleMouseEvent(int x, int y, bool abs, Qt::MouseButto QPoint pos(m_x + m_xoffset, m_y + m_yoffset); // Cannot track the keyboard modifiers ourselves here. Instead, report the // modifiers from the last key event that has been seen by QGuiApplication. - QWindowSystemInterface::handleMouseEvent(0, pos, pos, buttons, QGuiApplication::keyboardModifiers()); + Qt::KeyboardModifiers mods = QGuiApplication::keyboardModifiers(); + QWindowSystemInterface::handleMouseEvent(0, pos, pos, buttons, button, type, mods); } void QEvdevMouseManager::handleWheelEvent(QPoint delta) diff --git a/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h b/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h index 10703655b3..13a8e3dec5 100644 --- a/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h +++ b/src/platformsupport/input/evdevmouse/qevdevmousemanager_p.h @@ -68,7 +68,8 @@ public: QEvdevMouseManager(const QString &key, const QString &specification, QObject *parent = 0); ~QEvdevMouseManager(); - void handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons); + void handleMouseEvent(int x, int y, bool abs, Qt::MouseButtons buttons, + Qt::MouseButton button, QEvent::Type type); void handleWheelEvent(QPoint delta); void addMouse(const QString &deviceNode = QString()); diff --git a/src/platformsupport/input/libinput/qlibinputpointer.cpp b/src/platformsupport/input/libinput/qlibinputpointer.cpp index d85a01b7d7..12379a83fa 100644 --- a/src/platformsupport/input/libinput/qlibinputpointer.cpp +++ b/src/platformsupport/input/libinput/qlibinputpointer.cpp @@ -39,6 +39,7 @@ #include "qlibinputpointer_p.h" #include <libinput.h> +#include <QtCore/QEvent> #include <QtGui/QGuiApplication> #include <QtGui/QScreen> #include <qpa/qwindowsysteminterface.h> @@ -78,7 +79,10 @@ void QLibInputPointer::processButton(libinput_event_pointer *e) m_buttons.setFlag(button, pressed); - QWindowSystemInterface::handleMouseEvent(nullptr, m_pos, m_pos, m_buttons, QGuiApplication::keyboardModifiers()); + QEvent::Type type = pressed ? QEvent::MouseButtonPress : QEvent::MouseButtonRelease; + Qt::KeyboardModifiers mods = QGuiApplication::keyboardModifiers(); + + QWindowSystemInterface::handleMouseEvent(nullptr, m_pos, m_pos, m_buttons, button, type, mods); } void QLibInputPointer::processMotion(libinput_event_pointer *e) @@ -91,7 +95,10 @@ void QLibInputPointer::processMotion(libinput_event_pointer *e) m_pos.setX(qBound(g.left(), qRound(m_pos.x() + dx), g.right())); m_pos.setY(qBound(g.top(), qRound(m_pos.y() + dy), g.bottom())); - QWindowSystemInterface::handleMouseEvent(nullptr, m_pos, m_pos, m_buttons, QGuiApplication::keyboardModifiers()); + Qt::KeyboardModifiers mods = QGuiApplication::keyboardModifiers(); + + QWindowSystemInterface::handleMouseEvent(nullptr, m_pos, m_pos, m_buttons, + Qt::NoButton, QEvent::MouseMove, mods); } void QLibInputPointer::processAxis(libinput_event_pointer *e) diff --git a/src/plugins/platforms/xcb/qxcbconnection.cpp b/src/plugins/platforms/xcb/qxcbconnection.cpp index de11ecfb6e..c5eae20266 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.cpp +++ b/src/plugins/platforms/xcb/qxcbconnection.cpp @@ -983,6 +983,12 @@ static Qt::MouseButtons translateMouseButtons(int s) return ret; } +void QXcbConnection::setButtonState(Qt::MouseButton button, bool down) +{ + m_buttonState.setFlag(button, down); + m_button = button; +} + Qt::MouseButton QXcbConnection::translateMouseButton(xcb_button_t s) { switch (s) { @@ -1055,7 +1061,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) // the event explicitly contains the state of the three first buttons, // the rest we need to manage ourselves m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); - m_buttonState |= translateMouseButton(ev->detail); + setButtonState(translateMouseButton(ev->detail), true); if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) qCDebug(lcQpaXInputEvents, "legacy mouse press, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState)); HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_press_event_t, event, handleButtonPressEvent); @@ -1064,7 +1070,7 @@ void QXcbConnection::handleXcbEvent(xcb_generic_event_t *event) xcb_button_release_event_t *ev = (xcb_button_release_event_t *)event; m_keyboard->updateXKBStateFromCore(ev->state); m_buttonState = (m_buttonState & ~0x7) | translateMouseButtons(ev->state); - m_buttonState &= ~translateMouseButton(ev->detail); + setButtonState(translateMouseButton(ev->detail), false); if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) qCDebug(lcQpaXInputEvents, "legacy mouse release, button %d state %X", ev->detail, static_cast<unsigned int>(m_buttonState)); HANDLE_PLATFORM_WINDOW_EVENT(xcb_button_release_event_t, event, handleButtonReleaseEvent); diff --git a/src/plugins/platforms/xcb/qxcbconnection.h b/src/plugins/platforms/xcb/qxcbconnection.h index efc5e666fc..725c01f77d 100644 --- a/src/plugins/platforms/xcb/qxcbconnection.h +++ b/src/plugins/platforms/xcb/qxcbconnection.h @@ -485,8 +485,9 @@ public: xcb_window_t getSelectionOwner(xcb_atom_t atom) const; xcb_window_t getQtSelectionOwner(); - void setButtonState(Qt::MouseButton button, bool down) { m_buttonState.setFlag(button, down); } + void setButtonState(Qt::MouseButton button, bool down); Qt::MouseButtons buttonState() const { return m_buttonState; } + Qt::MouseButton button() const { return m_button; } Qt::MouseButton translateMouseButton(xcb_button_t s); QXcbWindow *focusWindow() const { return m_focusWindow; } @@ -700,6 +701,7 @@ private: bool has_render_extension = false; Qt::MouseButtons m_buttonState = 0; + Qt::MouseButton m_button = Qt::NoButton; QXcbWindow *m_focusWindow = nullptr; QXcbWindow *m_mouseGrabber = nullptr; diff --git a/src/plugins/platforms/xcb/qxcbwindow.cpp b/src/plugins/platforms/xcb/qxcbwindow.cpp index eeaed86e98..475a4e37f3 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.cpp +++ b/src/plugins/platforms/xcb/qxcbwindow.cpp @@ -2111,7 +2111,8 @@ void QXcbWindow::handleUnmapNotifyEvent(const xcb_unmap_notify_event_t *event) } void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y, - int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source) + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, + QEvent::Type type, Qt::MouseEventSource source) { const bool isWheel = detail >= 4 && detail <= 7; if (!isWheel && window() != QGuiApplication::focusWindow()) { @@ -2160,11 +2161,12 @@ void QXcbWindow::handleButtonPressEvent(int event_x, int event_y, int root_x, in connection()->setMousePressWindow(this); - handleMouseEvent(timestamp, local, global, modifiers, source); + handleMouseEvent(timestamp, local, global, modifiers, type, source); } void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y, - int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source) + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, + QEvent::Type type, Qt::MouseEventSource source) { QPoint local(event_x, event_y); QPoint global(root_x, root_y); @@ -2177,7 +2179,7 @@ void QXcbWindow::handleButtonReleaseEvent(int event_x, int event_y, int root_x, if (connection()->buttonState() == Qt::NoButton) connection()->setMousePressWindow(nullptr); - handleMouseEvent(timestamp, local, global, modifiers, source); + handleMouseEvent(timestamp, local, global, modifiers, type, source); } static inline bool doCheckUnGrabAncestor(QXcbConnection *conn) @@ -2278,7 +2280,8 @@ void QXcbWindow::handleLeaveNotifyEvent(int root_x, int root_y, } void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y, - Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source) + Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, + QEvent::Type type, Qt::MouseEventSource source) { QPoint local(event_x, event_y); QPoint global(root_x, root_y); @@ -2292,27 +2295,28 @@ void QXcbWindow::handleMotionNotifyEvent(int event_x, int event_y, int root_x, i else if (hasMousePressWindow && !isMouseButtonPressed) connection()->setMousePressWindow(nullptr); - handleMouseEvent(timestamp, local, global, modifiers, source); + handleMouseEvent(timestamp, local, global, modifiers, type, source); } void QXcbWindow::handleButtonPressEvent(const xcb_button_press_event_t *event) { Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); handleButtonPressEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->detail, - modifiers, event->time); + modifiers, event->time, QEvent::MouseButtonPress); } void QXcbWindow::handleButtonReleaseEvent(const xcb_button_release_event_t *event) { Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); handleButtonReleaseEvent(event->event_x, event->event_y, event->root_x, event->root_y, event->detail, - modifiers, event->time); + modifiers, event->time, QEvent::MouseButtonRelease); } void QXcbWindow::handleMotionNotifyEvent(const xcb_motion_notify_event_t *event) { Qt::KeyboardModifiers modifiers = connection()->keyboard()->translateModifiers(event->state); - handleMotionNotifyEvent(event->event_x, event->event_y, event->root_x, event->root_y, modifiers, event->time); + handleMotionNotifyEvent(event->event_x, event->event_y, event->root_x, event->root_y, modifiers, + event->time, QEvent::MouseMove); } #if QT_CONFIG(xinput2) @@ -2363,18 +2367,18 @@ void QXcbWindow::handleXIMouseEvent(xcb_ge_event_t *event, Qt::MouseEventSource if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) qCDebug(lcQpaXInputEvents, "XI2 mouse press, button %d, time %d, source %s", button, ev->time, sourceName); conn->setButtonState(button, true); - handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, source); + handleButtonPressEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonPress, source); break; case XI_ButtonRelease: if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) qCDebug(lcQpaXInputEvents, "XI2 mouse release, button %d, time %d, source %s", button, ev->time, sourceName); conn->setButtonState(button, false); - handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, source); + handleButtonReleaseEvent(event_x, event_y, root_x, root_y, ev->detail, modifiers, ev->time, QEvent::MouseButtonRelease, source); break; case XI_Motion: if (Q_UNLIKELY(lcQpaXInputEvents().isDebugEnabled())) qCDebug(lcQpaXInputEvents, "XI2 mouse motion %d,%d, time %d, source %s", event_x, event_y, ev->time, sourceName); - handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, source); + handleMotionNotifyEvent(event_x, event_y, root_x, root_y, modifiers, ev->time, QEvent::MouseMove, source); break; default: qWarning() << "Unrecognized XI2 mouse event" << ev->evtype; @@ -2419,10 +2423,13 @@ void QXcbWindow::handleXIEnterLeave(xcb_ge_event_t *event) QXcbWindow *QXcbWindow::toWindow() { return this; } void QXcbWindow::handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, - Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source) + Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source) { connection()->setTime(time); - QWindowSystemInterface::handleMouseEvent(window(), time, local, global, connection()->buttonState(), modifiers, source); + Qt::MouseButton button = type == QEvent::MouseMove ? Qt::NoButton : connection()->button(); + QWindowSystemInterface::handleMouseEvent(window(), time, local, global, + connection()->buttonState(), button, + type, modifiers, source); } void QXcbWindow::handleEnterNotifyEvent(const xcb_enter_notify_event_t *event) diff --git a/src/plugins/platforms/xcb/qxcbwindow.h b/src/plugins/platforms/xcb/qxcbwindow.h index 176f9a234c..b89dddf72f 100644 --- a/src/plugins/platforms/xcb/qxcbwindow.h +++ b/src/plugins/platforms/xcb/qxcbwindow.h @@ -146,7 +146,7 @@ public: QXcbWindow *toWindow() override; void handleMouseEvent(xcb_timestamp_t time, const QPoint &local, const QPoint &global, - Qt::KeyboardModifiers modifiers, Qt::MouseEventSource source); + Qt::KeyboardModifiers modifiers, QEvent::Type type, Qt::MouseEventSource source); void updateNetWmUserTime(xcb_timestamp_t timestamp); @@ -221,13 +221,16 @@ protected: bool compressExposeEvent(QRegion &exposeRegion); void handleButtonPressEvent(int event_x, int event_y, int root_x, int root_y, - int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, + QEvent::Type type, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); void handleButtonReleaseEvent(int event_x, int event_y, int root_x, int root_y, - int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + int detail, Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, + QEvent::Type type, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); void handleMotionNotifyEvent(int event_x, int event_y, int root_x, int root_y, - Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); + Qt::KeyboardModifiers modifiers, xcb_timestamp_t timestamp, + QEvent::Type type, Qt::MouseEventSource source = Qt::MouseEventNotSynthesized); void handleEnterNotifyEvent(int event_x, int event_y, int root_x, int root_y, quint8 mode, quint8 detail, xcb_timestamp_t timestamp); diff --git a/src/testlib/qtestmouse.h b/src/testlib/qtestmouse.h index 8f55c1801f..55f8baa003 100644 --- a/src/testlib/qtestmouse.h +++ b/src/testlib/qtestmouse.h @@ -64,7 +64,9 @@ QT_BEGIN_NAMESPACE -Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *w, const QPointF &local, const QPointF &global, Qt::MouseButtons b, Qt::KeyboardModifiers mods, int timestamp); +Q_GUI_EXPORT void qt_handleMouseEvent(QWindow *window, const QPointF &local, const QPointF &global, + Qt::MouseButtons state, Qt::MouseButton button, + QEvent::Type type, Qt::KeyboardModifiers mods, int timestamp); namespace QTest { @@ -120,23 +122,28 @@ namespace QTest switch (action) { case MouseDClick: - qt_handleMouseEvent(w, pos, global, button, stateKey, ++lastMouseTimestamp); - qt_handleMouseEvent(w, pos, global, Qt::NoButton, stateKey, ++lastMouseTimestamp); + qt_handleMouseEvent(w, pos, global, button, button, QEvent::MouseButtonPress, + stateKey, ++lastMouseTimestamp); + qt_handleMouseEvent(w, pos, global, Qt::NoButton, button, QEvent::MouseButtonRelease, + stateKey, ++lastMouseTimestamp); Q_FALLTHROUGH(); case MousePress: case MouseClick: - qt_handleMouseEvent(w, pos, global, button, stateKey, ++lastMouseTimestamp); + qt_handleMouseEvent(w, pos, global, button, button, QEvent::MouseButtonPress, + stateKey, ++lastMouseTimestamp); lastMouseButton = button; if (action == MousePress) break; Q_FALLTHROUGH(); case MouseRelease: - qt_handleMouseEvent(w, pos, global, Qt::NoButton, stateKey, ++lastMouseTimestamp); + qt_handleMouseEvent(w, pos, global, Qt::NoButton, button, QEvent::MouseButtonRelease, + stateKey, ++lastMouseTimestamp); lastMouseTimestamp += mouseDoubleClickInterval; // avoid double clicks being generated lastMouseButton = Qt::NoButton; break; case MouseMove: - qt_handleMouseEvent(w, pos, global, lastMouseButton, stateKey, ++lastMouseTimestamp); + qt_handleMouseEvent(w, pos, global, lastMouseButton, Qt::NoButton, QEvent::MouseMove, + stateKey, ++lastMouseTimestamp); // No QCursor::setPos() call here. That could potentially result in mouse events sent by the windowing system // which is highly undesired here. Tests must avoid relying on QCursor. break; |