Created
September 24, 2022 20:39
-
-
Save dharmx/d11c1e93d20ebc9c79ffd025b1644f5e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
* { all: unset; } | |
label { | |
font-family: Phosphor, Dosis; | |
font-size: 4em; | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(defwindow window | |
:windowtype "normal" | |
:wm-ignore true | |
:geometry (geometry :anchor "center" :y 100 :width "10%" :height "10%") | |
(label :text {keymon})) | |
(deflisten keymon "./xkb -s ") |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* cc -O3 --std=c11 -pedantic -Wall xkb -o xkb.c -lX11 -lXi */ | |
#include <X11/X.h> | |
#include <X11/XKBlib.h> | |
#include <X11/Xlib.h> | |
#include <X11/extensions/XI2.h> | |
#include <X11/extensions/XInput2.h> | |
#include <getopt.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#define HELP_MESSAGE "xkb -[p|l|h] ...\n" | |
#define BEGIN_XOP _setup(); | |
#define END_XOP _finish(); | |
Display* display = NULL; | |
typedef struct dump_t { | |
int xi_opcode; | |
int first_event; | |
int first_error; | |
int xkb_opcode; | |
int xkb_event; | |
int xkb_error; | |
int xkb_major_inout; | |
int xkb_minor_inout; | |
Status query_result; | |
Status xi_query_result; | |
Status xkb_query_result; | |
} dump_t; | |
void | |
_setup(void) { | |
display = XOpenDisplay(None); | |
} | |
void | |
_finish(void) { | |
if (display != NULL) { | |
XFlush(display); | |
XCloseDisplay(display); | |
} | |
} | |
void | |
list_extensions(char* delimiter) { | |
delimiter = delimiter ? delimiter : "\n"; | |
int size; | |
char** extensions = XListExtensions(display, &size); | |
for (int index = 1; index < size; ++index) printf("%s%s", extensions[index], delimiter); | |
printf("%s", strcmp(delimiter, "\n") ? "\n" : ""); | |
} | |
void init_logger(dump_t* dump, int version[2]) { | |
dump->query_result = XQueryExtension(display, "XInputExtension", &dump->xi_opcode, &dump->first_event, &dump->first_error); | |
dump->xi_query_result = XIQueryVersion(display, &version[0], &version[1]); | |
dump->xkb_query_result = XkbQueryExtension(display, | |
&dump->xkb_opcode, | |
&dump->xkb_event, | |
&dump->xkb_error, | |
&dump->xkb_major_inout, | |
&dump->xkb_minor_inout); | |
} | |
Bool | |
handle_rawkey(XIRawEvent* event, const char* prefix, Bool only_icon) { | |
KeySym keysym = XkbKeycodeToKeysym(display, event->detail, None, None); | |
if (keysym == NoSymbol) return False; | |
char* keystring = XKeysymToString(keysym); | |
if (keystring == NULL) return False; | |
printf("%s%s\n", prefix, only_icon ? "" : keystring); | |
fflush(stdout); | |
return True; | |
} | |
void | |
start_logger(const char* up, const char* down, Bool only_icon) { | |
int version[2] = {2, 0}; | |
dump_t dump; | |
memset(&dump, None, sizeof(dump_t)); | |
init_logger(&dump, version); | |
if (!dump.query_result) perror("ERROR: XInputExtension does not exist!"); | |
if (dump.xi_query_result != Success) perror("ERROR: XI2 is not supported!"); | |
if (!dump.xkb_query_result) perror("ERROR: XKBlib is not compatible!"); | |
XIEventMask mask; | |
memset(&mask, None, sizeof(XIEventMask)); | |
mask.deviceid = XIAllMasterDevices; | |
mask.mask_len = XIMaskLen(XI_LASTEVENT); | |
mask.mask = calloc(mask.mask_len, sizeof(char)); | |
XISetMask(mask.mask, XI_RawKeyPress); | |
XISetMask(mask.mask, XI_RawKeyRelease); | |
Window root = DefaultRootWindow(display); | |
XISelectEvents(display, root, &mask, 1); | |
XFree(mask.mask); | |
XEvent event; | |
XGenericEventCookie* cookie; | |
memset(&event, None, sizeof(XEvent)); | |
while (True) { | |
cookie = &event.xcookie; | |
XNextEvent(display, &event); | |
if (XGetEventData(display, cookie) && cookie->type == GenericEvent && cookie->extension == dump.xi_opcode) { | |
XIRawEvent* raw_event = cookie->data; | |
switch (cookie->evtype) { | |
case XI_RawKeyPress: | |
if (!handle_rawkey(raw_event, down, only_icon)) continue; | |
break; | |
case XI_RawKeyRelease: | |
if (!handle_rawkey(raw_event, up, only_icon)) continue; | |
break; | |
default: continue; | |
} | |
XFreeEventData(display, cookie); | |
} | |
} | |
} | |
int | |
main(int argc, char** argv) { | |
BEGIN_XOP | |
int optlog = 0; | |
int option; | |
while ((option = getopt(argc, argv, ":spl::h")) != -1) { | |
switch (option) { | |
case 'p': optlog = 1; break; | |
case 's': optlog = 2; break; | |
case 'l': list_extensions(optarg); break; | |
case 'h': fprintf(stdout, HELP_MESSAGE); break; | |
case '?': fprintf(stderr, HELP_MESSAGE); break; | |
default: perror("undefined"); break; | |
} | |
} | |
switch (optlog) { | |
case 1: | |
if (argc - optind == 2) start_logger(argv[optind], argv[optind + 1], False); | |
else start_logger("@", "~", False); | |
case 2: | |
if (argc - optind == 2) start_logger(argv[optind], argv[optind + 1], True); | |
else start_logger("@", "~", False); | |
} | |
END_XOP | |
return EXIT_SUCCESS; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
keymon.mp4