From 4c7752c965ab9e10ddb18b10077bdb4cdd52df6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Gr=C3=A4=C3=9Flin?= Date: Wed, 5 Oct 2016 11:50:20 +0200 Subject: [PATCH] Support LEDs in Xkb and libinput Summary: The Xkb implementation starts to track the state of the LEDs in the keymap and emits a signal whenever the LEDs change. This signal is connected to a method in LibInput::Connection which updates the led state on all devices and uses it to init the state of the led when a new device gets connected. BUG: 369214 FIXED-IN: 5.8.2 Test Plan: Connected a keyboard with LEDs and enabled NumLock and ScrollLock. Reviewers: #kwin, #plasma_on_wayland Subscribers: plasma-devel, kwin Tags: #plasma_on_wayland, #kwin Differential Revision: https://phabricator.kde.org/D2943 --- input.cpp | 2 ++ keyboard_input.cpp | 27 +++++++++++++++++++++++++++ keyboard_input.h | 21 +++++++++++++++++++++ libinput/connection.cpp | 33 +++++++++++++++++++++++++++++++++ libinput/connection.h | 4 ++++ 5 files changed, 87 insertions(+) diff --git a/input.cpp b/input.cpp index f9237b58e0..52bca7cf10 100644 --- a/input.cpp +++ b/input.cpp @@ -1233,7 +1233,9 @@ void InputRedirection::setupLibInput() m_libInput = conn; if (conn) { conn->setInputConfig(m_inputConfig); + conn->updateLEDs(m_keyboard->xkb()->leds()); conn->setup(); + connect(m_keyboard, &KeyboardInputRedirection::ledsChanged, conn, &LibInput::Connection::updateLEDs); connect(conn, &LibInput::Connection::eventsRead, this, [this] { m_libInput->processEvents(); diff --git a/keyboard_input.cpp b/keyboard_input.cpp index 6c3a457042..52c50df46e 100644 --- a/keyboard_input.cpp +++ b/keyboard_input.cpp @@ -90,10 +90,15 @@ Xkb::Xkb(InputRedirection *input) , m_controlModifier(0) , m_altModifier(0) , m_metaModifier(0) + , m_numLock(0) + , m_capsLock(0) + , m_scrollLock(0) , m_modifiers(Qt::NoModifier) , m_consumedModifiers(Qt::NoModifier) , m_keysym(XKB_KEY_NoSymbol) + , m_leds() { + qRegisterMetaType(); if (!m_context) { qCDebug(KWIN_XKB) << "Could not create xkb context"; } else { @@ -219,6 +224,11 @@ 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_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); + m_scrollLock = xkb_keymap_led_get_index(m_keymap, XKB_LED_NAME_SCROLL); + m_currentLayout = xkb_state_serialize_layout(m_state, XKB_STATE_LAYOUT_EFFECTIVE); createKeymapFile(); @@ -346,6 +356,23 @@ void Xkb::updateModifiers() mods |= Qt::MetaModifier; } m_modifiers = mods; + + // update LEDs + LEDs leds; + if (xkb_state_led_index_is_active(m_state, m_numLock) == 1) { + leds = leds | LED::NumLock; + } + if (xkb_state_led_index_is_active(m_state, m_capsLock) == 1) { + leds = leds | LED::CapsLock; + } + if (xkb_state_led_index_is_active(m_state, m_scrollLock) == 1) { + leds = leds | LED::ScrollLock; + } + if (m_leds != leds) { + m_leds = leds; + emit m_input->keyboard()->ledsChanged(m_leds); + } + const xkb_layout_index_t layout = xkb_state_serialize_layout(m_state, XKB_STATE_LAYOUT_EFFECTIVE); if (layout != m_currentLayout) { m_currentLayout = layout; diff --git a/keyboard_input.h b/keyboard_input.h index dd43326556..69b35b5592 100644 --- a/keyboard_input.h +++ b/keyboard_input.h @@ -36,6 +36,7 @@ struct xkb_state; struct xkb_compose_table; struct xkb_compose_state; typedef uint32_t xkb_mod_index_t; +typedef uint32_t xkb_led_index_t; typedef uint32_t xkb_keysym_t; namespace KWin @@ -71,6 +72,16 @@ public: void switchToNextLayout(); + enum class LED { + NumLock = 1 << 0, + CapsLock = 1 << 1, + ScrollLock = 1 << 2 + }; + Q_DECLARE_FLAGS(LEDs, LED) + LEDs leds() const { + return m_leds; + } + private: xkb_keymap *loadKeymapFromConfig(); xkb_keymap *loadDefaultKeymap(); @@ -87,6 +98,9 @@ private: xkb_mod_index_t m_controlModifier; xkb_mod_index_t m_altModifier; xkb_mod_index_t m_metaModifier; + xkb_led_index_t m_numLock; + xkb_led_index_t m_capsLock; + xkb_led_index_t m_scrollLock; Qt::KeyboardModifiers m_modifiers; Qt::KeyboardModifiers m_consumedModifiers; xkb_keysym_t m_keysym; @@ -100,6 +114,7 @@ private: xkb_compose_table *table = nullptr; xkb_compose_state *state = nullptr; } m_compose; + LEDs m_leds; }; class KeyboardInputRedirection : public QObject @@ -133,6 +148,9 @@ public: return m_xkb->modifiers(); } +Q_SIGNALS: + void ledsChanged(KWin::Xkb::LEDs); + private Q_SLOTS: void reconfigure(); @@ -156,4 +174,7 @@ Qt::KeyboardModifiers Xkb::modifiers() const } +Q_DECLARE_METATYPE(KWin::Xkb::LED) +Q_DECLARE_METATYPE(KWin::Xkb::LEDs) + #endif diff --git a/libinput/connection.cpp b/libinput/connection.cpp index 6831736b30..fe22bc2f9e 100644 --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -47,6 +47,21 @@ QThread *Connection::s_thread = nullptr; static Context *s_context = nullptr; +static quint32 toLibinputLEDS(Xkb::LEDs leds) +{ + quint32 libinputLeds = 0; + if (leds.testFlag(Xkb::LED::NumLock)) { + libinputLeds = libinputLeds | LIBINPUT_LED_NUM_LOCK; + } + if (leds.testFlag(Xkb::LED::CapsLock)) { + libinputLeds = libinputLeds | LIBINPUT_LED_CAPS_LOCK; + } + if (leds.testFlag(Xkb::LED::ScrollLock)) { + libinputLeds = libinputLeds | LIBINPUT_LED_SCROLL_LOCK; + } + return libinputLeds; +} + Connection::Connection(QObject *parent) : Connection(nullptr, parent) { @@ -95,6 +110,7 @@ Connection::Connection(Context *input, QObject *parent) , m_input(input) , m_notifier(nullptr) , m_mutex(QMutex::Recursive) + , m_leds() { Q_ASSERT(m_input); @@ -246,6 +262,10 @@ void Connection::processEvents() } } applyDeviceConfig(device); + + // enable possible leds + libinput_device_led_update(device->device(), static_cast(toLibinputLEDS(m_leds))); + emit deviceAdded(device); break; } @@ -513,5 +533,18 @@ void Connection::toggleTouchpads() } } +void Connection::updateLEDs(Xkb::LEDs leds) +{ + if (m_leds == leds) { + return; + } + m_leds = leds; + // update on devices + const libinput_led l = static_cast(toLibinputLEDS(leds)); + for (auto it = m_devices.constBegin(), end = m_devices.constEnd(); it != end; ++it) { + libinput_device_led_update((*it)->device(), l); + } +} + } } diff --git a/libinput/connection.h b/libinput/connection.h index 03996d3fbf..10d703588d 100644 --- a/libinput/connection.h +++ b/libinput/connection.h @@ -21,6 +21,7 @@ along with this program. If not, see . #define KWIN_LIBINPUT_CONNECTION_H #include "../input.h" +#include "../keyboard_input.h" #include #include @@ -82,6 +83,8 @@ public: return m_devices; } + void updateLEDs(KWin::Xkb::LEDs leds); + Q_SIGNALS: void keyChanged(quint32 key, KWin::InputRedirection::KeyboardKeyState, quint32 time, KWin::LibInput::Device *device); void pointerButtonChanged(quint32 button, KWin::InputRedirection::PointerButtonState state, quint32 time, KWin::LibInput::Device *device); @@ -135,6 +138,7 @@ private: QVector m_devices; KSharedConfigPtr m_config; bool m_touchpadsEnabled = true; + Xkb::LEDs m_leds; KWIN_SINGLETON(Connection) static QThread *s_thread;