From 638c3ac10003f66ef4af43f50ee365c9036da0fe Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Sat, 24 Jun 2023 20:26:29 +1200 Subject: feat: Added ; as a command separator --- keybinds.cpp | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'keybinds.cpp') diff --git a/keybinds.cpp b/keybinds.cpp index 64d3fc8..8448eed 100644 --- a/keybinds.cpp +++ b/keybinds.cpp @@ -39,11 +39,14 @@ const void KeybindsModule::handleKeypress(XKeyEvent e) const void KeybindsModule::bind(const CommandArg* argv) { - Err e = commandsModule.checkCommand(argv[1].str); - if(e.code != NOERR) + std::vector errs = commandsModule.checkCommand(argv[1].str); + for(Err e : errs) { - e.message = "Binding fail - " + e.message; - throw e; + if(e.code != NOERR) + { + e.message = "Binding fail - " + e.message; + throw e; + } } std::vector keys = split(argv[0].str, '+'); Keybind bind; -- cgit v1.2.3 From 37a2725da41e363fcdca12d0374b192cd03905d0 Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Wed, 28 Jun 2023 21:24:59 +1200 Subject: feat: Added key chording Probably a hacky mess but oh well. Key chords can be done by seperating binds in string with ` `. You can set the quit bind with `quitkey`, default mod+g. (Chords also exited when pressing unbound keys). --- keybinds.cpp | 144 +++++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 121 insertions(+), 23 deletions(-) (limited to 'keybinds.cpp') diff --git a/keybinds.cpp b/keybinds.cpp index 8448eed..b51bf6e 100644 --- a/keybinds.cpp +++ b/keybinds.cpp @@ -2,53 +2,98 @@ #include #include #include +#include #include +#include "commands.h" #include "error.h" #include "keybinds.h" #include "util.h" using std::string, std::cout, std::endl; +bool Keybind::operator<(const Keybind &o) const { + if(key != o.key) + { + return key < o.key; + } + else return modifiers < o.modifiers; +} +bool Keybind::operator==(const Keybind &o) const { + return (key == o.key && modifiers == o.modifiers); +} + KeybindsModule::KeybindsModule(CommandsModule& commandsModule, Config& cfg, Globals& globals, void (*updateMousePos)()) :commandsModule(commandsModule), globals(globals), cfg(cfg) { commandsModule.addCommand("bind", &KeybindsModule::bind, 2, {STR, STR_REST}, this); + commandsModule.addCommand("quitkey", &KeybindsModule::quitKey, 1, {STR}, this); this->updateMousePos = updateMousePos; + keyMaps.insert({0, std::map()}); +} + +void KeybindsModule::changeMap(int newMapID) +{ + if(currentMapID == newMapID) + return; + if(currentMapID != 0) + XUngrabKeyboard(globals.dpy, CurrentTime); + XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); + currentMapID = newMapID; + if(newMapID == 0) + { + for(std::pair pair : getKeymap(currentMapID)) + { + Keybind bind = pair.first; + KeyCode c = XKeysymToKeycode(globals.dpy, bind.key); + XGrabKey(globals.dpy, c, bind.modifiers, globals.root, false, GrabModeAsync, GrabModeAsync); + } + } + else + { + XGrabKeyboard(globals.dpy, globals.root, false, GrabModeAsync, GrabModeAsync, CurrentTime); + } } const void KeybindsModule::handleKeypress(XKeyEvent e) { if(e.same_screen!=1) return; - //cout << "Key Pressed" << endl; - //cout << "\tState: " << e.state << endl; - //cout << "\tCode: " << XKeysymToString(XKeycodeToKeysym(globals.dpy, e.keycode, 0)) << endl; + // cout << "Key Pressed" << endl; + // cout << "\tState: " << e.state << endl; + // cout << "\tCode: " << XKeysymToString(XKeycodeToKeysym(globals.dpy, e.keycode, 0)) << endl; updateMousePos(); const unsigned int masks = ShiftMask | ControlMask | Mod1Mask | Mod4Mask; - for(Keybind bind : binds) + Keybind k = {XLookupKeysym(&e, 0), e.state & masks}; + if(k == exitBind) { - if(bind.modifiers == (e.state & masks) && bind.key == XLookupKeysym(&e, 0)) + changeMap(0); + } + else if(getKeymap(currentMapID).count(k) > 0) + { + KeyFunction& c = getKeymap(currentMapID).find(k)->second; + if(getKeymap(c.mapID).size() == 0) + { + commandsModule.runCommand(c.command); + changeMap(0); + } + else { - commandsModule.runCommand(bind.command); + XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); + changeMap(c.mapID); } } + else if(std::find(std::begin(ignoredKeys), std::end(ignoredKeys), e.keycode) == std::end(ignoredKeys)) + { + changeMap(0); + } } -const void KeybindsModule::bind(const CommandArg* argv) +Keybind KeybindsModule::getKeybind(string bindString) { - std::vector errs = commandsModule.checkCommand(argv[1].str); - for(Err e : errs) - { - if(e.code != NOERR) - { - e.message = "Binding fail - " + e.message; - throw e; - } - } - std::vector keys = split(argv[0].str, '+'); + std::vector keys = split(bindString, '+'); Keybind bind; bind.modifiers = 0; for(string key : keys) @@ -75,19 +120,72 @@ const void KeybindsModule::bind(const CommandArg* argv) bind.key = s; if(bind.key == NoSymbol) { - throw Err(CFG_ERR_KEYBIND, "Keybind '" + string(argv[0].str) + "' is invalid!"); + throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); continue; } } } - bind.command = argv[1].str; - KeyCode c = XKeysymToKeycode(globals.dpy, bind.key); - XGrabKey(globals.dpy, c, bind.modifiers, globals.root, False, GrabModeAsync, GrabModeAsync); - binds.push_back(bind); + return bind; +} + +const void KeybindsModule::bind(const CommandArg* argv) +{ + std::vector errs = commandsModule.checkCommand(argv[1].str); + for(Err e : errs) + { + if(e.code != NOERR) + { + e.message = "Binding fail - " + e.message; + throw e; + } + } + std::vector keys = split(argv[0].str, ' '); + int currentBindingMap = 0; + for(int i = 0; i < keys.size() - 1; i++) + { + Keybind bind = getKeybind(keys[i]); + if(getKeymap(currentBindingMap).count(bind) > 0) + { + currentBindingMap = getKeymap(currentBindingMap).find(bind)->second.mapID; + } + else + { + KeyFunction newMap = {"", nextKeymapID}; + keyMaps.insert({nextKeymapID, std::map()}); + nextKeymapID++; + getKeymap(currentBindingMap).insert({bind, newMap}); + currentBindingMap = getKeymap(currentBindingMap).find(bind)->second.mapID; + } + } + Keybind bind = getKeybind(keys[keys.size() - 1]); + if(getKeymap(currentBindingMap).count(bind) <= 0) + { + KeyFunction function = {argv[1].str, nextKeymapID}; + keyMaps.insert({nextKeymapID, std::map()}); + nextKeymapID++; + getKeymap(currentBindingMap).insert({bind, function}); + if(currentBindingMap == currentMapID) + { + KeyCode c = XKeysymToKeycode(globals.dpy, bind.key); + XGrabKey(globals.dpy, c, bind.modifiers, globals.root, false, GrabModeAsync, GrabModeAsync); + } + } + else + { + throw Err(CFG_ERR_KEYBIND, "Bind is a keymap already!"); + } + // cout << "Added bind" << endl; + // cout << "\t" << argv[0].str << endl; +} + +const void KeybindsModule::quitKey(const CommandArg* argv) +{ + exitBind = getKeybind(argv[0].str); } const void KeybindsModule::clearKeybinds() { XUngrabButton(globals.dpy, AnyKey, AnyModifier, globals.root); - binds = std::vector(); + keyMaps = std::map>(); + keyMaps.insert({0, std::map()}); } -- cgit v1.2.3 From ea569d9c9c61eb26f7d325b41d8ac839dc470eec Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Tue, 15 Aug 2023 21:27:51 +1200 Subject: feat: Made the bind modes work Numlock still seems to mess with keybindings. Also switched from storing keybinds with KeySym to KeyCode --- keybinds.cpp | 86 +++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 7 deletions(-) (limited to 'keybinds.cpp') diff --git a/keybinds.cpp b/keybinds.cpp index b51bf6e..88a43fe 100644 --- a/keybinds.cpp +++ b/keybinds.cpp @@ -1,5 +1,6 @@ #include #include +#include #include #include #include @@ -30,6 +31,14 @@ KeybindsModule::KeybindsModule(CommandsModule& commandsModule, Config& cfg, Glob { commandsModule.addCommand("bind", &KeybindsModule::bind, 2, {STR, STR_REST}, this); commandsModule.addCommand("quitkey", &KeybindsModule::quitKey, 1, {STR}, this); + commandsModule.addCommand("bindmode", &KeybindsModule::bindMode, 1, {STR}, this); + + bindModes = { + {"normal", &KeybindsModule::normalBindMode}, + {"emacs", &KeybindsModule::emacsBindMode} + }; + bindFunc = &KeybindsModule::normalBindMode; + this->updateMousePos = updateMousePos; keyMaps.insert({0, std::map()}); } @@ -47,8 +56,7 @@ void KeybindsModule::changeMap(int newMapID) for(std::pair pair : getKeymap(currentMapID)) { Keybind bind = pair.first; - KeyCode c = XKeysymToKeycode(globals.dpy, bind.key); - XGrabKey(globals.dpy, c, bind.modifiers, globals.root, false, GrabModeAsync, GrabModeAsync); + XGrabKey(globals.dpy, bind.key, bind.modifiers, globals.root, false, GrabModeAsync, GrabModeAsync); } } else @@ -66,7 +74,7 @@ const void KeybindsModule::handleKeypress(XKeyEvent e) updateMousePos(); const unsigned int masks = ShiftMask | ControlMask | Mod1Mask | Mod4Mask; - Keybind k = {XLookupKeysym(&e, 0), e.state & masks}; + Keybind k = {(KeyCode)e.keycode, e.state & masks}; if(k == exitBind) { changeMap(0); @@ -91,7 +99,28 @@ const void KeybindsModule::handleKeypress(XKeyEvent e) } } -Keybind KeybindsModule::getKeybind(string bindString) +bool isUpper(const std::string& s) { + return std::all_of(s.begin(), s.end(), [](unsigned char c){ return std::isupper(c); }); +} + +const void KeybindsModule::bindMode(const CommandArg* argv) +{ + if(bindModes.count(argv[0].str) < 1) + { + throw Err(CFG_ERR_KEYBIND, "Bind mode: " + string(argv[0].str) + " does not exist"); + } + else + { + bindFunc = bindModes.find(argv[0].str)->second; + } +} + +Keybind KeybindsModule::getKeybind(std::string bindString) +{ + return (this->*bindFunc)(bindString); +} + +const Keybind KeybindsModule::normalBindMode(string bindString) { std::vector keys = split(bindString, '+'); Keybind bind; @@ -116,15 +145,58 @@ Keybind KeybindsModule::getKeybind(string bindString) } else { + if(isUpper(key)) + { + bind.modifiers |= ShiftMask; + } + KeySym s = XStringToKeysym(key.c_str()); + if(s == NoSymbol) + { + throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); + } + bind.key = XKeysymToKeycode(globals.dpy, s); + } + } + if(!bind.key) + throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); + return bind; +} + +const Keybind KeybindsModule::emacsBindMode(string bindString) +{ + std::vector keys = split(bindString, '-'); + Keybind bind; + bind.modifiers = 0; + for(string key : keys) + { + if(key == "s") + { + bind.modifiers |= Mod4Mask >> 3 * cfg.swapSuperAlt; + } + else if(key == "M") + { + bind.modifiers |= Mod1Mask << 3 * cfg.swapSuperAlt; + } + else if(key == "C") + { + bind.modifiers |= ControlMask; + } + else + { + if(isUpper(key)) + { + bind.modifiers |= ShiftMask; + } KeySym s = XStringToKeysym(key.c_str()); - bind.key = s; - if(bind.key == NoSymbol) + if(s == NoSymbol) { throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); - continue; } + bind.key = XKeysymToKeycode(globals.dpy, s); } } + if(!bind.key) + throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); return bind; } -- cgit v1.2.3 From ba3ca53aef521467049a58aa766104041f987c5e Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Tue, 22 Aug 2023 11:51:15 +1200 Subject: feat: Made the emacs bind mode function better It now uses a regex to split out the different modifiers and keys. --- keybinds.cpp | 67 +++++++++++++++++++++++++++++++++++++----------------------- 1 file changed, 41 insertions(+), 26 deletions(-) (limited to 'keybinds.cpp') diff --git a/keybinds.cpp b/keybinds.cpp index 88a43fe..a4a78c0 100644 --- a/keybinds.cpp +++ b/keybinds.cpp @@ -5,13 +5,14 @@ #include #include #include +#include #include "commands.h" #include "error.h" #include "keybinds.h" #include "util.h" -using std::string, std::cout, std::endl; +using std::string; bool Keybind::operator<(const Keybind &o) const { if(key != o.key) @@ -164,39 +165,53 @@ const Keybind KeybindsModule::normalBindMode(string bindString) const Keybind KeybindsModule::emacsBindMode(string bindString) { - std::vector keys = split(bindString, '-'); Keybind bind; bind.modifiers = 0; - for(string key : keys) + + const std::regex keyRegex("^(?:([CMs])-)?(?:([CMs])-)?(?:([CMs])-)?([^\\s]+)$"); + std::smatch keyMatch; + if(std::regex_match(bindString, keyMatch, keyRegex)) { - if(key == "s") - { - bind.modifiers |= Mod4Mask >> 3 * cfg.swapSuperAlt; - } - else if(key == "M") - { - bind.modifiers |= Mod1Mask << 3 * cfg.swapSuperAlt; - } - else if(key == "C") + for (int i = 1; i < 3; i++) { - bind.modifiers |= ControlMask; - } - else - { - if(isUpper(key)) - { - bind.modifiers |= ShiftMask; - } - KeySym s = XStringToKeysym(key.c_str()); - if(s == NoSymbol) + std::ssub_match modifierMatch = keyMatch[i]; + if(modifierMatch.matched) { - throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); + std::string modifier = modifierMatch.str(); + if(modifier == "s") + { + bind.modifiers |= Mod4Mask >> 3 * cfg.swapSuperAlt; + } + else if(modifier == "M") + { + bind.modifiers |= Mod1Mask << 3 * cfg.swapSuperAlt; + } + else if(modifier == "C") + { + bind.modifiers |= ControlMask; + } } - bind.key = XKeysymToKeycode(globals.dpy, s); } } - if(!bind.key) - throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!"); + KeySym keySym = XStringToKeysym(keyMatch[4].str().c_str()); + + if(isUpper(keyMatch[4].str().c_str()) && keySym != NoSymbol) + { + bind.modifiers |= ShiftMask; + } + if(keySym == NoSymbol) + { + if(keyMatch[4].str() == "RET") + keySym = XK_Return; + if(keyMatch[4].str() == "ESC") + keySym = XK_Escape; + if(keyMatch[4].str() == "SPC") + keySym = XK_space; + else + throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid"); + } + bind.key = XKeysymToKeycode(globals.dpy, keySym); + return bind; } -- cgit v1.2.3 From 6e5d3c8aec03d34b5d195cc920cc4c2f123a1cb2 Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Tue, 22 Aug 2023 11:58:07 +1200 Subject: fixup: Made regex work better --- keybinds.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'keybinds.cpp') diff --git a/keybinds.cpp b/keybinds.cpp index a4a78c0..2e4ebe2 100644 --- a/keybinds.cpp +++ b/keybinds.cpp @@ -168,7 +168,7 @@ const Keybind KeybindsModule::emacsBindMode(string bindString) Keybind bind; bind.modifiers = 0; - const std::regex keyRegex("^(?:([CMs])-)?(?:([CMs])-)?(?:([CMs])-)?([^\\s]+)$"); + const std::regex keyRegex("^(?:([CMs])-)?(?:([CMs])-)?(?:([CMs])-)?([^\s]|(SPC|ESC|RET|))$"); std::smatch keyMatch; if(std::regex_match(bindString, keyMatch, keyRegex)) { -- cgit v1.2.3 From d22b5d2363ed8a90960446a209482180f6d27fc0 Mon Sep 17 00:00:00 2001 From: BossCode45 Date: Wed, 23 Aug 2023 21:32:50 +1200 Subject: feat: Added documentation Also fixed up the special cases for keybinds, such as SPC, ESC, RET, -, and +. --- keybinds.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) (limited to 'keybinds.cpp') diff --git a/keybinds.cpp b/keybinds.cpp index 2e4ebe2..c41452f 100644 --- a/keybinds.cpp +++ b/keybinds.cpp @@ -168,7 +168,7 @@ const Keybind KeybindsModule::emacsBindMode(string bindString) Keybind bind; bind.modifiers = 0; - const std::regex keyRegex("^(?:([CMs])-)?(?:([CMs])-)?(?:([CMs])-)?([^\s]|(SPC|ESC|RET|))$"); + const std::regex keyRegex("^(?:([CMs])-)?(?:([CMs])-)?(?:([CMs])-)?([^\\s]|(SPC|ESC|RET|))$"); std::smatch keyMatch; if(std::regex_match(bindString, keyMatch, keyRegex)) { @@ -203,10 +203,14 @@ const Keybind KeybindsModule::emacsBindMode(string bindString) { if(keyMatch[4].str() == "RET") keySym = XK_Return; - if(keyMatch[4].str() == "ESC") + else if(keyMatch[4].str() == "ESC") keySym = XK_Escape; - if(keyMatch[4].str() == "SPC") + else if(keyMatch[4].str() == "SPC") keySym = XK_space; + else if(keyMatch[4].str() == "-") + keySym = XK_minus; + else if(keyMatch[4].str() == "+") + keySym = XK_plus; else throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid"); } -- cgit v1.2.3