summaryrefslogtreecommitdiff
path: root/keybinds.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'keybinds.cpp')
-rw-r--r--keybinds.cpp236
1 files changed, 214 insertions, 22 deletions
diff --git a/keybinds.cpp b/keybinds.cpp
index 64d3fc8..c41452f 100644
--- a/keybinds.cpp
+++ b/keybinds.cpp
@@ -1,14 +1,29 @@
#include <X11/X.h>
#include <X11/Xlib.h>
+#include <cctype>
#include <iostream>
#include <sstream>
+#include <utility>
#include <vector>
+#include <regex>
+#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)
+ {
+ 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),
@@ -16,36 +31,99 @@ KeybindsModule::KeybindsModule(CommandsModule& commandsModule, Config& cfg, Glob
cfg(cfg)
{
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<Keybind, KeyFunction>()});
+}
+
+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<Keybind, KeyFunction> pair : getKeymap(currentMapID))
+ {
+ Keybind bind = pair.first;
+ XGrabKey(globals.dpy, bind.key, 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 = {(KeyCode)e.keycode, e.state & masks};
+ if(k == exitBind)
+ {
+ changeMap(0);
+ }
+ else if(getKeymap(currentMapID).count(k) > 0)
{
- if(bind.modifiers == (e.state & masks) && bind.key == XLookupKeysym(&e, 0))
+ KeyFunction& c = getKeymap(currentMapID).find(k)->second;
+ if(getKeymap(c.mapID).size() == 0)
{
- commandsModule.runCommand(bind.command);
+ commandsModule.runCommand(c.command);
+ changeMap(0);
}
+ else
+ {
+ 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)
+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)
{
- Err e = commandsModule.checkCommand(argv[1].str);
- if(e.code != NOERR)
+ if(bindModes.count(argv[0].str) < 1)
+ {
+ throw Err(CFG_ERR_KEYBIND, "Bind mode: " + string(argv[0].str) + " does not exist");
+ }
+ else
{
- e.message = "Binding fail - " + e.message;
- throw e;
+ bindFunc = bindModes.find(argv[0].str)->second;
}
- std::vector<string> keys = split(argv[0].str, '+');
+}
+
+Keybind KeybindsModule::getKeybind(std::string bindString)
+{
+ return (this->*bindFunc)(bindString);
+}
+
+const Keybind KeybindsModule::normalBindMode(string bindString)
+{
+ std::vector<string> keys = split(bindString, '+');
Keybind bind;
bind.modifiers = 0;
for(string key : keys)
@@ -68,23 +146,137 @@ const void KeybindsModule::bind(const CommandArg* argv)
}
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 '" + string(argv[0].str) + "' is invalid!");
- continue;
+ throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!");
}
+ bind.key = XKeysymToKeycode(globals.dpy, s);
}
}
- 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);
+ if(!bind.key)
+ throw Err(CFG_ERR_KEYBIND, "Keybind '" + bindString + "' is invalid!");
+ return bind;
+}
+
+const Keybind KeybindsModule::emacsBindMode(string bindString)
+{
+ Keybind bind;
+ bind.modifiers = 0;
+
+ const std::regex keyRegex("^(?:([CMs])-)?(?:([CMs])-)?(?:([CMs])-)?([^\\s]|(SPC|ESC|RET|))$");
+ std::smatch keyMatch;
+ if(std::regex_match(bindString, keyMatch, keyRegex))
+ {
+ for (int i = 1; i < 3; i++)
+ {
+ std::ssub_match modifierMatch = keyMatch[i];
+ if(modifierMatch.matched)
+ {
+ 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;
+ }
+ }
+ }
+ }
+ 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;
+ else if(keyMatch[4].str() == "ESC")
+ keySym = XK_Escape;
+ 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");
+ }
+ bind.key = XKeysymToKeycode(globals.dpy, keySym);
+
+ return bind;
+}
+
+const void KeybindsModule::bind(const CommandArg* argv)
+{
+ std::vector<Err> errs = commandsModule.checkCommand(argv[1].str);
+ for(Err e : errs)
+ {
+ if(e.code != NOERR)
+ {
+ e.message = "Binding fail - " + e.message;
+ throw e;
+ }
+ }
+ std::vector<string> 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<Keybind, KeyFunction>()});
+ 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<Keybind, KeyFunction>()});
+ 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<Keybind>();
+ keyMaps = std::map<int, std::map<Keybind, KeyFunction>>();
+ keyMaps.insert({0, std::map<Keybind, KeyFunction>()});
}