Skip to content

Commit d0e3af5

Browse files
committed
sinput: add capability sub_types for most common controllers
The previous commit 6e66d80 ("sinput: refactor to make unknown controllers fully dynamic") introduces the ability to add dynamic capabilities for uknown controllers without hardcoding them to SDL. This commit introduces 8 major types of controller capabilities that are found in the market. Specifically, it adds a normal XInput capability map. Then, it adds XInput + share, which covers most handhelds without extra buttons, switch controllers, and new Xbox controllers. Following, it adds combinations with 2 and 4 paddles, which include e.g., devices such as the Legion Go S and Stadia controllers with 2 paddles, and Legion Go/Xbox Elite with 4 paddles. Finally, it adds the same paddle combos + clicks, where e.g., click + 2 paddles covers the Go S when emulating the touchpad and click + 4 paddles covers the dualsense edge controller capabilities fully.
1 parent 2f53f0a commit d0e3af5

File tree

3 files changed

+107
-23
lines changed

3 files changed

+107
-23
lines changed

src/joystick/SDL_gamepad.c

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -818,7 +818,28 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
818818
// Apply mapping profile for type
819819
switch (sinput_id) {
820820
default:
821-
case 0:
821+
case SDL_SUBTYPE_XINPUT_ONLY:
822+
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));
823+
break;
824+
case SDL_SUBTYPE_XINPUT_SHARE_NONE:
825+
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));
826+
break;
827+
case SDL_SUBTYPE_XINPUT_SHARE_DUAL:
828+
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));
829+
break;
830+
case SDL_SUBTYPE_XINPUT_SHARE_QUAD:
831+
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));
832+
break;
833+
case SDL_SUBTYPE_XINPUT_SHARE_NONE_CLICK:
834+
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));
835+
break;
836+
case SDL_SUBTYPE_XINPUT_SHARE_DUAL_CLICK:
837+
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));
838+
break;
839+
case SDL_SUBTYPE_XINPUT_SHARE_QUAD_CLICK:
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:b8,paddle2:b9,start:b10,back:b11,guide:b12,misc1:b13,paddle3:b14,paddle4:b15,touchpad:b16,", sizeof(mapping_string));
841+
break;
842+
case SDL_SUBTYPE_FULL_MAPPING:
822843
// Default Fully Exposed Mapping
823844
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));
824845
break;

src/joystick/SDL_joystick_c.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,26 @@ extern "C" {
3434
struct SDL_JoystickDriver;
3535
struct SDL_SteamVirtualGamepadInfo;
3636

37+
// Subtypes define the buttons and axes available on the device to
38+
// generate a mapping string. Everything else is dynamic.
39+
// Xinput means all Xbox360 buttons.
40+
// Xinput_share adds a share button, and then dual, quad add 2, 4 paddles
41+
// to those. Click adds a touchpad click. Touchpad is not used in the name
42+
// because not all of them have clicks. In fact, there are no controllers
43+
// with dual touchpads w/ clicks so there is no point in adding them. Yet.
44+
typedef enum
45+
{
46+
SDL_SUBTYPE_FULL_MAPPING = 0x00,
47+
SDL_SUBTYPE_XINPUT_ONLY = 0x01,
48+
SDL_SUBTYPE_XINPUT_SHARE_NONE = 0x02,
49+
SDL_SUBTYPE_XINPUT_SHARE_DUAL = 0x03,
50+
SDL_SUBTYPE_XINPUT_SHARE_QUAD = 0x04,
51+
SDL_SUBTYPE_XINPUT_SHARE_NONE_CLICK = 0x05,
52+
SDL_SUBTYPE_XINPUT_SHARE_DUAL_CLICK = 0x06,
53+
SDL_SUBTYPE_XINPUT_SHARE_QUAD_CLICK = 0x07,
54+
SDL_SUBTYPE_LOAD_FIRMWARE = 0xff,
55+
} SDL_GamepadSubType;
56+
3757
// Initialization and shutdown functions
3858
extern bool SDL_InitJoysticks(void);
3959
extern void SDL_QuitJoysticks(void);

src/joystick/hidapi/SDL_hidapi_sinput.c

Lines changed: 65 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -296,30 +296,73 @@ static void ProcessSDLFeaturesResponse(SDL_HIDAPI_Device *device, Uint8 *data)
296296
device->product_id == USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE
297297
);
298298
if (known)
299-
ctx->sub_type = 0xFF;
299+
ctx->sub_type = SDL_SUBTYPE_LOAD_FIRMWARE;
300300

301301
switch (ctx->sub_type) {
302-
case 0xFF:
303-
ctx->usage_masks[0] = buttons[0];
304-
ctx->usage_masks[1] = buttons[1];
305-
ctx->usage_masks[2] = buttons[2];
306-
ctx->usage_masks[3] = buttons[3];
307-
ctx->left_analog_stick_supported = left_analog_stick_supported;
308-
ctx->right_analog_stick_supported = right_analog_stick_supported;
309-
ctx->left_analog_trigger_supported = left_analog_trigger_supported;
310-
ctx->right_analog_trigger_supported = right_analog_trigger_supported;
311-
break;
312-
default:
313-
ctx->usage_masks[0] = 0xFF;
314-
ctx->usage_masks[1] = 0xFF;
315-
ctx->usage_masks[2] = 0xFF;
316-
ctx->usage_masks[3] = 0xFF;
317-
ctx->left_analog_stick_supported = true;
318-
ctx->right_analog_stick_supported = true;
319-
ctx->left_analog_trigger_supported = true;
320-
ctx->right_analog_trigger_supported = true;
321-
break;
322-
}
302+
case SDL_SUBTYPE_XINPUT_ONLY:
303+
case SDL_SUBTYPE_XINPUT_SHARE_NONE:
304+
case SDL_SUBTYPE_XINPUT_SHARE_DUAL:
305+
case SDL_SUBTYPE_XINPUT_SHARE_QUAD:
306+
case SDL_SUBTYPE_XINPUT_SHARE_NONE_CLICK:
307+
case SDL_SUBTYPE_XINPUT_SHARE_DUAL_CLICK:
308+
case SDL_SUBTYPE_XINPUT_SHARE_QUAD_CLICK:
309+
// Basic xinput mask with share
310+
ctx->usage_masks[0] = 0xFF;
311+
ctx->usage_masks[1] = 0x0F;
312+
ctx->usage_masks[2] = 0x0F;
313+
ctx->usage_masks[3] = 0x00;
314+
ctx->left_analog_stick_supported = true;
315+
ctx->right_analog_stick_supported = true;
316+
ctx->left_analog_trigger_supported = true;
317+
ctx->right_analog_trigger_supported = true;
318+
319+
// Add primary paddles
320+
if (
321+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_DUAL ||
322+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_QUAD ||
323+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_DUAL_CLICK ||
324+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_QUAD_CLICK)
325+
ctx->usage_masks[1] |= 0xC0;
326+
327+
// Remove share/capture button if not supported
328+
if (ctx->sub_type == SDL_SUBTYPE_XINPUT_ONLY)
329+
ctx->usage_masks[2] &= ~0x08;
330+
331+
// Add secondary paddles
332+
if (
333+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_QUAD ||
334+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_QUAD_CLICK)
335+
ctx->usage_masks[2] |= 0x30;
336+
337+
// Add touchpad click
338+
if (
339+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_NONE_CLICK ||
340+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_DUAL_CLICK ||
341+
ctx->sub_type == SDL_SUBTYPE_XINPUT_SHARE_QUAD_CLICK)
342+
ctx->usage_masks[2] |= 0x40;
343+
break;
344+
case SDL_SUBTYPE_LOAD_FIRMWARE:
345+
ctx->usage_masks[0] = buttons[0];
346+
ctx->usage_masks[1] = buttons[1];
347+
ctx->usage_masks[2] = buttons[2];
348+
ctx->usage_masks[3] = buttons[3];
349+
ctx->left_analog_stick_supported = left_analog_stick_supported;
350+
ctx->right_analog_stick_supported = right_analog_stick_supported;
351+
ctx->left_analog_trigger_supported = left_analog_trigger_supported;
352+
ctx->right_analog_trigger_supported = right_analog_trigger_supported;
353+
break;
354+
case SDL_SUBTYPE_FULL_MAPPING:
355+
default:
356+
ctx->usage_masks[0] = 0xFF;
357+
ctx->usage_masks[1] = 0xFF;
358+
ctx->usage_masks[2] = 0xFF;
359+
ctx->usage_masks[3] = 0xFF;
360+
ctx->left_analog_stick_supported = true;
361+
ctx->right_analog_stick_supported = true;
362+
ctx->left_analog_trigger_supported = true;
363+
ctx->right_analog_trigger_supported = true;
364+
break;
365+
}
323366

324367
// Since SDL uses fixed mappings, unfortunately we cannot use the
325368
// button mask from the protocol. SInput defines a set of predefined

0 commit comments

Comments
 (0)