diff --git a/input.cpp b/input.cpp --- a/input.cpp +++ b/input.cpp @@ -1233,7 +1233,9 @@ 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.h b/keyboard_input.h --- a/keyboard_input.h +++ b/keyboard_input.h @@ -36,6 +36,7 @@ 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 @@ 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 @@ 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 @@ xkb_compose_table *table = nullptr; xkb_compose_state *state = nullptr; } m_compose; + LEDs m_leds; }; class KeyboardInputRedirection : public QObject @@ -133,6 +148,9 @@ return m_xkb->modifiers(); } +Q_SIGNALS: + void ledsChanged(KWin::Xkb::LEDs); + private Q_SLOTS: void reconfigure(); @@ -156,4 +174,7 @@ } +Q_DECLARE_METATYPE(KWin::Xkb::LED) +Q_DECLARE_METATYPE(KWin::Xkb::LEDs) + #endif diff --git a/keyboard_input.cpp b/keyboard_input.cpp --- a/keyboard_input.cpp +++ b/keyboard_input.cpp @@ -90,10 +90,15 @@ , 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 @@ 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 @@ 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/libinput/connection.h b/libinput/connection.h --- a/libinput/connection.h +++ b/libinput/connection.h @@ -21,6 +21,7 @@ #define KWIN_LIBINPUT_CONNECTION_H #include "../input.h" +#include "../keyboard_input.h" #include #include @@ -82,6 +83,8 @@ 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 @@ QVector m_devices; KSharedConfigPtr m_config; bool m_touchpadsEnabled = true; + Xkb::LEDs m_leds; KWIN_SINGLETON(Connection) static QThread *s_thread; diff --git a/libinput/connection.cpp b/libinput/connection.cpp --- a/libinput/connection.cpp +++ b/libinput/connection.cpp @@ -47,6 +47,21 @@ 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 @@ , m_input(input) , m_notifier(nullptr) , m_mutex(QMutex::Recursive) + , m_leds() { Q_ASSERT(m_input); @@ -246,6 +262,10 @@ } } 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::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); + } +} + } }