Commit Diff


commit - 193276b680731f03b45f7fe6d86fcfe75f573466
commit + 91009a76b6a0313a1be930d77b9c79c312d0da61
blob - 0368179e9c5d6888c5404ef0219b0d559a0c3d0a
blob + d554e22e149f851f331d3b11d8534de9a6713e81
--- bxhkd.c
+++ bxhkd.c
@@ -5,3 +5,172 @@
  * See LICENSE.md and README.md for details.
 */
 
+/* bxhkd - basic X hotkey daemon */
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/wait.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <X11/Xlib.h>
+#include <X11/keysym.h>
+
+#include "config.h"
+
+#define LENGTH(arr) (sizeof(arr) / sizeof(arr[0]))
+
+#define SOCKET_SUFFIX "/.local/tmp/bxwm.sock"
+
+static Display *dpy;
+static Window root;
+static volatile sig_atomic_t running = 1;
+
+static void grabkeys(void);
+static void keypress(XKeyEvent *ev);
+static void spawn(const char *cmd);
+static void send_cmd(char *cmd) 
+static void sigchld(int sig);
+static void cleanup(void);
+
+static void
+grabkeys(void)
+{
+    unsigned int i, j;
+    KeyCode code;
+    unsigned int modifiers[] = { 0, LockMask, Mod2Mask, LockMask|Mod2Mask };
+
+    XUngrabKey(dpy, AnyKey, AnyModifier, root);
+    for (i = 0; i < LENGTH(keys); i++) {
+        code = XKeysymToKeycode(dpy, keys[i].keysym);
+        if (code == 0)
+            continue;
+        for (j = 0; j < LENGTH(modifiers); j++)
+            XGrabKey(dpy, code, keys[i].mod | modifiers[j],
+                     root, True, GrabModeAsync, GrabModeAsync);
+    }
+}
+
+static void
+keypress(XKeyEvent *ev)
+{
+    KeySym keysym;
+    unsigned int i;
+
+    keysym = XLookupKeysym(ev, 0);
+    for (i = 0; i < LENGTH(keys); i++) {
+        if (keysym == keys[i].keysym
+            && CLEANMASK(keys[i].mod) == CLEANMASK(ev->state)) {
+            spawn(keys[i].command);
+            return;
+        }
+    }
+}
+
+static void
+spawn(const char *cmd)
+{
+    char buf[256];
+    char *argv[64];
+    char *tok;
+    int argc = 0;
+
+    strncpy(buf, cmd, sizeof(buf) - 1);
+    buf[sizeof(buf) - 1] = '\0';
+
+    tok = strtok(buf, " ");
+    while (tok && argc < 63) {
+        argv[argc++] = tok;
+        tok = strtok(NULL, " ");
+    }
+    argv[argc] = NULL;
+
+    if (fork() == 0) {
+        if (dpy)
+            close(ConnectionNumber(dpy));
+        setsid();
+        execvp(argv[0], argv);
+        fprintf(stderr, "bxhkd: execvp %s failed\n", argv[0]);
+        _exit(EXIT_FAILURE);
+    }
+}
+
+static void
+mappingnotify(XMappingEvent *ev)
+{
+    XRefreshKeyboardMapping(ev);
+    if (ev->request == MappingKeyboard)
+        grabkeys();
+}
+
+static void
+send_cmd(char *cmd) {
+    int sock;
+    struct sockaddr_un addr;
+    char *home = getenv("HOME");
+    char path[256];
+
+    snprintf(path, sizeof(path), "%s%s", home, "/.local/tmp/bxwm.sock");
+
+    if ((sock = socket(AF_UNIX, SOCK_STREAM, 0)) == -1) return;
+
+    addr.sun_family = AF_UNIX;
+    strncpy(addr.sun_path, path, sizeof(addr.sun_path)-1);
+
+    if (connect(sock, (struct sockaddr*)&addr, sizeof(addr)) != -1) {
+        write(sock, cmd, strlen(cmd));
+    }
+    close(sock);
+}
+
+static void
+sigchld(int sig)
+{
+    (void)sig;
+    while (waitpid(-1, NULL, WNOHANG) > 0);
+}
+
+static void
+sig_term(int sig)
+{
+    (void)sig;
+    running = 0;
+}
+
+static void
+cleanup(void)
+{
+    XUngrabKey(dpy, AnyKey, AnyModifier, root);
+    XCloseDisplay(dpy);
+}
+
+int
+main(void)
+{
+    XEvent ev;
+
+    signal(SIGCHLD, sigchld);
+    signal(SIGINT, sig_term);
+    signal(SIGTERM, sig_term);
+
+    if (!(dpy = XOpenDisplay(NULL))) {
+        fprintf(stderr, "bxhkd: cannot open display\n");
+        return EXIT_FAILURE;
+    }
+    root = DefaultRootWindow(dpy);
+
+    XSelectInput(dpy, root, KeyPressMask|StructureNotifyMask);
+    grabkeys();
+
+    while (running && XNextEvent(dpy, &ev) == 0) {
+        if (ev.type == KeyPress)
+            keypress(&ev.xkey);
+        else if (ev.type == MappingNotify)
+            mappingnotify(&ev.xmapping);
+    }
+
+    cleanup();
+    return EXIT_SUCCESS;
+}
+