From 03f8528315fa46c95991a34f3325d7b33ae5538c Mon Sep 17 00:00:00 2001
From: Edward Rudd <urkle@outoforder.cc>
Date: Sat, 02 May 2020 21:48:36 +0000
Subject: [PATCH] Update source to SDL2 2.0.12

---
 source/src/joystick/linux/SDL_sysjoystick.c |  404 +++++++++++++++++++++++++++++----------------------------
 1 files changed, 206 insertions(+), 198 deletions(-)

diff --git a/source/src/joystick/linux/SDL_sysjoystick.c b/source/src/joystick/linux/SDL_sysjoystick.c
index 06a2d9a..fcfc0f3 100644
--- a/source/src/joystick/linux/SDL_sysjoystick.c
+++ b/source/src/joystick/linux/SDL_sysjoystick.c
@@ -1,6 +1,6 @@
 /*
   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
@@ -34,11 +34,13 @@
 #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"
@@ -56,9 +58,7 @@
 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
@@ -79,110 +79,53 @@
 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 */
@@ -202,28 +145,36 @@
     }
 #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);
@@ -279,8 +230,6 @@
 }
 #endif /* SDL_USE_LIBUDEV */
 
-
-/* !!! FIXME: I would love to dump this code and use libudev instead. */
 static int
 MaybeAddDevice(const char *path)
 {
@@ -356,7 +305,6 @@
 }
 
 #if SDL_USE_LIBUDEV
-/* !!! FIXME: I would love to dump this code and use libudev instead. */
 static int
 MaybeRemoveDevice(const char *path)
 {
@@ -401,45 +349,46 @@
 }
 #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)
 {
@@ -512,6 +461,49 @@
     }
 }
 
+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)
 {
@@ -535,26 +527,34 @@
                              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 *
@@ -586,6 +586,11 @@
 LINUX_JoystickGetDevicePlayerIndex(int device_index)
 {
     return -1;
+}
+
+static void
+LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
+{
 }
 
 static SDL_JoystickGUID
@@ -711,17 +716,18 @@
         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)) {
@@ -776,6 +782,7 @@
     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;
@@ -816,7 +823,7 @@
 }
 
 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;
 
@@ -824,7 +831,7 @@
         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) {
@@ -833,7 +840,7 @@
         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 {
@@ -841,7 +848,11 @@
     }
 
     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;
@@ -874,8 +885,7 @@
     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]]);
     }
 }
 
@@ -919,36 +929,26 @@
 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++;
         }
     }
 }
@@ -986,14 +986,16 @@
                 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;
@@ -1023,6 +1025,11 @@
                 break;
             }
         }
+    }
+
+    if (errno == ENODEV) {
+        /* We have to wait until the JoystickDetect callback to remove this */
+        joystick->hwdata->gone = SDL_TRUE;
     }
 }
 
@@ -1107,6 +1114,7 @@
     LINUX_JoystickDetect,
     LINUX_JoystickGetDeviceName,
     LINUX_JoystickGetDevicePlayerIndex,
+    LINUX_JoystickSetDevicePlayerIndex,
     LINUX_JoystickGetDeviceGUID,
     LINUX_JoystickGetDeviceInstanceID,
     LINUX_JoystickOpen,

--
Gitblit v1.9.3