Convert mappings using labeled buttons to positional buttons

We were accidentally skipping all of the mappings that used the SDL_GAMECONTROLLER_USE_BUTTON_LABELS hint, because they used the '!' negate operator with a default hint value of 1. Instead we just want to use that hint to determine whether the mapping has positional buttons or not, and swap the buttons as needed.

Fixes https://github.com/libsdl-org/SDL/issues/9190
main
Sam Lantinga 2024-03-03 14:17:03 -08:00
parent ccd309c433
commit 9be35d4603
1 changed files with 77 additions and 12 deletions

View File

@ -1885,17 +1885,59 @@ int SDL_ReloadGamepadMappings(void)
return 0;
}
static char *SDL_ConvertMappingToPositional(const char *mapping)
{
/* Add space for '!' and null terminator */
size_t length = SDL_strlen(mapping) + 1 + 1;
char *remapped = (char *)SDL_malloc(length);
if (remapped) {
char *button_A;
char *button_B;
char *button_X;
char *button_Y;
char *hint;
SDL_strlcpy(remapped, mapping, length);
button_A = SDL_strstr(remapped, "a:");
button_B = SDL_strstr(remapped, "b:");
button_X = SDL_strstr(remapped, "x:");
button_Y = SDL_strstr(remapped, "y:");
hint = SDL_strstr(remapped, "hint:SDL_GAMECONTROLLER_USE_BUTTON_LABELS");
if (button_A) {
*button_A = 'b';
}
if (button_B) {
*button_B = 'a';
}
if (button_X) {
*button_X = 'y';
}
if (button_Y) {
*button_Y = 'x';
}
if (hint) {
hint += 5;
SDL_memmove(hint + 1, hint, SDL_strlen(hint) + 1);
*hint = '!';
}
}
return remapped;
}
/*
* Add or update an entry into the Mappings Database with a priority
*/
static int SDL_PrivateAddGamepadMapping(const char *mappingString, SDL_GamepadMappingPriority priority)
{
char *remapped = NULL;
char *pchGUID;
SDL_JoystickGUID jGUID;
SDL_bool is_default_mapping = SDL_FALSE;
SDL_bool is_xinput_mapping = SDL_FALSE;
SDL_bool existing = SDL_FALSE;
GamepadMapping_t *pGamepadMapping;
int retval = -1;
SDL_AssertJoysticksLocked();
@ -1934,12 +1976,27 @@ static int SDL_PrivateAddGamepadMapping(const char *mappingString, SDL_GamepadMa
default_value = SDL_FALSE;
}
value = SDL_GetHintBoolean(hint, default_value);
if (negate) {
value = !value;
}
if (!value) {
return 0;
if (SDL_strcmp(hint, "SDL_GAMECONTROLLER_USE_BUTTON_LABELS") == 0) {
/* This hint is used to signal whether the mapping uses positional buttons or not */
if (negate) {
/* This mapping uses positional buttons, we can use it as-is */
} else {
/* This mapping uses labeled buttons, we need to swap them to positional */
remapped = SDL_ConvertMappingToPositional(mappingString);
if (!remapped) {
goto done;
}
mappingString = remapped;
}
} else {
value = SDL_GetHintBoolean(hint, default_value);
if (negate) {
value = !value;
}
if (!value) {
retval = 0;
goto done;
}
}
}
}
@ -1952,14 +2009,16 @@ static int SDL_PrivateAddGamepadMapping(const char *mappingString, SDL_GamepadMa
if (tmp) {
tmp += SDL_GAMEPAD_SDKGE_FIELD_SIZE;
if (!(SDL_GetAndroidSDKVersion() >= SDL_atoi(tmp))) {
return SDL_SetError("SDK version %d < minimum version %d", SDL_GetAndroidSDKVersion(), SDL_atoi(tmp));
SDL_SetError("SDK version %d < minimum version %d", SDL_GetAndroidSDKVersion(), SDL_atoi(tmp));
goto done;
}
}
tmp = SDL_strstr(mappingString, SDL_GAMEPAD_SDKLE_FIELD);
if (tmp) {
tmp += SDL_GAMEPAD_SDKLE_FIELD_SIZE;
if (!(SDL_GetAndroidSDKVersion() <= SDL_atoi(tmp))) {
return SDL_SetError("SDK version %d > maximum version %d", SDL_GetAndroidSDKVersion(), SDL_atoi(tmp));
SDL_SetError("SDK version %d > maximum version %d", SDL_GetAndroidSDKVersion(), SDL_atoi(tmp));
goto done;
}
}
}
@ -1967,7 +2026,8 @@ static int SDL_PrivateAddGamepadMapping(const char *mappingString, SDL_GamepadMa
pchGUID = SDL_PrivateGetGamepadGUIDFromMappingString(mappingString);
if (!pchGUID) {
return SDL_SetError("Couldn't parse GUID from %s", mappingString);
SDL_SetError("Couldn't parse GUID from %s", mappingString);
goto done;
}
if (!SDL_strcasecmp(pchGUID, "default")) {
is_default_mapping = SDL_TRUE;
@ -1979,19 +2039,24 @@ static int SDL_PrivateAddGamepadMapping(const char *mappingString, SDL_GamepadMa
pGamepadMapping = SDL_PrivateAddMappingForGUID(jGUID, mappingString, &existing, priority);
if (!pGamepadMapping) {
return -1;
goto done;
}
if (existing) {
return 0;
retval = 0;
} else {
if (is_default_mapping) {
s_pDefaultMapping = pGamepadMapping;
} else if (is_xinput_mapping) {
s_pXInputMapping = pGamepadMapping;
}
return 1;
retval = 1;
}
done:
if (remapped) {
SDL_free(remapped);
}
return retval;
}
/*