Skip to content

New gamepad types, button labels, conventional/default "confirm"/"cancel" buttons#15891

Open
nstbayless wants to merge 1 commit into
libsdl-org:mainfrom
nstbayless:additional-gamepad-layouts
Open

New gamepad types, button labels, conventional/default "confirm"/"cancel" buttons#15891
nstbayless wants to merge 1 commit into
libsdl-org:mainfrom
nstbayless:additional-gamepad-layouts

Conversation

@nstbayless

@nstbayless nstbayless commented Jun 26, 2026

Copy link
Copy Markdown
  • I confirm that I am the author of this code and release it to the SDL project under the Zlib license. This contribution does not contain code from other sources, including code generated by a Large Language Model ("AI").

Description

It's a long-standing problem that games don't properly respect "confirm" and "cancel" buttons on some gamepad types (they'll either assume xbox convention of EAST=cancel, SOUTH=confirm; or, more rarely -- but I've seen this on some recent steam demos for example -- nintendo convention of EAST=confirm and SOUTH=cancel). Additionally, games have to roll their own detection of gamepad type to determine what kind of glyphs to show.

This is particularly bothersome when using, for example, a SNES controller with a usb adaptor, or other retro gamepads with USB adaptors. It's not common for games to detect these more rare kinds of gamepads. Sega layout in particular tends to confuse games.

I'd like to make progress toward the eventual goal of having SDL be able to identify exactly what glyphs should be shown (even if SDL doesn't itself ship with the actual glyphs), and make it easier for game devs to identify and handle different gamepad types more broadly.

New Gamepad Types

I've added a handful of gamepad type enums that I think are famous and interesting enough to warrant supporting their glyphs, and not similar enough to any existing gamepad to be able to be rolled into e.g. the standard or xbox 360 layout. This includes: NES, SNES, N64, SEGA Master System, Sega Genesis, Sega Saturn, TurboGrafx-16, Neo Geo, and 3DO.

I've also clarified the comments here a bit to reflect what I've found in the code and the standard practices in SDL GamepadControllerDB.

New Gamepad Button Labels

There was already some work in this direction in SDL, but it was incomplete. I've fleshed it out now, adding all the most common button labels I've encountered, including all button labels used by the gamepad types above. I've also added labels for numbers 1-9 even though only some of those are actually used by supported controllers right now, under the expectation that they'll eventually gain support in the future. (For example, atari/jaguar models with keypads 1-9? Or arcade gamepads?)

"Conventional Actions"

For common UI actions that are platform-dependent. For now, I've just added "confirm" and "cancel" (since these are generally either SOUTH/EAST or EAST/SOUTH, though on gamecube it's SOUTH/WEST) but I could see onscreen keyboard controls being added to this too. For PS4 (and PS3?) it's region-dependent, so users in japan with a PS4 controller will get the expected CIRCLE=confirm, CROSS=cancel.

Removals

  • Removed "face:" field in db; it seems like this basically wasn't used anyway and it's less info than is in the new "type:" field.

Lingering Issues

  • Axes don't get labels yet. There's no way to know, for example, that what SDL calls "left trigger" is actually the sega genesis "R" button. (It seems weird to me, but that's actually the standard for some reason!)
  • db can now be updated with tags like type:snes and so on. This was suggested in an issue for the DB before, but it was suggested to be pushed upstream to SDL first I think?
  • Since SDL3 is moving away from "a/b/x/y" notation in favour of the more general "south/east/west/north" notation, it'd be nice to let the gamepad db use that notation too instead, e.g. "south:b0".
  • What is a SDL_GAMEPAD_TYPE_STEAM? Is it any controller under steam input, or only steam controller? steam deck? SC1 and SC2 have different button labels... Not sure what to do here!
  • SDL_GetGamepadButtonFromString seems broken to me... it turns a button string into its enum equivalent, but for some reason also takes into account abxy/axby arrangement? and doesn't handle playstation button names? I'm not sure what it's even trying to achieve here. I think this is all caused by not using compass notation and somebody got confused.

@icculus

icculus commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

I don't know that we need all the different controller layouts (but I'm not necessarily against it), but I do like the confirm/cancel idea.

@nstbayless

Copy link
Copy Markdown
Author

Okay, I can roll SNES/NES into one gamepad type; Saturn/Genesis into one gamepad type; and postpone Master System/TurboGrafx-16/Neo Geo/3DO to a later PR if we're not sure about those yet (they're definitely less common). But at least SNES, Sega, and N64 are important to codify IMO, they're very common, and Sega layout even has documentation on the db readme, and relevant to the confirm/cancel convention.

@icculus

icculus commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

Let's hold off until @slouken chimes in.

I don't think having this list is useless, because (for example) a Genesis controller doesn't map well to modern gamepads and that's worth knowing if you hit this situation, but I also wonder if games will be interested in offering that level of customization when the gamepad API is meant to avoid those details. Also, I worry about the slippery slope of the whole thing. But that's not me saying it's a bad idea!

But no matter what else, I definitely want the confirm/cancel functionality. This has come up for me multiple times on shipping console titles.

@cgutman

cgutman commented Jun 27, 2026

Copy link
Copy Markdown
Collaborator

We could also add SDL_GamepadConventionalAction values for primary/secondary menu buttons. For example, games typically use SDL_GAMEPAD_BUTTON_TOUCHPAD for accessing in-game inventory, map, etc. on PS4/PS5 controllers, while they use SDL_GAMEPAD_BUTTON_BACK for the inventory/map on Xbox.

Comment on lines +3847 to +3874
static bool SDL_GamepadLocaleIsJP(void)
{
int count = 0;
int i;
SDL_Locale **locales = SDL_GetPreferredLocales(&count);

face_style = gamepad->face_style;
// check if first locale which specifies a country is jp
if (locales) {
for (i = 0; i < count; ++i)
{
if (locales[i]->country)
{
if (SDL_strcasecmp(locales[i]->country, "jp") == 0)
{
SDL_free(locales);
return true;
}
else
{
SDL_free(locales);
return false;
}
}
}
SDL_free(locales);
}
SDL_UnlockJoysticks();
return false;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
static bool SDL_GamepadLocaleIsJP(void)
{
int count = 0;
int i;
SDL_Locale **locales = SDL_GetPreferredLocales(&count);
face_style = gamepad->face_style;
// check if first locale which specifies a country is jp
if (locales) {
for (i = 0; i < count; ++i)
{
if (locales[i]->country)
{
if (SDL_strcasecmp(locales[i]->country, "jp") == 0)
{
SDL_free(locales);
return true;
}
else
{
SDL_free(locales);
return false;
}
}
}
SDL_free(locales);
}
SDL_UnlockJoysticks();
return false;
}
static bool SDL_GamepadLocaleIsJP(void)
{
bool japanese_locale = false;
SDL_Locale **locales = SDL_GetPreferredLocales(NULL);
// check if first locale which specifies a country is jp
if (locales) {
for (int i = 0; locales[i]; ++i) {
if (locales[i]->country) {
if (SDL_strcasecmp(locales[i]->country, "jp") == 0) {
japanese_locale = true;
}
break;
}
}
SDL_free(locales);
}
return japanese_locale;
}

@slouken

slouken commented Jun 28, 2026

Copy link
Copy Markdown
Collaborator

My first impression is that this is a little much, but let me think on it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants