diff options
-rw-r--r-- | xlockkbd.c | 78 |
1 files changed, 72 insertions, 6 deletions
@@ -1,13 +1,54 @@ +#include <stdarg.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <unistd.h> #include <X11/Xlib.h> #include <X11/keysym.h> -static void die(const char *s) +struct named_mask { + const char *name; + unsigned int mask; +}; + +static const struct named_mask named_masks[] = { + { "Shift", ShiftMask }, + { "Control", ControlMask }, + { "Ctrl", ControlMask }, + { "Alt", Mod1Mask }, + { "Super", Mod4Mask }, + { "Mod1", Mod1Mask }, + { "Mod2", Mod2Mask }, + { "Mod3", Mod3Mask }, + { "Mod4", Mod4Mask }, + { "Mod5", Mod5Mask } +}; +#define len_named_masks (sizeof(named_masks) / sizeof(*named_masks)) + +static unsigned int str_to_mask(const char *s) +{ + for (size_t i = 0; i < len_named_masks; ++i) { + const struct named_mask *m = named_masks + i; + if (!strcmp(s, m->name)) + return m->mask; + } + + return 0; +} + +static void die(const char *fmt, ...) { - fprintf(stderr, "xlockkbd: %s\n", s); + va_list ap; + va_start(ap, fmt); + + char *s; + if (vasprintf(&s, fmt, ap) != -1) + fprintf(stderr, "xlockkbd: %s\n", s); + else + fprintf(stderr, "xlockkbd: unknown error\n"); + + va_end(ap); exit(1); } @@ -30,18 +71,43 @@ static bool grab_kbd(Display *d, int screen) return (res == GrabSuccess); } -static void wait_for_key(Display *d) +static void wait_for_release(Display *d, KeySym key, unsigned int mask) { XEvent ev; while (!XNextEvent(d, &ev)) { if (ev.type == KeyPress && - XLookupKeysym(&ev.xkey, 0) == XK_Escape) + XLookupKeysym(&ev.xkey, 0) == key && + (mask & ev.xkey.state) == mask) break; } } -int main() +int main(int argc, char **argv) { + unsigned int mask = 0, arg_mask; + KeySym key = NoSymbol, arg_key; + + for (int i = 1; i < argc; ++i) { + if ((arg_mask = str_to_mask(argv[i]))) { + mask = mask | arg_mask; + } else if (key != NoSymbol) { + die("more than one non-modifier key provided"); + } else { + if ((arg_key = XStringToKeysym(argv[i])) == NoSymbol) + die("unknown key: %s", argv[i]); + if (arg_key >= XK_A && arg_key <= XK_Z) + die("use Shift modifier for uppercase key: %s", + argv[i]); + key = arg_key; + } + } + + if (key == NoSymbol) { + if (mask) + die("no non-modifier key provided"); + key = XK_Escape; + } + Display *d = XOpenDisplay(NULL); if (!d) die("cannot open display"); @@ -51,6 +117,6 @@ int main() die("failed to grab keyboard"); } - wait_for_key(d); + wait_for_release(d, key, mask); return 0; } |