summaryrefslogtreecommitdiffstats
path: root/src/platformsupport/input/libinput/qlibinputkeyboard.cpp
diff options
context:
space:
mode:
authorGatis Paeglis <gatis.paeglis@qt.io>2018-11-30 12:14:51 +0100
committerGatis Paeglis <gatis.paeglis@qt.io>2019-03-01 14:31:28 +0000
commita34e81ab8be6445877e040b1afb85deeaa725f86 (patch)
tree39c1dbb4103c1cdfb3a044404994b277a40e1b83 /src/platformsupport/input/libinput/qlibinputkeyboard.cpp
parentf9421f0968b8067ca79d83dc75e35092ac4a4948 (diff)
platformsupport/input: add xkbcommon utilities lib
xcb/eglfs/wayland - all use XKB keyboard configs and APIs. There is a lot of duplicated and naturally a diverging code. This patch adds a helper library to avoid all the mentioned problems and unify feature set between these platforms. qlibinputkeyboard: Added a fixup for 2803cdf758dbae1006a0c50300af12dac9f71531. From spec: "keysyms, when bound to modifiers, affect the rules [..]", meaning we can't look at keys in isolation, but have to check if bounding exists in the keymap. This is done by using xkb_state_mod_name_is_active() API, but that API has its limitations - https://github.com/xkbcommon/libxkbcommon/issues/88 I will fix this separately in the LTS (5.12) branch. We need to read the modifier state before the key action. This patch fixes a regression introduced by aforementioned patch, which caused modifiers being reported wrongly in QKeyEvent::modifiers(). qtwayland: Moved toKeysym(QKeyEvent) from qtwayland repository into this library. For this and other key mapping functionality wayland was duplicating the key table. All of that will be removed from qtwayland, and calls will be replaced to use this lib. Adjusted toKeysym() to fix QTBUG-71301. Qt keys don't map to ASCII codes, so first we need search in our key table, instead of mapping from unicode. lookupStringNoKeysymTransformations(): fixed off-by-one error, where we were including terminating NUL in QString. Fixes: QTBUG-71301 Task-number: QTBUG-65503 Change-Id: Idfddea5b34ad620235dc08c0b9e5a0669111821a Reviewed-by: Johan Helsing <johan.helsing@qt.io>
Diffstat (limited to 'src/platformsupport/input/libinput/qlibinputkeyboard.cpp')
-rw-r--r--src/platformsupport/input/libinput/qlibinputkeyboard.cpp185
1 files changed, 19 insertions, 166 deletions
diff --git a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp
index baef769bc98..6586b084f10 100644
--- a/src/platformsupport/input/libinput/qlibinputkeyboard.cpp
+++ b/src/platformsupport/input/libinput/qlibinputkeyboard.cpp
@@ -47,6 +47,7 @@
#if QT_CONFIG(xkbcommon)
#include <xkbcommon/xkbcommon-keysyms.h>
#include <xkbcommon/xkbcommon-names.h>
+#include <QtXkbCommonSupport/private/qxkbcommon_p.h>
#endif
QT_BEGIN_NAMESPACE
@@ -56,88 +57,7 @@ Q_DECLARE_LOGGING_CATEGORY(qLcLibInput)
const int REPEAT_DELAY = 500;
const int REPEAT_RATE = 100;
-#if QT_CONFIG(xkbcommon)
-struct KeyTabEntry {
- int xkbkey;
- int qtkey;
-};
-
-static inline bool operator==(const KeyTabEntry &a, const KeyTabEntry &b)
-{
- return a.xkbkey == b.xkbkey;
-}
-
-static const KeyTabEntry keyTab[] = {
- { XKB_KEY_Escape, Qt::Key_Escape },
- { XKB_KEY_Tab, Qt::Key_Tab },
- { XKB_KEY_ISO_Left_Tab, Qt::Key_Backtab },
- { XKB_KEY_BackSpace, Qt::Key_Backspace },
- { XKB_KEY_Return, Qt::Key_Return },
- { XKB_KEY_Insert, Qt::Key_Insert },
- { XKB_KEY_Delete, Qt::Key_Delete },
- { XKB_KEY_Clear, Qt::Key_Delete },
- { XKB_KEY_Pause, Qt::Key_Pause },
- { XKB_KEY_Print, Qt::Key_Print },
-
- { XKB_KEY_Home, Qt::Key_Home },
- { XKB_KEY_End, Qt::Key_End },
- { XKB_KEY_Left, Qt::Key_Left },
- { XKB_KEY_Up, Qt::Key_Up },
- { XKB_KEY_Right, Qt::Key_Right },
- { XKB_KEY_Down, Qt::Key_Down },
- { XKB_KEY_Prior, Qt::Key_PageUp },
- { XKB_KEY_Next, Qt::Key_PageDown },
-
- { XKB_KEY_Shift_L, Qt::Key_Shift },
- { XKB_KEY_Shift_R, Qt::Key_Shift },
- { XKB_KEY_Shift_Lock, Qt::Key_Shift },
- { XKB_KEY_Control_L, Qt::Key_Control },
- { XKB_KEY_Control_R, Qt::Key_Control },
- { XKB_KEY_Meta_L, Qt::Key_Meta },
- { XKB_KEY_Meta_R, Qt::Key_Meta },
- { XKB_KEY_Alt_L, Qt::Key_Alt },
- { XKB_KEY_Alt_R, Qt::Key_Alt },
- { XKB_KEY_Caps_Lock, Qt::Key_CapsLock },
- { XKB_KEY_Num_Lock, Qt::Key_NumLock },
- { XKB_KEY_Scroll_Lock, Qt::Key_ScrollLock },
- { XKB_KEY_Super_L, Qt::Key_Super_L },
- { XKB_KEY_Super_R, Qt::Key_Super_R },
- { XKB_KEY_Menu, Qt::Key_Menu },
- { XKB_KEY_Hyper_L, Qt::Key_Hyper_L },
- { XKB_KEY_Hyper_R, Qt::Key_Hyper_R },
- { XKB_KEY_Help, Qt::Key_Help },
-
- { XKB_KEY_KP_Space, Qt::Key_Space },
- { XKB_KEY_KP_Tab, Qt::Key_Tab },
- { XKB_KEY_KP_Enter, Qt::Key_Enter },
- { XKB_KEY_KP_Home, Qt::Key_Home },
- { XKB_KEY_KP_Left, Qt::Key_Left },
- { XKB_KEY_KP_Up, Qt::Key_Up },
- { XKB_KEY_KP_Right, Qt::Key_Right },
- { XKB_KEY_KP_Down, Qt::Key_Down },
- { XKB_KEY_KP_Prior, Qt::Key_PageUp },
- { XKB_KEY_KP_Next, Qt::Key_PageDown },
- { XKB_KEY_KP_End, Qt::Key_End },
- { XKB_KEY_KP_Begin, Qt::Key_Clear },
- { XKB_KEY_KP_Insert, Qt::Key_Insert },
- { XKB_KEY_KP_Delete, Qt::Key_Delete },
- { XKB_KEY_KP_Equal, Qt::Key_Equal },
- { XKB_KEY_KP_Multiply, Qt::Key_Asterisk },
- { XKB_KEY_KP_Add, Qt::Key_Plus },
- { XKB_KEY_KP_Separator, Qt::Key_Comma },
- { XKB_KEY_KP_Subtract, Qt::Key_Minus },
- { XKB_KEY_KP_Decimal, Qt::Key_Period },
- { XKB_KEY_KP_Divide, Qt::Key_Slash },
-};
-#endif
-
QLibInputKeyboard::QLibInputKeyboard()
-#if QT_CONFIG(xkbcommon)
- : m_ctx(0),
- m_keymap(0),
- m_state(0),
- m_mods(Qt::NoModifier)
-#endif
{
#if QT_CONFIG(xkbcommon)
qCDebug(qLcLibInput) << "Using xkbcommon for key mapping";
@@ -148,18 +68,14 @@ QLibInputKeyboard::QLibInputKeyboard()
}
m_keymap = xkb_keymap_new_from_names(m_ctx, nullptr, XKB_KEYMAP_COMPILE_NO_FLAGS);
if (!m_keymap) {
- qWarning("Failed to compile keymap");
+ qCWarning(qLcLibInput, "Failed to compile keymap");
return;
}
m_state = xkb_state_new(m_keymap);
if (!m_state) {
- qWarning("Failed to create xkb state");
+ qCWarning(qLcLibInput, "Failed to create xkb state");
return;
}
- m_modindex[0] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_CTRL);
- m_modindex[1] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_ALT);
- m_modindex[2] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_SHIFT);
- m_modindex[3] = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_LOGO);
m_repeatTimer.setSingleShot(true);
connect(&m_repeatTimer, &QTimer::timeout, this, &QLibInputKeyboard::handleRepeat);
@@ -186,52 +102,33 @@ void QLibInputKeyboard::processKey(libinput_event_keyboard *e)
if (!m_ctx || !m_keymap || !m_state)
return;
- const uint32_t k = libinput_event_keyboard_get_key(e) + 8;
+ const uint32_t keycode = libinput_event_keyboard_get_key(e) + 8;
+ const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, keycode);
const bool pressed = libinput_event_keyboard_get_key_state(e) == LIBINPUT_KEY_STATE_PRESSED;
- QVarLengthArray<char, 32> chars(32);
- const int size = xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size());
- if (Q_UNLIKELY(size + 1 > chars.size())) { // +1 for NUL
- chars.resize(size + 1);
- xkb_state_key_get_utf8(m_state, k, chars.data(), chars.size());
- }
- const QString text = QString::fromUtf8(chars.constData(), size);
-
- const xkb_keysym_t sym = xkb_state_key_get_one_sym(m_state, k);
+ // Modifiers here is the modifier state before the event, i.e. not
+ // including the current key in case it is a modifier. See the XOR
+ // logic in QKeyEvent::modifiers(). ### QTBUG-73826
+ Qt::KeyboardModifiers modifiers = QXkbCommon::modifiers(m_state);
- // 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);
+ const QString text = QXkbCommon::lookupString(m_state, keycode);
+ const int qtkey = QXkbCommon::keysymToQtKey(sym, modifiers, m_state, keycode);
- if (qtkey == Qt::Key_Control)
- mods |= Qt::ControlModifier;
- if (qtkey == Qt::Key_Alt)
- mods |= Qt::AltModifier;
- if (qtkey == Qt::Key_Shift)
- mods |= Qt::ShiftModifier;
- if (qtkey == Qt::Key_Meta)
- mods |= Qt::MetaModifier;
- xkb_state_update_key(m_state, k, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
+ xkb_state_update_key(m_state, keycode, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
- if (mods != Qt::NoModifier) {
- if (pressed)
- m_mods |= mods;
- else
- m_mods &= ~mods;
+ Qt::KeyboardModifiers modifiersAfterStateChange = QXkbCommon::modifiers(m_state);
+ QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(modifiersAfterStateChange);
- QGuiApplicationPrivate::inputDeviceManager()->setKeyboardModifiers(m_mods);
- }
QWindowSystemInterface::handleExtendedKeyEvent(nullptr,
pressed ? QEvent::KeyPress : QEvent::KeyRelease,
- qtkey, m_mods, k, sym, m_mods, text);
+ qtkey, modifiers, keycode, sym, modifiers, text);
- if (pressed && xkb_keymap_key_repeats(m_keymap, k)) {
+ if (pressed && xkb_keymap_key_repeats(m_keymap, keycode)) {
m_repeatData.qtkey = qtkey;
- m_repeatData.mods = mods;
- m_repeatData.nativeScanCode = k;
+ m_repeatData.mods = modifiers;
+ m_repeatData.nativeScanCode = keycode;
m_repeatData.virtualKey = sym;
- m_repeatData.nativeMods = mods;
+ m_repeatData.nativeMods = modifiers;
m_repeatData.unicodeText = text;
m_repeatData.repeatCount = 1;
m_repeatTimer.setInterval(REPEAT_DELAY);
@@ -256,50 +153,6 @@ void QLibInputKeyboard::handleRepeat()
m_repeatTimer.setInterval(REPEAT_RATE);
m_repeatTimer.start();
}
-
-int QLibInputKeyboard::keysymToQtKey(xkb_keysym_t key) const
-{
- const size_t elemCount = sizeof(keyTab) / sizeof(KeyTabEntry);
- KeyTabEntry e;
- e.xkbkey = key;
- const KeyTabEntry *result = std::find(keyTab, keyTab + elemCount, e);
- return result != keyTab + elemCount ? result->qtkey : 0;
-}
-
-int QLibInputKeyboard::keysymToQtKey(xkb_keysym_t keysym, Qt::KeyboardModifiers *modifiers, const QString &text) const
-{
- int code = 0;
-#if QT_CONFIG(textcodec)
- QTextCodec *systemCodec = QTextCodec::codecForLocale();
-#endif
- if (keysym < 128 || (keysym < 256
-#if QT_CONFIG(textcodec)
- && systemCodec->mibEnum() == 4
-#endif
- )) {
- // upper-case key, if known
- code = isprint((int)keysym) ? toupper((int)keysym) : 0;
- } else if (keysym >= XKB_KEY_F1 && keysym <= XKB_KEY_F35) {
- // function keys
- code = Qt::Key_F1 + ((int)keysym - XKB_KEY_F1);
- } else if (keysym >= XKB_KEY_KP_Space && keysym <= XKB_KEY_KP_9) {
- if (keysym >= XKB_KEY_KP_0) {
- // numeric keypad keys
- code = Qt::Key_0 + ((int)keysym - XKB_KEY_KP_0);
- } else {
- code = keysymToQtKey(keysym);
- }
- *modifiers |= Qt::KeypadModifier;
- } else if (text.length() == 1 && text.unicode()->unicode() > 0x1f
- && text.unicode()->unicode() != 0x7f
- && !(keysym >= XKB_KEY_dead_grave && keysym <= XKB_KEY_dead_longsolidusoverlay)) {
- code = text.unicode()->toUpper().unicode();
- } else {
- // any other keys
- code = keysymToQtKey(keysym);
- }
- return code;
-}
#endif
QT_END_NAMESPACE