Polling x.org’s keyboard state
Recently I needed to write a script that changed its behavior when the shift-key was held down. After some research to find a pre-made (and command-line-friendly) solution, I gave up and decided to rip open xkbwatch and see how it does it. It turned out not to be so scary and so I extracted the meaningful bits of code from it and condensed it into a more general-purpose tool. Let me know if I overlooked a really easy or simple way of doing this.
/* ** xkbdump.c ** Dumps the modifier keys onto the command line in a space-separated list. */ #include <stdio.h> #include <X11/Xlib.h> #include <X11/XKBlib.h> int main() { Display *dpy = XOpenDisplay(0); XkbStateRec state; // I don't fully understand this structure. // I only know that it reports my modifier keys. XkbGetState(dpy, XkbUseCoreKbd, &state); int i; for (i = 0; i < (sizeof(state.mods) * 8); ++i) if ((1 << i) & state.mods) printf("%d ", (1 << i) & state.mods); printf("\n"); return 0; }
The use-case I had imagined was something like this.
#!/usr/bin/env bash SHIFT_KEYCODE=1 CTRL_KEYCODE=4 # ^ Inferred above just by running xkbdump with ctrl/shift held down both_held=$(xkbdump | grep "\<$SHIFT_KEYCODE\>" | grep "\<$CTRL_KEYCODE\>"); shift_held=$(xkbdump | grep "\<$SHIFT_KEYCODE\>"); ctrl_held=$(xkbdump | grep "\<$CTRL_KEYCODE\>"); if [ "$both_held" ]; then echo "Both shift and control were held down"; elif [ "$shift_held" ]; then echo "Only shift was held down"; elif [ "$ctrl_held" ]; then echo "Only control was held down"; else echo "Neither shift nor control were held down"; fi
One last note. In order to build this, you need to tell gcc where to link against X11. Build with a gcc command like this.
gcc xkbdump.c -o xkbdump -lX11