Report modifiers correctly in mouse events with evdev and libinput

Task-number: QTBUG-60694
Change-Id: I7b1625e5f31e49cd2ab18a83bbd0f65f9b58088d
Reviewed-by: Andy Nichols <andy.nichols@qt.io>
This commit is contained in:
Laszlo Agocs 2017-12-11 15:15:56 +01:00
parent 7257862fb2
commit 782eb1a114
6 changed files with 74 additions and 5 deletions

View File

@ -92,4 +92,48 @@ void QInputDeviceManager::setCursorPos(const QPoint &pos)
emit cursorPositionChangeRequested(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 QT_END_NAMESPACE

View File

@ -78,6 +78,9 @@ public:
void setCursorPos(const QPoint &pos); void setCursorPos(const QPoint &pos);
Qt::KeyboardModifiers keyboardModifiers() const;
void setKeyboardModifiers(Qt::KeyboardModifiers modsBeforeEvent, int key);
signals: signals:
void deviceListChanged(QInputDeviceManager::DeviceType type); void deviceListChanged(QInputDeviceManager::DeviceType type);
void cursorPositionChangeRequested(const QPoint &pos); void cursorPositionChangeRequested(const QPoint &pos);

View File

@ -69,6 +69,8 @@ public:
void setDeviceCount(QInputDeviceManager::DeviceType type, int count); void setDeviceCount(QInputDeviceManager::DeviceType type, int count);
QMap<QInputDeviceManager::DeviceType, int> m_deviceCount; QMap<QInputDeviceManager::DeviceType, int> m_deviceCount;
Qt::KeyboardModifiers keyboardModifiers;
}; };
QT_END_NAMESPACE QT_END_NAMESPACE

View File

@ -49,6 +49,9 @@
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
#include <private/qcore_unix_p.h> #include <private/qcore_unix_p.h>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qinputdevicemanager_p.h>
#ifdef Q_OS_FREEBSD #ifdef Q_OS_FREEBSD
#include <dev/evdev/input.h> #include <dev/evdev/input.h>
#else #else
@ -222,6 +225,8 @@ void QEvdevKeyboardHandler::readKeycode()
void QEvdevKeyboardHandler::processKeyEvent(int nativecode, int unicode, int qtcode, void QEvdevKeyboardHandler::processKeyEvent(int nativecode, int unicode, int qtcode,
Qt::KeyboardModifiers modifiers, bool isPress, bool autoRepeat) Qt::KeyboardModifiers modifiers, bool isPress, bool autoRepeat)
{ {
QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(modifiers, qtcode);
QWindowSystemInterface::handleExtendedKeyEvent(0, (isPress ? QEvent::KeyPress : QEvent::KeyRelease), QWindowSystemInterface::handleExtendedKeyEvent(0, (isPress ? QEvent::KeyPress : QEvent::KeyRelease),
qtcode, modifiers, nativecode + 8, 0, int(modifiers), qtcode, modifiers, nativecode + 8, 0, int(modifiers),
(unicode != 0xffff ) ? QString(unicode) : QString(), autoRepeat); (unicode != 0xffff ) ? QString(unicode) : QString(), autoRepeat);
@ -403,6 +408,8 @@ QEvdevKeyboardHandler::KeycodeAction QEvdevKeyboardHandler::processKeycode(quint
Qt::KeyboardModifiers qtmods = Qt::KeyboardModifiers(qtcode & modmask); Qt::KeyboardModifiers qtmods = Qt::KeyboardModifiers(qtcode & modmask);
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)); qCDebug(qLcEvdevKeyMap, "Processing: uni=%04x, qt=%08x, qtmod=%08x", unicode, qtcode, int(qtmods));
// If NumLockOff and keypad key pressed remap event sent // If NumLockOff and keypad key pressed remap event sent

View File

@ -40,6 +40,8 @@
#include "qlibinputkeyboard_p.h" #include "qlibinputkeyboard_p.h"
#include <QtCore/QTextCodec> #include <QtCore/QTextCodec>
#include <QtCore/QLoggingCategory> #include <QtCore/QLoggingCategory>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qinputdevicemanager_p.h>
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
#include <libinput.h> #include <libinput.h>
#ifndef QT_NO_XKBCOMMON_EVDEV #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); 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; Qt::KeyboardModifiers mods = Qt::NoModifier;
const int qtkey = keysymToQtKey(sym, &mods, text); 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); xkb_state_update_key(m_state, k, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(mods, qtkey);
QWindowSystemInterface::handleExtendedKeyEvent(Q_NULLPTR, QWindowSystemInterface::handleExtendedKeyEvent(Q_NULLPTR,
pressed ? QEvent::KeyPress : QEvent::KeyRelease, pressed ? QEvent::KeyPress : QEvent::KeyRelease,
qtkey, mods, k, sym, mods, text); qtkey, mods, k, sym, mods, text);

View File

@ -41,6 +41,8 @@
#include <libinput.h> #include <libinput.h>
#include <QtGui/QGuiApplication> #include <QtGui/QGuiApplication>
#include <QtGui/QScreen> #include <QtGui/QScreen>
#include <QtGui/private/qguiapplication_p.h>
#include <QtGui/private/qinputdevicemanager_p.h>
#include <qpa/qwindowsysteminterface.h> #include <qpa/qwindowsysteminterface.h>
#include <private/qhighdpiscaling_p.h> #include <private/qhighdpiscaling_p.h>
@ -78,7 +80,8 @@ void QLibInputPointer::processButton(libinput_event_pointer *e)
m_buttons.setFlag(button, pressed); 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) 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.setX(qBound(g.left(), qRound(m_pos.x() + dx), g.right()));
m_pos.setY(qBound(g.top(), qRound(m_pos.y() + dy), g.bottom())); 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) 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 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 const Qt::Orientation ori = libinput_event_pointer_get_axis(e) == LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL
? Qt::Vertical : Qt::Horizontal; ? 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 #else
if (libinput_event_pointer_has_axis(e, LIBINPUT_POINTER_AXIS_SCROLL_VERTICAL)) { 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; 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)) { 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; 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 #endif
} }