Skip to content

Instantly share code, notes, and snippets.

@dharmx
Last active September 27, 2022 19:18
Show Gist options
  • Save dharmx/0d131b5af8c30922dcc5dc753b2187e6 to your computer and use it in GitHub Desktop.
Save dharmx/0d131b5af8c30922dcc5dc753b2187e6 to your computer and use it in GitHub Desktop.
xkb indicator logger
/* compile command: cc -O3 --std=c11 -pedantic -Wall xkb.c -o xkb -lX11 -lXi */
/* Headers and Defines {{{*/
#include <X11/XKBlib.h>
#include <getopt.h>
#include <stdio.h>
#include <stdlib.h>
#define HELP_MESSAGE \
"xkb -[s] ...\n" \
"\n" \
"OPTIONS:\n" \
" -s indicators CAPS_LOCK_STATE NUM_LOCK_STATE\n" \
" -j {\"caps\":\"CAPS_LOCK_STATE\",\"num\":\"NUM_LOCK_STATE\"\n" \
"\n" \
"EXAMPLES:\n" \
" -s1 will print the initial value\n" \
" -s0 won't print the initial value / not providing any args will have the same effect\n" \
" -j[1|0] same as -s\n" \
"\n"
#define BEGIN_XOP _setup();
#define END_XOP _finish();
#define ON_OR_OFF(S) (S ? "on" : "off")
/*}}}*/
/* Boilerplates {{{*/
typedef enum {
NO_STATE = 0,
CAPS_LOCK_STATE = 1,
NUM_LOCK_STATE = 2,
BOTH_LOCK_STATE = 3,
} ind_state_t;
Display* display = NULL;
void
_setup(void) {
display = XOpenDisplay(None);
}
void
_finish(void) {
if (display != NULL) {
XFlush(display);
XCloseDisplay(display);
}
}
/*}}}*/
void
display_ind_state(Bool ind_keys[2], int event_state, Bool json) {
switch (event_state) {
case NO_STATE: ind_keys[0] = ind_keys[1] = False; break;
case CAPS_LOCK_STATE: ind_keys[0] = True; break;
case NUM_LOCK_STATE: ind_keys[1] = True; break;
case BOTH_LOCK_STATE: ind_keys[0] = ind_keys[1] = True; break;
}
printf(json ? "{\"caps\":\"%s\",\"num\":\"%s\"}\n" : "indicators %s %s\n",
ON_OR_OFF(ind_keys[0]),
ON_OR_OFF(ind_keys[1]));
fflush(stdout);
}
void
start_led_logger(Bool first_blood, Bool json) {
Bool ind_keys[2] = {False, False};
if (first_blood) {
unsigned int start_state;
XkbGetIndicatorState(display, XkbUseCoreKbd, &start_state);
display_ind_state(ind_keys, start_state, json);
}
XkbSelectEvents(display, XkbUseCoreKbd, XkbIndicatorStateNotifyMask, XkbIndicatorStateNotifyMask);
XkbIndicatorNotifyEvent event;
while (True) {
XNextEvent(display, (XEvent*) &event);
display_ind_state(ind_keys, event.state, json);
}
}
/* Main {{{*/
int
main(int argc, char** argv) {
BEGIN_XOP
int option;
while ((option = getopt(argc, argv, "-j::s::h")) != -1) {
switch (option) {
case 's': start_led_logger(atoi(optarg ? optarg : "0"), False); break;
case 'j': start_led_logger(atoi(optarg ? optarg : "0"), True); break;
case 'h': fprintf(stdout, HELP_MESSAGE); break;
case '?': fprintf(stderr, HELP_MESSAGE); break;
default: fprintf(stderr, "./xkb: options are prefixed with '-'\n%s", HELP_MESSAGE); break;
}
}
END_XOP
return EXIT_SUCCESS;
}
/*}}}*/
// vim:filetype=c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment