Skip to content

Commit

Permalink
joystick: Use a better heuristic to guess what is a joystick
Browse files Browse the repository at this point in the history
Previously we only checked for at least one button or key and at least
the X and Y absolute axes, but this has both false positives and false
negatives.

Graphics tablets, trackpads and touchscreens all have buttons and
absolute X and Y axes, but we don't want to detect those as joysticks.
On normal Linux systems ordinary users do not have access to these
device nodes, but members of the 'input' group do.

Conversely, some game controllers only have digital buttons and no
analogue axes (the Nintendo Wiimote is an example), and some have axes
and no buttons (steering wheels or flight simulator rudders might not
have buttons).

Use the more elaborate heuristic factored out from SDL's udev code path
to handle these cases.

In an ideal world we could use exactly the same heuristic as udev's
input_id builtin, but that isn't under a suitable license for inclusion
in SDL, so we have to use a parallel implementation of something
vaguely similar.

Signed-off-by: Simon McVittie <smcv@collabora.com>
  • Loading branch information
smcv committed Nov 12, 2020
1 parent 8db3171 commit fdd945f
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 7 deletions.
2 changes: 1 addition & 1 deletion src/core/linux/SDL_evdev_capabilities.c
Expand Up @@ -22,7 +22,7 @@

#include "SDL_evdev_capabilities.h"

#if HAVE_LIBUDEV_H
#if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)

extern int
SDL_EVDEV_GuessDeviceClass(unsigned long bitmask_ev[NBITS(EV_MAX)],
Expand Down
4 changes: 2 additions & 2 deletions src/core/linux/SDL_evdev_capabilities.h
Expand Up @@ -25,7 +25,7 @@
#ifndef SDL_evdev_capabilities_h_
#define SDL_evdev_capabilities_h_

#if HAVE_LIBUDEV_H
#if HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX)

#include <linux/input.h>

Expand All @@ -51,7 +51,7 @@ extern int SDL_EVDEV_GuessDeviceClass(unsigned long bitmask_ev[NBITS(EV_MAX)],
unsigned long bitmask_key[NBITS(KEY_MAX)],
unsigned long bitmask_rel[NBITS(REL_MAX)]);

#endif /* HAVE_LIBUDEV_H */
#endif /* HAVE_LIBUDEV_H || defined(SDL_JOYSTICK_LINUX) */

#endif /* SDL_evdev_capabilities_h_ */

Expand Down
12 changes: 8 additions & 4 deletions src/joystick/linux/SDL_sysjoystick.c
Expand Up @@ -160,19 +160,23 @@ GuessIsJoystick(int fd)
unsigned long evbit[NBITS(EV_MAX)] = { 0 };
unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
unsigned long relbit[NBITS(REL_MAX)] = { 0 };
int devclass;

if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
(ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
(ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) < 0) ||
(ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
return (0);
}

if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
return 0;
devclass = SDL_EVDEV_GuessDeviceClass(evbit, absbit, keybit, relbit);

if (devclass & SDL_UDEV_DEVICE_JOYSTICK) {
return 1;
}

return 1;
return 0;
}

static int
Expand Down

0 comments on commit fdd945f

Please sign in to comment.