| | |
| | | /* |
| | | 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 <limits.h> /* For the definition of PATH_MAX */ |
| | | #include <sys/ioctl.h> |
| | | #include <unistd.h> |
| | | #include <dirent.h> |
| | | #include <linux/joystick.h> |
| | | |
| | | #include "SDL_assert.h" |
| | | #include "SDL_joystick.h" |
| | | #include "SDL_endian.h" |
| | | #include "SDL_timer.h" |
| | | #include "../../events/SDL_events_c.h" |
| | | #include "../SDL_sysjoystick.h" |
| | | #include "../SDL_joystick_c.h" |
| | |
| | | static int MaybeAddDevice(const char *path); |
| | | #if SDL_USE_LIBUDEV |
| | | static int MaybeRemoveDevice(const char *path); |
| | | static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath); |
| | | #endif /* SDL_USE_LIBUDEV */ |
| | | |
| | | |
| | | /* A linked list of available joysticks */ |
| | | typedef struct SDL_joylist_item |
| | |
| | | static SDL_joylist_item *SDL_joylist_tail = NULL; |
| | | static int numjoysticks = 0; |
| | | |
| | | #if !SDL_USE_LIBUDEV |
| | | static Uint32 last_joy_detect_time; |
| | | static time_t last_input_dir_mtime; |
| | | #endif |
| | | |
| | | #define test_bit(nr, addr) \ |
| | | (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0) |
| | | #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1) |
| | | |
| | | static int |
| | | PrefixMatch(const char *a, const char *b) |
| | | { |
| | | int matchlen = 0; |
| | | while (*a && *b) { |
| | | if (*a++ == *b++) { |
| | | ++matchlen; |
| | | } else { |
| | | break; |
| | | } |
| | | } |
| | | return matchlen; |
| | | } |
| | | |
| | | static void |
| | | FixupDeviceInfoForMapping(int fd, struct input_id *inpid) |
| | | { |
| | | if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) { |
| | | /* This is a Microsoft Xbox One Elite Series 2 controller */ |
| | | unsigned long keybit[NBITS(KEY_MAX)] = { 0 }; |
| | | |
| | | /* The first version of the firmware duplicated all the inputs */ |
| | | if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) && |
| | | test_bit(0x2c0, keybit)) { |
| | | /* Change the version to 0x0902, so we can map it differently */ |
| | | inpid->version = 0x0902; |
| | | } |
| | | } |
| | | } |
| | | |
| | | |
| | | static int |
| | | IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid) |
| | | { |
| | | /* This list is taken from: |
| | | https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py |
| | | */ |
| | | static Uint32 joystick_blacklist[] = { |
| | | /* Microsoft Microsoft Wireless Optical Desktop® 2.10 */ |
| | | /* Microsoft Wireless Desktop - Comfort Edition */ |
| | | MAKE_VIDPID(0x045e, 0x009d), |
| | | |
| | | /* Microsoft Microsoft® Digital Media Pro Keyboard */ |
| | | /* Microsoft Corp. Digital Media Pro Keyboard */ |
| | | MAKE_VIDPID(0x045e, 0x00b0), |
| | | |
| | | /* Microsoft Microsoft® Digital Media Keyboard */ |
| | | /* Microsoft Corp. Digital Media Keyboard 1.0A */ |
| | | MAKE_VIDPID(0x045e, 0x00b4), |
| | | |
| | | /* Microsoft Microsoft® Digital Media Keyboard 3000 */ |
| | | MAKE_VIDPID(0x045e, 0x0730), |
| | | |
| | | /* Microsoft Microsoft® 2.4GHz Transceiver v6.0 */ |
| | | /* Microsoft Microsoft® 2.4GHz Transceiver v8.0 */ |
| | | /* Microsoft Corp. Nano Transceiver v1.0 for Bluetooth */ |
| | | /* Microsoft Wireless Mobile Mouse 1000 */ |
| | | /* Microsoft Wireless Desktop 3000 */ |
| | | MAKE_VIDPID(0x045e, 0x0745), |
| | | |
| | | /* Microsoft® SideWinder(TM) 2.4GHz Transceiver */ |
| | | MAKE_VIDPID(0x045e, 0x0748), |
| | | |
| | | /* Microsoft Corp. Wired Keyboard 600 */ |
| | | MAKE_VIDPID(0x045e, 0x0750), |
| | | |
| | | /* Microsoft Corp. Sidewinder X4 keyboard */ |
| | | MAKE_VIDPID(0x045e, 0x0768), |
| | | |
| | | /* Microsoft Corp. Arc Touch Mouse Transceiver */ |
| | | MAKE_VIDPID(0x045e, 0x0773), |
| | | |
| | | /* Microsoft® 2.4GHz Transceiver v9.0 */ |
| | | /* Microsoft® Nano Transceiver v2.1 */ |
| | | /* Microsoft Sculpt Ergonomic Keyboard (5KV-00001) */ |
| | | MAKE_VIDPID(0x045e, 0x07a5), |
| | | |
| | | /* Microsoft® Nano Transceiver v1.0 */ |
| | | /* Microsoft Wireless Keyboard 800 */ |
| | | MAKE_VIDPID(0x045e, 0x07b2), |
| | | |
| | | /* Microsoft® Nano Transceiver v2.0 */ |
| | | MAKE_VIDPID(0x045e, 0x0800), |
| | | |
| | | /* List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs */ |
| | | MAKE_VIDPID(0x056a, 0x0010), /* Wacom ET-0405 Graphire */ |
| | | MAKE_VIDPID(0x056a, 0x0011), /* Wacom ET-0405A Graphire2 (4x5) */ |
| | | MAKE_VIDPID(0x056a, 0x0012), /* Wacom ET-0507A Graphire2 (5x7) */ |
| | | MAKE_VIDPID(0x056a, 0x0013), /* Wacom CTE-430 Graphire3 (4x5) */ |
| | | MAKE_VIDPID(0x056a, 0x0014), /* Wacom CTE-630 Graphire3 (6x8) */ |
| | | MAKE_VIDPID(0x056a, 0x0015), /* Wacom CTE-440 Graphire4 (4x5) */ |
| | | MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire4 (6x8) */ |
| | | MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun (4x5) */ |
| | | MAKE_VIDPID(0x056a, 0x0016), /* Wacom CTE-640 Graphire 4 6x8 */ |
| | | MAKE_VIDPID(0x056a, 0x0017), /* Wacom CTE-450 Bamboo Fun 4x5 */ |
| | | MAKE_VIDPID(0x056a, 0x0018), /* Wacom CTE-650 Bamboo Fun 6x8 */ |
| | | MAKE_VIDPID(0x056a, 0x0019), /* Wacom CTE-631 Bamboo One */ |
| | | MAKE_VIDPID(0x056a, 0x00d1), /* Wacom Bamboo Pen and Touch CTH-460 */ |
| | | |
| | | MAKE_VIDPID(0x09da, 0x054f), /* A4 Tech Co., G7 750 mouse */ |
| | | MAKE_VIDPID(0x09da, 0x3043), /* A4 Tech Co., Ltd Bloody R8A Gaming Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x31b5), /* A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x3997), /* A4 Tech Co., Ltd Bloody RT7 Terminator Wireless */ |
| | | MAKE_VIDPID(0x09da, 0x3f8b), /* A4 Tech Co., Ltd Bloody V8 mouse */ |
| | | MAKE_VIDPID(0x09da, 0x51f4), /* Modecom MC-5006 Keyboard */ |
| | | MAKE_VIDPID(0x09da, 0x5589), /* A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x7b22), /* A4 Tech Co., Ltd Bloody V5 */ |
| | | MAKE_VIDPID(0x09da, 0x7f2d), /* A4 Tech Co., Ltd Bloody R3 mouse */ |
| | | MAKE_VIDPID(0x09da, 0x8090), /* A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x9066), /* A4 Tech Co., Sharkoon Fireglider Optical */ |
| | | MAKE_VIDPID(0x09da, 0x9090), /* A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse */ |
| | | MAKE_VIDPID(0x09da, 0x90c0), /* A4 Tech Co., Ltd X7 G800V keyboard */ |
| | | MAKE_VIDPID(0x09da, 0xf012), /* A4 Tech Co., Ltd Bloody V7 mouse */ |
| | | MAKE_VIDPID(0x09da, 0xf32a), /* A4 Tech Co., Ltd Bloody B540 keyboard */ |
| | | MAKE_VIDPID(0x09da, 0xf613), /* A4 Tech Co., Ltd Bloody V2 mouse */ |
| | | MAKE_VIDPID(0x09da, 0xf624), /* A4 Tech Co., Ltd Bloody B120 Keyboard */ |
| | | |
| | | MAKE_VIDPID(0x1d57, 0xad03), /* [T3] 2.4GHz and IR Air Mouse Remote Control */ |
| | | |
| | | MAKE_VIDPID(0x1e7d, 0x2e4a), /* Roccat Tyon Mouse */ |
| | | |
| | | MAKE_VIDPID(0x20a0, 0x422d), /* Winkeyless.kr Keyboards */ |
| | | |
| | | MAKE_VIDPID(0x2516, 0x001f), /* Cooler Master Storm Mizar Mouse */ |
| | | MAKE_VIDPID(0x2516, 0x0028), /* Cooler Master Storm Alcor Mouse */ |
| | | }; |
| | | struct input_id inpid; |
| | | int i; |
| | | Uint32 id; |
| | | Uint16 *guid16 = (Uint16 *)guid->data; |
| | | const char *name; |
| | | const char *spot; |
| | | |
| | | #if !SDL_USE_LIBUDEV |
| | | /* When udev is enabled we only get joystick devices here, so there's no need to test them */ |
| | |
| | | } |
| | | #endif |
| | | |
| | | if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) { |
| | | return 0; |
| | | } |
| | | |
| | | if (ioctl(fd, EVIOCGID, &inpid) < 0) { |
| | | return 0; |
| | | } |
| | | |
| | | name = SDL_GetCustomJoystickName(inpid.vendor, inpid.product); |
| | | if (name) { |
| | | SDL_strlcpy(namebuf, name, namebuflen); |
| | | } else { |
| | | if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) { |
| | | return 0; |
| | | } |
| | | |
| | | /* Remove duplicate manufacturer in the name */ |
| | | for (spot = namebuf + 1; *spot; ++spot) { |
| | | int matchlen = PrefixMatch(namebuf, spot); |
| | | if (matchlen > 0 && spot[matchlen - 1] == ' ') { |
| | | SDL_memmove(namebuf, spot, SDL_strlen(spot)+1); |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | #ifdef SDL_JOYSTICK_HIDAPI |
| | | if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version)) { |
| | | if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, namebuf)) { |
| | | /* The HIDAPI driver is taking care of this device */ |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | | /* Check the joystick blacklist */ |
| | | id = MAKE_VIDPID(inpid.vendor, inpid.product); |
| | | for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) { |
| | | if (id == joystick_blacklist[i]) { |
| | | return 0; |
| | | } |
| | | } |
| | | FixupDeviceInfoForMapping(fd, &inpid); |
| | | |
| | | #ifdef DEBUG_JOYSTICK |
| | | printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version); |
| | |
| | | } |
| | | #endif /* SDL_USE_LIBUDEV */ |
| | | |
| | | |
| | | /* !!! FIXME: I would love to dump this code and use libudev instead. */ |
| | | static int |
| | | MaybeAddDevice(const char *path) |
| | | { |
| | |
| | | } |
| | | |
| | | #if SDL_USE_LIBUDEV |
| | | /* !!! FIXME: I would love to dump this code and use libudev instead. */ |
| | | static int |
| | | MaybeRemoveDevice(const char *path) |
| | | { |
| | |
| | | } |
| | | #endif |
| | | |
| | | #if ! SDL_USE_LIBUDEV |
| | | static int |
| | | JoystickInitWithoutUdev(void) |
| | | static void |
| | | HandlePendingRemovals(void) |
| | | { |
| | | int i; |
| | | char path[PATH_MAX]; |
| | | SDL_joylist_item *prev = NULL; |
| | | SDL_joylist_item *item = SDL_joylist; |
| | | |
| | | /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */ |
| | | /* !!! FIXME: we could at least readdir() through /dev/input...? */ |
| | | /* !!! FIXME: (or delete this and rely on libudev?) */ |
| | | for (i = 0; i < 32; i++) { |
| | | SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i); |
| | | MaybeAddDevice(path); |
| | | while (item != NULL) { |
| | | if (item->hwdata && item->hwdata->gone) { |
| | | item->hwdata->item = NULL; |
| | | |
| | | if (prev != NULL) { |
| | | prev->next = item->next; |
| | | } else { |
| | | SDL_assert(SDL_joylist == item); |
| | | SDL_joylist = item->next; |
| | | } |
| | | if (item == SDL_joylist_tail) { |
| | | SDL_joylist_tail = prev; |
| | | } |
| | | |
| | | /* Need to decrement the joystick count before we post the event */ |
| | | --numjoysticks; |
| | | |
| | | SDL_PrivateJoystickRemoved(item->device_instance); |
| | | |
| | | SDL_free(item->path); |
| | | SDL_free(item->name); |
| | | SDL_free(item); |
| | | |
| | | if (prev != NULL) { |
| | | item = prev->next; |
| | | } else { |
| | | item = SDL_joylist; |
| | | } |
| | | } else { |
| | | prev = item; |
| | | item = item->next; |
| | | } |
| | | } |
| | | |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | | #if SDL_USE_LIBUDEV |
| | | static int |
| | | JoystickInitWithUdev(void) |
| | | { |
| | | if (SDL_UDEV_Init() < 0) { |
| | | return SDL_SetError("Could not initialize UDEV"); |
| | | } |
| | | |
| | | /* Set up the udev callback */ |
| | | if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) { |
| | | SDL_UDEV_Quit(); |
| | | return SDL_SetError("Could not set up joystick <-> udev callback"); |
| | | } |
| | | |
| | | /* Force a scan to build the initial device list */ |
| | | SDL_UDEV_Scan(); |
| | | |
| | | return 0; |
| | | } |
| | | #endif |
| | | |
| | | static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance) |
| | | { |
| | |
| | | } |
| | | } |
| | | |
| | | static void |
| | | LINUX_JoystickDetect(void) |
| | | { |
| | | #if SDL_USE_LIBUDEV |
| | | SDL_UDEV_Poll(); |
| | | #else |
| | | const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */ |
| | | Uint32 now = SDL_GetTicks(); |
| | | |
| | | if (!last_joy_detect_time || SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) { |
| | | struct stat sb; |
| | | |
| | | /* Opening input devices can generate synchronous device I/O, so avoid it if we can */ |
| | | if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) { |
| | | DIR *folder; |
| | | struct dirent *dent; |
| | | |
| | | folder = opendir("/dev/input"); |
| | | if (folder) { |
| | | while ((dent = readdir(folder))) { |
| | | int len = SDL_strlen(dent->d_name); |
| | | if (len > 5 && SDL_strncmp(dent->d_name, "event", 5) == 0) { |
| | | char path[PATH_MAX]; |
| | | SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", dent->d_name); |
| | | MaybeAddDevice(path); |
| | | } |
| | | } |
| | | |
| | | closedir(folder); |
| | | } |
| | | |
| | | last_input_dir_mtime = sb.st_mtime; |
| | | } |
| | | |
| | | last_joy_detect_time = now; |
| | | } |
| | | #endif |
| | | |
| | | HandlePendingRemovals(); |
| | | |
| | | SDL_UpdateSteamControllers(); |
| | | } |
| | | |
| | | static int |
| | | LINUX_JoystickInit(void) |
| | | { |
| | |
| | | SteamControllerDisconnectedCallback); |
| | | |
| | | #if SDL_USE_LIBUDEV |
| | | return JoystickInitWithUdev(); |
| | | #else |
| | | return JoystickInitWithoutUdev(); |
| | | if (SDL_UDEV_Init() < 0) { |
| | | return SDL_SetError("Could not initialize UDEV"); |
| | | } |
| | | |
| | | /* Set up the udev callback */ |
| | | if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) { |
| | | SDL_UDEV_Quit(); |
| | | return SDL_SetError("Could not set up joystick <-> udev callback"); |
| | | } |
| | | |
| | | /* Force a scan to build the initial device list */ |
| | | SDL_UDEV_Scan(); |
| | | #else |
| | | /* Force immediate joystick detection */ |
| | | last_joy_detect_time = 0; |
| | | last_input_dir_mtime = 0; |
| | | |
| | | /* Report all devices currently present */ |
| | | LINUX_JoystickDetect(); |
| | | #endif |
| | | |
| | | return 0; |
| | | } |
| | | |
| | | static int |
| | | LINUX_JoystickGetCount(void) |
| | | { |
| | | return numjoysticks; |
| | | } |
| | | |
| | | static void |
| | | LINUX_JoystickDetect(void) |
| | | { |
| | | #if SDL_USE_LIBUDEV |
| | | SDL_UDEV_Poll(); |
| | | #endif |
| | | |
| | | SDL_UpdateSteamControllers(); |
| | | } |
| | | |
| | | static SDL_joylist_item * |
| | |
| | | LINUX_JoystickGetDevicePlayerIndex(int device_index) |
| | | { |
| | | return -1; |
| | | } |
| | | |
| | | static void |
| | | LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index) |
| | | { |
| | | } |
| | | |
| | | static SDL_JoystickGUID |
| | |
| | | for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) { |
| | | if (test_bit(i, absbit) || test_bit(i + 1, absbit)) { |
| | | struct input_absinfo absinfo; |
| | | int hat_index = (i - ABS_HAT0X) / 2; |
| | | |
| | | if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) { |
| | | continue; |
| | | } |
| | | #ifdef DEBUG_INPUT_EVENTS |
| | | printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2); |
| | | printf("Joystick has hat %d\n", hat_index); |
| | | printf("Values = { %d, %d, %d, %d, %d }\n", |
| | | absinfo.value, absinfo.minimum, absinfo.maximum, |
| | | absinfo.fuzz, absinfo.flat); |
| | | #endif /* DEBUG_INPUT_EVENTS */ |
| | | ++joystick->nhats; |
| | | joystick->hwdata->hats_indices[hat_index] = joystick->nhats++; |
| | | } |
| | | } |
| | | if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) { |
| | |
| | | joystick->hwdata->guid = item->guid; |
| | | joystick->hwdata->effect.id = -1; |
| | | joystick->hwdata->m_bSteamController = item->m_bSteamController; |
| | | SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map)); |
| | | |
| | | if (item->m_bSteamController) { |
| | | joystick->hwdata->fd = -1; |
| | |
| | | } |
| | | |
| | | static int |
| | | LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms) |
| | | LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble) |
| | | { |
| | | struct input_event event; |
| | | |
| | |
| | | struct ff_effect *effect = &joystick->hwdata->effect; |
| | | |
| | | effect->type = FF_RUMBLE; |
| | | effect->replay.length = SDL_min(duration_ms, 32767); |
| | | effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS; |
| | | effect->u.rumble.strong_magnitude = low_frequency_rumble; |
| | | effect->u.rumble.weak_magnitude = high_frequency_rumble; |
| | | } else if (joystick->hwdata->ff_sine) { |
| | |
| | | struct ff_effect *effect = &joystick->hwdata->effect; |
| | | |
| | | effect->type = FF_PERIODIC; |
| | | effect->replay.length = SDL_min(duration_ms, 32767); |
| | | effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS; |
| | | effect->u.periodic.waveform = FF_SINE; |
| | | effect->u.periodic.magnitude = magnitude; |
| | | } else { |
| | |
| | | } |
| | | |
| | | if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) { |
| | | return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno)); |
| | | /* The kernel may have lost this effect, try to allocate a new one */ |
| | | joystick->hwdata->effect.id = -1; |
| | | if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) { |
| | | return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno)); |
| | | } |
| | | } |
| | | |
| | | event.type = EV_FF; |
| | |
| | | if (value != the_hat->axis[axis]) { |
| | | the_hat->axis[axis] = value; |
| | | SDL_PrivateJoystickHat(stick, hat, |
| | | position_map[the_hat-> |
| | | axis[1]][the_hat->axis[0]]); |
| | | position_map[the_hat->axis[1]][the_hat->axis[0]]); |
| | | } |
| | | } |
| | | |
| | |
| | | PollAllValues(SDL_Joystick * joystick) |
| | | { |
| | | struct input_absinfo absinfo; |
| | | int a, b = 0; |
| | | int i; |
| | | |
| | | /* Poll all axis */ |
| | | for (a = ABS_X; b < ABS_MAX; a++) { |
| | | switch (a) { |
| | | case ABS_HAT0X: |
| | | case ABS_HAT0Y: |
| | | case ABS_HAT1X: |
| | | case ABS_HAT1Y: |
| | | case ABS_HAT2X: |
| | | case ABS_HAT2Y: |
| | | case ABS_HAT3X: |
| | | case ABS_HAT3Y: |
| | | /* ingore hats */ |
| | | break; |
| | | default: |
| | | if (joystick->hwdata->abs_correct[b].used) { |
| | | if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) { |
| | | absinfo.value = AxisCorrect(joystick, b, absinfo.value); |
| | | for (i = ABS_X; i < ABS_MAX; i++) { |
| | | if (i == ABS_HAT0X) { |
| | | i = ABS_HAT3Y; |
| | | continue; |
| | | } |
| | | if (joystick->hwdata->abs_correct[i].used) { |
| | | if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) { |
| | | absinfo.value = AxisCorrect(joystick, i, absinfo.value); |
| | | |
| | | #ifdef DEBUG_INPUT_EVENTS |
| | | printf("Joystick : Re-read Axis %d (%d) val= %d\n", |
| | | joystick->hwdata->abs_map[b], a, absinfo.value); |
| | | printf("Joystick : Re-read Axis %d (%d) val= %d\n", |
| | | joystick->hwdata->abs_map[i], i, absinfo.value); |
| | | #endif |
| | | SDL_PrivateJoystickAxis(joystick, |
| | | joystick->hwdata->abs_map[b], |
| | | absinfo.value); |
| | | } |
| | | SDL_PrivateJoystickAxis(joystick, |
| | | joystick->hwdata->abs_map[i], |
| | | absinfo.value); |
| | | } |
| | | b++; |
| | | } |
| | | } |
| | | } |
| | |
| | | case ABS_HAT3X: |
| | | case ABS_HAT3Y: |
| | | code -= ABS_HAT0X; |
| | | HandleHat(joystick, code / 2, code % 2, events[i].value); |
| | | HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value); |
| | | break; |
| | | default: |
| | | events[i].value = |
| | | AxisCorrect(joystick, code, events[i].value); |
| | | SDL_PrivateJoystickAxis(joystick, |
| | | joystick->hwdata->abs_map[code], |
| | | events[i].value); |
| | | if (joystick->hwdata->abs_map[code] != 0xFF) { |
| | | events[i].value = |
| | | AxisCorrect(joystick, code, events[i].value); |
| | | SDL_PrivateJoystickAxis(joystick, |
| | | joystick->hwdata->abs_map[code], |
| | | events[i].value); |
| | | } |
| | | break; |
| | | } |
| | | break; |
| | |
| | | break; |
| | | } |
| | | } |
| | | } |
| | | |
| | | if (errno == ENODEV) { |
| | | /* We have to wait until the JoystickDetect callback to remove this */ |
| | | joystick->hwdata->gone = SDL_TRUE; |
| | | } |
| | | } |
| | | |
| | |
| | | LINUX_JoystickDetect, |
| | | LINUX_JoystickGetDeviceName, |
| | | LINUX_JoystickGetDevicePlayerIndex, |
| | | LINUX_JoystickSetDevicePlayerIndex, |
| | | LINUX_JoystickGetDeviceGUID, |
| | | LINUX_JoystickGetDeviceInstanceID, |
| | | LINUX_JoystickOpen, |