From d693c448366131de9e5729690a6d894fd1adff5e Mon Sep 17 00:00:00 2001 From: Gabriel Ford Date: Thu, 16 May 2024 10:48:30 +0000 Subject: keybinds: add keybind combos and add Left and Right mod distinction. (#5966) --- src/managers/KeybindManager.cpp | 84 +++++++++++++++++++++++++++++++++-------- src/managers/KeybindManager.hpp | 43 ++++++++++++++------- 2 files changed, 97 insertions(+), 30 deletions(-) (limited to 'src/managers') diff --git a/src/managers/KeybindManager.cpp b/src/managers/KeybindManager.cpp index ead83fa8..ea064031 100644 --- a/src/managers/KeybindManager.cpp +++ b/src/managers/KeybindManager.cpp @@ -8,7 +8,9 @@ #include "../devices/IKeyboard.hpp" #include "../managers/SeatManager.hpp" +#include #include +#include #include #include @@ -536,8 +538,48 @@ int repeatKeyHandler(void* data) { return 0; } +eMultiKeyCase CKeybindManager::mkKeysymSetMatches(const std::set keybindKeysyms, const std::set pressedKeysyms) { + // Returns whether two sets of keysyms are equal, partially equal, or not + // matching. (Partially matching means that pressed is a subset of bound) + + std::set boundKeysNotPressed; + std::set pressedKeysNotBound; + + std::set_difference(keybindKeysyms.begin(), keybindKeysyms.end(), pressedKeysyms.begin(), pressedKeysyms.end(), + std::inserter(boundKeysNotPressed, boundKeysNotPressed.begin())); + std::set_difference(pressedKeysyms.begin(), pressedKeysyms.end(), keybindKeysyms.begin(), keybindKeysyms.end(), + std::inserter(pressedKeysNotBound, pressedKeysNotBound.begin())); + + if (boundKeysNotPressed.empty() && pressedKeysNotBound.empty()) + return MK_FULL_MATCH; + + if (boundKeysNotPressed.size() && pressedKeysNotBound.empty()) + return MK_PARTIAL_MATCH; + + return MK_NO_MATCH; +} + +eMultiKeyCase CKeybindManager::mkBindMatches(const SKeybind keybind) { + if (mkKeysymSetMatches(keybind.sMkMods, m_sMkMods) != MK_FULL_MATCH) + return MK_NO_MATCH; + + return mkKeysymSetMatches(keybind.sMkKeys, m_sMkKeys); +} + bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWithMods& key, bool pressed) { - bool found = false; + bool found = false; + + if (pressed) { + if (keycodeToModifier(key.keycode)) + m_sMkMods.insert(key.keysym); + else + m_sMkKeys.insert(key.keysym); + } else { + if (keycodeToModifier(key.keycode)) + m_sMkMods.erase(key.keysym); + else + m_sMkKeys.erase(key.keysym); + } static auto PDISABLEINHIBIT = CConfigValue("binds:disable_keybind_grabbing"); @@ -559,7 +601,13 @@ bool CKeybindManager::handleKeybinds(const uint32_t modmask, const SPressedKeyWi if (!IGNORECONDITIONS && ((modmask != k.modmask && !k.ignoreMods) || k.submap != m_szCurrentSelectedSubmap || k.shadowed)) continue; - if (!key.keyName.empty()) { + if (k.multiKey) { + switch (mkBindMatches(k)) { + case MK_NO_MATCH: continue; + case MK_PARTIAL_MATCH: found = true; continue; + case MK_FULL_MATCH: found = true; + } + } else if (!key.keyName.empty()) { if (key.keyName != k.key) continue; } else if (k.keycode != 0) { @@ -672,25 +720,29 @@ void CKeybindManager::shadowKeybinds(const xkb_keysym_t& doesntHave, const uint3 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); - const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); + if (k.multiKey && (mkBindMatches(k) == MK_FULL_MATCH)) + shadow = true; + else { + const auto KBKEY = xkb_keysym_from_name(k.key.c_str(), XKB_KEYSYM_CASE_INSENSITIVE); + const auto KBKEYUPPER = xkb_keysym_to_upper(KBKEY); - for (auto& pk : m_dPressedKeys) { - if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) { - shadow = true; + for (auto& pk : m_dPressedKeys) { + if ((pk.keysym != 0 && (pk.keysym == KBKEY || pk.keysym == KBKEYUPPER))) { + shadow = true; - if (pk.keysym == doesntHave && doesntHave != 0) { - shadow = false; - break; + if (pk.keysym == doesntHave && doesntHave != 0) { + shadow = false; + break; + } } - } - if (pk.keycode != 0 && pk.keycode == k.keycode) { - shadow = true; + if (pk.keycode != 0 && pk.keycode == k.keycode) { + shadow = true; - if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) { - shadow = false; - break; + if (pk.keycode == doesntHaveCode && doesntHaveCode != 0) { + shadow = false; + break; + } } } } diff --git a/src/managers/KeybindManager.hpp b/src/managers/KeybindManager.hpp index da98a749..a2025bb0 100644 --- a/src/managers/KeybindManager.hpp +++ b/src/managers/KeybindManager.hpp @@ -2,6 +2,7 @@ #include "../defines.hpp" #include +#include #include "../Compositor.hpp" #include #include @@ -13,20 +14,23 @@ class CPluginSystem; class IKeyboard; struct SKeybind { - std::string key = ""; - uint32_t keycode = 0; - bool catchAll = false; - uint32_t modmask = 0; - std::string handler = ""; - std::string arg = ""; - bool locked = false; - std::string submap = ""; - bool release = false; - bool repeat = false; - bool mouse = false; - bool nonConsuming = false; - bool transparent = false; - bool ignoreMods = false; + std::string key = ""; + std::set sMkKeys = {}; + uint32_t keycode = 0; + bool catchAll = false; + uint32_t modmask = 0; + std::set sMkMods = {}; + std::string handler = ""; + std::string arg = ""; + bool locked = false; + std::string submap = ""; + bool release = false; + bool repeat = false; + bool mouse = false; + bool nonConsuming = false; + bool transparent = false; + bool ignoreMods = false; + bool multiKey = false; // DO NOT INITIALIZE bool shadowed = false; @@ -57,6 +61,12 @@ struct SParsedKey { bool catchAll = false; }; +enum eMultiKeyCase { + MK_NO_MATCH = 0, + MK_PARTIAL_MATCH, + MK_FULL_MATCH +}; + class CKeybindManager { public: CKeybindManager(); @@ -105,6 +115,11 @@ class CKeybindManager { bool handleKeybinds(const uint32_t, const SPressedKeyWithMods&, bool); + std::set m_sMkKeys = {}; + std::set m_sMkMods = {}; + eMultiKeyCase mkBindMatches(const SKeybind); + eMultiKeyCase mkKeysymSetMatches(const std::set, const std::set); + bool handleInternalKeybinds(xkb_keysym_t); bool handleVT(xkb_keysym_t); -- cgit v1.2.3