diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 7574adc6c0..a4d86688c7 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -1043,6 +1043,27 @@ static void CleanupSensorFusion(SDL_Joystick *joystick) } } +static bool ShouldSwapFaceButtons(const SDL_SteamVirtualGamepadInfo *info) +{ + // When "Use Nintendo Button Layout" is enabled under Steam (the default) + // it will send button 0 for the A (east) button and button 1 for the + // B (south) button. This is done so that games that interpret the + // buttons as Xbox input will get button 0 for "A" as they expect. + // + // However, SDL reports positional buttons, so we need to swap + // the buttons so they show up in the correct position. This provides + // consistent behavior regardless of whether we're running under Steam, + // under the default settings. + if (info && + (info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO || + info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_LEFT || + info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_RIGHT || + info->type == SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_JOYCON_PAIR)) { + return true; + } + return false; +} + /* * Open a joystick for use - the index passed as an argument refers to * the N'th joystick on the system. This index is the value which will @@ -1148,6 +1169,7 @@ SDL_Joystick *SDL_OpenJoystick(SDL_JoystickID instance_id) info = SDL_GetJoystickVirtualGamepadInfoForID(instance_id); if (info) { joystick->steam_handle = info->handle; + joystick->swap_face_buttons = ShouldSwapFaceButtons(info); } // Use system gyro and accelerometer if the gamepad doesn't have built-in sensors @@ -2305,6 +2327,25 @@ void SDL_SendJoystickButton(Uint64 timestamp, SDL_Joystick *joystick, Uint8 butt event.type = SDL_EVENT_JOYSTICK_BUTTON_UP; } + if (joystick->swap_face_buttons) { + switch (button) { + case 0: + button = 1; + break; + case 1: + button = 0; + break; + case 2: + button = 3; + break; + case 3: + button = 2; + break; + default: + break; + } + } + // Make sure we're not getting garbage or duplicate events if (button >= joystick->nbuttons) { return; @@ -2353,11 +2394,13 @@ static void SendSteamHandleUpdateEvents(void) if (info) { if (joystick->steam_handle != info->handle) { joystick->steam_handle = info->handle; + joystick->swap_face_buttons = ShouldSwapFaceButtons(info); changed = true; } } else { if (joystick->steam_handle != 0) { joystick->steam_handle = 0; + joystick->swap_face_buttons = false; changed = true; } } diff --git a/src/joystick/SDL_sysjoystick.h b/src/joystick/SDL_sysjoystick.h index 343d2061e7..97f145de9a 100644 --- a/src/joystick/SDL_sysjoystick.h +++ b/src/joystick/SDL_sysjoystick.h @@ -83,6 +83,7 @@ struct SDL_Joystick SDL_GUID guid _guarded; // Joystick guid Uint16 firmware_version _guarded; // Firmware version, if available Uint64 steam_handle _guarded; // Steam controller API handle + bool swap_face_buttons _guarded; // Whether we should swap face buttons int naxes _guarded; // Number of axis controls on the joystick SDL_JoystickAxisInfo *axes _guarded;