From 260bfaf056c08330ec2ed292e8d9def550e662ec Mon Sep 17 00:00:00 2001 From: Gatis Paeglis Date: Tue, 16 Apr 2013 19:55:54 +0200 Subject: [PATCH] Added possibleKeys(QKeyEvent *) to QXcbIntegration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is required for a modifier+key shortcut support. Also fixes old Qt bug when keymap group changes were not handled properly for shortcut functionality. Task-number: QTBUG-26902 Task-number: QTBUG-4845 Change-Id: I04d2c2ad7049df7420999816154605848fa670e1 Reviewed-by: Friedemann Kleint Reviewed-by: Samuel Rødal --- src/plugins/platforms/xcb/qxcbintegration.cpp | 5 ++ src/plugins/platforms/xcb/qxcbintegration.h | 1 + src/plugins/platforms/xcb/qxcbkeyboard.cpp | 83 +++++++++++++++++++ src/plugins/platforms/xcb/qxcbkeyboard.h | 1 + 4 files changed, 90 insertions(+) diff --git a/src/plugins/platforms/xcb/qxcbintegration.cpp b/src/plugins/platforms/xcb/qxcbintegration.cpp index de26353e1b..9ce9c34828 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.cpp +++ b/src/plugins/platforms/xcb/qxcbintegration.cpp @@ -327,6 +327,11 @@ Qt::KeyboardModifiers QXcbIntegration::queryKeyboardModifiers() const return conn->keyboard()->translateModifiers(keybMask); } +QList QXcbIntegration::possibleKeys(const QKeyEvent *e) const +{ + return m_connections.at(0)->keyboard()->possibleKeys(e); +} + QStringList QXcbIntegration::themeNames() const { return QGenericUnixTheme::themeNames(); diff --git a/src/plugins/platforms/xcb/qxcbintegration.h b/src/plugins/platforms/xcb/qxcbintegration.h index fad5222049..7042628203 100644 --- a/src/plugins/platforms/xcb/qxcbintegration.h +++ b/src/plugins/platforms/xcb/qxcbintegration.h @@ -91,6 +91,7 @@ public: QPlatformServices *services() const; Qt::KeyboardModifiers queryKeyboardModifiers() const; + QList possibleKeys(const QKeyEvent *e) const; QStringList themeNames() const; QPlatformTheme *createPlatformTheme(const QString &name) const; diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.cpp b/src/plugins/platforms/xcb/qxcbkeyboard.cpp index 1a96a49890..e7dabd3351 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.cpp +++ b/src/plugins/platforms/xcb/qxcbkeyboard.cpp @@ -559,6 +559,19 @@ static const unsigned int KeyTbl[] = { 0, 0 }; +// Possible modifier states. +static const Qt::KeyboardModifiers ModsTbl[] = { + Qt::NoModifier, // 0 + Qt::ShiftModifier, // 1 + Qt::ControlModifier, // 2 + Qt::ControlModifier | Qt::ShiftModifier, // 3 + Qt::AltModifier, // 4 + Qt::AltModifier | Qt::ShiftModifier, // 5 + Qt::AltModifier | Qt::ControlModifier, // 6 + Qt::AltModifier | Qt::ShiftModifier | Qt::ControlModifier, // 7 + Qt::NoModifier // Fall-back to raw Key_* +}; + Qt::KeyboardModifiers QXcbKeyboard::translateModifiers(int s) const { Qt::KeyboardModifiers ret = 0; @@ -707,6 +720,76 @@ void QXcbKeyboard::updateXKBState(xcb_xkb_state_notify_event_t *state) } } +QList QXcbKeyboard::possibleKeys(const QKeyEvent *event) const +{ + // turn off the modifier bits which doesn't participate in shortcuts + Qt::KeyboardModifiers notNeeded = Qt::MetaModifier | Qt::KeypadModifier | Qt::GroupSwitchModifier; + Qt::KeyboardModifiers modifiers = event->modifiers() &= ~notNeeded; + // create a fresh kb state and test against the relevant modifier combinations + // NOTE: it should be possible to query the keymap directly, once it gets + // supported by libxkbcommon + struct xkb_state * kb_state = xkb_state_new(xkb_keymap); + if (!kb_state) { + qWarning("QXcbKeyboard: failed to compile xkb keymap"); + return QList(); + } + // get kb state from the master xkb_state and update the temporary kb_state + xkb_layout_index_t baseLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_DEPRESSED); + xkb_layout_index_t latchedLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_LATCHED); + xkb_layout_index_t lockedLayout = xkb_state_serialize_layout(xkb_state, XKB_STATE_LAYOUT_LOCKED); + xkb_mod_index_t latchedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LATCHED); + xkb_mod_index_t lockedMods = xkb_state_serialize_mods(xkb_state, XKB_STATE_MODS_LOCKED); + + xkb_state_update_mask(kb_state, 0, latchedMods, lockedMods, + baseLayout, latchedLayout, lockedLayout); + + xkb_keysym_t baseKeysym = xkb_state_key_get_one_sym(kb_state, event->nativeScanCode()); + if (baseKeysym == XKB_KEY_NoSymbol) { + return QList(); + } + + QList result; + int qtKey = keysymToQtKey(baseKeysym, modifiers, keysymToUnicode(baseKeysym)); + result += (qtKey + modifiers); // The base key is _always_ valid, of course + + xkb_mod_index_t shiftMod = xkb_keymap_mod_get_index(xkb_keymap, "Shift"); + xkb_mod_index_t altMod = xkb_keymap_mod_get_index(xkb_keymap, "Alt"); + xkb_mod_index_t controlMod = xkb_keymap_mod_get_index(xkb_keymap, "Control"); + + xkb_keysym_t sym; + xkb_mod_mask_t depressed = 0; + + //obtain a list of possible shortcuts for the given key event + for (uint i = 1; i < sizeof(ModsTbl) / sizeof(*ModsTbl) ; ++i) { + Qt::KeyboardModifiers neededMods = ModsTbl[i]; + if ((modifiers & neededMods) == neededMods) { + + if (neededMods & Qt::AltModifier) + depressed |= (1 << altMod); + if (neededMods & Qt::ShiftModifier) + depressed |= (1 << shiftMod); + if (neededMods & Qt::ControlModifier) + depressed |= (1 << controlMod); + + // update a keyboard state from a set of explicit masks + xkb_state_update_mask(kb_state, depressed, latchedMods, lockedMods, + baseLayout, latchedLayout, lockedLayout); + sym = xkb_state_key_get_one_sym(kb_state, event->nativeScanCode()); + + if (sym == XKB_KEY_NoSymbol || sym == baseKeysym) + continue; + + Qt::KeyboardModifiers mods = modifiers & ~neededMods; + qtKey = keysymToQtKey(sym, mods, keysymToUnicode(sym)); + result += (qtKey + mods); + depressed = 0; + } + } + + xkb_state_unref(kb_state); + return result; + } + int QXcbKeyboard::keysymToQtKey(xcb_keysym_t key) const { int code = 0; diff --git a/src/plugins/platforms/xcb/qxcbkeyboard.h b/src/plugins/platforms/xcb/qxcbkeyboard.h index ff774197d2..9c278eeb8c 100644 --- a/src/plugins/platforms/xcb/qxcbkeyboard.h +++ b/src/plugins/platforms/xcb/qxcbkeyboard.h @@ -65,6 +65,7 @@ public: void handleMappingNotifyEvent(const xcb_xkb_map_notify_event_t *event); Qt::KeyboardModifiers translateModifiers(int s) const; + QList possibleKeys(const QKeyEvent *e) const; void updateKeymap(); void updateXKBState(xcb_xkb_state_notify_event_t *state);