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
I'm Eli.