evdev: check well-known keyboard keys on joystick/gamepad detection
authorJosé Expósito <jose.exposito89@gmail.com>
Tue, 1 Mar 2022 19:08:11 +0000 (20:08 +0100)
committerJosé Expósito <jose.exposito89@gmail.com>
Wed, 2 Mar 2022 07:21:49 +0000 (08:21 +0100)
Create a list of well-known keyboard keys containing one the most
representative key(s) of a group.
The rule is based on the assumption that if the representative key is
present, other keys of the group should be present as well.

The groups are:

 - Modifiers group: KEY_LEFTCTRL.
 - Character group: KEY_CAPSLOCK.
 - Numeric group: KEY_NUMLOCK.
 - Editing keys: KEY_INSERT.
 - Multimedia keys: KEY_MUTE, KEY_CALC, KEY_FILE, KEY_MAIL,
   KEY_PLAYPAUSE and KEY_BRIGHTNESSDOWN.

When 4 of these keys are found, the device is tagged as a keyboard.

Fix #745

Signed-off-by: José Expósito <jose.exposito89@gmail.com>
src/evdev.c

index 6d81f58..453ac3f 100644 (file)
@@ -88,6 +88,19 @@ static const struct evdev_udev_tag_match evdev_udev_tag_matches[] = {
        {"ID_INPUT_SWITCH",             EVDEV_UDEV_TAG_SWITCH},
 };
 
+static const unsigned int well_known_keyboard_keys[] = {
+       KEY_LEFTCTRL,
+       KEY_CAPSLOCK,
+       KEY_NUMLOCK,
+       KEY_INSERT,
+       KEY_MUTE,
+       KEY_CALC,
+       KEY_FILE,
+       KEY_MAIL,
+       KEY_PLAYPAUSE,
+       KEY_BRIGHTNESSDOWN,
+};
+
 static inline bool
 parse_udev_flag(struct evdev_device *device,
                struct udev_device *udev_device,
@@ -1868,8 +1881,9 @@ evdev_device_is_joystick_or_gamepad(struct evdev_device *device)
         * differentiate them from keyboards, apply the following rules:
         *
         *  1. The device is tagged as joystick but not as tablet
-        *  2. It has at least 2 joystick buttons
-        *  3. It doesn't have 10 keyboard keys */
+        *  2. The device doesn't have 4 well-known keyboard keys
+        *  3. It has at least 2 joystick buttons
+        *  4. It doesn't have 10 keyboard keys */
 
        udev_tags = evdev_device_get_udev_tags(device, device->udev_device);
        has_joystick_tags = (udev_tags & EVDEV_UDEV_TAG_JOYSTICK) &&
@@ -1880,6 +1894,17 @@ evdev_device_is_joystick_or_gamepad(struct evdev_device *device)
                return false;
 
 
+       unsigned int num_well_known_keys = 0;
+
+       for (size_t i = 0; i < ARRAY_LENGTH(well_known_keyboard_keys); i++) {
+               code = well_known_keyboard_keys[i];
+               if (libevdev_has_event_code(evdev, EV_KEY, code))
+                       num_well_known_keys++;
+       }
+
+       if (num_well_known_keys >= 4) /* should not have 4 well-known keys */
+               return false;
+
        for (code = BTN_JOYSTICK; code < BTN_DIGI; code++) {
                if (libevdev_has_event_code(evdev, EV_KEY, code))
                        num_joystick_btns++;