summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJosé Expósito <jose.exposito89@gmail.com>2021-11-23 18:07:53 +0100
committerPeter Hutterer <peter.hutterer@who-t.net>2021-12-03 00:20:47 +0000
commit8dd8786c482b8811cf0628571e6724e540ce61d7 (patch)
treefecb552fd896a5d7d99728e427702f49e4656a7b
parenta694a06b925009d836e5ba17cb73e29fdbcb188c (diff)
downloadlibinput-8dd8786c482b8811cf0628571e6724e540ce61d7.tar.gz
evdev: improve joystick and gamepad detection
The EVDEV_UDEV_TAG_JOYSTICK is set when a joystick or gamepad button is found. However, it can not be used to identify joysticks or gamepads because there are keyboards that also have it. Even worse, many joysticks also map KEY_* and thus are tagged as keyboards. In order to be able to detect joysticks and gamepads and 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 Fix #701 Fix #415 Fix #703 Signed-off-by: José Expósito <jose.exposito89@gmail.com>
-rw-r--r--src/evdev.c58
1 files changed, 55 insertions, 3 deletions
diff --git a/src/evdev.c b/src/evdev.c
index 9eb2d30b..cf0a2846 100644
--- a/src/evdev.c
+++ b/src/evdev.c
@@ -1854,12 +1854,64 @@ static bool
evdev_device_is_joystick_or_gamepad(struct evdev_device *device)
{
enum evdev_device_udev_tags udev_tags;
+ bool has_joystick_tags;
+ struct libevdev *evdev = device->evdev;
+ unsigned int code, num_joystick_btns = 0, num_keys = 0;
+
+ /* The EVDEV_UDEV_TAG_JOYSTICK is set when a joystick or gamepad button
+ * is found. However, it can not be used to identify joysticks or
+ * gamepads because there are keyboards that also have it. Even worse,
+ * many joysticks also map KEY_* and thus are tagged as keyboards.
+ *
+ * In order to be able to detect joysticks and gamepads and
+ * 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 */
udev_tags = evdev_device_get_udev_tags(device, device->udev_device);
- if (udev_tags == (EVDEV_UDEV_TAG_INPUT|EVDEV_UDEV_TAG_JOYSTICK))
- return true;
+ has_joystick_tags = (udev_tags & EVDEV_UDEV_TAG_JOYSTICK) &&
+ !(udev_tags & EVDEV_UDEV_TAG_TABLET) &&
+ !(udev_tags & EVDEV_UDEV_TAG_TABLET_PAD);
- return false;
+ if (!has_joystick_tags)
+ return false;
+
+
+ for (code = BTN_JOYSTICK; code < BTN_DIGI; code++) {
+ if (libevdev_has_event_code(evdev, EV_KEY, code))
+ num_joystick_btns++;
+ }
+
+ for (code = BTN_TRIGGER_HAPPY; code <= BTN_TRIGGER_HAPPY40; code++) {
+ if (libevdev_has_event_code(evdev, EV_KEY, code))
+ num_joystick_btns++;
+ }
+
+ if (num_joystick_btns < 2) /* require at least 2 joystick buttons */
+ return false;
+
+
+ for (code = KEY_ESC; code <= KEY_MICMUTE; code++) {
+ if (libevdev_has_event_code(evdev, EV_KEY, code) )
+ num_keys++;
+ }
+
+ for (code = KEY_OK; code <= KEY_LIGHTS_TOGGLE; code++) {
+ if (libevdev_has_event_code(evdev, EV_KEY, code) )
+ num_keys++;
+ }
+
+ for (code = KEY_ALS_TOGGLE; code < BTN_TRIGGER_HAPPY; code++) {
+ if (libevdev_has_event_code(evdev, EV_KEY, code) )
+ num_keys++;
+ }
+
+ if (num_keys >= 10) /* should not have 10 keyboard keys */
+ return false;
+
+ return true;
}
static struct evdev_dispatch *