diff --git a/src/config/ConfigManager.cpp b/src/config/ConfigManager.cpp index 4ae62392627..59de33bb53e 100644 --- a/src/config/ConfigManager.cpp +++ b/src/config/ConfigManager.cpp @@ -1732,6 +1732,17 @@ std::optional CConfigManager::handleAnimation(const std::string& co return {}; } +SParsedKey parseKey(const std::string& key) { + if (isNumber(key) && std::stoi(key) > 9) + return {.keycode = std::stoi(key)}; + else if (key.starts_with("code:") && isNumber(key.substr(5))) + return {.keycode = std::stoi(key.substr(5))}; + else if (key == "catchall") + return {.catchAll = true}; + else + return {.key = key}; +} + std::optional CConfigManager::handleBind(const std::string& command, const std::string& value) { // example: // bind[fl]=SUPER,G,exec,dmenu_run @@ -1807,14 +1818,15 @@ std::optional CConfigManager::handleBind(const std::string& command } 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, transparent, ignoreMods}); - else if (KEY.starts_with("code:") && isNumber(KEY.substr(5))) - g_pKeybindManager->addKeybind( - SKeybind{"", std::stoi(KEY.substr(5)), MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods}); - else - g_pKeybindManager->addKeybind(SKeybind{KEY, 0, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, nonConsuming, transparent, ignoreMods}); + SParsedKey parsedKey = parseKey(KEY); + + if (parsedKey.catchAll && m_szCurrentSubmap == "") { + Debug::log(ERR, "Catchall not allowed outside of submap!"); + return "Invalid catchall, catchall keybinds are only allowed in submaps."; + } + + g_pKeybindManager->addKeybind(SKeybind{parsedKey.key, parsedKey.keycode, parsedKey.catchAll, MOD, HANDLER, COMMAND, locked, m_szCurrentSubmap, release, repeat, mouse, + nonConsuming, transparent, ignoreMods}); } return {}; @@ -1825,7 +1837,7 @@ std::optional CConfigManager::handleUnbind(const std::string& comma const auto MOD = g_pKeybindManager->stringToModMask(ARGS[0]); - const auto KEY = ARGS[1]; + const auto KEY = parseKey(ARGS[1]); g_pKeybindManager->removeKeybind(MOD, KEY); diff --git a/src/debug/HyprCtl.cpp b/src/debug/HyprCtl.cpp index 962496f79a3..a65533d2db2 100644 --- a/src/debug/HyprCtl.cpp +++ b/src/debug/HyprCtl.cpp @@ -718,8 +718,8 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { if (kb.nonConsuming) ret += "n"; - ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, kb.key, kb.keycode, kb.handler, - kb.arg); + ret += std::format("\n\tmodmask: {}\n\tsubmap: {}\n\tkey: {}\n\tkeycode: {}\n\tcatchall: {}\n\tdispatcher: {}\n\targ: {}\n\n", kb.modmask, kb.submap, kb.key, + kb.keycode, kb.catchAll, kb.handler, kb.arg); } } else { // json @@ -737,11 +737,13 @@ std::string bindsRequest(eHyprCtlOutputFormat format, std::string request) { "submap": "{}", "key": "{}", "keycode": {}, + "catch_all": {}, "dispatcher": "{}", "arg": "{}" }},)#", kb.locked ? "true" : "false", kb.mouse ? "true" : "false", kb.release ? "true" : "false", kb.repeat ? "true" : "false", kb.nonConsuming ? "true" : "false", - kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, escapeJSONStrings(kb.handler), escapeJSONStrings(kb.arg)); + kb.modmask, escapeJSONStrings(kb.submap), escapeJSONStrings(kb.key), kb.keycode, kb.catchAll ? "true" : "false", escapeJSONStrings(kb.handler), + escapeJSONStrings(kb.arg)); } trimTrailingComma(ret); ret += "]"; diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index 1ab8fa91189..28c720298a6 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -95,18 +95,9 @@ void CKeybindManager::addKeybind(SKeybind kb) { m_pActiveKeybind = nullptr; } -void CKeybindManager::removeKeybind(uint32_t mod, const std::string& key) { +void CKeybindManager::removeKeybind(uint32_t mod, const SParsedKey& key) { for (auto it = m_lKeybinds.begin(); it != m_lKeybinds.end(); ++it) { - if (isNumber(key) && std::stoi(key) > 9) { - const uint32_t KEYNUM = std::stoi(key); - - if (it->modmask == mod && it->keycode == KEYNUM) { - it = m_lKeybinds.erase(it); - - if (it == m_lKeybinds.end()) - break; - } - } else if (it->modmask == mod && it->key == key) { + if (it->modmask == mod && it->key == key.key && it->keycode == key.keycode && it->catchAll == key.catchAll) { it = m_lKeybinds.erase(it); if (it == m_lKeybinds.end()) @@ -527,6 +518,9 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi } else if (k.keycode != 0) { if (key.keycode != k.keycode) continue; + } else if (k.catchAll) { + if (found) + continue; } else { // oMg such performance hit!!11! // this little maneouver is gonna cost us 4µs diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index edd9ede253d..561ee1ab4ad 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -13,6 +13,7 @@ class CPluginSystem; struct SKeybind { std::string key = ""; uint32_t keycode = 0; + bool catchAll = false; uint32_t modmask = 0; std::string handler = ""; std::string arg = ""; @@ -44,6 +45,12 @@ struct SPressedKeyWithMods { bool sent = false; }; +struct SParsedKey { + std::string key = ""; + uint32_t keycode = 0; + bool catchAll = false; +}; + class CKeybindManager { public: CKeybindManager(); @@ -57,7 +64,7 @@ class CKeybindManager { void onSwitchOffEvent(const std::string&); void addKeybind(SKeybind); - void removeKeybind(uint32_t, const std::string&); + void removeKeybind(uint32_t, const SParsedKey&); uint32_t stringToModMask(std::string); uint32_t keycodeToModifier(xkb_keycode_t); void clearKeybinds();