From 757c984ddb8e95098b227f85d2687fb5f9d82880 Mon Sep 17 00:00:00 2001
From: Ethan Lee <[EMAIL REDACTED]>
Date: Mon, 27 Nov 2023 17:12:01 -0500
Subject: [PATCH] gamecontroller: Backport 3.0 'type:' field to 2.0
---
include/SDL_gamecontroller.h | 3 +-
src/joystick/SDL_gamecontroller.c | 95 ++++++++++++++++++++++++++++++-
2 files changed, 96 insertions(+), 2 deletions(-)
diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h
index 140054d36ee6..bee07c4df0ae 100644
--- a/include/SDL_gamecontroller.h
+++ b/include/SDL_gamecontroller.h
@@ -73,7 +73,8 @@ typedef enum
SDL_CONTROLLER_TYPE_NVIDIA_SHIELD,
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_LEFT,
SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT,
- SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR
+ SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_JOYCON_PAIR,
+ SDL_CONTROLLER_TYPE_MAX
} SDL_GameControllerType;
typedef enum
diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index b4c08a793b13..c4f8d654220f 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -45,6 +45,8 @@
#define SDL_CONTROLLER_CRC_FIELD "crc:"
#define SDL_CONTROLLER_CRC_FIELD_SIZE 4 /* hard-coded for speed */
+#define SDL_CONTROLLER_TYPE_FIELD "type:"
+#define SDL_CONTROLLER_TYPE_FIELD_SIZE SDL_strlen(SDL_CONTROLLER_TYPE_FIELD)
#define SDL_CONTROLLER_PLATFORM_FIELD "platform:"
#define SDL_CONTROLLER_PLATFORM_FIELD_SIZE SDL_strlen(SDL_CONTROLLER_PLATFORM_FIELD)
#define SDL_CONTROLLER_HINT_FIELD "hint:"
@@ -133,6 +135,7 @@ struct _SDL_GameController
int ref_count _guarded;
const char *name _guarded;
+ SDL_GameControllerType type _guarded;
ControllerMapping_t *mapping _guarded;
int num_bindings _guarded;
SDL_ExtendedGameControllerBind *bindings _guarded;
@@ -850,6 +853,47 @@ static ControllerMapping_t *SDL_PrivateGetControllerMappingForGUID(SDL_JoystickG
return mapping;
}
+static const char *map_StringForGameControllerType[] = {
+ "unknown",
+ "xbox360",
+ "xboxone",
+ "ps3",
+ "ps4",
+ "switchpro",
+ "virtual",
+ "ps5",
+ "amazonluna",
+ "googlestadia",
+ "nvidiashield",
+ "joyconleft",
+ "joyconright",
+ "joyconpair"
+};
+SDL_COMPILE_TIME_ASSERT(map_StringForGameControllerType, SDL_arraysize(map_StringForGameControllerType) == SDL_CONTROLLER_TYPE_MAX);
+
+/*
+ * convert a string to its enum equivalent
+ */
+static SDL_GameControllerType SDL_GetGameControllerTypeFromString(const char *str)
+{
+ int i;
+
+ if (!str || str[0] == '\0') {
+ return SDL_CONTROLLER_TYPE_UNKNOWN;
+ }
+
+ if (*str == '+' || *str == '-') {
+ ++str;
+ }
+
+ for (i = 0; i < SDL_arraysize(map_StringForGameControllerType); ++i) {
+ if (SDL_strcasecmp(str, map_StringForGameControllerType[i]) == 0) {
+ return (SDL_GameControllerType)i;
+ }
+ }
+ return SDL_CONTROLLER_TYPE_UNKNOWN;
+}
+
static const char *map_StringForControllerAxis[] = {
"leftx",
"lefty",
@@ -1095,6 +1139,31 @@ static void SDL_PrivateGameControllerParseControllerConfigString(SDL_GameControl
}
}
+static void SDL_UpdateGameControllerType(SDL_GameController *gamecontroller)
+{
+ char *type_string, *comma;
+
+ SDL_AssertJoysticksLocked();
+
+ gamecontroller->type = SDL_CONTROLLER_TYPE_UNKNOWN;
+
+ type_string = SDL_strstr(gamecontroller->mapping->mapping, SDL_CONTROLLER_TYPE_FIELD);
+ if (type_string) {
+ type_string += SDL_CONTROLLER_TYPE_FIELD_SIZE;
+ comma = SDL_strchr(type_string, ',');
+ if (comma) {
+ *comma = '\0';
+ gamecontroller->type = SDL_GetGameControllerTypeFromString(type_string);
+ *comma = ',';
+ } else {
+ gamecontroller->type = SDL_GetGameControllerTypeFromString(type_string);
+ }
+ }
+ if (gamecontroller->type == SDL_CONTROLLER_TYPE_UNKNOWN) {
+ gamecontroller->type = SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGetGUID(gamecontroller->joystick), SDL_JoystickName(gamecontroller->joystick));
+ }
+}
+
/*
* Make a new button mapping struct
*/
@@ -1113,6 +1182,8 @@ static void SDL_PrivateLoadButtonMapping(SDL_GameController *gamecontroller, Con
SDL_PrivateGameControllerParseControllerConfigString(gamecontroller, pControllerMapping->mapping);
+ SDL_UpdateGameControllerType(gamecontroller);
+
/* Set the zero point for triggers */
for (i = 0; i < gamecontroller->num_bindings; ++i) {
SDL_ExtendedGameControllerBind *binding = &gamecontroller->bindings[i];
@@ -1976,7 +2047,26 @@ const char *SDL_GameControllerPathForIndex(int joystick_index)
*/
SDL_GameControllerType SDL_GameControllerTypeForIndex(int joystick_index)
{
- return SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGetDeviceGUID(joystick_index), SDL_JoystickNameForIndex(joystick_index));
+ SDL_JoystickGUID joystick_guid = SDL_JoystickGetDeviceGUID(joystick_index);
+ const char *mapping = SDL_GameControllerMappingForGUID(joystick_guid);
+ char *type_string, *comma;
+ SDL_GameControllerType type;
+ if (mapping) {
+ type_string = SDL_strstr(mapping, SDL_CONTROLLER_TYPE_FIELD);
+ if (type_string) {
+ type_string += SDL_CONTROLLER_TYPE_FIELD_SIZE;
+ comma = SDL_strchr(type_string, ',');
+ if (comma) {
+ *comma = '\0';
+ type = SDL_GetGameControllerTypeFromString(type_string);
+ *comma = ',';
+ } else {
+ type = SDL_GetGameControllerTypeFromString(type_string);
+ }
+ return type;
+ }
+ }
+ return SDL_GetJoystickGameControllerTypeFromGUID(joystick_guid, SDL_JoystickNameForIndex(joystick_index));
}
/**
@@ -2675,6 +2765,9 @@ SDL_GameControllerType SDL_GameControllerGetType(SDL_GameController *gamecontrol
if (!joystick) {
return SDL_CONTROLLER_TYPE_UNKNOWN;
}
+ if (gamecontroller->type != SDL_CONTROLLER_TYPE_UNKNOWN) {
+ return gamecontroller->type;
+ }
return SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGetGUID(joystick), SDL_JoystickName(joystick));
}