diff --git a/autotests/integration/globalshortcuts_test.cpp b/autotests/integration/globalshortcuts_test.cpp --- a/autotests/integration/globalshortcuts_test.cpp +++ b/autotests/integration/globalshortcuts_test.cpp @@ -89,7 +89,6 @@ kwinApp()->platform()->keyboardKeyPressed(KEY_LEFTSHIFT, timestamp++); QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier); kwinApp()->platform()->keyboardKeyPressed(KEY_5, timestamp++); - QEXPECT_FAIL("", "Consumed modifiers are not removed from checking", Continue); QTRY_COMPARE(triggeredSpy.count(), 1); kwinApp()->platform()->keyboardKeyReleased(KEY_5, timestamp++); diff --git a/autotests/integration/tabbox_test.cpp b/autotests/integration/tabbox_test.cpp --- a/autotests/integration/tabbox_test.cpp +++ b/autotests/integration/tabbox_test.cpp @@ -138,7 +138,6 @@ QCOMPARE(input()->keyboardModifiers(), Qt::NoModifier); QCOMPARE(tabboxClosedSpy.count(), 1); QCOMPARE(TabBox::TabBox::self()->isGrabbed(), false); - QEXPECT_FAIL("", "capslock modifies the shortcut to walk back", Continue); QCOMPARE(workspace()->activeClient(), c2); surface3.reset(); diff --git a/globalshortcuts.cpp b/globalshortcuts.cpp --- a/globalshortcuts.cpp +++ b/globalshortcuts.cpp @@ -247,16 +247,33 @@ bool GlobalShortcutsManager::processKey(Qt::KeyboardModifiers mods, uint32_t key) { if (m_kglobalAccelInterface) { - bool retVal = false; int keyQt = 0; if (KKeyServer::symXToKeyQt(key, &keyQt)) { - QMetaObject::invokeMethod(m_kglobalAccelInterface, - "checkKeyPressed", - Qt::DirectConnection, - Q_RETURN_ARG(bool, retVal), - Q_ARG(int, int(mods) | keyQt)); - if (retVal) { + auto check = [this] (Qt::KeyboardModifiers mods, int keyQt) { + bool retVal = false; + QMetaObject::invokeMethod(m_kglobalAccelInterface, + "checkKeyPressed", + Qt::DirectConnection, + Q_RETURN_ARG(bool, retVal), + Q_ARG(int, int(mods) | keyQt)); + return retVal; + }; + if (check(mods, keyQt)) { return true; + } else if (keyQt == Qt::Key_Backtab) { + // KGlobalAccel on X11 has some workaround for Backtab + // see kglobalaccel/src/runtime/plugins/xcb/kglobalccel_x11.cpp method x11KeyPress + // Apparently KKeySequenceWidget captures Shift+Tab instead of Backtab + // thus if the key is backtab we should adjust to add shift again and use tab + // in addition KWin registers the shortcut incorrectly as Alt+Shift+Backtab + // this should be changed to either Alt+Backtab or Alt+Shift+Tab to match KKeySequenceWidget + // trying the variants + if (check(mods | Qt::ShiftModifier, keyQt)) { + return true; + } + if (check(mods | Qt::ShiftModifier, Qt::Key_Tab)) { + return true; + } } } } diff --git a/input.cpp b/input.cpp --- a/input.cpp +++ b/input.cpp @@ -436,7 +436,7 @@ } bool keyEvent(QKeyEvent *event) override { if (event->type() == QEvent::KeyPress) { - return input()->shortcuts()->processKey(event->modifiers(), event->nativeVirtualKey()); + return input()->shortcuts()->processKey(input()->keyboard()->xkb()->modifiersRelevantForGlobalShortcuts(), event->nativeVirtualKey()); } return false; } diff --git a/keyboard_input.h b/keyboard_input.h --- a/keyboard_input.h +++ b/keyboard_input.h @@ -66,6 +66,7 @@ QString toString(xkb_keysym_t keysym); Qt::Key toQtKey(xkb_keysym_t keysym); Qt::KeyboardModifiers modifiers() const; + Qt::KeyboardModifiers modifiersRelevantForGlobalShortcuts() const; bool shouldKeyRepeat(quint32 key) const; void switchToNextLayout(); @@ -76,6 +77,7 @@ void updateKeymap(xkb_keymap *keymap); void createKeymapFile(); void updateModifiers(); + void updateConsumedModifiers(uint32_t key); InputRedirection *m_input; xkb_context *m_context; xkb_keymap *m_keymap; @@ -86,6 +88,7 @@ xkb_mod_index_t m_altModifier; xkb_mod_index_t m_metaModifier; Qt::KeyboardModifiers m_modifiers; + Qt::KeyboardModifiers m_consumedModifiers; xkb_keysym_t m_keysym; struct { uint pressCount = 0; diff --git a/keyboard_input.cpp b/keyboard_input.cpp --- a/keyboard_input.cpp +++ b/keyboard_input.cpp @@ -91,6 +91,7 @@ , m_altModifier(0) , m_metaModifier(0) , m_modifiers(Qt::NoModifier) + , m_consumedModifiers(Qt::NoModifier) , m_keysym(XKB_KEY_NoSymbol) { if (!m_context) { @@ -295,6 +296,7 @@ } } updateModifiers(); + updateConsumedModifiers(key); if (state == InputRedirection::KeyboardKeyPressed) { m_modOnlyShortcut.pressCount++; if (m_modOnlyShortcut.pressCount == 1 && @@ -368,6 +370,42 @@ } } +void Xkb::updateConsumedModifiers(uint32_t key) +{ + Qt::KeyboardModifiers mods = Qt::NoModifier; + if (xkb_state_mod_index_is_consumed(m_state, key + 8, m_shiftModifier) == 1) { + mods |= Qt::ShiftModifier; + } + if (xkb_state_mod_index_is_consumed(m_state, key + 8, m_altModifier) == 1) { + mods |= Qt::AltModifier; + } + if (xkb_state_mod_index_is_consumed(m_state, key + 8, m_controlModifier) == 1) { + mods |= Qt::ControlModifier; + } + if (xkb_state_mod_index_is_consumed(m_state, key + 8, m_metaModifier) == 1) { + mods |= Qt::MetaModifier; + } + m_consumedModifiers = mods; +} + +Qt::KeyboardModifiers Xkb::modifiersRelevantForGlobalShortcuts() const +{ + Qt::KeyboardModifiers mods = Qt::NoModifier; + if (xkb_state_mod_index_is_active(m_state, m_shiftModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { + mods |= Qt::ShiftModifier; + } + if (xkb_state_mod_index_is_active(m_state, m_altModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { + mods |= Qt::AltModifier; + } + if (xkb_state_mod_index_is_active(m_state, m_controlModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { + mods |= Qt::ControlModifier; + } + if (xkb_state_mod_index_is_active(m_state, m_metaModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { + mods |= Qt::MetaModifier; + } + return mods & ~m_consumedModifiers; +} + xkb_keysym_t Xkb::toKeysym(uint32_t key) { if (!m_state) {