From d91e96e7f50b9c3cb0e1dacda39274b4af037a96 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Sat, 17 Jun 2023 08:59:52 -0700 Subject: [PATCH] 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. --- include/SDL3/SDL_hints.h | 11 +++- src/joystick/SDL_gamepad.c | 78 ++----------------------- src/joystick/SDL_joystick.c | 107 +++++++++++++++++++++++++++------- src/joystick/SDL_joystick_c.h | 12 ++++ 4 files changed, 112 insertions(+), 96 deletions(-) diff --git a/include/SDL3/SDL_hints.h b/include/SDL3/SDL_hints.h index 9114c2f2c..e47561976 100644 --- a/include/SDL3/SDL_hints.h +++ b/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" diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index 3282c7284..8443ba03a 100644 --- a/src/joystick/SDL_gamepad.c +++ b/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); } /* diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 993871b11..20f35b224 100644 --- a/src/joystick/SDL_joystick.c +++ b/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); + } +} diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 46de50d0a..0af5aafb9 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/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 }