Skip to content

Commit 43f3da0

Browse files
committed
sinput: allow dynamic loading, defining of subtypes/states for controllers
Add a controller type for sinput to allow loading the driver dynamically via an environment variable override. Then, cleanup the mapping code in SDL_gamepad.c and SDL_hidapi_sinput.c by placing the vid:pid and subtype logic in HIDAPI_DriverSInput_GetControllerType. This function can arbitrarily decide the layout and face style of a controller based on its vid, pid, version, and subtype. This allows for up to 65336 different combinations of controller types/face styles per vid:pid. Then, add 8 controller layouts and face styles for the vid:pid pair 0x16d0:0x145b that will be used to virtually test the sinput driver. To defer making a decision, for other vid:pid pairs, FullMapping will always be used, except for the generic sinput pid, which will load different face styles based on the upper three bits of subtype.
1 parent 23e08f7 commit 43f3da0

File tree

7 files changed

+264
-94
lines changed

7 files changed

+264
-94
lines changed

src/joystick/SDL_gamepad.c

Lines changed: 49 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#include "controller_type.h"
3131
#include "usb_ids.h"
3232
#include "hidapi/SDL_hidapi_nintendo.h"
33+
#include "hidapi/SDL_hidapi_sinput.h"
3334
#include "../events/SDL_events_c.h"
3435

3536

@@ -697,10 +698,11 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
697698
char mapping_string[1024];
698699
Uint16 vendor;
699700
Uint16 product;
701+
Uint16 version;
700702

701703
SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string));
702704

703-
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL);
705+
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, &version, NULL);
704706

705707
if (SDL_IsJoystickWheel(vendor, product)) {
706708
// We don't want to pick up Logitech FFB wheels here
@@ -799,55 +801,63 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
799801
// This controller has no guide button
800802
SDL_strlcat(mapping_string, "a:b1,b:b0,back:b4,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b9,leftstick:b7,lefttrigger:a4,leftx:a0,lefty:a1,rightshoulder:b10,rightstick:b8,righttrigger:a5,rightx:a2,righty:a3,start:b6,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
801803
} else if (SDL_IsJoystickSInputController(vendor, product)) {
802-
Uint8 face_style = (guid.data[15] & 0xE0) >> 5;
803-
Uint8 sub_type = guid.data[15] & 0x1F;
804+
ESinputControllerType controller_type;
805+
ESinputFaceStyle face_style;
806+
HIDAPI_DriverSInput_GetControllerType(vendor, product, version, guid.data[15], &controller_type, &face_style);
807+
808+
// Apply mapping profile for type
809+
switch (controller_type) {
810+
case k_eSInputControllerType_XInputOnly:
811+
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,start:b8,back:b9,guide:b10,", sizeof(mapping_string));
812+
break;
813+
case k_eSInputControllerType_XInputShareNone:
814+
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,start:b8,back:b9,guide:b10,misc1:b11,", sizeof(mapping_string));
815+
break;
816+
case k_eSInputControllerType_XInputShareDual:
817+
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b8,paddle2:b9,start:b10,back:b11,guide:b12,misc1:b13,", sizeof(mapping_string));
818+
break;
819+
case k_eSInputControllerType_XInputShareQuad:
820+
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b8,paddle2:b9,start:b10,back:b11,guide:b12,misc1:b13,paddle3:b14,paddle4:b15,", sizeof(mapping_string));
821+
break;
822+
case k_eSInputControllerType_XInputShareNoneClick:
823+
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,start:b8,back:b9,guide:b10,misc1:b11,touchpad:b12,", sizeof(mapping_string));
824+
break;
825+
case k_eSInputControllerType_XInputShareDualClick:
826+
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b8,paddle2:b9,start:b10,back:b11,guide:b12,misc1:b13,touchpad:b14,", sizeof(mapping_string));
827+
break;
828+
case k_eSInputControllerType_XInputShareQuadClick:
829+
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b8,paddle2:b9,start:b10,back:b11,guide:b12,misc1:b13,paddle3:b14,paddle4:b15,touchpad:b16,", sizeof(mapping_string));
830+
break;
831+
case k_eSInputControllerType_HHL_PROGCC:
832+
SDL_strlcat(mapping_string, "a:b1,b:b0,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
833+
break;
834+
case k_eSInputControllerType_HHL_GCCULT:
835+
SDL_strlcat(mapping_string, "a:b0,b:b2,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b7,rightstick:b5,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b1,y:b3,misc3:b8,misc4:b9,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
836+
break;
837+
default:
838+
case k_eSInputControllerType_FullMapping:
839+
// Default Fully Exposed Mapping
840+
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b10,paddle2:b11,start:b12,back:b13,guide:b14,misc1:b15,paddle3:b16,paddle4:b17,touchpad:b18,misc2:b19,misc3:b20,misc4:b21,misc5:b22,misc6:b23", sizeof(mapping_string));
841+
break;
842+
}
804843

805-
// Apply face style according to gamepad response
844+
// Apply face style
806845
switch (face_style) {
807-
default:
846+
case k_eSInputFaceStyle_abxy:
808847
SDL_strlcat(mapping_string, "face:abxy,", sizeof(mapping_string));
809848
break;
810-
case 2:
849+
case k_eSInputFaceStyle_axby:
811850
SDL_strlcat(mapping_string, "face:axby,", sizeof(mapping_string));
812851
break;
813-
case 3:
852+
case k_eSInputFaceStyle_bayx:
814853
SDL_strlcat(mapping_string, "face:bayx,", sizeof(mapping_string));
815854
break;
816-
case 4:
855+
case k_eSInputFaceStyle_sony:
817856
SDL_strlcat(mapping_string, "face:sony,", sizeof(mapping_string));
818857
break;
819-
}
820-
821-
switch (product) {
822-
case USB_PRODUCT_HANDHELDLEGEND_PROGCC:
823-
switch (sub_type) {
824-
default:
825-
// ProGCC Primary Mapping
826-
SDL_strlcat(mapping_string, "a:b1,b:b0,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:b8,leftx:a0,lefty:a1,misc1:b13,rightshoulder:b7,rightstick:b5,righttrigger:b9,rightx:a2,righty:a3,start:b10,x:b3,y:b2,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
827-
break;
828-
}
829-
break;
830-
case USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE:
831-
switch (sub_type) {
832-
default:
833-
// GC Ultimate Primary Map
834-
SDL_strlcat(mapping_string, "a:b0,b:b2,back:b11,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b6,leftstick:b4,lefttrigger:a4,leftx:a0,lefty:a1,misc1:b13,misc2:b14,rightshoulder:b7,rightstick:b5,righttrigger:a5,rightx:a2,righty:a3,start:b10,x:b1,y:b3,misc3:b8,misc4:b9,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
835-
break;
836-
}
837-
break;
838-
case USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC:
839-
switch (sub_type) {
840-
default:
841-
// Default Fully Exposed Mapping (Development Purposes)
842-
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,b:b0,a:b1,y:b2,x:b3,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftstick:b4,rightstick:b5,leftshoulder:b6,rightshoulder:b7,paddle1:b10,paddle2:b11,start:b12,back:b13,guide:b14,misc1:b15,paddle3:b16,paddle4:b17,touchpad:b18,misc2:b19,misc3:b20,misc4:b21,misc5:b22,misc6:b23", sizeof(mapping_string));
843-
break;
844-
}
845-
break;
846-
847-
case USB_PRODUCT_BONZIRICHANNEL_FIREBIRD:
858+
case k_eSInputFaceStyle_ukwn:
848859
default:
849-
// Unmapped device
850-
return NULL;
860+
break;
851861
}
852862
} else {
853863
// All other gamepads have the standard set of 19 buttons and 6 axes

src/joystick/SDL_joystick.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3216,7 +3216,9 @@ bool SDL_IsJoystickSInputController(Uint16 vendor_id, Uint16 product_id)
32163216
return true;
32173217
}
32183218
}
3219-
return false;
3219+
3220+
EControllerType eType = GuessControllerType(vendor_id, product_id);
3221+
return eType == k_eControllerType_Sinput;
32203222
}
32213223

32223224
bool SDL_IsJoystickFlydigiController(Uint16 vendor_id, Uint16 product_id)

src/joystick/controller_list.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -598,4 +598,7 @@ static const ControllerDescription_t arrControllers[] = {
598598
{ MAKE_CONTROLLER_ID( 0x28de, 0x1201 ), k_eControllerType_SteamControllerV2, NULL }, // Valve wired Steam Controller (HEADCRAB)
599599
{ MAKE_CONTROLLER_ID( 0x28de, 0x1202 ), k_eControllerType_SteamControllerV2, NULL }, // Valve Bluetooth Steam Controller (HEADCRAB)
600600
{ MAKE_CONTROLLER_ID( 0x28de, 0x1205 ), k_eControllerType_SteamControllerNeptune, NULL }, // Valve Steam Deck Builtin Controller
601+
602+
// Sinput controllers
603+
{ MAKE_CONTROLLER_ID( 0x16d0, 0x145b ), k_eControllerType_Sinput, NULL },
601604
};

src/joystick/controller_type.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,10 @@ EControllerType GuessControllerType( int nVID, int nPID )
106106
{
107107
return k_eControllerType_SteamController;
108108
}
109+
if ( SDL_strncasecmp( pszOverride, "sinput", 5 ) == 0 )
110+
{
111+
return k_eControllerType_Sinput;
112+
}
109113
return k_eControllerType_UnknownNonSteamController;
110114
}
111115

src/joystick/controller_type.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ typedef enum
5757
k_eControllerType_XInputSwitchController = 44, // Client-side only, used to mark Nintendo Switch style controllers as using XInput instead of the Nintendo Switch protocol
5858
k_eControllerType_PS5Controller = 45,
5959
k_eControllerType_XInputPS4Controller = 46, // Client-side only, used to mark DualShock 4 style controllers using XInput instead of the DualShock 4 controller protocol
60+
k_eControllerType_Sinput = 47,
6061
k_eControllerType_LastController, // Don't add game controllers below this enumeration - this enumeration can change value
6162

6263
// Keyboards and Mice

0 commit comments

Comments
 (0)