Commit 040bd7a91bf12049bea90751cd5ce8a872a200e8

Luca Weiss 2020-12-28T00:55:28

Fix udev not detecting ID_INPUT_KEY devices when udev is not running https://bugzilla.libsdl.org/show_bug.cgi?id=5308 The udev code labels devices that are found by this code with ID_INPUT_KEY which in turn gets used by SDL to label the devices as SDL_UDEV_DEVICE_KEYBOARD. This was missing for the code path when udev is not running and as such devices such as the power button of a phone was not detected as keyboard input and no devices were emitted.

diff --git a/src/core/linux/SDL_evdev_capabilities.c b/src/core/linux/SDL_evdev_capabilities.c
index 12185fe..92f247e 100644
--- a/src/core/linux/SDL_evdev_capabilities.c
+++ b/src/core/linux/SDL_evdev_capabilities.c
@@ -24,12 +24,34 @@
 
 #if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)
 
+/* missing defines in older Linux kernel headers */
+#ifndef BTN_TRIGGER_HAPPY
+#define BTN_TRIGGER_HAPPY 0x2c0
+#endif
+#ifndef BTN_DPAD_UP
+#define BTN_DPAD_UP       0x220
+#endif
+#ifndef KEY_ALS_TOGGLE
+#define KEY_ALS_TOGGLE    0x230
+#endif
+
 extern int
 SDL_EVDEV_GuessDeviceClass(unsigned long bitmask_ev[NBITS(EV_MAX)],
                            unsigned long bitmask_abs[NBITS(ABS_MAX)],
                            unsigned long bitmask_key[NBITS(KEY_MAX)],
                            unsigned long bitmask_rel[NBITS(REL_MAX)])
 {
+    struct range {
+        unsigned start;
+        unsigned end;
+    };
+
+    /* key code ranges above BTN_MISC (start is inclusive, stop is exclusive)*/
+    static const struct range high_key_blocks[] = {
+        { KEY_OK, BTN_DPAD_UP },
+        { KEY_ALS_TOGGLE, BTN_TRIGGER_HAPPY }
+    };
+
     int devclass = 0;
     unsigned long keyboard_mask;
 
@@ -86,6 +108,31 @@ SDL_EVDEV_GuessDeviceClass(unsigned long bitmask_ev[NBITS(EV_MAX)],
         devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */
     }
 
+    if (test_bit(EV_KEY, bitmask_ev)) {
+        unsigned i;
+        unsigned long found = 0;
+
+        for (i = 0; i < BTN_MISC/BITS_PER_LONG; ++i) {
+            found |= bitmask_key[i];
+        }
+        /* If there are no keys in the lower block, check the higher blocks */
+        if (!found) {
+            unsigned block;
+            for (block = 0; block < (sizeof(high_key_blocks) / sizeof(struct range)); ++block) {
+                for (i = high_key_blocks[block].start; i < high_key_blocks[block].end; ++i) {
+                    if (test_bit(i, bitmask_key)) {
+                        found = 1;
+                        break;
+                    }
+                }
+            }
+        }
+
+        if (found > 0) {
+            devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEY */
+        }
+    }
+
     /* the first 32 bits are ESC, numbers, and Q to D; if we have any of
      * those, consider it a keyboard device; do not test KEY_RESERVED, though */
     keyboard_mask = 0xFFFFFFFE;