From 782eb1a114c0aaa729925899b2061d47f494435f Mon Sep 17 00:00:00 2001 From: Laszlo Agocs Date: Mon, 11 Dec 2017 15:15:56 +0100 Subject: [PATCH] Report modifiers correctly in mouse events with evdev and libinput Task-number: QTBUG-60694 Change-Id: I7b1625e5f31e49cd2ab18a83bbd0f65f9b58088d Reviewed-by: Andy Nichols --- src/gui/kernel/qinputdevicemanager.cpp | 44 +++++++++++++++++++ src/gui/kernel/qinputdevicemanager_p.h | 3 ++ src/gui/kernel/qinputdevicemanager_p_p.h | 2 + .../evdevkeyboard/qevdevkeyboardhandler.cpp | 7 +++ .../input/libinput/qlibinputkeyboard.cpp | 6 +++ .../input/libinput/qlibinputpointer.cpp | 17 ++++--- 6 files changed, 74 insertions(+), 5 deletions(-) diff --git a/src/gui/kernel/qinputdevicemanager.cpp b/src/gui/kernel/qinputdevicemanager.cpp index 2d231ae26f..37b1450d5a 100644 --- a/src/gui/kernel/qinputdevicemanager.cpp +++ b/src/gui/kernel/qinputdevicemanager.cpp @@ -92,4 +92,48 @@ void QInputDeviceManager::setCursorPos(const QPoint &pos) emit cursorPositionChangeRequested(pos); } +/*! + \return the keyboard modifier state stored in the QInputDeviceManager object. + + Keyboard input handlers are expected to keep this up-to-date via + setKeyboardModifiers(). + + Querying the state via this function (e.g. from a mouse handler that needs + to include the modifier state in mouse events) is the preferred alternative + over QGuiApplication::keyboardModifiers() since the latter may not report + the current state due to asynchronous QPA event processing. + */ +Qt::KeyboardModifiers QInputDeviceManager::keyboardModifiers() const +{ + Q_D(const QInputDeviceManager); + return d->keyboardModifiers; +} + +void QInputDeviceManager::setKeyboardModifiers(Qt::KeyboardModifiers modsBeforeEvent, int key) +{ + Q_D(QInputDeviceManager); + Qt::KeyboardModifiers mods; + switch (key) { + case Qt::Key_Shift: + mods = Qt::KeyboardModifiers(modsBeforeEvent ^ Qt::ShiftModifier); + break; + case Qt::Key_Control: + mods = Qt::KeyboardModifiers(modsBeforeEvent ^ Qt::ControlModifier); + break; + case Qt::Key_Alt: + mods = Qt::KeyboardModifiers(modsBeforeEvent ^ Qt::AltModifier); + break; + case Qt::Key_Meta: + mods = Qt::KeyboardModifiers(modsBeforeEvent ^ Qt::MetaModifier); + break; + case Qt::Key_AltGr: + mods = Qt::KeyboardModifiers(modsBeforeEvent ^ Qt::GroupSwitchModifier); + break; + default: + mods = modsBeforeEvent; + break; + } + d->keyboardModifiers = mods; +} + QT_END_NAMESPACE diff --git a/src/gui/kernel/qinputdevicemanager_p.h b/src/gui/kernel/qinputdevicemanager_p.h index db9d0596b6..ddf1e6befa 100644 --- a/src/gui/kernel/qinputdevicemanager_p.h +++ b/src/gui/kernel/qinputdevicemanager_p.h @@ -78,6 +78,9 @@ public: void setCursorPos(const QPoint &pos); + Qt::KeyboardModifiers keyboardModifiers() const; + void setKeyboardModifiers(Qt::KeyboardModifiers modsBeforeEvent, int key); + signals: void deviceListChanged(QInputDeviceManager::DeviceType type); void cursorPositionChangeRequested(const QPoint &pos); diff --git a/src/gui/kernel/qinputdevicemanager_p_p.h b/src/gui/kernel/qinputdevicemanager_p_p.h index ae91f3a2ab..0a91252fbc 100644 --- a/src/gui/kernel/qinputdevicemanager_p_p.h +++ b/src/gui/kernel/qinputdevicemanager_p_p.h @@ -69,6 +69,8 @@ public: void setDeviceCount(QInputDeviceManager::DeviceType type, int count); QMap m_deviceCount; + + Qt::KeyboardModifiers keyboardModifiers; }; QT_END_NAMESPACE diff --git a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp index 5c87cb7c9c..a069a48388 100644 --- a/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp +++ b/src/platformsupport/input/evdevkeyboard/qevdevkeyboardhandler.cpp @@ -49,6 +49,9 @@ #include #include +#include +#include + #ifdef Q_OS_FREEBSD #include #else @@ -222,6 +225,8 @@ void QEvdevKeyboardHandler::readKeycode() void QEvdevKeyboardHandler::processKeyEvent(int nativecode, int unicode, int qtcode, Qt::KeyboardModifiers modifiers, bool isPress, bool autoRepeat) { + QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(modifiers, qtcode); + QWindowSystemInterface::handleExtendedKeyEvent(0, (isPress ? QEvent::KeyPress : QEvent::KeyRelease), qtcode, modifiers, nativecode + 8, 0, int(modifiers), (unicode != 0xffff ) ? QString(unicode) : QString(), autoRepeat); @@ -403,6 +408,8 @@ QEvdevKeyboardHandler::KeycodeAction QEvdevKeyboardHandler::processKeycode(quint Qt::KeyboardModifiers qtmods = Qt::KeyboardModifiers(qtcode & modmask); qtcode &= ~modmask; + // qtmods here is the modifier state before the event, i.e. not + // including the current key in case it is a modifier. qCDebug(qLcEvdevKeyMap, "Processing: uni=%04x, qt=%08x, qtmod=%08x", unicode, qtcode, int(qtmods)); // If NumLockOff and keypad key pressed remap event sent diff --git a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp index f14a2e8f04..3722c1ceca 100644 --- a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp +++ b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp @@ -40,6 +40,8 @@ #include "qlibinputkeyboard_p.h" #include #include +#include +#include #include #include #ifndef QT_NO_XKBCOMMON_EVDEV @@ -196,6 +198,8 @@ void QLibInputKeyboard::processKey(libinput_event_keyboard *e) const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, k); + // mods here is the modifier state before the event, i.e. not + // including the current key in case it is a modifier. Qt::KeyboardModifiers mods = Qt::NoModifier; const int qtkey = keysymToQtKey(sym, &mods, text); @@ -211,6 +215,8 @@ void QLibInputKeyboard::processKey(libinput_event_keyboard *e) xkb_state_update_key(m_state, k, pressed ? XKB_KEY_DOWN : XKB_KEY_UP); + QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(mods, qtkey); + QWindowSystemInterface::handleExtendedKeyEvent(Q_NULLPTR, pressed ? QEvent::KeyPress : QEvent::KeyRelease, qtkey, mods, k, sym, mods, text); diff --git a/src/platformsupport/input/libinput/qlibinputpointer.cpp b/src/platformsupport/input/libinput/qlibinputpointer.cpp index bdeac8db7e..734d2fbbc0 100644 --- a/src/platformsupport/input/libinput/qlibinputpointer.cpp +++ b/src/platformsupport/input/libinput/qlibinputpointer.cpp @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include @@ -78,7 +80,8 @@ void QLibInputPointer::processButton(libinput_event_pointer *e) m_buttons.setFlag(button, pressed); - QWindowSystemInterface::handleMouseEvent(Q_NULLPTR, m_pos, m_pos, m_buttons, QGuiApplication::keyboardModifiers()); + QWindowSystemInterface::handleMouseEvent(Q_NULLPTR, m_pos, m_pos, m_buttons, + QGuiApplicationPrivate::inputDeviceManager()->keyboardModifiers()); } void QLibInputPointer::processMotion(libinput_event_pointer *e) @@ -91,7 +94,8 @@ 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(Q_NULLPTR, m_pos, m_pos, m_buttons, QGuiApplication::keyboardModifiers()); + QWindowSystemInterface::handleMouseEvent(Q_NULLPTR, m_pos, m_pos, m_buttons, + QGuiApplicationPrivate::inputDeviceManager()->keyboardModifiers()); } void QLibInputPointer::processAxis(libinput_event_pointer *e) @@ -100,15 +104,18 @@ void QLibInputPointer::processAxis(libinput_event_pointer *e) const double v = libinput_event_pointer_get_axis_value(e) * 120; const Qt::Orientation ori = libinput_event_pointer_get_axis(e) == LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL ? Qt::Vertical : Qt::Horizontal; - QWindowSystemInterface::handleWheelEvent(Q_NULLPTR, m_pos, m_pos, qRound(-v), ori, QGuiApplication::keyboardModifiers()); + QWindowSystemInterface::handleWheelEvent(Q_NULLPTR, m_pos, m_pos, qRound(-v), ori, + QGuiApplicationPrivate::inputDeviceManager()->keyboardModifiers()); #else if (libinput_event_pointer_has_axis(e, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { const double v = libinput_event_pointer_get_axis_value(e, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL) * 120; - QWindowSystemInterface::handleWheelEvent(Q_NULLPTR, m_pos, m_pos, qRound(-v), Qt::Vertical, QGuiApplication::keyboardModifiers()); + QWindowSystemInterface::handleWheelEvent(Q_NULLPTR, m_pos, m_pos, qRound(-v), Qt::Vertical, + QGuiApplicationPrivate::inputDeviceManager()->keyboardModifiers()); } if (libinput_event_pointer_has_axis(e, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL)) { const double v = libinput_event_pointer_get_axis_value(e, LIBINPUT_POINTER_AXIS_SCROLL_HORIZONTAL) * 120; - QWindowSystemInterface::handleWheelEvent(Q_NULLPTR, m_pos, m_pos, qRound(-v), Qt::Horizontal, QGuiApplication::keyboardModifiers()); + QWindowSystemInterface::handleWheelEvent(Q_NULLPTR, m_pos, m_pos, qRound(-v), Qt::Horizontal, + QGuiApplicationPrivate::inputDeviceManager()->keyboardModifiers()); } #endif }