Просмотр исходного кода

Added support for several Turtle Beach Nintendo Switch 2 controllers

* Turtle Beach Afterglow Wired Controller for Nintendo Switch 2
* Turtle Beach Afterglow Wave Wired Controller for Nintendo Switch 2
* Turtle Beach Afterglow Wireless RGB Gaming Controller for Nintendo Switch 2
* Turtle Beach Rematch Wired Controller for Nintendo Switch 2
* Turtle Beach Rematch Wireless RGB Gaming Controller for Nintendo Switch 2
Sam Lantinga 3 дней назад
Родитель
Сommit
1be08afec5

+ 1 - 0
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;

+ 5 - 1
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));

+ 14 - 1
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);

+ 2 - 0
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);

+ 4 - 0
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

+ 1 - 0
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

+ 33 - 4
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]) {