From aa9de95b6f86faab2209ff93710fffab06d4fe8d Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 6 Nov 2023 16:26:17 -0800 Subject: [PATCH] Added functions to get the face button labels and primary and secondary actions for a gamepad --- docs/README-migration.md | 2 +- include/SDL3/SDL_gamepad.h | 94 +++++++++++++ src/dynapi/SDL_dynapi.sym | 6 + src/dynapi/SDL_dynapi_overrides.h | 6 + src/dynapi/SDL_dynapi_procs.h | 6 + src/joystick/SDL_gamepad.c | 214 +++++++++++++++++++++++++++++- test/gamepadutils.c | 72 +++------- test/gamepadutils.h | 12 +- test/testcontroller.c | 100 ++++++++------ 9 files changed, 405 insertions(+), 107 deletions(-) diff --git a/docs/README-migration.md b/docs/README-migration.md index 6c26da54d81a1..f2f5f48a1cf18 100644 --- a/docs/README-migration.md +++ b/docs/README-migration.md @@ -390,7 +390,7 @@ The SDL_EVENT_GAMEPAD_ADDED event now provides the joystick instance ID in the w The functions SDL_GetGamepads(), SDL_GetGamepadInstanceName(), SDL_GetGamepadInstancePath(), SDL_GetGamepadInstancePlayerIndex(), SDL_GetGamepadInstanceGUID(), SDL_GetGamepadInstanceVendor(), SDL_GetGamepadInstanceProduct(), SDL_GetGamepadInstanceProductVersion(), and SDL_GetGamepadInstanceType() have been added to directly query the list of available gamepads. -The gamepad face buttons have been renamed to indicate that they are positional rather than Xbox-centric. +The gamepad face buttons have been renamed from A/B/X/Y to North/South/East/West to indicate that they are positional rather than Xbox-centric. You can use SDL_GetGamepadButtonLabel() to get the labels for the face buttons and SDL_GetGamepadPrimaryAction() and SDL_GetGamepadSecondaryAction() to get the buttons used for primary and secondary actions (A and B on an Xbox controller). SDL_GameControllerGetSensorDataWithTimestamp() has been removed. If you want timestamps for the sensor data, you should use the sensor_timestamp member of SDL_EVENT_GAMEPAD_SENSOR_UPDATE events. diff --git a/include/SDL3/SDL_gamepad.h b/include/SDL3/SDL_gamepad.h index 97869d7bdab82..79b0cce9ecc91 100644 --- a/include/SDL3/SDL_gamepad.h +++ b/include/SDL3/SDL_gamepad.h @@ -105,6 +105,26 @@ typedef enum SDL_GAMEPAD_BUTTON_MAX } SDL_GamepadButton; +/** + * The set of gamepad button labels + * + * This isn't a complete set, just the face buttons to make it easy to show button prompts. + * + * For a complete set, you should look at the button and gamepad type and have a set of symbols that work well with your art style. + */ +typedef enum +{ + SDL_GAMEPAD_BUTTON_LABEL_UNKNOWN, + SDL_GAMEPAD_BUTTON_LABEL_A, /**< The south button for Xbox controllers, the east button for Nintendo controllers */ + SDL_GAMEPAD_BUTTON_LABEL_B, /**< The east button for Xbox controllers, the south button for Nintendo controllers */ + SDL_GAMEPAD_BUTTON_LABEL_X, /**< The west button for Xbox controllers, the north button for Nintendo controllers */ + SDL_GAMEPAD_BUTTON_LABEL_Y, /**< The north button for Xbox controllers, the west button for Nintendo controllers */ + SDL_GAMEPAD_BUTTON_LABEL_CROSS, /**< The south button for Playstation controllers */ + SDL_GAMEPAD_BUTTON_LABEL_CIRCLE, /**< The east button for Playstation controllers */ + SDL_GAMEPAD_BUTTON_LABEL_SQUARE, /**< The west button for Playstation controllers */ + SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE /**< The north button for Playstation controllers */ +} SDL_GamepadButtonLabel; + /** * The list of axes available on a gamepad * @@ -990,6 +1010,80 @@ extern DECLSPEC SDL_bool SDLCALL SDL_GamepadHasButton(SDL_Gamepad *gamepad, SDL_ */ extern DECLSPEC Uint8 SDLCALL SDL_GetGamepadButton(SDL_Gamepad *gamepad, SDL_GamepadButton button); +/** + * Get the label of a button on a gamepad. + * + * \param type the type of gamepad to check + * \param button a button index (one of the SDL_GamepadButton values) + * \returns the SDL_GamepadButtonLabel enum corresponding to the button label + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepadButtonLabel + */ +extern DECLSPEC SDL_GamepadButtonLabel SDLCALL SDL_GetGamepadButtonLabelForType(SDL_GamepadType type, SDL_GamepadButton button); + +/** + * Get the label of a button on a gamepad. + * + * \param gamepad a gamepad + * \param button a button index (one of the SDL_GamepadButton values) + * \returns the SDL_GamepadButtonLabel enum corresponding to the button label + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepadButtonLabelForType + */ +extern DECLSPEC SDL_GamepadButtonLabel SDLCALL SDL_GetGamepadButtonLabel(SDL_Gamepad *gamepad, SDL_GamepadButton button); + +/** + * Get the primary action button of a gamepad. + * + * \param type the type of the gamepad to check + * \returns the SDL_GamepadButton corresponding to the primary action (e.g. A on an Xbox controller) + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepadPrimaryAction + */ +extern DECLSPEC SDL_GamepadButton SDLCALL SDL_GetGamepadPrimaryActionForType(SDL_GamepadType type); + +/** + * Get the primary action button of a gamepad. + * + * \param gamepad a gamepad + * \returns the SDL_GamepadButton corresponding to the primary action (e.g. A on an Xbox controller) + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepadPrimaryActionForType + */ +extern DECLSPEC SDL_GamepadButton SDLCALL SDL_GetGamepadPrimaryAction(SDL_Gamepad *gamepad); + +/** + * Get the secondary action button of a gamepad. + * + * \param type the type of the gamepad to check + * \returns the SDL_GamepadButton corresponding to the secondary action (e.g. B on an Xbox controller) + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepadSecondaryAction + */ +extern DECLSPEC SDL_GamepadButton SDLCALL SDL_GetGamepadSecondaryActionForType(SDL_GamepadType type); + +/** + * Get the secondary action button of a gamepad. + * + * \param gamepad a gamepad + * \returns the SDL_GamepadButton corresponding to the secondary action (e.g. B on an Xbox controller) + * + * \since This function is available since SDL 3.0.0. + * + * \sa SDL_GetGamepadSecondaryActionForType + */ +extern DECLSPEC SDL_GamepadButton SDLCALL SDL_GetGamepadSecondaryAction(SDL_Gamepad *gamepad); + /** * Get the number of touchpads on a gamepad. * diff --git a/src/dynapi/SDL_dynapi.sym b/src/dynapi/SDL_dynapi.sym index 4d1999c23937c..ddd70b8ff2ae0 100644 --- a/src/dynapi/SDL_dynapi.sym +++ b/src/dynapi/SDL_dynapi.sym @@ -923,6 +923,12 @@ SDL3_0.0.0 { SDL_RWprintf; SDL_RWvprintf; SDL_AllocateEventMemory; + SDL_GetGamepadButtonLabelForType; + SDL_GetGamepadButtonLabel; + SDL_GetGamepadPrimaryActionForType; + SDL_GetGamepadPrimaryAction; + SDL_GetGamepadSecondaryActionForType; + SDL_GetGamepadSecondaryAction; # extra symbols go here (don't modify this line) local: *; }; diff --git a/src/dynapi/SDL_dynapi_overrides.h b/src/dynapi/SDL_dynapi_overrides.h index 799e29f2f2388..a57045c3d39fc 100644 --- a/src/dynapi/SDL_dynapi_overrides.h +++ b/src/dynapi/SDL_dynapi_overrides.h @@ -948,3 +948,9 @@ #define SDL_RWprintf SDL_RWprintf_REAL #define SDL_RWvprintf SDL_RWvprintf_REAL #define SDL_AllocateEventMemory SDL_AllocateEventMemory_REAL +#define SDL_GetGamepadButtonLabelForType SDL_GetGamepadButtonLabelForType_REAL +#define SDL_GetGamepadButtonLabel SDL_GetGamepadButtonLabel_REAL +#define SDL_GetGamepadPrimaryActionForType SDL_GetGamepadPrimaryActionForType_REAL +#define SDL_GetGamepadPrimaryAction SDL_GetGamepadPrimaryAction_REAL +#define SDL_GetGamepadSecondaryActionForType SDL_GetGamepadSecondaryActionForType_REAL +#define SDL_GetGamepadSecondaryAction SDL_GetGamepadSecondaryAction_REAL diff --git a/src/dynapi/SDL_dynapi_procs.h b/src/dynapi/SDL_dynapi_procs.h index 048aba36fef78..ff303a7c7098d 100644 --- a/src/dynapi/SDL_dynapi_procs.h +++ b/src/dynapi/SDL_dynapi_procs.h @@ -981,3 +981,9 @@ SDL_DYNAPI_PROC(int,SDL_ClearProperty,(SDL_PropertiesID a, const char *b),(a,b), SDL_DYNAPI_PROC(int,SDL_EnterAppMainCallbacks,(int a, char *b[], SDL_AppInit_func c, SDL_AppIterate_func d, SDL_AppEvent_func e, SDL_AppQuit_func f),(a,b,c,d,e,f),return) SDL_DYNAPI_PROC(size_t,SDL_RWvprintf,(SDL_RWops *a, const char *b, va_list c),(a,b,c),return) SDL_DYNAPI_PROC(void*,SDL_AllocateEventMemory,(size_t a),(a),return) +SDL_DYNAPI_PROC(SDL_GamepadButtonLabel,SDL_GetGamepadButtonLabelForType,(SDL_GamepadType a, SDL_GamepadButton b),(a,b),return) +SDL_DYNAPI_PROC(SDL_GamepadButtonLabel,SDL_GetGamepadButtonLabel,(SDL_Gamepad *a, SDL_GamepadButton b),(a,b),return) +SDL_DYNAPI_PROC(SDL_GamepadButton,SDL_GetGamepadPrimaryActionForType,(SDL_GamepadType a),(a),return) +SDL_DYNAPI_PROC(SDL_GamepadButton,SDL_GetGamepadPrimaryAction,(SDL_Gamepad *a),(a),return) +SDL_DYNAPI_PROC(SDL_GamepadButton,SDL_GetGamepadSecondaryActionForType,(SDL_GamepadType a),(a),return) +SDL_DYNAPI_PROC(SDL_GamepadButton,SDL_GetGamepadSecondaryAction,(SDL_Gamepad *a),(a),return) diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index 905d4462145c9..f7038522ab8e2 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -57,6 +57,14 @@ static SDL_bool SDL_gamepads_initialized; static SDL_Gamepad *SDL_gamepads SDL_GUARDED_BY(SDL_joystick_lock) = NULL; +/* The face button style of a gamepad */ +typedef enum +{ + SDL_GAMEPAD_FACE_STYLE_ABXY, + SDL_GAMEPAD_FACE_STYLE_BAYX, + SDL_GAMEPAD_FACE_STYLE_SONY, +} SDL_GamepadFaceStyle; + /* our hard coded list of mapping support */ typedef enum { @@ -107,6 +115,7 @@ struct SDL_Gamepad int ref_count _guarded; const char *name _guarded; + SDL_GamepadFaceStyle face_style _guarded; GamepadMapping_t *mapping _guarded; int num_bindings _guarded; SDL_GamepadBinding *bindings _guarded; @@ -1257,6 +1266,36 @@ static int SDL_PrivateParseGamepadConfigString(SDL_Gamepad *gamepad, const char return 0; } +static SDL_GamepadFaceStyle SDL_GetGamepadFaceStyleForGamepadType(SDL_GamepadType type) +{ + switch (type) { + case SDL_GAMEPAD_TYPE_PS3: + case SDL_GAMEPAD_TYPE_PS4: + case SDL_GAMEPAD_TYPE_PS5: + return SDL_GAMEPAD_FACE_STYLE_SONY; + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: + case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: + return SDL_GAMEPAD_FACE_STYLE_BAYX; + default: + return SDL_GAMEPAD_FACE_STYLE_ABXY; + } +} + +static void SDL_UpdateGamepadFaceStyle(SDL_Gamepad *gamepad) +{ + SDL_AssertJoysticksLocked(); + + if (SDL_strstr(gamepad->mapping->mapping, SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS)) { + /* This controller uses Nintendo button style */ + gamepad->face_style = SDL_GAMEPAD_FACE_STYLE_BAYX; + } else { + gamepad->face_style = SDL_GetGamepadFaceStyleForGamepadType(SDL_GetGamepadType(gamepad)); + } +} + + /* * Make a new button mapping struct */ @@ -1288,6 +1327,8 @@ static void SDL_PrivateLoadButtonMapping(SDL_Gamepad *gamepad, GamepadMapping_t } } } + + SDL_UpdateGamepadFaceStyle(gamepad); } /* @@ -2242,7 +2283,6 @@ SDL_GamepadType SDL_GetGamepadInstanceType(SDL_JoystickID instance_id) *comma = ','; } } - } } SDL_UnlockJoysticks(); @@ -2654,6 +2694,178 @@ Uint8 SDL_GetGamepadButton(SDL_Gamepad *gamepad, SDL_GamepadButton button) return retval; } +/** + * Get the label of a button on a gamepad. + */ +SDL_GamepadButtonLabel SDL_GetGamepadButtonLabelForFaceStyle(SDL_GamepadFaceStyle face_style, SDL_GamepadButton button) +{ + SDL_GamepadButtonLabel label = SDL_GAMEPAD_BUTTON_LABEL_UNKNOWN; + + switch (face_style) { + case SDL_GAMEPAD_FACE_STYLE_ABXY: + switch (button) { + case SDL_GAMEPAD_BUTTON_SOUTH: + label = SDL_GAMEPAD_BUTTON_LABEL_A; + break; + case SDL_GAMEPAD_BUTTON_EAST: + label = SDL_GAMEPAD_BUTTON_LABEL_B; + break; + case SDL_GAMEPAD_BUTTON_WEST: + label = SDL_GAMEPAD_BUTTON_LABEL_X; + break; + case SDL_GAMEPAD_BUTTON_NORTH: + label = SDL_GAMEPAD_BUTTON_LABEL_Y; + break; + default: + break; + } + break; + case SDL_GAMEPAD_FACE_STYLE_BAYX: + switch (button) { + case SDL_GAMEPAD_BUTTON_SOUTH: + label = SDL_GAMEPAD_BUTTON_LABEL_B; + break; + case SDL_GAMEPAD_BUTTON_EAST: + label = SDL_GAMEPAD_BUTTON_LABEL_A; + break; + case SDL_GAMEPAD_BUTTON_WEST: + label = SDL_GAMEPAD_BUTTON_LABEL_Y; + break; + case SDL_GAMEPAD_BUTTON_NORTH: + label = SDL_GAMEPAD_BUTTON_LABEL_X; + break; + default: + break; + } + break; + case SDL_GAMEPAD_FACE_STYLE_SONY: + switch (button) { + case SDL_GAMEPAD_BUTTON_SOUTH: + label = SDL_GAMEPAD_BUTTON_LABEL_CROSS; + break; + case SDL_GAMEPAD_BUTTON_EAST: + label = SDL_GAMEPAD_BUTTON_LABEL_CIRCLE; + break; + case SDL_GAMEPAD_BUTTON_WEST: + label = SDL_GAMEPAD_BUTTON_LABEL_SQUARE; + break; + case SDL_GAMEPAD_BUTTON_NORTH: + label = SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE; + break; + default: + break; + } + break; + default: + break; + } + return label; +} + +/** + * Get the label of a button on a gamepad. + */ +SDL_GamepadButtonLabel SDL_GetGamepadButtonLabelForType(SDL_GamepadType type, SDL_GamepadButton button) +{ + return SDL_GetGamepadButtonLabelForFaceStyle(SDL_GetGamepadFaceStyleForGamepadType(type), button); +} + +/** + * Get the label of a button on a gamepad. + */ +SDL_GamepadButtonLabel SDL_GetGamepadButtonLabel(SDL_Gamepad *gamepad, SDL_GamepadButton button) +{ + SDL_GamepadFaceStyle face_style; + + SDL_LockJoysticks(); + { + CHECK_GAMEPAD_MAGIC(gamepad, SDL_GAMEPAD_BUTTON_LABEL_UNKNOWN); + + face_style = gamepad->face_style; + } + SDL_UnlockJoysticks(); + + return SDL_GetGamepadButtonLabelForFaceStyle(face_style, button); +} + +/** + * Get the primary action button of a gamepad. + */ +static SDL_GamepadButton SDL_GetGamepadPrimaryActionForFaceStyle(SDL_GamepadFaceStyle face_style) +{ + if (face_style == SDL_GAMEPAD_FACE_STYLE_BAYX && + SDL_GetHintBoolean(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, SDL_TRUE)) { + return SDL_GAMEPAD_BUTTON_EAST; + } else { + return SDL_GAMEPAD_BUTTON_SOUTH; + } +} + +/** + * Get the primary action button of a gamepad. + */ +SDL_GamepadButton SDL_GetGamepadPrimaryActionForType(SDL_GamepadType type) +{ + return SDL_GetGamepadPrimaryActionForFaceStyle(SDL_GetGamepadFaceStyleForGamepadType(type)); +} + +/** + * Get the primary action button of a gamepad. + */ +SDL_GamepadButton SDL_GetGamepadPrimaryAction(SDL_Gamepad *gamepad) +{ + SDL_GamepadFaceStyle face_style; + + SDL_LockJoysticks(); + { + CHECK_GAMEPAD_MAGIC(gamepad, SDL_GAMEPAD_BUTTON_INVALID); + + face_style = gamepad->face_style; + } + SDL_UnlockJoysticks(); + + return SDL_GetGamepadPrimaryActionForFaceStyle(face_style); +} + +/** + * Get the secondary action button of a gamepad. + */ +static SDL_GamepadButton SDL_GetGamepadSecondaryActionForFaceStyle(SDL_GamepadFaceStyle face_style) +{ + if (face_style == SDL_GAMEPAD_FACE_STYLE_BAYX && + SDL_GetHintBoolean(SDL_HINT_GAMECONTROLLER_USE_BUTTON_LABELS, SDL_TRUE)) { + return SDL_GAMEPAD_BUTTON_SOUTH; + } else { + return SDL_GAMEPAD_BUTTON_EAST; + } +} + +/** + * Get the secondary action button of a gamepad. + */ +SDL_GamepadButton SDL_GetGamepadSecondaryActionForType(SDL_GamepadType type) +{ + return SDL_GetGamepadSecondaryActionForFaceStyle(SDL_GetGamepadFaceStyleForGamepadType(type)); +} + +/** + * Get the secondary action button of a gamepad. + */ +SDL_GamepadButton SDL_GetGamepadSecondaryAction(SDL_Gamepad *gamepad) +{ + SDL_GamepadFaceStyle face_style; + + SDL_LockJoysticks(); + { + CHECK_GAMEPAD_MAGIC(gamepad, SDL_GAMEPAD_BUTTON_INVALID); + + face_style = gamepad->face_style; + } + SDL_UnlockJoysticks(); + + return SDL_GetGamepadSecondaryActionForFaceStyle(face_style); +} + /** * Get the number of touchpads on a gamepad. */ diff --git a/test/gamepadutils.c b/test/gamepadutils.c index eba4e80ab464e..9c7ebd836ae37 100644 --- a/test/gamepadutils.c +++ b/test/gamepadutils.c @@ -120,7 +120,7 @@ struct GamepadImage int y; SDL_bool showing_front; SDL_bool showing_touchpad; - GamepadImageFaceStyle face_style; + SDL_GamepadType type; ControllerDisplayMode display_mode; SDL_bool elements[SDL_GAMEPAD_ELEMENT_MAX]; @@ -146,29 +146,6 @@ static SDL_Texture *CreateTexture(SDL_Renderer *renderer, unsigned char *data, u return texture; } -static SDL_GamepadButton GetRemappedButton(GamepadImageFaceStyle face_style, SDL_GamepadButton button) -{ - if (face_style == GAMEPAD_IMAGE_FACE_BAYX) { - switch (button) { - case SDL_GAMEPAD_BUTTON_SOUTH: - button = SDL_GAMEPAD_BUTTON_EAST; - break; - case SDL_GAMEPAD_BUTTON_EAST: - button = SDL_GAMEPAD_BUTTON_SOUTH; - break; - case SDL_GAMEPAD_BUTTON_WEST: - button = SDL_GAMEPAD_BUTTON_NORTH; - break; - case SDL_GAMEPAD_BUTTON_NORTH: - button = SDL_GAMEPAD_BUTTON_WEST; - break; - default: - break; - } - } - return button; -} - GamepadImage *CreateGamepadImage(SDL_Renderer *renderer) { GamepadImage *ctx = SDL_calloc(1, sizeof(*ctx)); @@ -241,22 +218,22 @@ void SetGamepadImageShowingFront(GamepadImage *ctx, SDL_bool showing_front) ctx->showing_front = showing_front; } -void SetGamepadImageFaceStyle(GamepadImage *ctx, GamepadImageFaceStyle face_style) +void SetGamepadImageFaceButtonType(GamepadImage *ctx, SDL_GamepadType type) { if (!ctx) { return; } - ctx->face_style = face_style; + ctx->type = type; } -GamepadImageFaceStyle GetGamepadImageFaceStyle(GamepadImage *ctx) +SDL_GamepadType GetGamepadImageType(GamepadImage *ctx) { if (!ctx) { - return GAMEPAD_IMAGE_FACE_BLANK; + return SDL_GAMEPAD_TYPE_UNKNOWN; } - return ctx->face_style; + return ctx->type; } void SetGamepadImageDisplayMode(GamepadImage *ctx, ControllerDisplayMode display_mode) @@ -407,7 +384,7 @@ int GetGamepadImageElementAt(GamepadImage *ctx, float x, float y) rect.w = (float)ctx->button_width; rect.h = (float)ctx->button_height; if (SDL_PointInRectFloat(&point, &rect)) { - return GetRemappedButton(ctx->face_style, (SDL_GamepadButton)i); + return (SDL_GamepadButton)i; } } } @@ -440,29 +417,14 @@ void UpdateGamepadImageFromGamepad(GamepadImage *ctx, SDL_Gamepad *gamepad) return; } + ctx->type = SDL_GetGamepadType(gamepad); char *mapping = SDL_GetGamepadMapping(gamepad); - SDL_GamepadType gamepad_type = SDL_GetGamepadType(gamepad); - switch (gamepad_type) { - case SDL_GAMEPAD_TYPE_PS3: - case SDL_GAMEPAD_TYPE_PS4: - case SDL_GAMEPAD_TYPE_PS5: - ctx->face_style = GAMEPAD_IMAGE_FACE_SONY; - break; - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO: - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT: - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT: - case SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR: - ctx->face_style = GAMEPAD_IMAGE_FACE_BAYX; - break; - default: - if (mapping && SDL_strstr(mapping, "SDL_GAMECONTROLLER_USE_BUTTON_LABELS")) { - ctx->face_style = GAMEPAD_IMAGE_FACE_BAYX; - } else { - ctx->face_style = GAMEPAD_IMAGE_FACE_ABXY; + if (mapping) { + if (SDL_strstr(mapping, "SDL_GAMECONTROLLER_USE_BUTTON_LABELS")) { + ctx->type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; } - break; + SDL_free(mapping); } - SDL_free(mapping); for (i = 0; i < SDL_GAMEPAD_BUTTON_TOUCHPAD; ++i) { const SDL_GamepadButton button = (SDL_GamepadButton)i; @@ -557,7 +519,7 @@ void RenderGamepadImage(GamepadImage *ctx) for (i = 0; i < SDL_arraysize(button_positions); ++i) { if (ctx->elements[i]) { - SDL_GamepadButton button_position = GetRemappedButton(ctx->face_style, (SDL_GamepadButton)i); + SDL_GamepadButton button_position = (SDL_GamepadButton)i; SDL_bool on_front = SDL_TRUE; if (i >= SDL_GAMEPAD_BUTTON_RIGHT_PADDLE1 && i <= SDL_GAMEPAD_BUTTON_LEFT_PADDLE2) { @@ -579,14 +541,14 @@ void RenderGamepadImage(GamepadImage *ctx) dst.w = (float)ctx->face_width; dst.h = (float)ctx->face_height; - switch (ctx->face_style) { - case GAMEPAD_IMAGE_FACE_ABXY: + switch (SDL_GetGamepadButtonLabelForType(ctx->type, SDL_GAMEPAD_BUTTON_SOUTH)) { + case SDL_GAMEPAD_BUTTON_LABEL_A: SDL_RenderTexture(ctx->renderer, ctx->face_abxy_texture, NULL, &dst); break; - case GAMEPAD_IMAGE_FACE_BAYX: + case SDL_GAMEPAD_BUTTON_LABEL_B: SDL_RenderTexture(ctx->renderer, ctx->face_bayx_texture, NULL, &dst); break; - case GAMEPAD_IMAGE_FACE_SONY: + case SDL_GAMEPAD_BUTTON_LABEL_CROSS: SDL_RenderTexture(ctx->renderer, ctx->face_sony_texture, NULL, &dst); break; default: diff --git a/test/gamepadutils.h b/test/gamepadutils.h index f0b62f9faf761..77ebe1bcb58a0 100644 --- a/test/gamepadutils.h +++ b/test/gamepadutils.h @@ -20,14 +20,6 @@ typedef enum CONTROLLER_MODE_BINDING, } ControllerDisplayMode; -typedef enum -{ - GAMEPAD_IMAGE_FACE_BLANK, - GAMEPAD_IMAGE_FACE_ABXY, - GAMEPAD_IMAGE_FACE_BAYX, - GAMEPAD_IMAGE_FACE_SONY, -} GamepadImageFaceStyle; - enum { SDL_GAMEPAD_ELEMENT_INVALID = -1, @@ -63,8 +55,8 @@ extern GamepadImage *CreateGamepadImage(SDL_Renderer *renderer); extern void SetGamepadImagePosition(GamepadImage *ctx, int x, int y); extern void GetGamepadImageArea(GamepadImage *ctx, SDL_Rect *area); extern void SetGamepadImageShowingFront(GamepadImage *ctx, SDL_bool showing_front); -extern void SetGamepadImageFaceStyle(GamepadImage *ctx, GamepadImageFaceStyle face_style); -extern GamepadImageFaceStyle GetGamepadImageFaceStyle(GamepadImage *ctx); +extern void SetGamepadImageType(GamepadImage *ctx, SDL_GamepadType type); +extern SDL_GamepadType GetGamepadImageType(GamepadImage *ctx); extern void SetGamepadImageDisplayMode(GamepadImage *ctx, ControllerDisplayMode display_mode); extern int GetGamepadImageButtonWidth(GamepadImage *ctx); extern int GetGamepadImageButtonHeight(GamepadImage *ctx); diff --git a/test/testcontroller.c b/test/testcontroller.c index 5b35c2d707789..607046f740a66 100644 --- a/test/testcontroller.c +++ b/test/testcontroller.c @@ -498,8 +498,11 @@ static void CommitBindingElement(const char *binding, SDL_bool force) if (!ignore_binding && binding_flow && !force) { int existing = GetElementForBinding(mapping, binding); if (existing != SDL_GAMEPAD_ELEMENT_INVALID) { - if (existing == SDL_GAMEPAD_BUTTON_SOUTH) { - if (binding_element == SDL_GAMEPAD_BUTTON_SOUTH) { + SDL_GamepadType type = GetGamepadImageType(image); + SDL_GamepadButton action_forward = SDL_GetGamepadPrimaryActionForType(type); + SDL_GamepadButton action_backward = SDL_GetGamepadSecondaryActionForType(type); + if (existing == action_forward) { + if (binding_element == action_forward) { /* Just move on to the next one */ ignore_binding = SDL_TRUE; SetNextBindingElement(); @@ -509,9 +512,9 @@ static void CommitBindingElement(const char *binding, SDL_bool force) direction = 1; force = SDL_TRUE; } - } else if (existing == SDL_GAMEPAD_BUTTON_EAST) { - if (binding_element != SDL_GAMEPAD_BUTTON_SOUTH && - last_binding_element != SDL_GAMEPAD_BUTTON_SOUTH) { + } else if (existing == action_backward) { + if (binding_element != action_forward && + last_binding_element != action_forward) { /* Clear the current binding and move to the previous one */ binding = NULL; direction = -1; @@ -521,8 +524,8 @@ static void CommitBindingElement(const char *binding, SDL_bool force) /* We're rebinding the same thing, just move to the next one */ ignore_binding = SDL_TRUE; SetNextBindingElement(); - } else if (binding_element != SDL_GAMEPAD_BUTTON_SOUTH && - binding_element != SDL_GAMEPAD_BUTTON_EAST) { + } else if (binding_element != action_forward && + binding_element != action_backward) { ignore_binding = SDL_TRUE; } } @@ -702,41 +705,30 @@ static const char *GetBindingInstruction(void) case SDL_GAMEPAD_ELEMENT_INVALID: return "Select an element to bind from the list on the left"; case SDL_GAMEPAD_BUTTON_SOUTH: - switch (GetGamepadImageFaceStyle(image)) { - case GAMEPAD_IMAGE_FACE_SONY: - return "Press the Cross (X) button"; - case GAMEPAD_IMAGE_FACE_BAYX: - return "Press the B button"; - default: - return "Press the A button"; - } case SDL_GAMEPAD_BUTTON_EAST: - switch (GetGamepadImageFaceStyle(image)) { - case GAMEPAD_IMAGE_FACE_SONY: - return "Press the Circle button"; - case GAMEPAD_IMAGE_FACE_BAYX: + case SDL_GAMEPAD_BUTTON_WEST: + case SDL_GAMEPAD_BUTTON_NORTH: + switch (SDL_GetGamepadButtonLabelForType(GetGamepadImageType(image), (SDL_GamepadButton)binding_element)) { + case SDL_GAMEPAD_BUTTON_LABEL_A: return "Press the A button"; - default: + case SDL_GAMEPAD_BUTTON_LABEL_B: return "Press the B button"; - } - case SDL_GAMEPAD_BUTTON_WEST: - switch (GetGamepadImageFaceStyle(image)) { - case GAMEPAD_IMAGE_FACE_SONY: - return "Press the Square button"; - case GAMEPAD_IMAGE_FACE_BAYX: - return "Press the Y button"; - default: + case SDL_GAMEPAD_BUTTON_LABEL_X: return "Press the X button"; - } - case SDL_GAMEPAD_BUTTON_NORTH: - switch (GetGamepadImageFaceStyle(image)) { - case GAMEPAD_IMAGE_FACE_SONY: + case SDL_GAMEPAD_BUTTON_LABEL_Y: + return "Press the Y button"; + case SDL_GAMEPAD_BUTTON_LABEL_CROSS: + return "Press the Cross (X) button"; + case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE: + return "Press the Circle button"; + case SDL_GAMEPAD_BUTTON_LABEL_SQUARE: + return "Press the Square button"; + case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE: return "Press the Triangle button"; - case GAMEPAD_IMAGE_FACE_BAYX: - return "Press the X button"; default: - return "Press the Y button"; + return ""; } + break; case SDL_GAMEPAD_BUTTON_BACK: return "Press the left center button (Back/View/Share)"; case SDL_GAMEPAD_BUTTON_GUIDE: @@ -1302,6 +1294,30 @@ static void DrawGamepadInfo(SDL_Renderer *renderer) } } +static const char *GetButtonLabel(SDL_GamepadType type, SDL_GamepadButton button) +{ + switch (SDL_GetGamepadButtonLabelForType(type, button)) { + case SDL_GAMEPAD_BUTTON_LABEL_A: + return "A"; + case SDL_GAMEPAD_BUTTON_LABEL_B: + return "B"; + case SDL_GAMEPAD_BUTTON_LABEL_X: + return "X"; + case SDL_GAMEPAD_BUTTON_LABEL_Y: + return "Y"; + case SDL_GAMEPAD_BUTTON_LABEL_CROSS: + return "Cross (X)"; + case SDL_GAMEPAD_BUTTON_LABEL_CIRCLE: + return "Circle"; + case SDL_GAMEPAD_BUTTON_LABEL_SQUARE: + return "Square"; + case SDL_GAMEPAD_BUTTON_LABEL_TRIANGLE: + return "Triangle"; + default: + return "UNKNOWN"; + } +} + static void DrawBindingTips(SDL_Renderer *renderer) { const char *text; @@ -1321,7 +1337,6 @@ static void DrawBindingTips(SDL_Renderer *renderer) } else { Uint8 r, g, b, a; SDL_FRect rect; - SDL_bool bound_A, bound_B; y -= (FONT_CHARACTER_SIZE + BUTTON_MARGIN) / 2; @@ -1343,10 +1358,15 @@ static void DrawBindingTips(SDL_Renderer *renderer) } else if (binding_element == SDL_GAMEPAD_ELEMENT_TYPE) { text = "(press ESC to cancel)"; } else { - bound_A = MappingHasElement(controller->mapping, SDL_GAMEPAD_BUTTON_SOUTH); - bound_B = MappingHasElement(controller->mapping, SDL_GAMEPAD_BUTTON_EAST); - if (binding_flow && bound_A && bound_B) { - text = "(press A to skip, B to go back, and ESC to cancel)"; + SDL_GamepadType type = GetGamepadImageType(image); + SDL_GamepadButton action_forward = SDL_GetGamepadPrimaryActionForType(type); + SDL_bool bound_forward = MappingHasElement(controller->mapping, action_forward); + SDL_GamepadButton action_backward = SDL_GetGamepadSecondaryActionForType(type); + SDL_bool bound_backward = MappingHasElement(controller->mapping, action_backward); + if (binding_flow && bound_forward && bound_backward) { + static char dynamic_text[128]; + SDL_snprintf(dynamic_text, sizeof(dynamic_text), "(press %s to skip, %s to go back, and ESC to cancel)", GetButtonLabel(type, action_forward), GetButtonLabel(type, action_backward)); + text = dynamic_text; } else { text = "(press SPACE to clear binding and ESC to cancel)"; }