diff --git a/src/inputmethod.cpp b/src/inputmethod.cpp index 12ce32958d..24ee6bd0a8 100644 --- a/src/inputmethod.cpp +++ b/src/inputmethod.cpp @@ -104,6 +104,8 @@ void InputMethod::init() connect(textInputV2, &TextInputV2Interface::enabledChanged, this, &InputMethod::textInputInterfaceV2EnabledChanged); connect(textInputV3, &TextInputV3Interface::enabledChanged, this, &InputMethod::textInputInterfaceV3EnabledChanged); } + + connect(input()->keyboard()->xkb(), &Xkb::modifierStateChanged, this, &InputMethod::forwardModifiers); } } @@ -484,6 +486,18 @@ void InputMethod::modifiers(quint32 serial, quint32 mods_depressed, quint32 mods xkb->updateModifiers(mods_depressed, mods_latched, mods_locked, group); } +void InputMethod::forwardModifiers() +{ + auto xkb = input()->keyboard()->xkb(); + if (m_keyboardGrab) { + m_keyboardGrab->sendModifiers(waylandServer()->display()->nextSerial(), + xkb->modifierState().depressed, + xkb->modifierState().latched, + xkb->modifierState().locked, + xkb->currentLayout()); + } +} + void InputMethod::adoptInputMethodContext() { auto inputContext = waylandServer()->inputMethod()->context(); @@ -640,6 +654,7 @@ void InputMethod::installKeyboardGrab(KWaylandServer::InputMethodGrabV1 *keyboar auto xkb = input()->keyboard()->xkb(); m_keyboardGrab = keyboardGrab; keyboardGrab->sendKeymap(xkb->keymapContents()); + forwardModifiers(); } void InputMethod::updateModifiersMap(const QByteArray &modifiers) diff --git a/src/inputmethod.h b/src/inputmethod.h index 578a268b7c..0ba9ce4a85 100644 --- a/src/inputmethod.h +++ b/src/inputmethod.h @@ -97,6 +97,7 @@ private: void updateModifiersMap(const QByteArray &modifiers); bool touchEventTriggered() const; + void forwardModifiers(); struct { QString text = QString(); diff --git a/src/xkb.cpp b/src/xkb.cpp index 2e8a505717..cb66780eb7 100644 --- a/src/xkb.cpp +++ b/src/xkb.cpp @@ -330,7 +330,10 @@ void Xkb::updateModifiers(uint32_t modsDepressed, uint32_t modsLatched, uint32_t if (!m_keymap || !m_state) { return; } - xkb_state_update_mask(m_state, modsDepressed, modsLatched, modsLocked, 0, 0, group); + // Avoid to create a infinite loop between input method and compositor. + if (xkb_state_update_mask(m_state, modsDepressed, modsLatched, modsLocked, 0, 0, group) == 0) { + return; + } updateModifiers(); forwardModifiers(); } @@ -400,10 +403,19 @@ void Xkb::updateModifiers() Q_EMIT ledsChanged(m_leds); } - m_currentLayout = xkb_state_serialize_layout(m_state, XKB_STATE_LAYOUT_EFFECTIVE); - m_modifierState.depressed = xkb_state_serialize_mods(m_state, xkb_state_component(XKB_STATE_MODS_DEPRESSED)); - 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)); + const uint32_t newLayout = xkb_state_serialize_layout(m_state, XKB_STATE_LAYOUT_EFFECTIVE); + const uint32_t depressed = xkb_state_serialize_mods(m_state, XKB_STATE_MODS_DEPRESSED); + const uint32_t latched = xkb_state_serialize_mods(m_state, XKB_STATE_MODS_LATCHED); + const uint32_t locked = xkb_state_serialize_mods(m_state, XKB_STATE_MODS_LOCKED); + + if (newLayout != m_currentLayout || depressed != m_modifierState.depressed || latched != m_modifierState.latched || locked != m_modifierState.locked) { + m_currentLayout = newLayout; + m_modifierState.depressed = depressed; + m_modifierState.latched = latched; + m_modifierState.locked = locked; + + Q_EMIT modifierStateChanged(); + } } void Xkb::forwardModifiers() diff --git a/src/xkb.h b/src/xkb.h index 8d5b8e504b..e44f356fcf 100644 --- a/src/xkb.h +++ b/src/xkb.h @@ -81,6 +81,11 @@ public: quint32 currentLayout() const { return m_currentLayout; } + + const auto &modifierState() const + { + return m_modifierState; + } QString layoutName(xkb_layout_index_t index) const; QString layoutName() const; QString layoutShortName(int index) const; @@ -96,6 +101,7 @@ public: Q_SIGNALS: void ledsChanged(const LEDs &leds); + void modifierStateChanged(); private: void applyEnvironmentRules(xkb_rule_names &);