From 6a5a5ed11e3aac6a73732781d7a24f8d0367183a Mon Sep 17 00:00:00 2001
From: vaxerski <43317083+vaxerski@users.noreply.github.com>
Date: Fri, 25 Aug 2023 12:35:24 +0200
Subject: [PATCH] input: add transparent binds

adds a new flag for binds to be transparent (non-shadowable)
fixes #3058
---
 src/config/ConfigManager.cpp    | 10 +++++++---
 src/managers/KeybindManager.cpp | 21 +++++++++++++--------
 src/managers/KeybindManager.hpp |  3 ++-
 3 files changed, 22 insertions(+), 12 deletions(-)

diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp
index 908f15ffb..a289be1a6 100644
--- a/src/config/ConfigManager.cpp
+++ b/src/config/ConfigManager.cpp
@@ -795,6 +795,7 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
     bool       repeat       = false;
     bool       mouse        = false;
     bool       nonConsuming = false;
+    bool       transparent  = false;
     const auto BINDARGS     = command.substr(4);
 
     for (auto& arg : BINDARGS) {
@@ -808,6 +809,8 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
             mouse = true;
         } else if (arg == 'n') {
             nonConsuming = true;
+        } else if (arg == 't') {
+            transparent = true;
         } else {
             parseError = "bind: invalid flag";
             return;
@@ -865,11 +868,12 @@ void CConfigManager::handleBind(const std::string& command, const std::string& v
 
     if (KEY != "") {
         if (isNumber(KEY) && std::stoi(KEY) > 9)
-            g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming});
+            g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent});
         else if (KEY.find("code:") == 0 && isNumber(KEY.substr(5)))
-            g_pKeybindManager->addKeybind(SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming});
+            g_pKeybindManager->addKeybind(
+                SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent});
         else
-            g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming});
+            g_pKeybindManager->addKeybind(SKeybind{KEY, -1, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent});
     }
 }
 
diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp
index 2a44137e7..c30d94d9d 100644
--- a/src/managers/KeybindManager.cpp
+++ b/src/managers/KeybindManager.cpp
@@ -388,10 +388,11 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
     if (g_pCompositor->m_sSeat.exclusiveClient)
         Debug::log(LOG, "Keybind handling only locked (inhibitor)");
 
-    if (pressed && m_kHeldBack) {
-        // release the held back event
-        wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, time, m_kHeldBack, WL_KEYBOARD_KEY_STATE_PRESSED);
-        m_kHeldBack = 0;
+    if (pressed && !m_vHeldBack.empty()) {
+        // release the held back events
+        for (auto& k : m_vHeldBack)
+            wlr_seat_keyboard_notify_key(g_pCompositor->m_sSeat.seat, time, k, WL_KEYBOARD_KEY_STATE_PRESSED);
+        m_vHeldBack.clear();
     }
 
     for (auto& k : m_lKeybinds) {
@@ -420,11 +421,15 @@ bool CKeybindManager::handleKeybinds(const uint32_t& modmask, const std::string&
 
         if (pressed && k.release) {
             if (k.nonConsuming)
-                return false;
+                continue;
+
+            found = true;
+
+            if (k.transparent)
+                continue;
 
             // suppress down event
-            m_kHeldBack = keysym;
-            return true;
+            m_vHeldBack.push_back(keysym);
         }
 
         const auto DISPATCHER = m_mDispatchers.find(k.mouse ? "mouse" : k.handler);
@@ -474,7 +479,7 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const int&
 
         bool shadow = false;
 
-        if (k.handler == "global")
+        if (k.handler == "global" || k.transparent)
             continue; // can't be shadowed
 
         const auto KBKEY      = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE);
diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp
index 33891d863..1c058c1c4 100644
--- a/src/managers/KeybindManager.hpp
+++ b/src/managers/KeybindManager.hpp
@@ -22,6 +22,7 @@ struct SKeybind {
     bool        repeat       = false;
     bool        mouse        = false;
     bool        nonConsuming = false;
+    bool        transparent  = false;
 
     // DO NOT INITIALIZE
     bool shadowed = false;
@@ -67,7 +68,7 @@ class CKeybindManager {
 
     inline static std::string m_szCurrentSelectedSubmap = "";
 
-    xkb_keysym_t              m_kHeldBack = 0;
+    std::vector<xkb_keysym_t> m_vHeldBack;
 
     SKeybind*                 m_pActiveKeybind = nullptr;