aboutsummaryrefslogtreecommitdiff
path: root/shotkey.c
diff options
context:
space:
mode:
authorAkshay Nair <phenax5@gmail.com>2020-06-20 15:28:05 +0530
committerAkshay Nair <phenax5@gmail.com>2020-06-20 15:28:05 +0530
commitaa146c847d7e03881a99382100f1f61e473475c7 (patch)
tree7061d727e808e278457b00fa3623d2156dae10a4 /shotkey.c
parent353dab50ea72a4c9b013d0305939f241260c4839 (diff)
downloadshotkey-aa146c847d7e03881a99382100f1f61e473475c7.tar.gz
shotkey-aa146c847d7e03881a99382100f1f61e473475c7.zip
Renames project to shotkey
Diffstat (limited to 'shotkey.c')
-rw-r--r--shotkey.c190
1 files changed, 190 insertions, 0 deletions
diff --git a/shotkey.c b/shotkey.c
new file mode 100644
index 0000000..d839ef4
--- /dev/null
+++ b/shotkey.c
@@ -0,0 +1,190 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <unistd.h>
+
+typedef struct Command {
+ char* command;
+ unsigned int mode;
+ int persist;
+} Command;
+
+typedef struct Key {
+ unsigned int mod;
+ KeySym key;
+ Command command;
+} Key;
+
+typedef struct ModeProperties {
+ char* label;
+} ModeProperties;
+
+#define NormalMode -1
+
+#define cmd(c) (Command) { c, NormalMode, False }
+#define mode(m, p) (Command) { NULL, m, p }
+
+#include "config.h"
+
+#define LENGTH(X) (sizeof X / sizeof X[0])
+#define CLEANMASK(mask) (mask & ~LockMask & (ShiftMask|ControlMask|Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask))
+
+int current_mode = NormalMode;
+int is_mode_persistent = 0;
+
+extern char** environ;
+
+void bind_key(Display *dpy, Window win, unsigned int mod, KeySym key) {
+ int keycode = XKeysymToKeycode(dpy, key);
+ XGrabKey(dpy, keycode, mod, win, False, GrabModeAsync, GrabModeAsync);
+}
+void unbind_key(Display *dpy, Window win, unsigned int mod, KeySym key) {
+ int keycode = XKeysymToKeycode(dpy, key);
+ XUngrabKey(dpy, keycode, mod, win);
+}
+
+int error_handler(Display *disp, XErrorEvent *xe) {
+ switch(xe->error_code) {
+ case BadAccess:
+ printf("shotkey: [BadAccess] Cant grab key binding. Already grabbed\n");
+ return 0;
+ }
+
+ printf("shotkey: Something went wrong\n");
+ return 1;
+}
+
+void spawn(char** command) {
+ if (fork() == 0) {
+ setsid();
+ execve(command[0], command, environ);
+ fprintf(stderr, "shotkey: execve %s", command[0]);
+ perror(" failed");
+ exit(0);
+ }
+}
+
+char* get_mode_label() {
+ if (current_mode == NormalMode) return "";
+ if (LENGTH(mode_properties) <= current_mode) return "";
+ ModeProperties props = mode_properties[current_mode];
+ return props.label;
+}
+
+void handle_mode_change() {
+ char str[255];
+
+ sprintf(str, "%d", current_mode);
+ setenv("MODE_ID", str, 1);
+
+ sprintf(str, "%s", get_mode_label());
+ setenv("MODE_LABEL", str, 1);
+
+ char* cmd[] = {shell, "-c", on_mode_change, NULL};
+ spawn(cmd);
+}
+
+void set_mode(int mode, unsigned int persist) {
+ current_mode = mode;
+ is_mode_persistent = persist;
+ handle_mode_change();
+}
+
+void run(Display* dpy, Window win, Command command) {
+ Key mode_key;
+ unsigned int i;
+
+ if (command.command) {
+ char* cmd[] = {shell, "-c", command.command, NULL};
+ spawn(cmd);
+ } else if(command.mode != NormalMode) {
+ // Bind keyboard for mode
+ XGrabKeyboard(dpy, win, False, GrabModeAsync, GrabModeAsync, CurrentTime);
+
+ // Bind an escape key to quit mode
+ bind_key(dpy, win, 0, XK_Escape);
+
+ // Set mode
+ set_mode(command.mode, command.persist);
+ }
+}
+
+void keypress(Display *dpy, Window win, XKeyEvent *ev) {
+ unsigned int i;
+ Key mode_key;
+ KeySym keysym = XKeycodeToKeysym(dpy, (KeyCode) ev->keycode, 0);
+
+ if (current_mode == NormalMode) {
+ // Bind all the normal mode keys
+ for (i = 0; i < LENGTH(keys); i++) {
+ if (keysym == keys[i].key && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)) {
+ run(dpy, win, keys[i].command);
+ }
+ }
+ } else {
+ // Will quit if the key pressed is not defined in the mode
+ is_mode_persistent = False;
+
+ if (modes[current_mode] && current_mode < LENGTH(modes)) {
+ // Check if key is in mode and execute
+ for (i = 0; i < LENGTH(modes[current_mode]); i++) {
+ mode_key = modes[current_mode][i];
+
+ if (keysym == mode_key.key && CLEANMASK(mode_key.mod) == CLEANMASK(ev->state)) {
+ // Action taken so keep the mode alive
+ is_mode_persistent = True;
+ run(dpy, win, mode_key.command);
+ }
+ }
+
+ if (!is_mode_persistent) {
+ // Unbind mode related keys
+ XUngrabKeyboard(dpy, CurrentTime);
+
+ // Unbind escape key
+ unbind_key(dpy, win, 0, XK_Escape);
+ }
+ }
+
+ if (!is_mode_persistent) {
+ set_mode(NormalMode, False);
+ }
+ }
+}
+
+int main() {
+ XSetErrorHandler(error_handler);
+
+ int running = 1, i = 0;
+
+ Display *dpy = XOpenDisplay(0);
+ Window root = DefaultRootWindow(dpy);
+
+ // Grab keys
+ for (i = 0; i < LENGTH(keys); i++) {
+ bind_key(dpy, root, keys[i].mod, keys[i].key);
+ }
+
+ XSelectInput(dpy, root, KeyPressMask);
+
+ handle_mode_change();
+
+ /* main event loop */
+ XEvent ev;
+ XSync(dpy, False);
+ while (running) {
+ XMaskEvent(dpy, KeyPressMask, &ev);
+
+ switch (ev.type) {
+ case KeyPress: {
+ keypress(dpy, root, &ev.xkey);
+ break;
+ }
+ }
+ }
+
+ XCloseDisplay(dpy);
+}
+