diff --git a/autotests/integration/modifier_only_shortcut_test.cpp b/autotests/integration/modifier_only_shortcut_test.cpp index b613276f8ddf371049e65cd8621d3eb216a9e89b..f38318551c471bc6e89e002b40757580e57f5196 100644 --- a/autotests/integration/modifier_only_shortcut_test.cpp +++ b/autotests/integration/modifier_only_shortcut_test.cpp @@ -48,6 +48,7 @@ private Q_SLOTS: void testTrigger_data(); void testTrigger(); + void testCapsLock(); }; class Target : public QObject @@ -244,5 +245,48 @@ void ModifierOnlyShortcutTest::testTrigger() QVERIFY(Test::unlockScreen()); } +void ModifierOnlyShortcutTest::testCapsLock() +{ + // this test verifies that Capslock does not trigger the shift shortcut + // and that the shift modifier on capslock does not trigger either + Target target; + QSignalSpy triggeredSpy(&target, &Target::shortcutTriggered); + QVERIFY(triggeredSpy.isValid()); + + KConfigGroup group = kwinApp()->config()->group("ModifierOnlyShortcuts"); + group.writeEntry("Meta", QStringList()); + group.writeEntry("Alt", QStringList()); + group.writeEntry("Shift", QStringList{s_serviceName, s_path, s_serviceName, QStringLiteral("shortcut")}); + group.writeEntry("Control", QStringList()); + group.sync(); + workspace()->slotReconfigure(); + + // first test that the normal shortcut triggers + quint32 timestamp = 1; + const int modifier = KEY_LEFTSHIFT; + kwinApp()->platform()->keyboardKeyPressed(modifier, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(modifier, timestamp++); + QCOMPARE(triggeredSpy.count(), 1); + + // now capslock + kwinApp()->platform()->keyboardKeyPressed(KEY_CAPSLOCK, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(KEY_CAPSLOCK, timestamp++); + QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier); + QCOMPARE(triggeredSpy.count(), 1); + + // currently caps lock is on + // shift is ignored + kwinApp()->platform()->keyboardKeyPressed(modifier, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(modifier, timestamp++); + QCOMPARE(input()->keyboardModifiers(), Qt::ShiftModifier); + QCOMPARE(triggeredSpy.count(), 1); + + // release caps lock + kwinApp()->platform()->keyboardKeyPressed(KEY_CAPSLOCK, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(KEY_CAPSLOCK, timestamp++); + QCOMPARE(input()->keyboardModifiers(), Qt::NoModifier); + QCOMPARE(triggeredSpy.count(), 1); +} + WAYLANDTEST_MAIN(ModifierOnlyShortcutTest) #include "modifier_only_shortcut_test.moc" diff --git a/keyboard_input.cpp b/keyboard_input.cpp index 1ce949c2cc1df052a19212ce2ada5584e796c676..e695795fdc45936bd53f4b08eae7a38861b5afd3 100644 --- a/keyboard_input.cpp +++ b/keyboard_input.cpp @@ -85,6 +85,7 @@ Xkb::Xkb(InputRedirection *input) , m_keymap(NULL) , m_state(NULL) , m_shiftModifier(0) + , m_capsModifier(0) , m_controlModifier(0) , m_altModifier(0) , m_metaModifier(0) @@ -191,6 +192,7 @@ void Xkb::updateKeymap(xkb_keymap *keymap) m_state = state; m_shiftModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_SHIFT); + m_capsModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_CAPS); m_controlModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_CTRL); m_altModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_ALT); m_metaModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_LOGO); @@ -250,12 +252,14 @@ void Xkb::updateKey(uint32_t key, InputRedirection::KeyboardKeyState state) if (!m_keymap || !m_state) { return; } + const auto oldMods = m_modifiers; xkb_state_update_key(m_state, key + 8, static_cast(state)); updateModifiers(); if (state == InputRedirection::KeyboardKeyPressed) { m_modOnlyShortcut.pressCount++; if (m_modOnlyShortcut.pressCount == 1 && !ScreenLockerWatcher::self()->isLocked() && + oldMods == Qt::NoModifier && m_input->qtButtonStates() == Qt::NoButton) { m_modOnlyShortcut.modifier = Qt::KeyboardModifier(int(m_modifiers)); } else { @@ -263,7 +267,8 @@ void Xkb::updateKey(uint32_t key, InputRedirection::KeyboardKeyState state) } } else { m_modOnlyShortcut.pressCount--; - if (m_modOnlyShortcut.pressCount == 0) { + if (m_modOnlyShortcut.pressCount == 0 && + m_modifiers == Qt::NoModifier) { if (m_modOnlyShortcut.modifier != Qt::NoModifier) { const auto list = options->modifierOnlyDBusShortcut(m_modOnlyShortcut.modifier); if (list.size() >= 4) { @@ -284,7 +289,8 @@ void Xkb::updateKey(uint32_t key, InputRedirection::KeyboardKeyState state) void Xkb::updateModifiers() { Qt::KeyboardModifiers mods = Qt::NoModifier; - if (xkb_state_mod_index_is_active(m_state, m_shiftModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { + if (xkb_state_mod_index_is_active(m_state, m_shiftModifier, XKB_STATE_MODS_EFFECTIVE) == 1 || + xkb_state_mod_index_is_active(m_state, m_capsModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { mods |= Qt::ShiftModifier; } if (xkb_state_mod_index_is_active(m_state, m_altModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { diff --git a/keyboard_input.h b/keyboard_input.h index 1e79e9b108c2f699bbabbc9b2714bd2aaf5743b6..1609d81fccb10f31afb2ad4256cc3f8e3bcba6ad 100644 --- a/keyboard_input.h +++ b/keyboard_input.h @@ -76,6 +76,7 @@ private: xkb_keymap *m_keymap; xkb_state *m_state; xkb_mod_index_t m_shiftModifier; + xkb_mod_index_t m_capsModifier; xkb_mod_index_t m_controlModifier; xkb_mod_index_t m_altModifier; xkb_mod_index_t m_metaModifier;