|
@@ -25,18 +25,19 @@ |
|
|
* udevadm info --query=all -n input/event3 (for a keyboard, mouse, etc) |
|
|
* udevadm info --query=property -n input/event2 |
|
|
*/ |
|
|
|
|
|
#include "SDL_udev.h" |
|
|
|
|
|
#ifdef SDL_USE_LIBUDEV |
|
|
|
|
|
#include <linux/input.h> |
|
|
|
|
|
#include "SDL.h" |
|
|
|
|
|
static char* SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" }; |
|
|
|
|
|
#define _THIS SDL_UDEV_PrivateData *_this |
|
|
static _THIS = NULL; |
|
|
|
|
|
#include "SDL.h" |
|
|
|
|
|
static SDL_bool SDL_UDEV_load_sym(const char *fn, void **addr); |
|
|
static int SDL_UDEV_load_syms(void); |
|
|
static SDL_bool SDL_UDEV_hotplug_update_available(void); |
|
@@ -64,7 +65,9 @@ SDL_UDEV_load_syms(void) |
|
|
SDL_UDEV_SYM(udev_device_get_action); |
|
|
SDL_UDEV_SYM(udev_device_get_devnode); |
|
|
SDL_UDEV_SYM(udev_device_get_subsystem); |
|
|
SDL_UDEV_SYM(udev_device_get_parent_with_subsystem_devtype); |
|
|
SDL_UDEV_SYM(udev_device_get_property_value); |
|
|
SDL_UDEV_SYM(udev_device_get_sysattr_value); |
|
|
SDL_UDEV_SYM(udev_device_new_from_syspath); |
|
|
SDL_UDEV_SYM(udev_device_unref); |
|
|
SDL_UDEV_SYM(udev_enumerate_add_match_property); |
|
@@ -274,6 +277,109 @@ SDL_UDEV_LoadLibrary(void) |
|
|
return retval; |
|
|
} |
|
|
|
|
|
#define BITS_PER_LONG (sizeof(unsigned long) * 8) |
|
|
#define NBITS(x) ((((x)-1)/BITS_PER_LONG)+1) |
|
|
#define OFF(x) ((x)%BITS_PER_LONG) |
|
|
#define BIT(x) (1UL<<OFF(x)) |
|
|
#define LONG(x) ((x)/BITS_PER_LONG) |
|
|
#define test_bit(bit, array) ((array[LONG(bit)] >> OFF(bit)) & 1) |
|
|
|
|
|
static void get_caps(struct udev_device *dev, struct udev_device *pdev, const char *attr, unsigned long *bitmask, size_t bitmask_len) |
|
|
{ |
|
|
const char *value; |
|
|
char text[4096]; |
|
|
char *word; |
|
|
int i; |
|
|
unsigned long v; |
|
|
|
|
|
SDL_memset(bitmask, 0, bitmask_len*sizeof(*bitmask)); |
|
|
value = _this->udev_device_get_sysattr_value(pdev, attr); |
|
|
if (!value) { |
|
|
return; |
|
|
} |
|
|
|
|
|
SDL_strlcpy(text, value, sizeof(text)); |
|
|
i = 0; |
|
|
while ((word = SDL_strrchr(text, ' ')) != NULL) { |
|
|
v = SDL_strtoul(word+1, NULL, 16); |
|
|
if (i < bitmask_len) { |
|
|
bitmask[i] = v; |
|
|
} |
|
|
++i; |
|
|
*word = '\0'; |
|
|
} |
|
|
v = SDL_strtoul(text, NULL, 16); |
|
|
if (i < bitmask_len) { |
|
|
bitmask[i] = v; |
|
|
} |
|
|
} |
|
|
|
|
|
static int |
|
|
guess_device_class(struct udev_device *dev) |
|
|
{ |
|
|
int devclass = 0; |
|
|
struct udev_device *pdev; |
|
|
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)]; |
|
|
unsigned long keyboard_mask; |
|
|
|
|
|
/* walk up the parental chain until we find the real input device; the |
|
|
* argument is very likely a subdevice of this, like eventN */ |
|
|
pdev = dev; |
|
|
while (pdev && !_this->udev_device_get_sysattr_value(pdev, "capabilities/ev")) { |
|
|
pdev = _this->udev_device_get_parent_with_subsystem_devtype(pdev, "input", NULL); |
|
|
} |
|
|
if (!pdev) { |
|
|
return 0; |
|
|
} |
|
|
|
|
|
get_caps(dev, pdev, "capabilities/ev", bitmask_ev, SDL_arraysize(bitmask_ev)); |
|
|
get_caps(dev, pdev, "capabilities/abs", bitmask_abs, SDL_arraysize(bitmask_abs)); |
|
|
get_caps(dev, pdev, "capabilities/rel", bitmask_rel, SDL_arraysize(bitmask_rel)); |
|
|
get_caps(dev, pdev, "capabilities/key", bitmask_key, SDL_arraysize(bitmask_key)); |
|
|
|
|
|
if (test_bit(EV_ABS, bitmask_ev) && |
|
|
test_bit(ABS_X, bitmask_abs) && test_bit(ABS_Y, bitmask_abs)) { |
|
|
if (test_bit(BTN_STYLUS, bitmask_key) || test_bit(BTN_TOOL_PEN, bitmask_key)) { |
|
|
; /* ID_INPUT_TABLET */ |
|
|
} else if (test_bit(BTN_TOOL_FINGER, bitmask_key) && !test_bit(BTN_TOOL_PEN, bitmask_key)) { |
|
|
; /* ID_INPUT_TOUCHPAD */ |
|
|
} else if (test_bit(BTN_MOUSE, bitmask_key)) { |
|
|
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */ |
|
|
} else if (test_bit(BTN_TOUCH, bitmask_key)) { |
|
|
; /* ID_INPUT_TOUCHSCREEN */ |
|
|
} else if (test_bit(BTN_TRIGGER, bitmask_key) || |
|
|
test_bit(BTN_A, bitmask_key) || |
|
|
test_bit(BTN_1, bitmask_key) || |
|
|
test_bit(ABS_RX, bitmask_abs) || |
|
|
test_bit(ABS_RY, bitmask_abs) || |
|
|
test_bit(ABS_RZ, bitmask_abs) || |
|
|
test_bit(ABS_THROTTLE, bitmask_abs) || |
|
|
test_bit(ABS_RUDDER, bitmask_abs) || |
|
|
test_bit(ABS_WHEEL, bitmask_abs) || |
|
|
test_bit(ABS_GAS, bitmask_abs) || |
|
|
test_bit(ABS_BRAKE, bitmask_abs)) { |
|
|
devclass |= SDL_UDEV_DEVICE_JOYSTICK; /* ID_INPUT_JOYSTICK */ |
|
|
} |
|
|
} |
|
|
|
|
|
if (test_bit(EV_REL, bitmask_ev) && |
|
|
test_bit(REL_X, bitmask_rel) && test_bit(REL_Y, bitmask_rel) && |
|
|
test_bit(BTN_MOUSE, bitmask_key)) { |
|
|
devclass |= SDL_UDEV_DEVICE_MOUSE; /* ID_INPUT_MOUSE */ |
|
|
} |
|
|
|
|
|
/* the first 32 bits are ESC, numbers, and Q to D; if we have all of |
|
|
* those, consider it a full keyboard; do not test KEY_RESERVED, though */ |
|
|
keyboard_mask = 0xFFFFFFFE; |
|
|
if ((bitmask_key[0] & keyboard_mask) == keyboard_mask) |
|
|
devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEYBOARD */ |
|
|
|
|
|
return devclass; |
|
|
} |
|
|
|
|
|
static void |
|
|
device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) |
|
|
{ |
|
@@ -308,7 +414,7 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) |
|
|
} |
|
|
|
|
|
if (devclass == 0) { |
|
|
// Fall back to old style input classes |
|
|
/* Fall back to old style input classes */ |
|
|
val = _this->udev_device_get_property_value(dev, "ID_CLASS"); |
|
|
if (val != NULL) { |
|
|
if (SDL_strcmp(val, "joystick") == 0) { |
|
@@ -321,7 +427,8 @@ device_event(SDL_UDEV_deviceevent type, struct udev_device *dev) |
|
|
return; |
|
|
} |
|
|
} else { |
|
|
return; |
|
|
/* We could be linked with libudev on a system that doesn't have udev running */ |
|
|
devclass = guess_device_class(dev); |
|
|
} |
|
|
} |
|
|
} else { |
|
|