diff --git a/src/SDL_utils.c b/src/SDL_utils.c index 50bfc8f5d5..fdad1e57ad 100644 --- a/src/SDL_utils.c +++ b/src/SDL_utils.c @@ -500,6 +500,7 @@ char *SDL_CreateDeviceName(Uint16 vendor, Uint16 product, const char *vendor_nam { "Performance Designed Products", "PDP" }, { "QANBA USA, LLC", "Qanba" }, { "QANBA USA,LLC", "Qanba" }, + { "Voyetra Turtle Beach,Inc.", "Turtle Beach" }, { "Unknown ", "" }, }; char *name = NULL; diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index e948fb13f1..2a693c28bb 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -717,7 +717,7 @@ static GamepadMapping_t *SDL_CreateMappingForAndroidGamepad(SDL_GUID guid) int button_mask; int axis_mask; Uint16 vendor, product; - + SDL_strlcpy(mapping_string, "none,", sizeof(mapping_string)); SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL); @@ -1265,6 +1265,10 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid) SDL_IsJoystickNintendoSwitchProInputOnly(vendor, product)) { // Nintendo Switch Pro controllers have a screenshot button SDL_strlcat(mapping_string, "misc1:b11,", sizeof(mapping_string)); + } else if (SDL_IsJoystickNintendoSwitch2Pro(vendor, product) || + SDL_IsJoystickNintendoSwitch2ProInputOnly(vendor, product)) { + // Nintendo Switch 2 Pro controllers have a screenshot button and C button + SDL_strlcat(mapping_string, "misc1:b11,misc2:b12", sizeof(mapping_string)); } else if (SDL_IsJoystickNintendoSwitchJoyConPair(vendor, product)) { // The Nintendo Switch Joy-Con combined controllers has a share button and paddles SDL_strlcat(mapping_string, "misc1:b11,paddle1:b12,paddle2:b13,paddle3:b14,paddle4:b15,", sizeof(mapping_string)); diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index fe46370652..c8ad87bd49 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -3131,6 +3131,7 @@ SDL_GamepadType SDL_GetGamepadTypeFromVIDPID(Uint16 vendor, Uint16 product, cons case k_eControllerType_SwitchProController: case k_eControllerType_Switch2ProController: case k_eControllerType_SwitchInputOnlyController: + case k_eControllerType_Switch2InputOnlyController: type = SDL_GAMEPAD_TYPE_NINTENDO_SWITCH_PRO; break; case k_eControllerType_XInputSwitchController: @@ -3255,16 +3256,28 @@ bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id) { EControllerType eType = GuessControllerType(vendor_id, product_id); return eType == k_eControllerType_SwitchProController || - eType == k_eControllerType_Switch2ProController || eType == k_eControllerType_SwitchInputOnlyController; } +bool SDL_IsJoystickNintendoSwitch2Pro(Uint16 vendor_id, Uint16 product_id) +{ + EControllerType eType = GuessControllerType(vendor_id, product_id); + return eType == k_eControllerType_Switch2ProController || + eType == k_eControllerType_Switch2InputOnlyController; +} + bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id) { EControllerType eType = GuessControllerType(vendor_id, product_id); return eType == k_eControllerType_SwitchInputOnlyController; } +bool SDL_IsJoystickNintendoSwitch2ProInputOnly(Uint16 vendor_id, Uint16 product_id) +{ + EControllerType eType = GuessControllerType(vendor_id, product_id); + return eType == k_eControllerType_Switch2InputOnlyController; +} + bool SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id) { EControllerType eType = GuessControllerType(vendor_id, product_id); diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 69e42b0209..c4d940edfa 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -107,7 +107,9 @@ extern bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id); // Function to return whether a joystick is a Nintendo Switch Pro controller extern bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id); +extern bool SDL_IsJoystickNintendoSwitch2Pro(Uint16 vendor_id, Uint16 product_id); extern bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id); +extern bool SDL_IsJoystickNintendoSwitch2ProInputOnly(Uint16 vendor_id, Uint16 product_id); extern bool SDL_IsJoystickNintendoSwitchJoyCon(Uint16 vendor_id, Uint16 product_id); extern bool SDL_IsJoystickNintendoSwitchJoyConLeft(Uint16 vendor_id, Uint16 product_id); extern bool SDL_IsJoystickNintendoSwitchJoyConRight(Uint16 vendor_id, Uint16 product_id); diff --git a/src/joystick/controller_list.h b/src/joystick/controller_list.h index 3ef20db39c..c0093acda4 100644 --- a/src/joystick/controller_list.h +++ b/src/joystick/controller_list.h @@ -623,6 +623,10 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x0e6f, 0x0188 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PDP Afterglow Wired Deluxe+ Audio Controller { MAKE_CONTROLLER_ID( 0x0e6f, 0x018b ), k_eControllerType_SwitchProController, NULL }, // PDP Afterglow Wave Wireless Controller for Switch { MAKE_CONTROLLER_ID( 0x0e6f, 0x018c ), k_eControllerType_SwitchProController, "PDP REALMz Wireless Controller" }, // PDP REALMz Wireless Controller for Switch + { MAKE_CONTROLLER_ID( 0x0e6f, 0x0193 ), k_eControllerType_Switch2ProController, NULL }, // Turtle Beach Afterglow Wireless RGB Gaming Controller for Nintendo Switch 2 and the Turtle Beach Rematch Wireless RGB Gaming Controller for Nintendo Switch 2 + { MAKE_CONTROLLER_ID( 0x0e6f, 0x0196 ), k_eControllerType_Switch2InputOnlyController, NULL }, // Turtle Beach Rematch Wired Controller for Nintendo Switch 2 + { MAKE_CONTROLLER_ID( 0x0e6f, 0x0197 ), k_eControllerType_Switch2InputOnlyController, NULL }, // Turtle Beach Afterglow Wave Wired Controller for Nintendo Switch 2 + { MAKE_CONTROLLER_ID( 0x0e6f, 0x0198 ), k_eControllerType_Switch2InputOnlyController, NULL }, // Turtle Beach Afterglow Wired Controller for Switch 2 { MAKE_CONTROLLER_ID( 0x0f0d, 0x00aa ), k_eControllerType_SwitchInputOnlyController, NULL }, // HORI Real Arcade Pro V Hayabusa in Switch Mode { MAKE_CONTROLLER_ID( 0x20d6, 0xa711 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Wired Controller Plus/PowerA Wired Controller Nintendo GameCube Style { MAKE_CONTROLLER_ID( 0x20d6, 0xa712 ), k_eControllerType_SwitchInputOnlyController, NULL }, // PowerA Nintendo Switch Fusion Fight Pad diff --git a/src/joystick/controller_type.h b/src/joystick/controller_type.h index 028a83dfac..94d75dafcb 100644 --- a/src/joystick/controller_type.h +++ b/src/joystick/controller_type.h @@ -64,6 +64,7 @@ typedef enum k_eControllerType_HoriSteamController = 49, k_eControllerType_8BitDoController = 50, k_eControllerType_Switch2ProController = 51, + k_eControllerType_Switch2InputOnlyController = 52, k_eControllerType_LastController, // Don't add game controllers below this enumeration - this enumeration can change value // Keyboards and Mice diff --git a/src/joystick/hidapi/SDL_hidapi_switch.c b/src/joystick/hidapi/SDL_hidapi_switch.c index 5b0b5bfa95..fe895dbbff 100644 --- a/src/joystick/hidapi/SDL_hidapi_switch.c +++ b/src/joystick/hidapi/SDL_hidapi_switch.c @@ -73,6 +73,19 @@ enum SDL_GAMEPAD_NUM_SWITCH_BUTTONS, }; +enum +{ + SDL_GAMEPAD_BUTTON_SWITCH_INPUT_ONLY_SHARE = 11, + SDL_GAMEPAD_NUM_SWITCH_INPUT_ONLY_BUTTONS, +}; + +enum +{ + SDL_GAMEPAD_BUTTON_SWITCH2_SHARE = 11, + SDL_GAMEPAD_BUTTON_SWITCH2_C, + SDL_GAMEPAD_NUM_SWITCH2_BUTTONS, +}; + typedef enum { k_eSwitchInputReportIDs_SubcommandReply = 0x21, @@ -286,6 +299,7 @@ typedef struct SDL_HIDAPI_Device *device; SDL_Joystick *joystick; bool m_bInputOnly; + bool m_bSwitch2; bool m_bUseButtonLabels; bool m_bPlayerLights; int m_nPlayerIndex; @@ -1425,7 +1439,7 @@ static bool HIDAPI_DriverSwitch_IsSupportedDevice(SDL_HIDAPI_Device *device, con controller to continually attempt to reconnect is to filter it out by manufacturer/product string. Note that the controller does have a different product string when connected over Bluetooth. */ - if (SDL_strcmp(name, "HORI Wireless Switch Pad") == 0) { + if (name && SDL_strcmp(name, "HORI Wireless Switch Pad") == 0) { return false; } @@ -1561,7 +1575,9 @@ static bool HIDAPI_DriverSwitch_InitDevice(SDL_HIDAPI_Device *device) ctx->m_bSyncWrite = true; // Find out whether or not we can send output reports - ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id); + ctx->m_bSwitch2 = SDL_IsJoystickNintendoSwitch2Pro(device->vendor_id, device->product_id); + ctx->m_bInputOnly = SDL_IsJoystickNintendoSwitchProInputOnly(device->vendor_id, device->product_id) || + SDL_IsJoystickNintendoSwitch2ProInputOnly(device->vendor_id, device->product_id); if (!ctx->m_bInputOnly) { // Initialize rumble data, important for reading device info on the MOBAPAD M073 SetNeutralRumble(device, &ctx->m_RumblePacket.rumbleData[0]); @@ -1689,7 +1705,13 @@ static bool HIDAPI_DriverSwitch_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys SDL_PlayerLEDHintChanged, ctx); // Initialize the joystick capabilities - joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH_BUTTONS; + if (ctx->m_bSwitch2) { + joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH2_BUTTONS; + } else if (ctx->m_bInputOnly) { + joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH_INPUT_ONLY_BUTTONS; + } else { + joystick->nbuttons = SDL_GAMEPAD_NUM_SWITCH_BUTTONS; + } joystick->naxes = SDL_GAMEPAD_AXIS_COUNT; joystick->nhats = 1; @@ -1944,7 +1966,11 @@ static void HandleInputOnlyControllerState(SDL_Joystick *joystick, SDL_DriverSwi if (packet->ucStickHat != ctx->m_lastInputOnlyState.ucStickHat) { Uint8 hat; - switch (packet->ucStickHat) { + if (ctx->m_bSwitch2) { + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_C, ((packet->ucStickHat & 0x80) != 0)); + } + + switch (packet->ucStickHat & 0x0F) { case 0: hat = SDL_HAT_UP; break; @@ -2596,6 +2622,9 @@ static void HandleFullControllerState(SDL_Joystick *joystick, SDL_DriverSwitch_C SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_GUIDE, ((data & 0x10) != 0)); SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH_SHARE, ((data & 0x20) != 0)); + if (ctx->m_bSwitch2) { + SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_SWITCH2_C, ((data & 0x40) != 0)); + } } if (packet->controllerState.rgucButtons[2] != ctx->m_lastFullState.controllerState.rgucButtons[2]) {