diff options
author | David Vazgenovich Shakaryan <dvshakaryan@gmail.com> | 2024-03-04 15:23:11 -0800 |
---|---|---|
committer | David Vazgenovich Shakaryan <dvshakaryan@gmail.com> | 2024-03-04 15:23:11 -0800 |
commit | f91c93e26fe5e891545dec7b2bdeeea2d6bd56e2 (patch) | |
tree | ad416fac0d54ed909d14346d230dd31423ec2b16 /xkbdlock.c | |
parent | 96adda818d355ca53e8b3d30dfc6cc87a2256003 (diff) | |
download | xkbdlock-f91c93e26fe5e891545dec7b2bdeeea2d6bd56e2.tar.gz xkbdlock-f91c93e26fe5e891545dec7b2bdeeea2d6bd56e2.tar.xz |
rename
Diffstat (limited to 'xkbdlock.c')
-rw-r--r-- | xkbdlock.c | 122 |
1 files changed, 122 insertions, 0 deletions
diff --git a/xkbdlock.c b/xkbdlock.c new file mode 100644 index 0000000..0cdaedf --- /dev/null +++ b/xkbdlock.c @@ -0,0 +1,122 @@ +#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> + +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, ...) +{ + va_list ap; + va_start(ap, fmt); + + char *s; + if (vasprintf(&s, fmt, ap) != -1) + fprintf(stderr, "xkbdlock: %s\n", s); + else + fprintf(stderr, "xkbdlock: unknown error\n"); + + va_end(ap); + exit(1); +} + +static bool grab_kbd(Display *d, int screen) +{ + Window w = RootWindow(d, screen); + int res; + + // attempt to grab keyboard for 500ms if already grabbed. + // thanks to slock code for the pointer. + for (int i = 0;;) { + res = XGrabKeyboard(d, w, True, GrabModeAsync, GrabModeAsync, + CurrentTime); + if (res != AlreadyGrabbed || ++i > 5) + break; + + usleep(100000); + } + + return (res == GrabSuccess); +} + +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) == key && + (mask & ev.xkey.state) == mask) + break; + } +} + +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"); + + for (int i = 0; i < ScreenCount(d); ++i) { + if (!grab_kbd(d, i)) + die("failed to grab keyboard"); + } + + wait_for_release(d, key, mask); + return 0; +} |