diff -Naur esekeyd-esekeyd-1.2.7/src/input.c esekeyd-esekeyd-1.2.7.patched/src/input.c --- esekeyd-esekeyd-1.2.7/src/input.c 2010-07-04 16:23:51.000000000 -0400 +++ esekeyd-esekeyd-1.2.7.patched/src/input.c 2020-11-01 20:22:49.777498592 -0500 @@ -10,6 +10,14 @@ #include "esekey.h" +#include +#define CLASS_DIR "/sys/class/input" +#define DEV_DIR "/dev/input" + +#ifndef PATH_MAX +# define PATH_MAX 1024 +#endif + signed char check_handlers (void) { FILE *fp = NULL; @@ -45,32 +53,63 @@ return 0; } -signed char find_input_dev (void) +/* return true if /dev/input/event is a keyboard. + This could also have been done by way of ioctls instead of reading + from /sys files. Hopefully the /sys API doesn't change... + It's documented thoroughly here: + https://unix.stackexchange.com/questions/74903/explain-ev-in-proc-bus-input-devices-data + */ +int is_keyboard(int devno) { - FILE *fp = NULL; - signed char have_evdev = -2; + char filename[PATH_MAX + 1]; + char *buf = NULL; + size_t len = 0, caps = 0; + size_t wantcaps = (1 << EV_SYN | 1 << EV_KEY | 1 << EV_MSC | 1 << EV_LED | 1 << EV_REP); + FILE *fp; + + sprintf(filename, "%s/event%d/device/capabilities/ev", CLASS_DIR, devno); + if(!(fp = fopen(filename, "r"))) return 0; + + getline(&buf, &len, fp); + fclose(fp); + if(!buf) return 0; - fp = fopen (INPUT_DEVICES, "r"); + caps = strtol(buf, NULL, 16); + free(buf); - if (!fp) + return (caps & wantcaps) == wantcaps; +} + +/* returns the highest-numbered keyboard found. The common case is + that the internal keyboard on a laptop is numbered lower than an external + keyboard, and we assume that if there's an external, it's the one the + user actually uses. If no keyboards are found, returns -1. */ +signed char find_input_dev (void) +{ + DIR *dir; + struct dirent *entry; + int last_kbd = -1; + char buf[PATH_MAX + 1]; + + dir = opendir(CLASS_DIR); + if(!dir) { + perror(CLASS_DIR); return -1; + } - while (!feof (fp)) - { - char *buff = NULL; - size_t len = 0; - short int number = -2; - getline (&buff, &len, fp); - sscanf (buff, "H: Handlers=kbd event%hu", &number); - free (buff); - if (number > -1) - { - have_evdev = number; - break; + while( (entry = readdir(dir)) ) { + sprintf(buf, "%s/%s", CLASS_DIR, entry->d_name); + if(strncmp(entry->d_name, "event", 5) == 0) { + int devno = atoi(entry->d_name + 5); + if(is_keyboard(devno)) { + fprintf(stderr, "event%d is a keyboard\n", devno); + if(devno > last_kbd) last_kbd = devno; + } } } + closedir(dir); - fclose (fp); + fprintf(stderr, "Autodetected keyboard: %s/event%d\n", DEV_DIR, last_kbd); - return have_evdev; + return last_kbd; }