From dec7875a6e23212021e4d9080330a42832dfe02a Mon Sep 17 00:00:00 2001
From: Edward Rudd <urkle@outoforder.cc>
Date: Tue, 15 Jun 2021 01:40:19 +0000
Subject: [PATCH] update SDL soruce to 2.0.14

---
 source/src/joystick/SDL_joystick.c |  806 +++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 690 insertions(+), 116 deletions(-)

diff --git a/source/src/joystick/SDL_joystick.c b/source/src/joystick/SDL_joystick.c
index 95aac9c..32eb7c2 100644
--- a/source/src/joystick/SDL_joystick.c
+++ b/source/src/joystick/SDL_joystick.c
@@ -26,7 +26,6 @@
 #include "SDL_atomic.h"
 #include "SDL_events.h"
 #include "SDL_sysjoystick.h"
-#include "SDL_assert.h"
 #include "SDL_hints.h"
 
 #if !SDL_EVENTS_DISABLED
@@ -46,7 +45,20 @@
 #include <tlhelp32.h>
 #endif
 
+#if SDL_JOYSTICK_VIRTUAL
+#include "./virtual/SDL_virtualjoystick_c.h"
+#endif
+
 static SDL_JoystickDriver *SDL_joystick_drivers[] = {
+#ifdef SDL_JOYSTICK_HIDAPI /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
+    &SDL_HIDAPI_JoystickDriver,
+#endif
+#ifdef SDL_JOYSTICK_RAWINPUT /* Before WINDOWS_ driver, as WINDOWS wants to check if this driver is handling things */
+    &SDL_RAWINPUT_JoystickDriver,
+#endif
+#if defined(SDL_JOYSTICK_WGI)
+    &SDL_WGI_JoystickDriver,
+#endif
 #if defined(SDL_JOYSTICK_DINPUT) || defined(SDL_JOYSTICK_XINPUT)
     &SDL_WINDOWS_JoystickDriver,
 #endif
@@ -56,7 +68,7 @@
 #ifdef SDL_JOYSTICK_IOKIT
     &SDL_DARWIN_JoystickDriver,
 #endif
-#if defined(__IPHONEOS__) || defined(__TVOS__)
+#if (defined(__MACOSX__) || defined(__IPHONEOS__) || defined(__TVOS__)) && !defined(SDL_JOYSTICK_DISABLED)
     &SDL_IOS_JoystickDriver,
 #endif
 #ifdef SDL_JOYSTICK_ANDROID
@@ -71,8 +83,8 @@
 #ifdef SDL_JOYSTICK_USBHID  /* !!! FIXME: "USBHID" is a generic name, and doubly-confusing with HIDAPI next to it. This is the *BSD interface, rename this. */
     &SDL_BSD_JoystickDriver,
 #endif
-#ifdef SDL_JOYSTICK_HIDAPI
-    &SDL_HIDAPI_JoystickDriver,
+#ifdef SDL_JOYSTICK_VIRTUAL
+    &SDL_VIRTUAL_JoystickDriver,
 #endif
 #if defined(SDL_JOYSTICK_DUMMY) || defined(SDL_JOYSTICK_DISABLED)
     &SDL_DUMMY_JoystickDriver
@@ -279,23 +291,6 @@
 }
 
 /*
- * Perform any needed fixups for joystick names
- */
-static const char *
-SDL_FixupJoystickName(const char *name)
-{
-    if (name) {
-        const char *skip_prefix = "NVIDIA Corporation ";
-
-        if (SDL_strncmp(name, skip_prefix, SDL_strlen(skip_prefix)) == 0) {
-            name += SDL_strlen(skip_prefix);
-        }
-    }
-    return name;
-}
-
-
-/*
  * Get the implementation dependent name of a joystick
  */
 const char *
@@ -306,7 +301,7 @@
 
     SDL_LockJoysticks();
     if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
-        name = SDL_FixupJoystickName(driver->GetDeviceName(device_index));
+        name = driver->GetDeviceName(device_index);
     }
     SDL_UnlockJoysticks();
 
@@ -472,12 +467,96 @@
     return joystick;
 }
 
+int
+SDL_JoystickAttachVirtual(SDL_JoystickType type,
+                          int naxes, int nbuttons, int nhats)
+{
+#if SDL_JOYSTICK_VIRTUAL
+    return SDL_JoystickAttachVirtualInner(type, naxes, nbuttons, nhats);
+#else
+    return SDL_SetError("SDL not built with virtual-joystick support");
+#endif
+}
+
+int
+SDL_JoystickDetachVirtual(int device_index)
+{
+#if SDL_JOYSTICK_VIRTUAL
+    SDL_JoystickDriver *driver;
+
+    SDL_LockJoysticks();
+    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
+        if (driver == &SDL_VIRTUAL_JoystickDriver) {
+            const int result = SDL_JoystickDetachVirtualInner(device_index);
+            SDL_UnlockJoysticks();
+            return result;
+        }
+    }
+    SDL_UnlockJoysticks();
+
+    return SDL_SetError("Virtual joystick not found at provided index");
+#else
+    return SDL_SetError("SDL not built with virtual-joystick support");
+#endif
+}
+
+SDL_bool
+SDL_JoystickIsVirtual(int device_index)
+{
+#if SDL_JOYSTICK_VIRTUAL
+    SDL_JoystickDriver *driver;
+    int driver_device_index;
+    SDL_bool is_virtual = SDL_FALSE;
+
+    SDL_LockJoysticks();
+    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &driver_device_index)) {
+        if (driver == &SDL_VIRTUAL_JoystickDriver) {
+            is_virtual = SDL_TRUE;
+        }
+    }
+    SDL_UnlockJoysticks();
+
+    return is_virtual;
+#else
+    return SDL_FALSE;
+#endif
+}
+
+int
+SDL_JoystickSetVirtualAxis(SDL_Joystick *joystick, int axis, Sint16 value)
+{
+#if SDL_JOYSTICK_VIRTUAL
+    return SDL_JoystickSetVirtualAxisInner(joystick, axis, value);
+#else
+    return SDL_SetError("SDL not built with virtual-joystick support");
+#endif
+}
+
+int
+SDL_JoystickSetVirtualButton(SDL_Joystick *joystick, int button, Uint8 value)
+{
+#if SDL_JOYSTICK_VIRTUAL
+    return SDL_JoystickSetVirtualButtonInner(joystick, button, value);
+#else
+    return SDL_SetError("SDL not built with virtual-joystick support");
+#endif
+}
+
+int
+SDL_JoystickSetVirtualHat(SDL_Joystick *joystick, int hat, Uint8 value)
+{
+#if SDL_JOYSTICK_VIRTUAL
+    return SDL_JoystickSetVirtualHatInner(joystick, hat, value);
+#else
+    return SDL_SetError("SDL not built with virtual-joystick support");
+#endif
+}
 
 /*
  * Checks to make sure the joystick is valid.
  */
 SDL_bool
-SDL_PrivateJoystickValid(SDL_Joystick * joystick)
+SDL_PrivateJoystickValid(SDL_Joystick *joystick)
 {
     SDL_bool valid;
 
@@ -491,11 +570,26 @@
     return valid;
 }
 
+SDL_bool
+SDL_PrivateJoystickGetAutoGamepadMapping(int device_index, SDL_GamepadMapping * out)
+{
+    SDL_JoystickDriver *driver;
+    SDL_bool is_ok = SDL_FALSE;
+
+    SDL_LockJoysticks();
+    if (SDL_GetDriverAndJoystickIndex(device_index, &driver, &device_index)) {
+        is_ok = driver->GetGamepadMapping(device_index, out);
+    }
+    SDL_UnlockJoysticks();
+
+    return is_ok;
+}
+
 /*
  * Get the number of multi-dimensional axis controls on a joystick
  */
 int
-SDL_JoystickNumAxes(SDL_Joystick * joystick)
+SDL_JoystickNumAxes(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return -1;
@@ -507,7 +601,7 @@
  * Get the number of hats on a joystick
  */
 int
-SDL_JoystickNumHats(SDL_Joystick * joystick)
+SDL_JoystickNumHats(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return -1;
@@ -519,7 +613,7 @@
  * Get the number of trackballs on a joystick
  */
 int
-SDL_JoystickNumBalls(SDL_Joystick * joystick)
+SDL_JoystickNumBalls(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return -1;
@@ -531,7 +625,7 @@
  * Get the number of buttons on a joystick
  */
 int
-SDL_JoystickNumButtons(SDL_Joystick * joystick)
+SDL_JoystickNumButtons(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return -1;
@@ -543,7 +637,7 @@
  * Get the current state of an axis control on a joystick
  */
 Sint16
-SDL_JoystickGetAxis(SDL_Joystick * joystick, int axis)
+SDL_JoystickGetAxis(SDL_Joystick *joystick, int axis)
 {
     Sint16 state;
 
@@ -563,7 +657,7 @@
  * Get the initial state of an axis control on a joystick
  */
 SDL_bool
-SDL_JoystickGetAxisInitialState(SDL_Joystick * joystick, int axis, Sint16 *state)
+SDL_JoystickGetAxisInitialState(SDL_Joystick *joystick, int axis, Sint16 *state)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return SDL_FALSE;
@@ -582,7 +676,7 @@
  * Get the current state of a hat on a joystick
  */
 Uint8
-SDL_JoystickGetHat(SDL_Joystick * joystick, int hat)
+SDL_JoystickGetHat(SDL_Joystick *joystick, int hat)
 {
     Uint8 state;
 
@@ -602,7 +696,7 @@
  * Get the ball axis change since the last poll
  */
 int
-SDL_JoystickGetBall(SDL_Joystick * joystick, int ball, int *dx, int *dy)
+SDL_JoystickGetBall(SDL_Joystick *joystick, int ball, int *dx, int *dy)
 {
     int retval;
 
@@ -630,7 +724,7 @@
  * Get the current state of a button on a joystick
  */
 Uint8
-SDL_JoystickGetButton(SDL_Joystick * joystick, int button)
+SDL_JoystickGetButton(SDL_Joystick *joystick, int button)
 {
     Uint8 state;
 
@@ -651,7 +745,7 @@
  *  \return SDL_FALSE if not plugged in, SDL_TRUE if still present.
  */
 SDL_bool
-SDL_JoystickGetAttached(SDL_Joystick * joystick)
+SDL_JoystickGetAttached(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return SDL_FALSE;
@@ -664,7 +758,7 @@
  * Get the instance id for this opened joystick
  */
 SDL_JoystickID
-SDL_JoystickInstanceID(SDL_Joystick * joystick)
+SDL_JoystickInstanceID(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return -1;
@@ -715,20 +809,20 @@
  * Get the friendly name of this joystick
  */
 const char *
-SDL_JoystickName(SDL_Joystick * joystick)
+SDL_JoystickName(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return NULL;
     }
 
-    return SDL_FixupJoystickName(joystick->name);
+    return joystick->name;
 }
 
 /**
  *  Get the player index of an opened joystick, or -1 if it's not available
  */
 int
-SDL_JoystickGetPlayerIndex(SDL_Joystick * joystick)
+SDL_JoystickGetPlayerIndex(SDL_Joystick *joystick)
 {
     int player_index;
 
@@ -747,7 +841,7 @@
  *  Set the player index of an opened joystick
  */
 void
-SDL_JoystickSetPlayerIndex(SDL_Joystick * joystick, int player_index)
+SDL_JoystickSetPlayerIndex(SDL_Joystick *joystick, int player_index)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return;
@@ -759,7 +853,7 @@
 }
 
 int
-SDL_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
+SDL_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
 {
     int result;
 
@@ -793,14 +887,97 @@
     return result;
 }
 
+int
+SDL_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble, Uint32 duration_ms)
+{
+    int result;
+
+    if (!SDL_PrivateJoystickValid(joystick)) {
+        return -1;
+    }
+
+    SDL_LockJoysticks();
+    if (left_rumble == joystick->left_trigger_rumble && right_rumble == joystick->right_trigger_rumble) {
+        /* Just update the expiration */
+        result = 0;
+    } else {
+        result = joystick->driver->RumbleTriggers(joystick, left_rumble, right_rumble);
+    }
+
+    /* Save the rumble value regardless of success, so we don't spam the driver */
+    joystick->left_trigger_rumble = left_rumble;
+    joystick->right_trigger_rumble = right_rumble;
+
+    if ((left_rumble || right_rumble) && duration_ms) {
+        joystick->trigger_rumble_expiration = SDL_GetTicks() + SDL_min(duration_ms, SDL_MAX_RUMBLE_DURATION_MS);
+        if (!joystick->trigger_rumble_expiration) {
+            joystick->trigger_rumble_expiration = 1;
+        }
+    } else {
+        joystick->trigger_rumble_expiration = 0;
+    }
+    SDL_UnlockJoysticks();
+
+    return result;
+}
+
+SDL_bool
+SDL_JoystickHasLED(SDL_Joystick *joystick)
+{
+    SDL_bool result;
+
+    if (!SDL_PrivateJoystickValid(joystick)) {
+        return SDL_FALSE;
+    }
+
+    SDL_LockJoysticks();
+
+    result = joystick->driver->HasLED(joystick);
+
+    SDL_UnlockJoysticks();
+
+    return result;
+}
+
+int
+SDL_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
+{
+    int result;
+
+    if (!SDL_PrivateJoystickValid(joystick)) {
+        return -1;
+    }
+
+    SDL_LockJoysticks();
+
+    if (red == joystick->led_red &&
+        green == joystick->led_green &&
+        blue == joystick->led_blue) {
+        /* Avoid spamming the driver */
+        result = 0;
+    } else {
+        result = joystick->driver->SetLED(joystick, red, green, blue);
+    }
+
+    /* Save the LED value regardless of success, so we don't spam the driver */
+    joystick->led_red = red;
+    joystick->led_green = green;
+    joystick->led_blue = blue;
+
+    SDL_UnlockJoysticks();
+
+    return result;
+}
+
 /*
  * Close a joystick previously opened with SDL_JoystickOpen()
  */
 void
-SDL_JoystickClose(SDL_Joystick * joystick)
+SDL_JoystickClose(SDL_Joystick *joystick)
 {
     SDL_Joystick *joysticklist;
     SDL_Joystick *joysticklistprev;
+    int i;
 
     if (!SDL_PrivateJoystickValid(joystick)) {
         return;
@@ -821,6 +998,9 @@
 
     if (joystick->rumble_expiration) {
         SDL_JoystickRumble(joystick, 0, 0, 0);
+    }
+    if (joystick->trigger_rumble_expiration) {
+        SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
     }
 
     joystick->driver->Close(joystick);
@@ -843,12 +1023,19 @@
     }
 
     SDL_free(joystick->name);
+    SDL_free(joystick->serial);
 
     /* Free the data associated with this joystick */
     SDL_free(joystick->axes);
     SDL_free(joystick->hats);
     SDL_free(joystick->balls);
     SDL_free(joystick->buttons);
+    for (i = 0; i < joystick->ntouchpads; i++) {
+        SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i];
+        SDL_free(touchpad->fingers);
+    }
+    SDL_free(joystick->touchpads);
+    SDL_free(joystick->sensors);
     SDL_free(joystick);
 
     SDL_UnlockJoysticks();
@@ -918,6 +1105,43 @@
 
 /* These are global for SDL_sysjoystick.c and SDL_events.c */
 
+void SDL_PrivateJoystickAddTouchpad(SDL_Joystick *joystick, int nfingers)
+{
+    int ntouchpads = joystick->ntouchpads + 1;
+    SDL_JoystickTouchpadInfo *touchpads = (SDL_JoystickTouchpadInfo *)SDL_realloc(joystick->touchpads, (ntouchpads * sizeof(SDL_JoystickTouchpadInfo)));
+    if (touchpads) {
+        SDL_JoystickTouchpadInfo *touchpad = &touchpads[ntouchpads - 1];
+        SDL_JoystickTouchpadFingerInfo *fingers = (SDL_JoystickTouchpadFingerInfo *)SDL_calloc(nfingers, sizeof(SDL_JoystickTouchpadFingerInfo));
+
+        if (fingers) {
+            touchpad->nfingers = nfingers;
+            touchpad->fingers = fingers;
+        } else {
+            /* Out of memory, this touchpad won't be active */
+            touchpad->nfingers = 0;
+            touchpad->fingers = NULL;
+        }
+
+        joystick->ntouchpads = ntouchpads;
+        joystick->touchpads = touchpads;
+    }
+}
+
+void SDL_PrivateJoystickAddSensor(SDL_Joystick *joystick, SDL_SensorType type)
+{
+    int nsensors = joystick->nsensors + 1;
+    SDL_JoystickSensorInfo *sensors = (SDL_JoystickSensorInfo *)SDL_realloc(joystick->sensors, (nsensors * sizeof(SDL_JoystickSensorInfo)));
+    if (sensors) {
+        SDL_JoystickSensorInfo *sensor = &sensors[nsensors - 1];
+
+        SDL_zerop(sensor);
+        sensor->type = type;
+
+        joystick->nsensors = nsensors;
+        joystick->sensors = sensors;
+    }
+}
+
 void SDL_PrivateJoystickAdded(SDL_JoystickID device_instance)
 {
     SDL_JoystickDriver *driver;
@@ -959,7 +1183,7 @@
  * to have the right value for which, because the number of controllers in
  * the system is now one less.
  */
-static void UpdateEventsForDeviceRemoval()
+static void UpdateEventsForDeviceRemoval(int device_index)
 {
     int i, num_events;
     SDL_Event *events;
@@ -977,21 +1201,78 @@
 
     num_events = SDL_PeepEvents(events, num_events, SDL_GETEVENT, SDL_JOYDEVICEADDED, SDL_JOYDEVICEADDED);
     for (i = 0; i < num_events; ++i) {
-        --events[i].jdevice.which;
+        if (events[i].cdevice.which < device_index) {
+            /* No change for index values lower than the removed device */
+        }
+        else if (events[i].cdevice.which == device_index) {
+            /* Drop this event entirely */
+            SDL_memmove(&events[i], &events[i + 1], sizeof(*events) * (num_events - (i + 1)));
+            --num_events;
+            --i;
+        }
+        else {
+            /* Fix up the device index if greater than the removed device */
+            --events[i].cdevice.which;
+        }
     }
     SDL_PeepEvents(events, num_events, SDL_ADDEVENT, 0, 0);
 
     SDL_small_free(events, isstack);
 }
 
+static void
+SDL_PrivateJoystickForceRecentering(SDL_Joystick *joystick)
+{
+    int i, j;
+
+    /* Tell the app that everything is centered/unpressed... */
+    for (i = 0; i < joystick->naxes; i++) {
+        if (joystick->axes[i].has_initial_value) {
+            SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
+        }
+    }
+
+    for (i = 0; i < joystick->nbuttons; i++) {
+        SDL_PrivateJoystickButton(joystick, i, SDL_RELEASED);
+    }
+
+    for (i = 0; i < joystick->nhats; i++) {
+        SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
+    }
+
+    for (i = 0; i < joystick->ntouchpads; i++) {
+        SDL_JoystickTouchpadInfo *touchpad = &joystick->touchpads[i];
+
+        for (j = 0; j < touchpad->nfingers; ++j) {
+            SDL_PrivateJoystickTouchpad(joystick, i, j, SDL_RELEASED, 0.0f, 0.0f, 0.0f);
+        }
+    }
+
+}
+
 void SDL_PrivateJoystickRemoved(SDL_JoystickID device_instance)
 {
-    SDL_Joystick *joystick;
+    SDL_Joystick *joystick = NULL;
     int player_index;
-
+    int device_index;
 #if !SDL_EVENTS_DISABLED
     SDL_Event event;
+#endif
 
+    /* Find this joystick... */
+    device_index = 0;
+    for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
+        if (joystick->instance_id == device_instance) {
+            SDL_PrivateJoystickForceRecentering(joystick);
+            joystick->attached = SDL_FALSE;
+            break;
+        }
+
+        ++device_index;
+    }
+
+#if !SDL_EVENTS_DISABLED
+    SDL_zero(event);
     event.type = SDL_JOYDEVICEREMOVED;
 
     if (SDL_GetEventState(event.type) == SDL_ENABLE) {
@@ -999,17 +1280,8 @@
         SDL_PushEvent(&event);
     }
 
-    UpdateEventsForDeviceRemoval();
+    UpdateEventsForDeviceRemoval(device_index);
 #endif /* !SDL_EVENTS_DISABLED */
-
-    /* Mark this joystick as no longer attached */
-    for (joystick = SDL_joysticks; joystick; joystick = joystick->next) {
-        if (joystick->instance_id == device_instance) {
-            joystick->attached = SDL_FALSE;
-            joystick->force_recentering = SDL_TRUE;
-            break;
-        }
-    }
 
     SDL_LockJoysticks();
     player_index = SDL_GetPlayerIndexForJoystickID(device_instance);
@@ -1020,7 +1292,7 @@
 }
 
 int
-SDL_PrivateJoystickAxis(SDL_Joystick * joystick, Uint8 axis, Sint16 value)
+SDL_PrivateJoystickAxis(SDL_Joystick *joystick, Uint8 axis, Sint16 value)
 {
     int posted;
     SDL_JoystickAxisInfo *info;
@@ -1032,16 +1304,15 @@
 
     info = &joystick->axes[axis];
     if (!info->has_initial_value ||
-        (!info->has_second_value && (info->initial_value == -32768 || info->initial_value == 32767) && SDL_abs(value) < (SDL_JOYSTICK_AXIS_MAX / 4))) {
+        (!info->has_second_value && (info->initial_value <= -32767 || info->initial_value == 32767) && SDL_abs(value) < (SDL_JOYSTICK_AXIS_MAX / 4))) {
         info->initial_value = value;
         info->value = value;
         info->zero = value;
         info->has_initial_value = SDL_TRUE;
+    } else if (value == info->value) {
+        return 0;
     } else {
         info->has_second_value = SDL_TRUE;
-    }
-    if (value == info->value) {
-        return 0;
     }
     if (!info->sent_initial_value) {
         /* Make sure we don't send motion until there's real activity on this axis */
@@ -1050,7 +1321,7 @@
             return 0;
         }
         info->sent_initial_value = SDL_TRUE;
-        info->value = value; /* Just so we pass the check above */
+        info->value = ~value; /* Just so we pass the check above */
         SDL_PrivateJoystickAxis(joystick, axis, info->initial_value);
     }
 
@@ -1083,7 +1354,7 @@
 }
 
 int
-SDL_PrivateJoystickHat(SDL_Joystick * joystick, Uint8 hat, Uint8 value)
+SDL_PrivateJoystickHat(SDL_Joystick *joystick, Uint8 hat, Uint8 value)
 {
     int posted;
 
@@ -1123,7 +1394,7 @@
 }
 
 int
-SDL_PrivateJoystickBall(SDL_Joystick * joystick, Uint8 ball,
+SDL_PrivateJoystickBall(SDL_Joystick *joystick, Uint8 ball,
                         Sint16 xrel, Sint16 yrel)
 {
     int posted;
@@ -1159,7 +1430,7 @@
 }
 
 int
-SDL_PrivateJoystickButton(SDL_Joystick * joystick, Uint8 button, Uint8 state)
+SDL_PrivateJoystickButton(SDL_Joystick *joystick, Uint8 button, Uint8 state)
 {
     int posted;
 #if !SDL_EVENTS_DISABLED
@@ -1260,23 +1531,14 @@
             SDL_UnlockJoysticks();
         }
 
-        if (joystick->force_recentering) {
-            /* Tell the app that everything is centered/unpressed... */
-            for (i = 0; i < joystick->naxes; i++) {
-                if (joystick->axes[i].has_initial_value) {
-                    SDL_PrivateJoystickAxis(joystick, i, joystick->axes[i].zero);
-                }
+        if (joystick->trigger_rumble_expiration) {
+            SDL_LockJoysticks();
+            /* Double check now that the lock is held */
+            if (joystick->trigger_rumble_expiration &&
+                SDL_TICKS_PASSED(SDL_GetTicks(), joystick->trigger_rumble_expiration)) {
+                SDL_JoystickRumbleTriggers(joystick, 0, 0, 0);
             }
-
-            for (i = 0; i < joystick->nbuttons; i++) {
-                SDL_PrivateJoystickButton(joystick, i, 0);
-            }
-
-            for (i = 0; i < joystick->nhats; i++) {
-                SDL_PrivateJoystickHat(joystick, i, SDL_HAT_CENTERED);
-            }
-
-            joystick->force_recentering = SDL_FALSE;
+            SDL_UnlockJoysticks();
         }
     }
 
@@ -1369,23 +1631,123 @@
     }
 }
 
-const char *
-SDL_GetCustomJoystickManufacturer(const char *manufacturer)
+static int
+PrefixMatch(const char *a, const char *b)
 {
-    if (manufacturer) {
-        if (SDL_strcmp(manufacturer, "Performance Designed Products") == 0) {
-            return "PDP";
-        } else if (SDL_strcmp(manufacturer, "HORI CO.,LTD") == 0) {
-            return "HORI";
+    int matchlen = 0;
+    while (*a && *b) {
+        if (SDL_tolower(*a++) == SDL_tolower(*b++)) {
+            ++matchlen;
+        } else {
+            break;
         }
     }
-    return manufacturer;
+    return matchlen;
 }
 
-const char *
-SDL_GetCustomJoystickName(Uint16 vendor, Uint16 product)
+char *
+SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *vendor_name, const char *product_name)
 {
-    return GuessControllerName(vendor, product);
+    static struct {
+        const char *prefix;
+        const char *replacement;
+    } replacements[] = {
+        { "NVIDIA Corporation ", "" },
+        { "Performance Designed Products", "PDP" },
+        { "HORI CO.,LTD.", "HORI" },
+        { "HORI CO.,LTD", "HORI" },
+    };
+    const char *custom_name;
+    char *name;
+    size_t i, len;
+
+    custom_name = GuessControllerName(vendor, product);
+    if (custom_name) {
+        return SDL_strdup(custom_name);
+    }
+
+    if (!vendor_name) {
+        vendor_name = "";
+    }
+    if (!product_name) {
+        product_name = "";
+    }
+
+    while (*vendor_name == ' ') {
+        ++vendor_name;
+    }
+    while (*product_name == ' ') {
+        ++product_name;
+    }
+
+    if (*vendor_name && *product_name) {
+        len = (SDL_strlen(vendor_name) + 1 + SDL_strlen(product_name) + 1);
+        name = (char *)SDL_malloc(len);
+        if (!name) {
+            return NULL;
+        }
+        SDL_snprintf(name, len, "%s %s", vendor_name, product_name);
+    } else if (*product_name) {
+        name = SDL_strdup(product_name);
+    } else if (vendor || product) {
+        len = (6 + 1 + 6 + 1);
+        name = (char *)SDL_malloc(len);
+        if (!name) {
+            return NULL;
+        }
+        SDL_snprintf(name, len, "0x%.4x/0x%.4x", vendor, product);
+    } else {
+        name = SDL_strdup("Controller");
+    }
+
+    /* Trim trailing whitespace */
+    for (len = SDL_strlen(name); (len > 0 && name[len - 1] == ' '); --len) {
+        /* continue */
+    }
+    name[len] = '\0';
+
+    /* Compress duplicate spaces */
+    for (i = 0; i < (len - 1); ) {
+        if (name[i] == ' ' && name[i+1] == ' ') {
+            SDL_memmove(&name[i], &name[i+1], (len - i));
+            --len;
+        } else {
+            ++i;
+        }
+    }
+
+    /* Remove duplicate manufacturer or product in the name */
+    for (i = 1; i < (len - 1); ++i) {
+        int matchlen = PrefixMatch(name, &name[i]);
+        if (matchlen > 0 && name[matchlen-1] == ' ') {
+            SDL_memmove(name, name+matchlen, len-matchlen+1);
+            len -= matchlen;
+            break;
+        } else if (matchlen > 0 && name[matchlen] == ' ') {
+            SDL_memmove(name, name+matchlen+1, len-matchlen);
+            len -= (matchlen + 1);
+            break;
+        }
+    }
+
+    /* Perform any manufacturer replacements */
+    for (i = 0; i < SDL_arraysize(replacements); ++i) {
+        size_t prefixlen = SDL_strlen(replacements[i].prefix);
+        if (SDL_strncasecmp(name, replacements[i].prefix, prefixlen) == 0) {
+            size_t replacementlen = SDL_strlen(replacements[i].replacement);
+            SDL_memcpy(name, replacements[i].replacement, replacementlen);
+            SDL_memmove(name+replacementlen, name+prefixlen, (len-prefixlen+1));
+            break;
+        }
+    }
+
+    return name;
+}
+
+SDL_GameControllerType
+SDL_GetJoystickGameControllerTypeFromVIDPID(Uint16 vendor, Uint16 product)
+{
+    return SDL_GetJoystickGameControllerType(NULL, vendor, product, -1, 0, 0, 0);
 }
 
 SDL_GameControllerType
@@ -1483,11 +1845,14 @@
     if (type == SDL_CONTROLLER_TYPE_UNKNOWN) {
         if (vendor == 0x0000 && product == 0x0000) {
             /* Some devices are only identifiable by their name */
-            if (SDL_strcmp(name, "Lic Pro Controller") == 0 ||
-                SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 ||
-                SDL_strcmp(name, "Wireless Gamepad") == 0) {
+            if (name &&
+                (SDL_strcmp(name, "Lic Pro Controller") == 0 ||
+                 SDL_strcmp(name, "Nintendo Wireless Gamepad") == 0 ||
+                 SDL_strcmp(name, "Wireless Gamepad") == 0)) {
                 /* HORI or PowerA Switch Pro Controller clone */
                 type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
+            } else if (name && SDL_strcmp(name, "Virtual Joystick") == 0) {
+                type = SDL_CONTROLLER_TYPE_VIRTUAL;
             } else {
                 type = SDL_CONTROLLER_TYPE_UNKNOWN;
             }
@@ -1509,6 +1874,9 @@
             case k_eControllerType_PS4Controller:
                 type = SDL_CONTROLLER_TYPE_PS4;
                 break;
+            case k_eControllerType_PS5Controller:
+                type = SDL_CONTROLLER_TYPE_PS5;
+                break;
             case k_eControllerType_SwitchProController:
             case k_eControllerType_SwitchInputOnlyController:
                 type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO;
@@ -1523,16 +1891,63 @@
 }
 
 SDL_bool
-SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor, Uint16 product)
+SDL_IsJoystickXboxOneElite(Uint16 vendor_id, Uint16 product_id)
 {
-    EControllerType eType = GuessControllerType(vendor, product);
+    if (vendor_id == USB_VENDOR_MICROSOFT) {
+        if (product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 ||
+            product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 ||
+            product_id == USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
+SDL_bool
+SDL_IsJoystickXboxOneSeriesX(Uint16 vendor_id, Uint16 product_id)
+{
+    if (vendor_id == USB_VENDOR_MICROSOFT) {
+        if (product_id == USB_PRODUCT_XBOX_ONE_SERIES_X ||
+            product_id == USB_PRODUCT_XBOX_ONE_SERIES_X_BLUETOOTH) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
+SDL_bool
+SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id)
+{
+    EControllerType eType = GuessControllerType(vendor_id, product_id);
+    return (eType == k_eControllerType_PS4Controller);
+}
+
+SDL_bool
+SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id)
+{
+    EControllerType eType = GuessControllerType(vendor_id, product_id);
+    return (eType == k_eControllerType_PS5Controller);
+}
+
+SDL_bool
+SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id)
+{
+    EControllerType eType = GuessControllerType(vendor_id, product_id);
+    return (eType == k_eControllerType_SwitchProController ||
+            eType == k_eControllerType_SwitchInputOnlyController);
+}
+
+SDL_bool
+SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id)
+{
+    EControllerType eType = GuessControllerType(vendor_id, product_id);
     return (eType == k_eControllerType_SwitchInputOnlyController);
 }
 
 SDL_bool
-SDL_IsJoystickSteamController(Uint16 vendor, Uint16 product)
+SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id)
 {
-    EControllerType eType = GuessControllerType(vendor, product);
+    EControllerType eType = GuessControllerType(vendor_id, product_id);
     return (eType == k_eControllerType_SteamController ||
             eType == k_eControllerType_SteamControllerV2);
 }
@@ -1544,9 +1959,27 @@
 }
 
 SDL_bool
+SDL_IsJoystickWGI(SDL_JoystickGUID guid)
+{
+    return (guid.data[14] == 'w') ? SDL_TRUE : SDL_FALSE;
+}
+
+SDL_bool
 SDL_IsJoystickHIDAPI(SDL_JoystickGUID guid)
 {
     return (guid.data[14] == 'h') ? SDL_TRUE : SDL_FALSE;
+}
+
+SDL_bool
+SDL_IsJoystickRAWINPUT(SDL_JoystickGUID guid)
+{
+    return (guid.data[14] == 'r') ? SDL_TRUE : SDL_FALSE;
+}
+
+SDL_bool
+SDL_IsJoystickVirtual(SDL_JoystickGUID guid)
+{
+    return (guid.data[14] == 'v') ? SDL_TRUE : SDL_FALSE;
 }
 
 static SDL_bool SDL_IsJoystickProductWheel(Uint32 vidpid)
@@ -1558,6 +1991,7 @@
         MAKE_VIDPID(0x046d, 0xc299),    /* Logitech G25 */
         MAKE_VIDPID(0x046d, 0xc29a),    /* Logitech Driving Force GT */
         MAKE_VIDPID(0x046d, 0xc29b),    /* Logitech G27 */
+        MAKE_VIDPID(0x046d, 0xc24f),    /* Logitech G29 */
         MAKE_VIDPID(0x046d, 0xc261),    /* Logitech G920 (initial mode) */
         MAKE_VIDPID(0x046d, 0xc262),    /* Logitech G920 (active mode) */
         MAKE_VIDPID(0x044f, 0xb65d),    /* Thrustmaster Wheel FFB */
@@ -1640,6 +2074,14 @@
         }
     }
 
+    if (SDL_IsJoystickWGI(guid)) {
+        return (SDL_JoystickType)guid.data[15];
+    }
+
+    if (SDL_IsJoystickVirtual(guid)) {
+        return (SDL_JoystickType)guid.data[15];
+    }
+
     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
     vidpid = MAKE_VIDPID(vendor, product);
 
@@ -1701,29 +2143,29 @@
        https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py
      */
     static Uint32 joystick_blacklist[] = {
-        /* Microsoft Microsoft Wireless Optical Desktop® 2.10 */
+        /* Microsoft Microsoft Wireless Optical Desktop 2.10 */
         /* Microsoft Wireless Desktop - Comfort Edition */
         MAKE_VIDPID(0x045e, 0x009d),
 
-        /* Microsoft Microsoft® Digital Media Pro Keyboard */
+        /* Microsoft Microsoft Digital Media Pro Keyboard */
         /* Microsoft Corp. Digital Media Pro Keyboard */
         MAKE_VIDPID(0x045e, 0x00b0),
 
-        /* Microsoft Microsoft® Digital Media Keyboard */
+        /* Microsoft Microsoft Digital Media Keyboard */
         /* Microsoft Corp. Digital Media Keyboard 1.0A */
         MAKE_VIDPID(0x045e, 0x00b4),
 
-        /* Microsoft Microsoft® Digital Media Keyboard 3000 */
+        /* 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 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 */
+        /* Microsoft SideWinder(TM) 2.4GHz Transceiver */
         MAKE_VIDPID(0x045e, 0x0748),
 
         /* Microsoft Corp. Wired Keyboard 600 */
@@ -1735,16 +2177,16 @@
         /* Microsoft Corp. Arc Touch Mouse Transceiver */
         MAKE_VIDPID(0x045e, 0x0773),
 
-        /* Microsoft® 2.4GHz Transceiver v9.0 */
-        /* Microsoft® Nano Transceiver v2.1 */
+        /* 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 Nano Transceiver v1.0 */
         /* Microsoft Wireless Keyboard 800 */
         MAKE_VIDPID(0x045e, 0x07b2),
 
-        /* Microsoft® Nano Transceiver v2.0 */
+        /* Microsoft Nano Transceiver v2.0 */
         MAKE_VIDPID(0x045e, 0x0800),
 
         MAKE_VIDPID(0x046d, 0xc30a),  /* Logitech, Inc. iTouch Composite keboard */
@@ -1801,6 +2243,7 @@
     Uint32 id;
     Uint16 vendor;
     Uint16 product;
+    SDL_GameControllerType type;
 
     SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL);
 
@@ -1812,7 +2255,8 @@
         }
     }
 
-    if (SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0) == SDL_CONTROLLER_TYPE_PS4 && SDL_IsPS4RemapperRunning()) {
+    type = SDL_GetJoystickGameControllerType(name, vendor, product, -1, 0, 0, 0);
+    if ((type == SDL_CONTROLLER_TYPE_PS4 || type == SDL_CONTROLLER_TYPE_PS5) && SDL_IsPS4RemapperRunning()) {
         return SDL_TRUE;
     }
 
@@ -1913,7 +2357,7 @@
     return device_index;
 }
 
-SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick * joystick)
+SDL_JoystickGUID SDL_JoystickGetGUID(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         SDL_JoystickGUID emptyGUID;
@@ -1923,7 +2367,7 @@
     return joystick->guid;
 }
 
-Uint16 SDL_JoystickGetVendor(SDL_Joystick * joystick)
+Uint16 SDL_JoystickGetVendor(SDL_Joystick *joystick)
 {
     Uint16 vendor;
     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
@@ -1932,7 +2376,7 @@
     return vendor;
 }
 
-Uint16 SDL_JoystickGetProduct(SDL_Joystick * joystick)
+Uint16 SDL_JoystickGetProduct(SDL_Joystick *joystick)
 {
     Uint16 product;
     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
@@ -1941,7 +2385,7 @@
     return product;
 }
 
-Uint16 SDL_JoystickGetProductVersion(SDL_Joystick * joystick)
+Uint16 SDL_JoystickGetProductVersion(SDL_Joystick *joystick)
 {
     Uint16 version;
     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
@@ -1950,7 +2394,15 @@
     return version;
 }
 
-SDL_JoystickType SDL_JoystickGetType(SDL_Joystick * joystick)
+const char *SDL_JoystickGetSerial(SDL_Joystick *joystick)
+{
+    if (!SDL_PrivateJoystickValid(joystick)) {
+        return NULL;
+    }
+    return joystick->serial;
+}
+
+SDL_JoystickType SDL_JoystickGetType(SDL_Joystick *joystick)
 {
     SDL_JoystickType type;
     SDL_JoystickGUID guid = SDL_JoystickGetGUID(joystick);
@@ -2032,13 +2484,13 @@
 }
 
 /* update the power level for this joystick */
-void SDL_PrivateJoystickBatteryLevel(SDL_Joystick * joystick, SDL_JoystickPowerLevel ePowerLevel)
+void SDL_PrivateJoystickBatteryLevel(SDL_Joystick *joystick, SDL_JoystickPowerLevel ePowerLevel)
 {
     joystick->epowerlevel = ePowerLevel;
 }
 
 /* return its power level */
-SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick * joystick)
+SDL_JoystickPowerLevel SDL_JoystickCurrentPowerLevel(SDL_Joystick *joystick)
 {
     if (!SDL_PrivateJoystickValid(joystick)) {
         return SDL_JOYSTICK_POWER_UNKNOWN;
@@ -2046,4 +2498,126 @@
     return joystick->epowerlevel;
 }
 
+int SDL_PrivateJoystickTouchpad(SDL_Joystick *joystick, int touchpad, int finger, Uint8 state, float x, float y, float pressure)
+{
+    SDL_JoystickTouchpadInfo *touchpad_info;
+    SDL_JoystickTouchpadFingerInfo *finger_info;
+    int posted;
+#if !SDL_EVENTS_DISABLED
+    Uint32 event_type;
+#endif
+
+    if (touchpad < 0 || touchpad >= joystick->ntouchpads) {
+        return 0;
+    }
+
+    touchpad_info = &joystick->touchpads[touchpad];
+    if (finger < 0 || finger >= touchpad_info->nfingers) {
+        return 0;
+    }
+
+    finger_info = &touchpad_info->fingers[finger];
+
+    if (!state) {
+        if (x == 0.0f && y == 0.0f) {
+            x = finger_info->x;
+            y = finger_info->y;
+        }
+        pressure = 0.0f;
+    }
+
+    if (x < 0.0f) {
+        x = 0.0f;
+    } else if (x > 1.0f) {
+        x = 1.0f;
+    }
+    if (y < 0.0f) {
+        y = 0.0f;
+    } else if (y > 1.0f) {
+        y = 1.0f;
+    }
+    if (pressure < 0.0f) {
+        pressure = 0.0f;
+    } else if (pressure > 1.0f) {
+        pressure = 1.0f;
+    }
+
+    if (state == finger_info->state) {
+        if (!state ||
+            (x == finger_info->x && y == finger_info->y && pressure == finger_info->pressure)) {
+            return 0;
+        }
+    }
+
+#if !SDL_EVENTS_DISABLED
+    if (state == finger_info->state) {
+        event_type = SDL_CONTROLLERTOUCHPADMOTION;
+    } else if (state) {
+        event_type = SDL_CONTROLLERTOUCHPADDOWN;
+    } else {
+        event_type = SDL_CONTROLLERTOUCHPADUP;
+    }
+#endif
+
+    /* Update internal joystick state */
+    finger_info->state = state;
+    finger_info->x = x;
+    finger_info->y = y;
+    finger_info->pressure = pressure;
+
+    /* Post the event, if desired */
+    posted = 0;
+#if !SDL_EVENTS_DISABLED
+    if (SDL_GetEventState(event_type) == SDL_ENABLE) {
+        SDL_Event event;
+        event.type = event_type;
+        event.ctouchpad.which = joystick->instance_id;
+        event.ctouchpad.touchpad = touchpad;
+        event.ctouchpad.finger = finger;
+        event.ctouchpad.x = x;
+        event.ctouchpad.y = y;
+        event.ctouchpad.pressure = pressure;
+        posted = SDL_PushEvent(&event) == 1;
+    }
+#endif /* !SDL_EVENTS_DISABLED */
+    return posted;
+}
+
+int SDL_PrivateJoystickSensor(SDL_Joystick *joystick, SDL_SensorType type, const float *data, int num_values)
+{
+    int i;
+    int posted = 0;
+
+    for (i = 0; i < joystick->nsensors; ++i) {
+        SDL_JoystickSensorInfo *sensor = &joystick->sensors[i];
+
+        if (sensor->type == type) {
+            if (sensor->enabled) {
+                num_values = SDL_min(num_values, SDL_arraysize(sensor->data));
+                if (SDL_memcmp(data, sensor->data, num_values*sizeof(*data)) != 0) {
+
+                    /* Update internal sensor state */
+                    SDL_memcpy(sensor->data, data, num_values*sizeof(*data));
+
+                    /* Post the event, if desired */
+#if !SDL_EVENTS_DISABLED
+                    if (SDL_GetEventState(SDL_CONTROLLERSENSORUPDATE) == SDL_ENABLE) {
+                        SDL_Event event;
+                        event.type = SDL_CONTROLLERSENSORUPDATE;
+                        event.csensor.which = joystick->instance_id;
+                        event.csensor.sensor = type;
+                        num_values = SDL_min(num_values, SDL_arraysize(event.csensor.data));
+                        SDL_memset(event.csensor.data, 0, sizeof(event.csensor.data));
+                        SDL_memcpy(event.csensor.data, data, num_values*sizeof(*data));
+                        posted = SDL_PushEvent(&event) == 1;
+                    }
+#endif /* !SDL_EVENTS_DISABLED */
+                }
+            }
+            break;
+        }
+    }
+    return posted;
+}
+
 /* vi: set ts=4 sw=4 expandtab: */

--
Gitblit v1.9.3