summaryrefslogtreecommitdiffstats
path: root/system/esekeyd/keyboard_detection.diff
blob: 97e93bcdceb73f17d3d0e701ae850f2ed85245e3 (plain)
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 <dirent.h>
+#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<devno> 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;
 }