From 7c3a851b040e3b7d33186ce787c43683ec076525 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Fl=C3=B6ser?= Date: Thu, 25 Oct 2018 19:46:36 +0200 Subject: [PATCH] Support enabling numlock on startup Summary: This change brings improved num lock support to KWin. The modifier state is read and also mapped to Qt::KeyboardModifiers. Furthermore the input config is read and the NumLock key is evaluated. If the requested state does not match the current num lock state the state is swapped. BUG: 375708 FIXED-IN: 5.15 Test Plan: New unit test added, no manual test due to lack of hardware Subscribers: kwin Tags: #kwin Differential Revision: https://phabricator.kde.org/D16428 --- .../integration/keyboard_layout_test.cpp | 43 +++++++++++++++++++ keyboard_input.cpp | 1 + xkb.cpp | 28 ++++++++++++ xkb.h | 11 +++++ 4 files changed, 83 insertions(+) diff --git a/autotests/integration/keyboard_layout_test.cpp b/autotests/integration/keyboard_layout_test.cpp index 65f125189c..13fbc9ca48 100644 --- a/autotests/integration/keyboard_layout_test.cpp +++ b/autotests/integration/keyboard_layout_test.cpp @@ -60,6 +60,7 @@ private Q_SLOTS: void testVirtualDesktopPolicy(); void testWindowPolicy(); void testApplicationPolicy(); + void testNumLock(); private: void reconfigureLayouts(); @@ -83,6 +84,7 @@ void KeyboardLayoutTest::initTestCase() kwinApp()->setConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig)); kwinApp()->setKxkbConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig)); + kwinApp()->setInputConfig(KSharedConfig::openConfig(QString(), KConfig::SimpleConfig)); kwinApp()->start(); QVERIFY(workspaceCreatedSpy.wait()); @@ -457,5 +459,46 @@ void KeyboardLayoutTest::testApplicationPolicy() QTRY_COMPARE(xkb->layoutName(), QStringLiteral("German (Neo 2)")); } +void KeyboardLayoutTest::testNumLock() +{ + qputenv("KWIN_FORCE_NUM_LOCK_EVALUATION", "1"); + auto xkb = input()->keyboard()->xkb(); + // by default not set + QVERIFY(!xkb->modifiers().testFlag(Qt::KeypadModifier)); + quint32 timestamp = 0; + kwinApp()->platform()->keyboardKeyPressed(KEY_NUMLOCK, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(KEY_NUMLOCK, timestamp++); + // now it should be on + QVERIFY(xkb->modifiers().testFlag(Qt::KeypadModifier)); + // and back to off + kwinApp()->platform()->keyboardKeyPressed(KEY_NUMLOCK, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(KEY_NUMLOCK, timestamp++); + QVERIFY(!xkb->modifiers().testFlag(Qt::KeypadModifier)); + + // let's reconfigure to enable through config + auto group = kwinApp()->inputConfig()->group("Keyboard"); + group.writeEntry("NumLock", 0); + group.sync(); + xkb->reconfigure(); + // now it should be on + QVERIFY(xkb->modifiers().testFlag(Qt::KeypadModifier)); + // pressing should result in it being off + kwinApp()->platform()->keyboardKeyPressed(KEY_NUMLOCK, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(KEY_NUMLOCK, timestamp++); + QVERIFY(!xkb->modifiers().testFlag(Qt::KeypadModifier)); + + // pressing again should enable it + kwinApp()->platform()->keyboardKeyPressed(KEY_NUMLOCK, timestamp++); + kwinApp()->platform()->keyboardKeyReleased(KEY_NUMLOCK, timestamp++); + QVERIFY(xkb->modifiers().testFlag(Qt::KeypadModifier)); + + // now reconfigure to disable on load + group.writeEntry("NumLock", 1); + group.sync(); + xkb->reconfigure(); + QVERIFY(!xkb->modifiers().testFlag(Qt::KeypadModifier)); +} + + WAYLANDTEST_MAIN(KeyboardLayoutTest) #include "keyboard_layout_test.moc" diff --git a/keyboard_input.cpp b/keyboard_input.cpp index cd2801b08a..243fe30b3f 100644 --- a/keyboard_input.cpp +++ b/keyboard_input.cpp @@ -111,6 +111,7 @@ void KeyboardInputRedirection::init() Q_ASSERT(!m_inited); m_inited = true; const auto config = kwinApp()->kxkbConfig(); + m_xkb->setNumLockConfig(kwinApp()->inputConfig()); m_xkb->setConfig(config); m_input->installInputEventSpy(new KeyStateChangedSpy(m_input)); diff --git a/xkb.cpp b/xkb.cpp index 87c7503cab..d334b1ebbc 100644 --- a/xkb.cpp +++ b/xkb.cpp @@ -34,6 +34,7 @@ along with this program. If not, see . // system #include #include +#include Q_LOGGING_CATEGORY(KWIN_XKB, "kwin_xkbcommon", QtCriticalMsg) @@ -75,6 +76,7 @@ Xkb::Xkb(QObject *parent) , m_controlModifier(0) , m_altModifier(0) , m_metaModifier(0) + , m_numModifier(0) , m_numLock(0) , m_capsLock(0) , m_scrollLock(0) @@ -214,6 +216,7 @@ void Xkb::installKeymap(int fd, uint32_t size) qCDebug(KWIN_XKB) << "Could not map keymap from file"; return; } + m_ownership = Ownership::Client; updateKeymap(keymap); } @@ -238,6 +241,7 @@ void Xkb::updateKeymap(xkb_keymap *keymap) 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); + m_numModifier = xkb_keymap_mod_get_index(m_keymap, XKB_MOD_NAME_NUM); m_numLock = xkb_keymap_led_get_index(m_keymap, XKB_LED_NAME_NUM); m_capsLock = xkb_keymap_led_get_index(m_keymap, XKB_LED_NAME_CAPS); @@ -249,8 +253,29 @@ void Xkb::updateKeymap(xkb_keymap *keymap) m_modifierState.latched = xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LATCHED)); m_modifierState.locked = xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LOCKED)); + static bool s_startup = true; + if (s_startup || qEnvironmentVariableIsSet("KWIN_FORCE_NUM_LOCK_EVALUATION")) { + s_startup = false; + if (m_ownership == Ownership::Server && m_numModifier != XKB_MOD_INVALID && m_numLockConfig) { + const KConfigGroup config = m_numLockConfig->group("Keyboard"); + // STATE_ON = 0, STATE_OFF = 1, STATE_UNCHANGED = 2, see plasma-desktop/kcms/keyboard/kcmmisc.h + const auto setting = config.readEntry("NumLock", 2); + const bool numLockIsOn = xkb_state_mod_index_is_active(m_state, m_numModifier, XKB_STATE_MODS_LOCKED); + if ((setting == 0 && !numLockIsOn) || (setting == 1 && numLockIsOn)) { + std::bitset mask{m_modifierState.locked}; + if (mask.size() > m_numModifier) { + mask[m_numModifier] = (setting == 0); + m_modifierState.locked = mask.to_ulong(); + xkb_state_update_mask(m_state, m_modifierState.depressed, m_modifierState.latched, m_modifierState.locked, 0, 0, m_currentLayout); + m_modifierState.locked = xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_LOCKED)); + } + } + } + } + createKeymapFile(); forwardModifiers(); + updateModifiers(); } void Xkb::createKeymapFile() @@ -344,6 +369,9 @@ void Xkb::updateModifiers() if (xkb_state_mod_index_is_active(m_state, m_metaModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { mods |= Qt::MetaModifier; } + if (xkb_state_mod_index_is_active(m_state, m_numModifier, XKB_STATE_MODS_EFFECTIVE) == 1) { + mods |= Qt::KeypadModifier; + } m_modifiers = mods; // update LEDs diff --git a/xkb.h b/xkb.h index bbe2e9312c..671f67b227 100644 --- a/xkb.h +++ b/xkb.h @@ -58,6 +58,9 @@ public: void setConfig(KSharedConfigPtr config) { m_config = config; } + void setNumLockConfig(KSharedConfigPtr config) { + m_numLockConfig = config; + } void reconfigure(); void installKeymap(int fd, uint32_t size); @@ -130,6 +133,7 @@ private: xkb_mod_index_t m_controlModifier; xkb_mod_index_t m_altModifier; xkb_mod_index_t m_metaModifier; + xkb_mod_index_t m_numModifier; xkb_led_index_t m_numLock; xkb_led_index_t m_capsLock; xkb_led_index_t m_scrollLock; @@ -144,6 +148,7 @@ private: } m_compose; LEDs m_leds; KSharedConfigPtr m_config; + KSharedConfigPtr m_numLockConfig; struct { xkb_mod_index_t depressed = 0; @@ -151,6 +156,12 @@ private: xkb_mod_index_t locked = 0; } m_modifierState; + enum class Ownership { + Server, + Client + }; + Ownership m_ownership = Ownership::Server; + QPointer m_seat; };