| | |
| | | /* |
| | | Simple DirectMedia Layer |
| | | Copyright (C) 1997-2018 Sam Lantinga <slouken@libsdl.org> |
| | | Copyright (C) 1997-2020 Sam Lantinga <slouken@libsdl.org> |
| | | |
| | | This software is provided 'as-is', without any express or implied |
| | | warranty. In no event will the authors be held liable for any damages |
| | |
| | | #include <linux/input.h> |
| | | |
| | | #include "SDL_assert.h" |
| | | #include "SDL_evdev_capabilities.h" |
| | | #include "SDL_loadso.h" |
| | | #include "SDL_timer.h" |
| | | #include "SDL_hints.h" |
| | | #include "../unix/SDL_poll.h" |
| | | |
| | | static const char *SDL_UDEV_LIBS[] = { "libudev.so.1", "libudev.so.0" }; |
| | |
| | | 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 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; |
| | |
| | | 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 */ |
| | |
| | | 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)) { |
| | | /* TODO: better determining between touchscreen and multitouch touchpad, |
| | | see https://github.com/systemd/systemd/blob/master/src/udev/udev-builtin-input_id.c */ |
| | | devclass |= SDL_UDEV_DEVICE_TOUCHSCREEN; /* ID_INPUT_TOUCHSCREEN */ |
| | | } |
| | | |
| | | 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 any of |
| | | * those, consider it a keyboard device; do not test KEY_RESERVED, though */ |
| | | keyboard_mask = 0xFFFFFFFE; |
| | | if ((bitmask_key[0] & keyboard_mask) != 0) |
| | | devclass |= SDL_UDEV_DEVICE_KEYBOARD; /* ID_INPUT_KEYBOARD */ |
| | | |
| | | return devclass; |
| | | return SDL_EVDEV_GuessDeviceClass(&bitmask_ev[0], |
| | | &bitmask_abs[0], |
| | | &bitmask_key[0], |
| | | &bitmask_rel[0]); |
| | | } |
| | | |
| | | static void |
| | |
| | | if (val != NULL && SDL_strcmp(val, "1") == 0 ) { |
| | | devclass |= SDL_UDEV_DEVICE_JOYSTICK; |
| | | } |
| | | |
| | | val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_ACCELEROMETER"); |
| | | if (SDL_GetHintBoolean(SDL_HINT_ACCELEROMETER_AS_JOYSTICK, SDL_TRUE) && |
| | | val != NULL && SDL_strcmp(val, "1") == 0 ) { |
| | | devclass |= SDL_UDEV_DEVICE_JOYSTICK; |
| | | } |
| | | |
| | | val = _this->syms.udev_device_get_property_value(dev, "ID_INPUT_MOUSE"); |
| | | if (val != NULL && SDL_strcmp(val, "1") == 0 ) { |