Browse Source

Use SDL_HINT_GAMECONTROLLER_SENSOR_FUSION as a list of controllers to enable sensor fusion

There are too many wraparound style controllers out there to enumerate them all, so instead make this a user option in applications that support it.
Sam Lantinga 1 year ago
parent
commit
d91e96e7f5
4 changed files with 112 additions and 96 deletions
  1. 9 2
      include/SDL3/SDL_hints.h
  2. 6 72
      src/joystick/SDL_gamepad.c
  3. 85 22
      src/joystick/SDL_joystick.c
  4. 12 0
      src/joystick/SDL_joystick_c.h

+ 9 - 2
include/SDL3/SDL_hints.h

@@ -620,11 +620,18 @@ extern "C" {
  *  \brief  Controls whether the device's built-in accelerometer and gyro should be used as sensors for gamepads.
  *
  *  The variable can be set to the following values:
- *    "auto"    - Sensor fusion is enabled for known wraparound controllers like the Razer Kishi and Backbone One
  *    "0"       - Sensor fusion is disabled
  *    "1"       - Sensor fusion is enabled for all controllers that lack sensors
  *
- *  The default value is "auto". This hint is checked when a gamepad is opened.
+ *  Or the variable can be a comma separated list of USB VID/PID pairs
+ *  in hexadecimal form, e.g.
+ *
+ *      0xAAAA/0xBBBB,0xCCCC/0xDDDD
+ *
+ *  The variable can also take the form of @file, in which case the named
+ *  file will be loaded and interpreted as the value of the variable.
+ *
+ *  This hint is checked when a gamepad is opened.
  */
 #define SDL_HINT_GAMECONTROLLER_SENSOR_FUSION "SDL_GAMECONTROLLER_SENSOR_FUSION"
 

+ 6 - 72
src/joystick/SDL_gamepad.c

@@ -150,61 +150,9 @@ struct SDL_Gamepad
         return retval;                                                       \
     }
 
-typedef struct
-{
-    int num_entries;
-    int max_entries;
-    Uint32 *entries;
-} SDL_vidpid_list;
-
 static SDL_vidpid_list SDL_allowed_gamepads;
 static SDL_vidpid_list SDL_ignored_gamepads;
 
-static void SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list)
-{
-    Uint32 entry;
-    char *spot;
-    char *file = NULL;
-
-    list->num_entries = 0;
-
-    if (hint && *hint == '@') {
-        spot = file = (char *)SDL_LoadFile(hint + 1, NULL);
-    } else {
-        spot = (char *)hint;
-    }
-
-    if (spot == NULL) {
-        return;
-    }
-
-    while ((spot = SDL_strstr(spot, "0x")) != NULL) {
-        entry = (Uint16)SDL_strtol(spot, &spot, 0);
-        entry <<= 16;
-        spot = SDL_strstr(spot, "0x");
-        if (spot == NULL) {
-            break;
-        }
-        entry |= (Uint16)SDL_strtol(spot, &spot, 0);
-
-        if (list->num_entries == list->max_entries) {
-            int max_entries = list->max_entries + 16;
-            Uint32 *entries = (Uint32 *)SDL_realloc(list->entries, max_entries * sizeof(*list->entries));
-            if (entries == NULL) {
-                /* Out of memory, go with what we have already */
-                break;
-            }
-            list->entries = entries;
-            list->max_entries = max_entries;
-        }
-        list->entries[list->num_entries++] = entry;
-    }
-
-    if (file) {
-        SDL_free(file);
-    }
-}
-
 static void SDLCALL SDL_GamepadIgnoreDevicesChanged(void *userdata, const char *name, const char *oldValue, const char *hint)
 {
     SDL_LoadVIDPIDListFromHint(hint, &SDL_ignored_gamepads);
@@ -2112,11 +2060,9 @@ static SDL_bool SDL_endswith(const char *string, const char *suffix)
  */
 SDL_bool SDL_ShouldIgnoreGamepad(const char *name, SDL_JoystickGUID guid)
 {
-    int i;
     Uint16 vendor;
     Uint16 product;
     Uint16 version;
-    Uint32 vidpid;
 
 #ifdef __LINUX__
     if (SDL_endswith(name, " Motion Sensors")) {
@@ -2165,20 +2111,14 @@ SDL_bool SDL_ShouldIgnoreGamepad(const char *name, SDL_JoystickGUID guid)
         }
     }
 
-    vidpid = MAKE_VIDPID(vendor, product);
-
     if (SDL_allowed_gamepads.num_entries > 0) {
-        for (i = 0; i < SDL_allowed_gamepads.num_entries; ++i) {
-            if (vidpid == SDL_allowed_gamepads.entries[i]) {
-                return SDL_FALSE;
-            }
+        if (SDL_VIDPIDInList(vendor, product, &SDL_allowed_gamepads)) {
+            return SDL_FALSE;
         }
         return SDL_TRUE;
     } else {
-        for (i = 0; i < SDL_ignored_gamepads.num_entries; ++i) {
-            if (vidpid == SDL_ignored_gamepads.entries[i]) {
-                return SDL_TRUE;
-            }
+        if (SDL_VIDPIDInList(vendor, product, &SDL_ignored_gamepads)) {
+            return SDL_TRUE;
         }
         return SDL_FALSE;
     }
@@ -3100,14 +3040,8 @@ void SDL_QuitGamepadMappings(void)
     SDL_DelHintCallback(SDL_HINT_GAMECONTROLLER_IGNORE_DEVICES_EXCEPT,
                         SDL_GamepadIgnoreDevicesExceptChanged, NULL);
 
-    if (SDL_allowed_gamepads.entries) {
-        SDL_free(SDL_allowed_gamepads.entries);
-        SDL_zero(SDL_allowed_gamepads);
-    }
-    if (SDL_ignored_gamepads.entries) {
-        SDL_free(SDL_ignored_gamepads.entries);
-        SDL_zero(SDL_ignored_gamepads);
-    }
+    SDL_FreeVIDPIDList(&SDL_allowed_gamepads);
+    SDL_FreeVIDPIDList(&SDL_ignored_gamepads);
 }
 
 /*

+ 85 - 22
src/joystick/SDL_joystick.c

@@ -564,19 +564,8 @@ static SDL_bool IsROGAlly(SDL_Joystick *joystick)
 
 static SDL_bool ShouldAttemptSensorFusion(SDL_Joystick *joystick, SDL_bool *invert_sensors)
 {
-    static Uint32 wraparound_gamepads[] = {
-        MAKE_VIDPID(0x1532, 0x0709),    /* Razer Junglecat (L) */
-        MAKE_VIDPID(0x1532, 0x070a),    /* Razer Junglecat (R) */
-        MAKE_VIDPID(0x1532, 0x0717),    /* Razer Edge controller */
-        MAKE_VIDPID(0x1949, 0x0402),    /* Ipega PG-9083S */
-        MAKE_VIDPID(0x27f8, 0x0bbc),    /* Gamevice */
-        MAKE_VIDPID(0x27f8, 0x0bbf),    /* Razer Kishi */
-    };
-    SDL_JoystickGUID guid;
-    Uint16 vendor, product;
-    Uint32 vidpid;
-    int i;
-    int hint;
+    const char *hint;
+    int hint_value;
 
     *invert_sensors = SDL_FALSE;
 
@@ -590,20 +579,28 @@ static SDL_bool ShouldAttemptSensorFusion(SDL_Joystick *joystick, SDL_bool *inve
         return SDL_FALSE;
     }
 
-    hint = SDL_GetStringInteger(SDL_GetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION), -1);
-    if (hint > 0) {
+    hint = SDL_GetHint(SDL_HINT_GAMECONTROLLER_SENSOR_FUSION);
+    hint_value = SDL_GetStringInteger(hint, -1);
+    if (hint_value > 0) {
         return SDL_TRUE;
     }
-    if (hint == 0) {
+    if (hint_value == 0) {
         return SDL_FALSE;
     }
 
-    /* See if the controller is in our list of wraparound gamepads */
-    guid = SDL_GetJoystickGUID(joystick);
-    SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL);
-    vidpid = MAKE_VIDPID(vendor, product);
-    for (i = 0; i < SDL_arraysize(wraparound_gamepads); ++i) {
-        if (vidpid == wraparound_gamepads[i]) {
+    if (hint) {
+        SDL_vidpid_list gamepads;
+        SDL_JoystickGUID guid;
+        Uint16 vendor, product;
+        SDL_bool enabled;
+
+        /* See if the gamepad is in our list of devices to enable */
+        guid = SDL_GetJoystickGUID(joystick);
+        SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL);
+        SDL_LoadVIDPIDListFromHint(hint, &gamepads);
+        enabled = SDL_VIDPIDInList(vendor, product, &gamepads);
+        SDL_FreeVIDPIDList(&gamepads);
+        if (enabled) {
             return SDL_TRUE;
         }
     }
@@ -3263,3 +3260,69 @@ int SDL_SendJoystickSensor(Uint64 timestamp, SDL_Joystick *joystick, SDL_SensorT
     }
     return posted;
 }
+
+void SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list)
+{
+    Uint32 entry;
+    char *spot;
+    char *file = NULL;
+
+    list->num_entries = 0;
+
+    if (hint && *hint == '@') {
+        spot = file = (char *)SDL_LoadFile(hint + 1, NULL);
+    } else {
+        spot = (char *)hint;
+    }
+
+    if (spot == NULL) {
+        return;
+    }
+
+    while ((spot = SDL_strstr(spot, "0x")) != NULL) {
+        entry = (Uint16)SDL_strtol(spot, &spot, 0);
+        entry <<= 16;
+        spot = SDL_strstr(spot, "0x");
+        if (spot == NULL) {
+            break;
+        }
+        entry |= (Uint16)SDL_strtol(spot, &spot, 0);
+
+        if (list->num_entries == list->max_entries) {
+            int max_entries = list->max_entries + 16;
+            Uint32 *entries = (Uint32 *)SDL_realloc(list->entries, max_entries * sizeof(*list->entries));
+            if (entries == NULL) {
+                /* Out of memory, go with what we have already */
+                break;
+            }
+            list->entries = entries;
+            list->max_entries = max_entries;
+        }
+        list->entries[list->num_entries++] = entry;
+    }
+
+    if (file) {
+        SDL_free(file);
+    }
+}
+
+SDL_bool SDL_VIDPIDInList(Uint16 vendor_id, Uint16 product_id, const SDL_vidpid_list *list)
+{
+    int i;
+    Uint32 vidpid = MAKE_VIDPID(vendor_id, product_id);
+
+    for (i = 0; i < list->num_entries; ++i) {
+        if (vidpid == list->entries[i]) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
+void SDL_FreeVIDPIDList(SDL_vidpid_list *list)
+{
+    if (list->entries) {
+        SDL_free(list->entries);
+        SDL_zerop(list);
+    }
+}

+ 12 - 0
src/joystick/SDL_joystick_c.h

@@ -202,6 +202,18 @@ typedef struct SDL_GamepadMapping
 extern SDL_bool SDL_PrivateJoystickGetAutoGamepadMapping(SDL_JoystickID instance_id,
                                                          SDL_GamepadMapping *out);
 
+
+typedef struct
+{
+    int num_entries;
+    int max_entries;
+    Uint32 *entries;
+} SDL_vidpid_list;
+
+extern void SDL_LoadVIDPIDListFromHint(const char *hint, SDL_vidpid_list *list);
+extern SDL_bool SDL_VIDPIDInList(Uint16 vendor_id, Uint16 product_id, const SDL_vidpid_list *list);
+extern void SDL_FreeVIDPIDList(SDL_vidpid_list *list);
+
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus
 }