From 3cc4387d73afbc79c95768b10dc241fcc296d6d4 Mon Sep 17 00:00:00 2001
From: Vaxry <vaxry@vaxry.net>
Date: Wed, 26 Jun 2024 12:30:03 +0200
Subject: [PATCH] keyboard mod fixes

---
 src/debug/HyprCtl.cpp               |  2 +-
 src/devices/IKeyboard.cpp           | 65 +++++++++++++++++------------
 src/devices/IKeyboard.hpp           |  5 ++-
 src/devices/Keyboard.cpp            |  7 +---
 src/managers/KeybindManager.cpp     |  6 +--
 src/managers/input/InputManager.cpp | 17 +-------
 6 files changed, 49 insertions(+), 53 deletions(-)

diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp
index 8e55886b2..703ff79bb 100644
--- a/src/debug/HyprCtl.cpp
+++ b/src/debug/HyprCtl.cpp
@@ -1141,7 +1141,7 @@ std::string switchXKBLayoutRequest(eHyprCtlOutputFormat format, std::string requ
     const auto         LAYOUTS      = xkb_keymap_num_layouts(KEEB->xkbKeymap);
     xkb_layout_index_t activeLayout = 0;
     while (activeLayout < LAYOUTS) {
-        if (xkb_state_layout_index_is_active(KEEB->xkbTranslationState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1)
+        if (xkb_state_layout_index_is_active(KEEB->xkbState, activeLayout, XKB_STATE_LAYOUT_EFFECTIVE) == 1)
             break;
 
         activeLayout++;
diff --git a/src/devices/IKeyboard.cpp b/src/devices/IKeyboard.cpp
index 5ecba556e..eb475b730 100644
--- a/src/devices/IKeyboard.cpp
+++ b/src/devices/IKeyboard.cpp
@@ -27,11 +27,11 @@ IKeyboard::~IKeyboard() {
 }
 
 void IKeyboard::clearManuallyAllocd() {
-    if (xkbTranslationState)
-        xkb_state_unref(xkbTranslationState);
+    if (xkbStaticState)
+        xkb_state_unref(xkbStaticState);
 
-    if (xkbInternalTranslationState)
-        xkb_state_unref(xkbInternalTranslationState);
+    if (xkbState)
+        xkb_state_unref(xkbState);
 
     if (xkbKeymap)
         xkb_keymap_unref(xkbKeymap);
@@ -39,9 +39,10 @@ void IKeyboard::clearManuallyAllocd() {
     if (xkbKeymapFD >= 0)
         close(xkbKeymapFD);
 
-    xkbKeymap           = nullptr;
-    xkbTranslationState = nullptr;
-    xkbKeymapFD         = -1;
+    xkbKeymap      = nullptr;
+    xkbState       = nullptr;
+    xkbStaticState = nullptr;
+    xkbKeymapFD    = -1;
 }
 
 void IKeyboard::setKeymap(const SStringRuleNames& rules) {
@@ -99,9 +100,9 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
 
     // set internal translation state
     // demo sunao ni ienai
-    xkbInternalTranslationState = xkb_state_new(xkbKeymap);
+    xkbStaticState = xkb_state_new(xkbKeymap);
 
-    updateXKBTranslationState();
+    updateXKBTranslationState(xkbKeymap);
 
     const auto NUMLOCKON = g_pConfigManager->getDeviceInt(hlName, "numlock_by_default", "input:numlock_by_default");
 
@@ -151,17 +152,17 @@ void IKeyboard::setKeymap(const SStringRuleNames& rules) {
 
 void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
 
-    if (xkbTranslationState)
-        xkb_state_unref(xkbTranslationState);
+    if (xkbState)
+        xkb_state_unref(xkbState);
 
     if (keymap) {
         Debug::log(LOG, "Updating keyboard {:x}'s translation state from a provided keymap", (uintptr_t)this);
-        xkbTranslationState = xkb_state_new(keymap);
+        xkbState = xkb_state_new(keymap);
         return;
     }
 
     const auto KEYMAP     = xkbKeymap;
-    const auto STATE      = xkbInternalTranslationState;
+    const auto STATE      = xkbState;
     const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
 
     const auto PCONTEXT = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
@@ -200,7 +201,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
                 KEYMAP       = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
             }
 
-            xkbTranslationState = xkb_state_new(KEYMAP);
+            xkbState = xkb_state_new(KEYMAP);
 
             xkb_keymap_unref(KEYMAP);
             xkb_context_unref(PCONTEXT);
@@ -221,7 +222,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
 
     const auto NEWKEYMAP = xkb_keymap_new_from_names(PCONTEXT, &rules, XKB_KEYMAP_COMPILE_NO_FLAGS);
 
-    xkbTranslationState = xkb_state_new(NEWKEYMAP);
+    xkbState = xkb_state_new(NEWKEYMAP);
 
     xkb_keymap_unref(NEWKEYMAP);
     xkb_context_unref(PCONTEXT);
@@ -229,7 +230,7 @@ void IKeyboard::updateXKBTranslationState(xkb_keymap* const keymap) {
 
 std::string IKeyboard::getActiveLayout() {
     const auto KEYMAP     = xkbKeymap;
-    const auto STATE      = xkbTranslationState;
+    const auto STATE      = xkbState;
     const auto LAYOUTSNUM = xkb_keymap_num_layouts(KEYMAP);
 
     for (uint32_t i = 0; i < LAYOUTSNUM; ++i) {
@@ -246,12 +247,12 @@ std::string IKeyboard::getActiveLayout() {
 }
 
 void IKeyboard::updateLEDs() {
-    if (xkbTranslationState == nullptr)
+    if (xkbState == nullptr)
         return;
 
     uint32_t leds = 0;
     for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
-        if (xkb_state_led_index_is_active(xkbTranslationState, ledIndexes.at(i)))
+        if (xkb_state_led_index_is_active(xkbState, ledIndexes.at(i)))
             leds |= (1 << i);
     }
 
@@ -259,7 +260,7 @@ void IKeyboard::updateLEDs() {
 }
 
 void IKeyboard::updateLEDs(uint32_t leds) {
-    if (!xkbTranslationState)
+    if (!xkbState)
         return;
 
     if (isVirtual() && g_pInputManager->shouldIgnoreVirtualKeyboard(self.lock()))
@@ -288,10 +289,10 @@ uint32_t IKeyboard::getModifiers() {
 }
 
 void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group) {
-    if (!xkbTranslationState)
+    if (!xkbState)
         return;
 
-    xkb_state_update_mask(xkbTranslationState, depressed, latched, locked, 0, 0, group);
+    xkb_state_update_mask(xkbState, depressed, latched, locked, 0, 0, group);
 
     if (!updateModifiersState())
         return;
@@ -300,13 +301,13 @@ void IKeyboard::updateModifiers(uint32_t depressed, uint32_t latched, uint32_t l
 }
 
 bool IKeyboard::updateModifiersState() {
-    if (!xkbTranslationState)
+    if (!xkbState)
         return false;
 
-    auto depressed = xkb_state_serialize_mods(xkbTranslationState, XKB_STATE_MODS_DEPRESSED);
-    auto latched   = xkb_state_serialize_mods(xkbTranslationState, XKB_STATE_MODS_LATCHED);
-    auto locked    = xkb_state_serialize_mods(xkbTranslationState, XKB_STATE_MODS_LOCKED);
-    auto group     = xkb_state_serialize_layout(xkbTranslationState, XKB_STATE_LAYOUT_EFFECTIVE);
+    auto depressed = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_DEPRESSED);
+    auto latched   = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LATCHED);
+    auto locked    = xkb_state_serialize_mods(xkbState, XKB_STATE_MODS_LOCKED);
+    auto group     = xkb_state_serialize_layout(xkbState, XKB_STATE_LAYOUT_EFFECTIVE);
 
     if (depressed == modifiersState.depressed && latched == modifiersState.latched && locked == modifiersState.locked && group == modifiersState.group)
         return false;
@@ -318,3 +319,15 @@ bool IKeyboard::updateModifiersState() {
 
     return true;
 }
+
+void IKeyboard::updateXkbStateWithKey(uint32_t xkbKey, bool pressed) {
+    xkb_state_update_key(xkbState, xkbKey, pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
+    if (updateModifiersState()) {
+        keyboardEvents.modifiers.emit(SModifiersEvent{
+            .depressed = modifiersState.depressed,
+            .latched   = modifiersState.latched,
+            .locked    = modifiersState.locked,
+            .group     = modifiersState.group,
+        });
+    }
+}
diff --git a/src/devices/IKeyboard.hpp b/src/devices/IKeyboard.hpp
index f1f355ecc..332b8ca05 100644
--- a/src/devices/IKeyboard.hpp
+++ b/src/devices/IKeyboard.hpp
@@ -58,12 +58,13 @@ class IKeyboard : public IHID {
     uint32_t           getModifiers();
     void               updateModifiers(uint32_t depressed, uint32_t latched, uint32_t locked, uint32_t group);
     bool               updateModifiersState(); // rets whether changed
+    void               updateXkbStateWithKey(uint32_t xkbKey, bool pressed);
 
     bool               active  = false;
     bool               enabled = true;
 
-    xkb_layout_index_t activeLayout        = 0;
-    xkb_state *        xkbTranslationState = nullptr, *xkbInternalTranslationState = nullptr;
+    xkb_layout_index_t activeLayout = 0;
+    xkb_state *        xkbState = nullptr, *xkbStaticState /* Static state: never gets modifiers or layout changes sent, used for keybinds. */ = nullptr;
     xkb_keymap*        xkbKeymap = nullptr;
 
     struct {
diff --git a/src/devices/Keyboard.cpp b/src/devices/Keyboard.cpp
index 56ec7bfb7..867d54a87 100644
--- a/src/devices/Keyboard.cpp
+++ b/src/devices/Keyboard.cpp
@@ -32,12 +32,7 @@ CKeyboard::CKeyboard(SP<Aquamarine::IKeyboard> keeb) : keyboard(keeb) {
     listeners.key = keeb->events.key.registerListener([this](std::any d) {
         auto     E = std::any_cast<Aquamarine::IKeyboard::SKeyEvent>(d);
 
-        uint32_t xkbKeycode = E.key + 8;
-        xkb_state_update_key(xkbTranslationState, xkbKeycode, E.pressed ? XKB_KEY_DOWN : XKB_KEY_UP);
-
-        // we have to do this for DRM sessions, as they never send modifiers events
-        if (g_pCompositor->m_pAqBackend->hasSession())
-            updateModifiersState();
+        updateXkbStateWithKey(E.key + 8, E.pressed);
 
         keyboardEvents.key.emit(SKeyEvent{
             .timeMs  = E.timeMs,
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index a98be2c3b..22bc47190 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -366,8 +366,8 @@ bool CKeybindManager::onKeyEvent(std::any event, SP<IKeyboard> pKeyboard) {
 
     const auto         KEYCODE = e.keycode + 8; // Because to xkbcommon it's +8 from libinput
 
-    const xkb_keysym_t keysym         = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbTranslationState : m_pXKBTranslationState, KEYCODE);
-    const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbInternalTranslationState, KEYCODE);
+    const xkb_keysym_t keysym         = xkb_state_key_get_one_sym(pKeyboard->resolveBindsBySym ? pKeyboard->xkbStaticState : m_pXKBTranslationState, KEYCODE);
+    const xkb_keysym_t internalKeysym = xkb_state_key_get_one_sym(pKeyboard->xkbState, KEYCODE);
 
     if (handleInternalKeybinds(internalKeysym))
         return true;
@@ -2121,7 +2121,7 @@ void CKeybindManager::sendshortcut(std::string args) {
 
         if (!g_pKeybindManager->m_mKeyToCodeCache.contains(KEYPAIRSTRING)) {
             xkb_keymap*   km = KB->xkbKeymap;
-            xkb_state*    ks = KB->xkbTranslationState;
+            xkb_state*    ks = KB->xkbState;
 
             xkb_keycode_t keycode_min, keycode_max;
             keycode_min = xkb_keymap_min_keycode(km);
diff --git a/src/managers/input/InputManager.cpp b/src/managers/input/InputManager.cpp
index 6388327c6..9e2a16c72 100644
--- a/src/managers/input/InputManager.cpp
+++ b/src/managers/input/InputManager.cpp
@@ -1192,10 +1192,6 @@ static void removeFromHIDs(WP<IHID> hid) {
 }
 
 void CInputManager::destroyKeyboard(SP<IKeyboard> pKeyboard) {
-    if (pKeyboard->xkbTranslationState)
-        xkb_state_unref(pKeyboard->xkbTranslationState);
-    pKeyboard->xkbTranslationState = nullptr;
-
     std::erase_if(m_vKeyboards, [pKeyboard](const auto& other) { return other == pKeyboard; });
 
     if (m_vKeyboards.size() > 0) {
@@ -1261,19 +1257,10 @@ void CInputManager::destroyTabletPad(SP<CTabletPad> pad) {
 }
 
 void CInputManager::updateKeyboardsLeds(SP<IKeyboard> pKeyboard) {
-    if (!pKeyboard || !pKeyboard->xkbTranslationState)
+    if (!pKeyboard)
         return;
 
-    // FIXME:
-    // uint32_t leds = 0;
-    // for (uint32_t i = 0; i < WLR_LED_COUNT; ++i) {
-    //     if (xkb_state_led_index_is_active(pKeyboard->xkbTranslationState, keyboard->led_indexes[i]))
-    //         leds |= (1 << i);
-    // }
-
-    // for (auto& k : m_vKeyboards) {
-    //     k->updateLEDs(leds);
-    // }
+    pKeyboard->updateLEDs();
 }
 
 void CInputManager::onKeyboardKey(std::any event, SP<IKeyboard> pKeyboard) {