mirror of
https://github.com/libsdl-org/SDL.git
synced 2025-09-29 06:28:29 +00:00
SInput: Version as a capabilities vehicle (#13667)
* SInput: version capabilities compression This commit includes additions relating to SInput generic device reporting capabilities in a bit more detail, to automatically choose the best input map possible for the given device. Thanks to Antheas Kapenekakis (git@antheas.dev) for contributing the neat compression algorithm, this is pulled from the PR Draft here: https://github.com/libsdl-org/SDL/pull/13565 Co-authored-by: Antheas Kapenekakis <git@antheas.dev>
This commit is contained in:
@@ -31,6 +31,7 @@
|
||||
#include "usb_ids.h"
|
||||
#include "hidapi/SDL_hidapi_flydigi.h"
|
||||
#include "hidapi/SDL_hidapi_nintendo.h"
|
||||
#include "hidapi/SDL_hidapi_sinput.h"
|
||||
#include "../events/SDL_events_c.h"
|
||||
|
||||
|
||||
@@ -55,6 +56,26 @@
|
||||
#define SDL_GAMEPAD_SDKLE_FIELD "sdk<=:"
|
||||
#define SDL_GAMEPAD_SDKLE_FIELD_SIZE SDL_strlen(SDL_GAMEPAD_SDKLE_FIELD)
|
||||
|
||||
// Helper function to add button mapping
|
||||
#ifndef ADD_BUTTON_MAPPING
|
||||
#define SDL_ADD_BUTTON_MAPPING(sdl_name, button_id, maxlen) \
|
||||
do { \
|
||||
char temp[32]; \
|
||||
(void)SDL_snprintf(temp, sizeof(temp), "%s:b%d,", sdl_name, button_id); \
|
||||
SDL_strlcat(mapping_string, temp, maxlen); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
// Helper function to add axis mapping
|
||||
#ifndef ADD_AXIS_MAPPING
|
||||
#define SDL_ADD_AXIS_MAPPING(sdl_name, axis_id, maxlen) \
|
||||
do { \
|
||||
char temp[32]; \
|
||||
(void)SDL_snprintf(temp, sizeof(temp), "%s:a%d,", sdl_name, axis_id); \
|
||||
SDL_strlcat(mapping_string, temp, maxlen); \
|
||||
} while (0)
|
||||
#endif
|
||||
|
||||
static bool SDL_gamepads_initialized;
|
||||
static SDL_Gamepad *SDL_gamepads SDL_GUARDED_BY(SDL_joystick_lock) = NULL;
|
||||
|
||||
@@ -689,6 +710,304 @@ static GamepadMapping_t *SDL_CreateMappingForAndroidGamepad(SDL_GUID guid)
|
||||
}
|
||||
#endif // SDL_PLATFORM_ANDROID
|
||||
|
||||
/*
|
||||
* Helper function to apply SInput decoded styles to the mapping string
|
||||
*/
|
||||
static inline void SDL_SInputStylesMapExtraction(SDL_SInputStyles_t* styles, char* mapping_string, size_t mapping_string_len)
|
||||
{
|
||||
int current_button = 0;
|
||||
int current_axis = 0;
|
||||
int misc_buttons = 0;
|
||||
bool digital_triggers = false;
|
||||
bool dualstage_triggers = false;
|
||||
int bumpers = 0;
|
||||
bool left_stick = false;
|
||||
bool right_stick = false;
|
||||
int paddle_pairs = 0;
|
||||
|
||||
// Determine how many misc buttons are used
|
||||
switch (styles->misc_style) {
|
||||
case SINPUT_MISCSTYLE_1:
|
||||
misc_buttons = 1;
|
||||
break;
|
||||
|
||||
case SINPUT_MISCSTYLE_2:
|
||||
misc_buttons = 2;
|
||||
break;
|
||||
|
||||
case SINPUT_MISCSTYLE_3:
|
||||
misc_buttons = 3;
|
||||
break;
|
||||
|
||||
case SINPUT_MISCSTYLE_4:
|
||||
misc_buttons = 4;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Analog joysticks (always come first in axis mapping)
|
||||
switch (styles->analog_style) {
|
||||
case SINPUT_ANALOGSTYLE_LEFTONLY:
|
||||
SDL_ADD_AXIS_MAPPING("leftx", current_axis++, mapping_string_len);
|
||||
SDL_ADD_AXIS_MAPPING("lefty", current_axis++, mapping_string_len);
|
||||
left_stick = true;
|
||||
break;
|
||||
|
||||
case SINPUT_ANALOGSTYLE_LEFTRIGHT:
|
||||
SDL_ADD_AXIS_MAPPING("leftx", current_axis++, mapping_string_len);
|
||||
SDL_ADD_AXIS_MAPPING("lefty", current_axis++, mapping_string_len);
|
||||
SDL_ADD_AXIS_MAPPING("rightx", current_axis++, mapping_string_len);
|
||||
SDL_ADD_AXIS_MAPPING("righty", current_axis++, mapping_string_len);
|
||||
left_stick = true;
|
||||
right_stick = true;
|
||||
break;
|
||||
|
||||
case SINPUT_ANALOGSTYLE_RIGHTONLY:
|
||||
SDL_ADD_AXIS_MAPPING("rightx", current_axis++, mapping_string_len);
|
||||
SDL_ADD_AXIS_MAPPING("righty", current_axis++, mapping_string_len);
|
||||
right_stick = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Bumpers
|
||||
switch (styles->bumper_style) {
|
||||
case SINPUT_BUMPERSTYLE_ONE:
|
||||
bumpers = 1;
|
||||
break;
|
||||
|
||||
case SINPUT_BUMPERSTYLE_TWO:
|
||||
bumpers = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Analog triggers
|
||||
switch (styles->trigger_style) {
|
||||
// Analog triggers
|
||||
case SINPUT_TRIGGERSTYLE_ANALOG:
|
||||
SDL_ADD_AXIS_MAPPING("lefttrigger", current_axis++, mapping_string_len);
|
||||
SDL_ADD_AXIS_MAPPING("righttrigger", current_axis++, mapping_string_len);
|
||||
break;
|
||||
|
||||
// Digital triggers
|
||||
case SINPUT_TRIGGERSTYLE_DIGITAL:
|
||||
digital_triggers = true;
|
||||
break;
|
||||
|
||||
// Analog triggers with digital press
|
||||
case SINPUT_TRIGGERSTYLE_DUALSTAGE:
|
||||
SDL_ADD_AXIS_MAPPING("lefttrigger", current_axis++, mapping_string_len);
|
||||
SDL_ADD_AXIS_MAPPING("righttrigger", current_axis++, mapping_string_len);
|
||||
dualstage_triggers = true;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (styles->paddle_style) {
|
||||
case SINPUT_PADDLESTYLE_TWO:
|
||||
paddle_pairs = 1;
|
||||
break;
|
||||
|
||||
case SINPUT_PADDLESTYLE_FOUR:
|
||||
paddle_pairs = 2;
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Digital button mappings
|
||||
// ABXY buttons (always applied as South, East, West, North)
|
||||
SDL_ADD_BUTTON_MAPPING("a", current_button++, mapping_string_len); // South (typically A on Xbox, X on PlayStation)
|
||||
SDL_ADD_BUTTON_MAPPING("b", current_button++, mapping_string_len); // East (typically B on Xbox, Circle on PlayStation)
|
||||
SDL_ADD_BUTTON_MAPPING("x", current_button++, mapping_string_len); // West (typically X on Xbox, Square on PlayStation)
|
||||
SDL_ADD_BUTTON_MAPPING("y", current_button++, mapping_string_len); // North (typically Y on Xbox, Triangle on PlayStation)
|
||||
|
||||
// D-Pad (always applied)
|
||||
SDL_strlcat(mapping_string, "dpup:h0.1,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,", mapping_string_len);
|
||||
|
||||
// Left and Right stick buttons
|
||||
if (left_stick) {
|
||||
SDL_ADD_BUTTON_MAPPING("leftstick", current_button++, mapping_string_len);
|
||||
}
|
||||
if (right_stick) {
|
||||
SDL_ADD_BUTTON_MAPPING("rightstick", current_button++, mapping_string_len);
|
||||
}
|
||||
|
||||
// Digital shoulder buttons (L/R Shoulder)
|
||||
if (bumpers > 0) {
|
||||
SDL_ADD_BUTTON_MAPPING("leftshoulder", current_button++, mapping_string_len);
|
||||
}
|
||||
if (bumpers > 1) {
|
||||
SDL_ADD_BUTTON_MAPPING("rightshoulder", current_button++, mapping_string_len);
|
||||
}
|
||||
|
||||
// Digital trigger buttons (capability overrides analog)
|
||||
if (digital_triggers) {
|
||||
SDL_ADD_BUTTON_MAPPING("lefttrigger", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("righttrigger", current_button++, mapping_string_len);
|
||||
} else if (dualstage_triggers) {
|
||||
// Dual-stage trigger buttons are appended as MISC buttons
|
||||
// but only if we have the space to use them.
|
||||
if (misc_buttons <= 2) {
|
||||
switch (misc_buttons) {
|
||||
case 0:
|
||||
SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
case 1:
|
||||
SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc5", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
SDL_ADD_BUTTON_MAPPING("misc5", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc6", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
// We do not overwrite other misc buttons if they are used.
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Paddle 1/2
|
||||
if (paddle_pairs > 0) {
|
||||
SDL_ADD_BUTTON_MAPPING("paddle1", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("paddle2", current_button++, mapping_string_len);
|
||||
}
|
||||
|
||||
// Start/Plus
|
||||
SDL_ADD_BUTTON_MAPPING("start", current_button++, mapping_string_len);
|
||||
|
||||
// Back/Minus, Guide/Home, Share/Capture
|
||||
switch (styles->meta_style) {
|
||||
case SINPUT_METASTYLE_BACK:
|
||||
SDL_ADD_BUTTON_MAPPING("back", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
case SINPUT_METASTYLE_BACKGUIDE:
|
||||
SDL_ADD_BUTTON_MAPPING("back", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("guide", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
case SINPUT_METASTYLE_BACKGUIDESHARE:
|
||||
SDL_ADD_BUTTON_MAPPING("back", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("guide", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc1", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Paddle 3/4
|
||||
if (paddle_pairs > 1) {
|
||||
SDL_ADD_BUTTON_MAPPING("paddle3", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("paddle4", current_button++, mapping_string_len);
|
||||
}
|
||||
|
||||
// Touchpad buttons
|
||||
switch (styles->touch_style) {
|
||||
case SINPUT_TOUCHSTYLE_SINGLE:
|
||||
SDL_ADD_BUTTON_MAPPING("touchpad", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
case SINPUT_TOUCHSTYLE_DOUBLE:
|
||||
SDL_ADD_BUTTON_MAPPING("touchpad", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc2", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
switch (misc_buttons) {
|
||||
case 1:
|
||||
SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc5", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
case 4:
|
||||
SDL_ADD_BUTTON_MAPPING("misc3", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc4", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc5", current_button++, mapping_string_len);
|
||||
SDL_ADD_BUTTON_MAPPING("misc6", current_button++, mapping_string_len);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to decode SInput features information packed into version
|
||||
*/
|
||||
static void SDL_CreateMappingStringForSInputGamepad(Uint16 vendor, Uint16 product, Uint8 sub_product, Uint16 version, Uint8 face_style, char* mapping_string, size_t mapping_string_len)
|
||||
{
|
||||
SDL_SInputStyles_t decoded = { 0 };
|
||||
|
||||
switch (face_style) {
|
||||
default:
|
||||
SDL_strlcat(mapping_string, "face:abxy,", mapping_string_len);
|
||||
break;
|
||||
case 2:
|
||||
SDL_strlcat(mapping_string, "face:axby,", mapping_string_len);
|
||||
break;
|
||||
case 3:
|
||||
SDL_strlcat(mapping_string, "face:bayx,", mapping_string_len);
|
||||
break;
|
||||
case 4:
|
||||
SDL_strlcat(mapping_string, "face:sony,", mapping_string_len);
|
||||
break;
|
||||
}
|
||||
|
||||
// Interpret the mapping string
|
||||
// dynamically based on the feature responses
|
||||
decoded.misc_style = (SInput_MiscStyleType)(version % SINPUT_MISCSTYLE_MAX);
|
||||
version /= SINPUT_MISCSTYLE_MAX;
|
||||
|
||||
decoded.touch_style = (SInput_TouchStyleType)(version % SINPUT_TOUCHSTYLE_MAX);
|
||||
version /= SINPUT_TOUCHSTYLE_MAX;
|
||||
|
||||
decoded.meta_style = (SInput_MetaStyleType)(version % SINPUT_METASTYLE_MAX);
|
||||
version /= SINPUT_METASTYLE_MAX;
|
||||
|
||||
decoded.paddle_style = (SInput_PaddleStyleType)(version % SINPUT_PADDLESTYLE_MAX);
|
||||
version /= SINPUT_PADDLESTYLE_MAX;
|
||||
|
||||
decoded.trigger_style = (SInput_TriggerStyleType)(version % SINPUT_TRIGGERSTYLE_MAX);
|
||||
version /= SINPUT_TRIGGERSTYLE_MAX;
|
||||
|
||||
decoded.bumper_style = (SInput_BumperStyleType)(version % SINPUT_BUMPERSTYLE_MAX);
|
||||
version /= SINPUT_BUMPERSTYLE_MAX;
|
||||
|
||||
decoded.analog_style = (SInput_AnalogStyleType)(version % SINPUT_ANALOGSTYLE_MAX);
|
||||
|
||||
SDL_SInputStylesMapExtraction(&decoded, mapping_string, mapping_string_len);
|
||||
}
|
||||
|
||||
/*
|
||||
* Helper function to guess at a mapping for HIDAPI gamepads
|
||||
*/
|
||||
@@ -698,10 +1017,11 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
||||
char mapping_string[1024];
|
||||
Uint16 vendor;
|
||||
Uint16 product;
|
||||
Uint16 version;
|
||||
|
||||
SDL_strlcpy(mapping_string, "none,*,", sizeof(mapping_string));
|
||||
|
||||
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, NULL, NULL);
|
||||
SDL_GetJoystickGUIDInfo(guid, &vendor, &product, &version, NULL);
|
||||
|
||||
if (SDL_IsJoystickWheel(vendor, product)) {
|
||||
// We don't want to pick up Logitech FFB wheels here
|
||||
@@ -827,56 +1147,11 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid)
|
||||
// This controller has no guide button
|
||||
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));
|
||||
} else if (SDL_IsJoystickSInputController(vendor, product)) {
|
||||
|
||||
Uint8 face_style = (guid.data[15] & 0xE0) >> 5;
|
||||
Uint8 sub_type = guid.data[15] & 0x1F;
|
||||
Uint8 sub_product = guid.data[15] & 0x1F;
|
||||
|
||||
// Apply face style according to gamepad response
|
||||
switch (face_style) {
|
||||
default:
|
||||
SDL_strlcat(mapping_string, "face:abxy,", sizeof(mapping_string));
|
||||
break;
|
||||
case 2:
|
||||
SDL_strlcat(mapping_string, "face:axby,", sizeof(mapping_string));
|
||||
break;
|
||||
case 3:
|
||||
SDL_strlcat(mapping_string, "face:bayx,", sizeof(mapping_string));
|
||||
break;
|
||||
case 4:
|
||||
SDL_strlcat(mapping_string, "face:sony,", sizeof(mapping_string));
|
||||
break;
|
||||
}
|
||||
|
||||
switch (product) {
|
||||
case USB_PRODUCT_HANDHELDLEGEND_PROGCC:
|
||||
switch (sub_type) {
|
||||
default:
|
||||
// ProGCC Primary Mapping
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,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,hint:!SDL_GAMECONTROLLER_USE_BUTTON_LABELS:=1,", sizeof(mapping_string));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE:
|
||||
switch (sub_type) {
|
||||
default:
|
||||
// GC Ultimate Primary Map
|
||||
SDL_strlcat(mapping_string, "a:b0,b:b1,x:b2,y:b3,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,misc3:b8,misc4:b9,hint:!SDL_GAMECONTROLLER_USE_GAMECUBE_LABELS:=1,", sizeof(mapping_string));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC:
|
||||
switch (sub_type) {
|
||||
default:
|
||||
// Default Fully Exposed Mapping (Development Purposes)
|
||||
SDL_strlcat(mapping_string, "leftx:a0,lefty:a1,rightx:a2,righty:a3,lefttrigger:a4,righttrigger:a5,a:b0,b:b1,x:b2,y: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));
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case USB_PRODUCT_BONZIRICHANNEL_FIREBIRD:
|
||||
default:
|
||||
// Unmapped device
|
||||
return NULL;
|
||||
}
|
||||
SDL_CreateMappingStringForSInputGamepad(vendor, product, sub_product, version, face_style, mapping_string, sizeof(mapping_string));
|
||||
} else {
|
||||
// All other gamepads have the standard set of 19 buttons and 6 axes
|
||||
if (SDL_IsJoystickGameCube(vendor, product)) {
|
||||
|
@@ -3221,7 +3221,8 @@ bool SDL_IsJoystickSInputController(Uint16 vendor_id, Uint16 product_id)
|
||||
if (product_id == USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC ||
|
||||
product_id == USB_PRODUCT_HANDHELDLEGEND_PROGCC ||
|
||||
product_id == USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE ||
|
||||
product_id == USB_PRODUCT_BONZIRICHANNEL_FIREBIRD) {
|
||||
product_id == USB_PRODUCT_BONZIRICHANNEL_FIREBIRD ||
|
||||
product_id == USB_PRODUCT_VOIDGAMING_PS4FIREBIRD) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@@ -27,12 +27,13 @@
|
||||
|
||||
#include "SDL_hidapijoystick_c.h"
|
||||
#include "SDL_hidapi_rumble.h"
|
||||
#include "SDL_hidapi_sinput.h"
|
||||
|
||||
#ifdef SDL_JOYSTICK_HIDAPI_SINPUT
|
||||
|
||||
/*****************************************************************************************************/
|
||||
// This protocol is documented at:
|
||||
// https://docs.handheldlegend.com/s/sinput/doc/sinput-hid-protocol-TkPYWlDMAg
|
||||
// https://docs.handheldlegend.com/s/sinput
|
||||
/*****************************************************************************************************/
|
||||
|
||||
// Define this if you want to log all packets from the controller
|
||||
@@ -119,6 +120,39 @@
|
||||
#define SINPUT_BUTTON_IDX_MISC9 30
|
||||
#define SINPUT_BUTTON_IDX_MISC10 31
|
||||
|
||||
#define SINPUT_BUTTONMASK_EAST 0x01
|
||||
#define SINPUT_BUTTONMASK_SOUTH 0x02
|
||||
#define SINPUT_BUTTONMASK_NORTH 0x04
|
||||
#define SINPUT_BUTTONMASK_WEST 0x08
|
||||
#define SINPUT_BUTTONMASK_DPAD_UP 0x10
|
||||
#define SINPUT_BUTTONMASK_DPAD_DOWN 0x20
|
||||
#define SINPUT_BUTTONMASK_DPAD_LEFT 0x40
|
||||
#define SINPUT_BUTTONMASK_DPAD_RIGHT 0x80
|
||||
#define SINPUT_BUTTONMASK_LEFT_STICK 0x01
|
||||
#define SINPUT_BUTTONMASK_RIGHT_STICK 0x02
|
||||
#define SINPUT_BUTTONMASK_LEFT_BUMPER 0x04
|
||||
#define SINPUT_BUTTONMASK_RIGHT_BUMPER 0x08
|
||||
#define SINPUT_BUTTONMASK_LEFT_TRIGGER 0x10
|
||||
#define SINPUT_BUTTONMASK_RIGHT_TRIGGER 0x20
|
||||
#define SINPUT_BUTTONMASK_LEFT_PADDLE1 0x40
|
||||
#define SINPUT_BUTTONMASK_RIGHT_PADDLE1 0x80
|
||||
#define SINPUT_BUTTONMASK_START 0x01
|
||||
#define SINPUT_BUTTONMASK_BACK 0x02
|
||||
#define SINPUT_BUTTONMASK_GUIDE 0x04
|
||||
#define SINPUT_BUTTONMASK_CAPTURE 0x08
|
||||
#define SINPUT_BUTTONMASK_LEFT_PADDLE2 0x10
|
||||
#define SINPUT_BUTTONMASK_RIGHT_PADDLE2 0x20
|
||||
#define SINPUT_BUTTONMASK_TOUCHPAD1 0x40
|
||||
#define SINPUT_BUTTONMASK_TOUCHPAD2 0x80
|
||||
#define SINPUT_BUTTONMASK_POWER 0x01
|
||||
#define SINPUT_BUTTONMASK_MISC4 0x02
|
||||
#define SINPUT_BUTTONMASK_MISC5 0x04
|
||||
#define SINPUT_BUTTONMASK_MISC6 0x08
|
||||
#define SINPUT_BUTTONMASK_MISC7 0x10
|
||||
#define SINPUT_BUTTONMASK_MISC8 0x20
|
||||
#define SINPUT_BUTTONMASK_MISC9 0x40
|
||||
#define SINPUT_BUTTONMASK_MISC10 0x80
|
||||
|
||||
#define SINPUT_REPORT_IDX_COMMAND_RESPONSE_ID 1
|
||||
#define SINPUT_REPORT_IDX_COMMAND_RESPONSE_BULK 2
|
||||
|
||||
@@ -139,7 +173,6 @@
|
||||
#define EXTRACTUINT32(data, idx) ((Uint32)((data)[(idx)] | ((data)[(idx) + 1] << 8) | ((data)[(idx) + 2] << 16) | ((data)[(idx) + 3] << 24)))
|
||||
#endif
|
||||
|
||||
|
||||
typedef struct
|
||||
{
|
||||
uint8_t type;
|
||||
@@ -183,6 +216,7 @@ typedef struct
|
||||
{
|
||||
SDL_HIDAPI_Device *device;
|
||||
Uint16 protocol_version;
|
||||
Uint16 usb_device_version;
|
||||
bool sensors_enabled;
|
||||
|
||||
Uint8 player_idx;
|
||||
@@ -203,8 +237,8 @@ typedef struct
|
||||
Uint8 touchpad_count; // 2 touchpads maximum
|
||||
Uint8 touchpad_finger_count; // 2 fingers for one touchpad, or 1 per touchpad (2 max)
|
||||
|
||||
Uint8 polling_rate_ms;
|
||||
Uint8 sub_type; // Subtype of the device, 0 in most cases
|
||||
Uint16 polling_rate_us;
|
||||
Uint8 sub_product; // Subtype of the device, 0 in most cases
|
||||
|
||||
Uint16 accelRange; // Example would be 2,4,8,16 +/- (g-force)
|
||||
Uint16 gyroRange; // Example would be 1000,2000,4000 +/- (degrees per second)
|
||||
@@ -213,6 +247,7 @@ typedef struct
|
||||
float gyroScale; // Scale factor for gyroscope values
|
||||
Uint8 last_state[USB_PACKET_LENGTH];
|
||||
|
||||
Uint8 axes_count;
|
||||
Uint8 buttons_count;
|
||||
Uint8 usage_masks[4];
|
||||
|
||||
@@ -233,6 +268,172 @@ static inline float CalculateAccelScale(uint16_t g_range)
|
||||
return SDL_STANDARD_GRAVITY / (32768.0f / (float)g_range);
|
||||
}
|
||||
|
||||
// This function uses base-n encoding to encode features into the version GUID bytes
|
||||
// that properly represents the supported device features
|
||||
// This also sets the driver context button mask correctly based on the features
|
||||
static void DeviceDynamicEncodingSetup(SDL_HIDAPI_Device *device)
|
||||
{
|
||||
SDL_DriverSInput_Context *ctx = device->context;
|
||||
|
||||
// A new button mask is generated to provide
|
||||
// SDL with a mapping string that is sane. In case of
|
||||
// an unconventional gamepad setup, the closest sane
|
||||
// mapping is provided to the driver.
|
||||
Uint8 mask[4] = { 0 };
|
||||
|
||||
// For all gamepads, there is a minimum SInput expectation
|
||||
// to have dpad, abxy, and start buttons
|
||||
|
||||
// ABXY + D-Pad
|
||||
mask[0] = 0xFF;
|
||||
ctx->dpad_supported = true;
|
||||
|
||||
// Start button
|
||||
mask[2] |= SINPUT_BUTTONMASK_START;
|
||||
|
||||
// Bumpers
|
||||
bool left_bumper = (ctx->usage_masks[1] & SINPUT_BUTTONMASK_LEFT_BUMPER) != 0;
|
||||
bool right_bumper = (ctx->usage_masks[1] & SINPUT_BUTTONMASK_RIGHT_BUMPER) != 0;
|
||||
|
||||
int bumperStyle = SINPUT_BUMPERSTYLE_NONE;
|
||||
if (left_bumper && right_bumper) {
|
||||
bumperStyle = SINPUT_BUMPERSTYLE_TWO;
|
||||
mask[1] |= (SINPUT_BUTTONMASK_LEFT_BUMPER | SINPUT_BUTTONMASK_RIGHT_BUMPER);
|
||||
} else if (left_bumper || right_bumper) {
|
||||
bumperStyle = SINPUT_BUMPERSTYLE_ONE;
|
||||
|
||||
if (left_bumper) {
|
||||
mask[1] |= SINPUT_BUTTONMASK_LEFT_BUMPER;
|
||||
} else if (right_bumper) {
|
||||
mask[1] |= SINPUT_BUTTONMASK_RIGHT_BUMPER;
|
||||
}
|
||||
}
|
||||
|
||||
// Trigger bits live in mask[1]
|
||||
bool digital_triggers = (ctx->usage_masks[1] & (SINPUT_BUTTONMASK_LEFT_TRIGGER | SINPUT_BUTTONMASK_RIGHT_TRIGGER)) != 0;
|
||||
|
||||
bool analog_triggers = ctx->left_analog_trigger_supported || ctx->right_analog_trigger_supported;
|
||||
|
||||
// Touchpads
|
||||
bool t1 = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_TOUCHPAD1) != 0;
|
||||
bool t2 = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_TOUCHPAD2) != 0;
|
||||
|
||||
int analogStyle = SINPUT_ANALOGSTYLE_NONE;
|
||||
if (ctx->left_analog_stick_supported && ctx->right_analog_stick_supported) {
|
||||
analogStyle = SINPUT_ANALOGSTYLE_LEFTRIGHT;
|
||||
mask[1] |= (SINPUT_BUTTONMASK_LEFT_STICK | SINPUT_BUTTONMASK_RIGHT_STICK);
|
||||
} else if (ctx->left_analog_stick_supported) {
|
||||
analogStyle = SINPUT_ANALOGSTYLE_LEFTONLY;
|
||||
mask[1] |= SINPUT_BUTTONMASK_LEFT_STICK;
|
||||
} else if (ctx->right_analog_stick_supported) {
|
||||
analogStyle = SINPUT_ANALOGSTYLE_RIGHTONLY;
|
||||
mask[1] |= SINPUT_BUTTONMASK_RIGHT_STICK;
|
||||
}
|
||||
|
||||
int triggerStyle = SINPUT_TRIGGERSTYLE_NONE;
|
||||
|
||||
if (analog_triggers && digital_triggers) {
|
||||
// When we have both analog triggers and digital triggers
|
||||
// this is interpreted as having dual-stage triggers
|
||||
triggerStyle = SINPUT_TRIGGERSTYLE_DUALSTAGE;
|
||||
mask[1] |= (SINPUT_BUTTONMASK_LEFT_TRIGGER | SINPUT_BUTTONMASK_RIGHT_TRIGGER);
|
||||
} else if (analog_triggers) {
|
||||
triggerStyle = SINPUT_TRIGGERSTYLE_ANALOG;
|
||||
} else if (digital_triggers) {
|
||||
triggerStyle = SINPUT_TRIGGERSTYLE_DIGITAL;
|
||||
mask[1] |= (SINPUT_BUTTONMASK_LEFT_TRIGGER | SINPUT_BUTTONMASK_RIGHT_TRIGGER);
|
||||
}
|
||||
|
||||
// Paddle bits may touch mask[1] and mask[2]
|
||||
bool pg1 = (ctx->usage_masks[1] & (SINPUT_BUTTONMASK_LEFT_PADDLE1 | SINPUT_BUTTONMASK_RIGHT_PADDLE1)) != 0;
|
||||
bool pg2 = (ctx->usage_masks[2] & (SINPUT_BUTTONMASK_LEFT_PADDLE2 | SINPUT_BUTTONMASK_RIGHT_PADDLE2)) != 0;
|
||||
|
||||
int paddleStyle = SINPUT_PADDLESTYLE_NONE;
|
||||
if (pg1 && pg2) {
|
||||
paddleStyle = SINPUT_PADDLESTYLE_FOUR;
|
||||
mask[1] |= (SINPUT_BUTTONMASK_LEFT_PADDLE1 | SINPUT_BUTTONMASK_RIGHT_PADDLE1);
|
||||
mask[2] |= (SINPUT_BUTTONMASK_LEFT_PADDLE2 | SINPUT_BUTTONMASK_RIGHT_PADDLE2);
|
||||
} else if (pg1) {
|
||||
paddleStyle = SINPUT_PADDLESTYLE_TWO;
|
||||
mask[1] |= (SINPUT_BUTTONMASK_LEFT_PADDLE1 | SINPUT_BUTTONMASK_RIGHT_PADDLE1);
|
||||
}
|
||||
|
||||
|
||||
// Meta Buttons (Back, Guide, Share)
|
||||
bool back = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_BACK) != 0;
|
||||
bool guide = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_GUIDE) != 0;
|
||||
bool share = (ctx->usage_masks[2] & SINPUT_BUTTONMASK_CAPTURE) != 0;
|
||||
|
||||
int metaStyle = SINPUT_METASTYLE_NONE;
|
||||
if (share) {
|
||||
metaStyle = SINPUT_METASTYLE_BACKGUIDESHARE;
|
||||
mask[2] |= (SINPUT_BUTTONMASK_BACK | SINPUT_BUTTONMASK_GUIDE | SINPUT_BUTTONMASK_CAPTURE);
|
||||
} else if (guide) {
|
||||
metaStyle = SINPUT_METASTYLE_BACKGUIDE;
|
||||
mask[2] |= (SINPUT_BUTTONMASK_BACK | SINPUT_BUTTONMASK_GUIDE);
|
||||
} else if (back) {
|
||||
metaStyle = SINPUT_METASTYLE_BACK;
|
||||
mask[2] |= (SINPUT_BUTTONMASK_BACK);
|
||||
}
|
||||
|
||||
int touchStyle = SINPUT_TOUCHSTYLE_NONE;
|
||||
if (t1 && t2) {
|
||||
touchStyle = SINPUT_TOUCHSTYLE_DOUBLE;
|
||||
mask[2] |= (SINPUT_BUTTONMASK_TOUCHPAD1 | SINPUT_BUTTONMASK_TOUCHPAD2);
|
||||
} else if (t1) {
|
||||
touchStyle = SINPUT_TOUCHSTYLE_SINGLE;
|
||||
mask[2] |= SINPUT_BUTTONMASK_TOUCHPAD1;
|
||||
}
|
||||
|
||||
// Misc Buttons
|
||||
int miscStyle = SINPUT_MISCSTYLE_NONE;
|
||||
Uint8 extra_misc = ctx->usage_masks[3] & 0x0F;
|
||||
switch (extra_misc) {
|
||||
case 0x0F:
|
||||
miscStyle = SINPUT_MISCSTYLE_4;
|
||||
mask[3] = 0x0F;
|
||||
break;
|
||||
case 0x07:
|
||||
miscStyle = SINPUT_MISCSTYLE_3;
|
||||
mask[3] = 0x07;
|
||||
break;
|
||||
case 0x03:
|
||||
miscStyle = SINPUT_MISCSTYLE_2;
|
||||
mask[3] = 0x03;
|
||||
break;
|
||||
case 0x01:
|
||||
miscStyle = SINPUT_MISCSTYLE_1;
|
||||
mask[3] = 0x01;
|
||||
break;
|
||||
default:
|
||||
miscStyle = SINPUT_MISCSTYLE_NONE;
|
||||
mask[3] = 0x00;
|
||||
break;
|
||||
}
|
||||
|
||||
int version = analogStyle;
|
||||
version = (version * (int)SINPUT_BUMPERSTYLE_MAX) + bumperStyle;
|
||||
version = (version * (int)SINPUT_TRIGGERSTYLE_MAX) + triggerStyle;
|
||||
version = (version * (int)SINPUT_PADDLESTYLE_MAX) + paddleStyle;
|
||||
version = (version * (int)SINPUT_METASTYLE_MAX) + metaStyle;
|
||||
version = (version * (int)SINPUT_TOUCHSTYLE_MAX) + touchStyle;
|
||||
version = (version * (int)SINPUT_MISCSTYLE_MAX) + miscStyle;
|
||||
|
||||
// Overwrite our button usage masks
|
||||
// with our sanitized masks
|
||||
ctx->usage_masks[0] = mask[0];
|
||||
ctx->usage_masks[1] = mask[1];
|
||||
ctx->usage_masks[2] = mask[2];
|
||||
ctx->usage_masks[3] = mask[3];
|
||||
|
||||
version = SDL_clamp(version, 0, UINT16_MAX);
|
||||
|
||||
// Overwrite 'Version' field of the GUID data
|
||||
device->guid.data[12] = (Uint8)(version & 0xFF);
|
||||
device->guid.data[13] = (Uint8)(version >> 8);
|
||||
}
|
||||
|
||||
|
||||
static void ProcessSDLFeaturesResponse(SDL_HIDAPI_Device *device, Uint8 *data)
|
||||
{
|
||||
SDL_DriverSInput_Context *ctx = (SDL_DriverSInput_Context *)device->context;
|
||||
@@ -266,69 +467,26 @@ static void ProcessSDLFeaturesResponse(SDL_HIDAPI_Device *device, Uint8 *data)
|
||||
// The 5 LSB represent a device sub-type
|
||||
device->guid.data[15] = data[5];
|
||||
|
||||
ctx->sub_type = (data[5] & 0x1F);
|
||||
ctx->sub_product = (data[5] & 0x1F);
|
||||
|
||||
#if defined(DEBUG_SINPUT_INIT)
|
||||
SDL_Log("SInput Face Style: %d", (data[5] & 0xE0) >> 5);
|
||||
SDL_Log("SInput Sub-type: %d", (data[5] & 0x1F));
|
||||
SDL_Log("SInput Sub-product: %d", (data[5] & 0x1F));
|
||||
#endif
|
||||
|
||||
ctx->polling_rate_ms = data[6];
|
||||
ctx->polling_rate_us = EXTRACTUINT16(data, 6);
|
||||
|
||||
#if defined(DEBUG_SINPUT_INIT)
|
||||
SDL_Log("SInput polling interval (microseconds): %d", ctx->polling_rate_us);
|
||||
#endif
|
||||
|
||||
ctx->accelRange = EXTRACTUINT16(data, 8);
|
||||
ctx->gyroRange = EXTRACTUINT16(data, 10);
|
||||
|
||||
|
||||
if ((device->product_id == USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC) && (device->vendor_id == USB_VENDOR_RASPBERRYPI)) {
|
||||
switch (ctx->sub_type) {
|
||||
// SInput generic device, exposes all buttons
|
||||
default:
|
||||
case 0:
|
||||
ctx->usage_masks[0] = 0xFF;
|
||||
ctx->usage_masks[1] = 0xFF;
|
||||
ctx->usage_masks[2] = 0xFF;
|
||||
ctx->usage_masks[3] = 0xFF;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
// Masks in LSB to MSB
|
||||
// South, East, West, North, DUp, DDown, DLeft, DRight
|
||||
ctx->usage_masks[0] = data[12];
|
||||
|
||||
// Stick Left, Stick Right, L Shoulder, R Shoulder,
|
||||
// L Digital Trigger, R Digital Trigger, L Paddle 1, R Paddle 1
|
||||
ctx->usage_masks[1] = data[13];
|
||||
|
||||
// Start, Back, Guide, Capture, L Paddle 2, R Paddle 2, Touchpad L, Touchpad R
|
||||
ctx->usage_masks[2] = data[14];
|
||||
|
||||
// Power, Misc 4 to 10
|
||||
ctx->usage_masks[3] = data[15];
|
||||
}
|
||||
|
||||
// Derive button count from mask
|
||||
for (Uint8 byte = 0; byte < 4; ++byte) {
|
||||
for (Uint8 bit = 0; bit < 8; ++bit) {
|
||||
if ((ctx->usage_masks[byte] & (1 << bit)) != 0) {
|
||||
++ctx->buttons_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert DPAD to hat
|
||||
const int DPAD_MASK = (1 << SINPUT_BUTTON_IDX_DPAD_UP) |
|
||||
(1 << SINPUT_BUTTON_IDX_DPAD_DOWN) |
|
||||
(1 << SINPUT_BUTTON_IDX_DPAD_LEFT) |
|
||||
(1 << SINPUT_BUTTON_IDX_DPAD_RIGHT);
|
||||
if ((ctx->usage_masks[0] & DPAD_MASK) == DPAD_MASK) {
|
||||
ctx->dpad_supported = true;
|
||||
ctx->usage_masks[0] &= ~DPAD_MASK;
|
||||
ctx->buttons_count -= 4;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_SINPUT_INIT)
|
||||
SDL_Log("Buttons count: %d", ctx->buttons_count);
|
||||
#endif
|
||||
|
||||
// Get and validate touchpad parameters
|
||||
ctx->touchpad_count = data[16];
|
||||
@@ -354,6 +512,48 @@ static void ProcessSDLFeaturesResponse(SDL_HIDAPI_Device *device, Uint8 *data)
|
||||
|
||||
ctx->accelScale = CalculateAccelScale(ctx->accelRange);
|
||||
ctx->gyroScale = CalculateGyroScale(ctx->gyroRange);
|
||||
|
||||
Uint8 axes = 0;
|
||||
if (ctx->left_analog_stick_supported) {
|
||||
axes += 2;
|
||||
}
|
||||
|
||||
if (ctx->right_analog_stick_supported) {
|
||||
axes += 2;
|
||||
}
|
||||
|
||||
if (ctx->left_analog_trigger_supported || ctx->right_analog_trigger_supported) {
|
||||
// Always add both analog trigger axes if one is present
|
||||
axes += 2;
|
||||
}
|
||||
|
||||
ctx->axes_count = axes;
|
||||
|
||||
DeviceDynamicEncodingSetup(device);
|
||||
|
||||
// Derive button count from mask
|
||||
for (Uint8 byte = 0; byte < 4; ++byte) {
|
||||
for (Uint8 bit = 0; bit < 8; ++bit) {
|
||||
if ((ctx->usage_masks[byte] & (1 << bit)) != 0) {
|
||||
++ctx->buttons_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Convert DPAD to hat
|
||||
const int DPAD_MASK = (1 << SINPUT_BUTTON_IDX_DPAD_UP) |
|
||||
(1 << SINPUT_BUTTON_IDX_DPAD_DOWN) |
|
||||
(1 << SINPUT_BUTTON_IDX_DPAD_LEFT) |
|
||||
(1 << SINPUT_BUTTON_IDX_DPAD_RIGHT);
|
||||
if ((ctx->usage_masks[0] & DPAD_MASK) == DPAD_MASK) {
|
||||
ctx->dpad_supported = true;
|
||||
ctx->usage_masks[0] &= ~DPAD_MASK;
|
||||
ctx->buttons_count -= 4;
|
||||
}
|
||||
|
||||
#if defined(DEBUG_SINPUT_INIT)
|
||||
SDL_Log("Buttons count: %d", ctx->buttons_count);
|
||||
#endif
|
||||
}
|
||||
|
||||
static bool RetrieveSDLFeatures(SDL_HIDAPI_Device *device)
|
||||
@@ -460,6 +660,9 @@ static bool HIDAPI_DriverSInput_InitDevice(SDL_HIDAPI_Device *device)
|
||||
return false;
|
||||
}
|
||||
|
||||
// Store the USB Device Version because we will overwrite this data
|
||||
ctx->usb_device_version = device->version;
|
||||
|
||||
switch (device->product_id) {
|
||||
case USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE:
|
||||
HIDAPI_SetDeviceName(device, "HHL GC Ultimate");
|
||||
@@ -467,8 +670,11 @@ static bool HIDAPI_DriverSInput_InitDevice(SDL_HIDAPI_Device *device)
|
||||
case USB_PRODUCT_HANDHELDLEGEND_PROGCC:
|
||||
HIDAPI_SetDeviceName(device, "HHL ProGCC");
|
||||
break;
|
||||
case USB_PRODUCT_VOIDGAMING_PS4FIREBIRD:
|
||||
HIDAPI_SetDeviceName(device, "Void Gaming PS4 FireBird");
|
||||
break;
|
||||
case USB_PRODUCT_BONZIRICHANNEL_FIREBIRD:
|
||||
HIDAPI_SetDeviceName(device, "Bonziri Firebird");
|
||||
HIDAPI_SetDeviceName(device, "Bonziri FireBird");
|
||||
break;
|
||||
case USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC:
|
||||
default:
|
||||
@@ -523,45 +729,18 @@ static bool HIDAPI_DriverSInput_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys
|
||||
|
||||
SDL_zeroa(ctx->last_state);
|
||||
|
||||
int axes = 0;
|
||||
if (ctx->left_analog_stick_supported) {
|
||||
axes += 2;
|
||||
}
|
||||
|
||||
if (ctx->right_analog_stick_supported) {
|
||||
axes += 2;
|
||||
}
|
||||
|
||||
if (ctx->left_analog_trigger_supported) {
|
||||
++axes;
|
||||
}
|
||||
|
||||
if (ctx->right_analog_trigger_supported) {
|
||||
++axes;
|
||||
}
|
||||
|
||||
if ((device->product_id == USB_PRODUCT_HANDHELDLEGEND_SINPUT_GENERIC) && (device->vendor_id == USB_VENDOR_RASPBERRYPI)) {
|
||||
switch (ctx->sub_type) {
|
||||
// Default generic device, exposes all axes
|
||||
default:
|
||||
case 0:
|
||||
axes = 6;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
joystick->naxes = axes;
|
||||
joystick->naxes = ctx->axes_count;
|
||||
|
||||
if (ctx->dpad_supported) {
|
||||
joystick->nhats = 1;
|
||||
}
|
||||
|
||||
if (ctx->accelerometer_supported) {
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 1000.0f / ctx->polling_rate_ms);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 1000000.0f / ctx->polling_rate_us);
|
||||
}
|
||||
|
||||
if (ctx->gyroscope_supported) {
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 1000.0f / ctx->polling_rate_ms);
|
||||
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 1000000.0f / ctx->polling_rate_us);
|
||||
}
|
||||
|
||||
if (ctx->touchpad_supported) {
|
||||
|
92
src/joystick/hidapi/SDL_hidapi_sinput.h
Normal file
92
src/joystick/hidapi/SDL_hidapi_sinput.h
Normal file
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
Simple DirectMedia Layer
|
||||
Copyright (C) 2025 Mitchell Cairns <mitch.cairns@handheldlegend.com>
|
||||
|
||||
This software is provided 'as-is', without any express or implied
|
||||
warranty. In no event will the authors be held liable for any damages
|
||||
arising from the use of this software.
|
||||
|
||||
Permission is granted to anyone to use this software for any purpose,
|
||||
including commercial applications, and to alter it and redistribute it
|
||||
freely, subject to the following restrictions:
|
||||
|
||||
1. The origin of this software must not be misrepresented; you must not
|
||||
claim that you wrote the original software. If you use this software
|
||||
in a product, an acknowledgment in the product documentation would be
|
||||
appreciated but is not required.
|
||||
2. Altered source versions must be plainly marked as such, and must not be
|
||||
misrepresented as being the original software.
|
||||
3. This notice may not be removed or altered from any source distribution.
|
||||
*/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_ANALOGSTYLE_NONE,
|
||||
SINPUT_ANALOGSTYLE_LEFTONLY,
|
||||
SINPUT_ANALOGSTYLE_RIGHTONLY,
|
||||
SINPUT_ANALOGSTYLE_LEFTRIGHT,
|
||||
SINPUT_ANALOGSTYLE_MAX,
|
||||
} SInput_AnalogStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_BUMPERSTYLE_NONE,
|
||||
SINPUT_BUMPERSTYLE_ONE,
|
||||
SINPUT_BUMPERSTYLE_TWO,
|
||||
SINPUT_BUMPERSTYLE_MAX,
|
||||
} SInput_BumperStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_TRIGGERSTYLE_NONE,
|
||||
SINPUT_TRIGGERSTYLE_ANALOG,
|
||||
SINPUT_TRIGGERSTYLE_DIGITAL,
|
||||
SINPUT_TRIGGERSTYLE_DUALSTAGE,
|
||||
SINPUT_TRIGGERSTYLE_MAX,
|
||||
} SInput_TriggerStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_PADDLESTYLE_NONE,
|
||||
SINPUT_PADDLESTYLE_TWO,
|
||||
SINPUT_PADDLESTYLE_FOUR,
|
||||
SINPUT_PADDLESTYLE_MAX,
|
||||
} SInput_PaddleStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_METASTYLE_NONE,
|
||||
SINPUT_METASTYLE_BACK,
|
||||
SINPUT_METASTYLE_BACKGUIDE,
|
||||
SINPUT_METASTYLE_BACKGUIDESHARE,
|
||||
SINPUT_METASTYLE_MAX,
|
||||
} SInput_MetaStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_TOUCHSTYLE_NONE,
|
||||
SINPUT_TOUCHSTYLE_SINGLE,
|
||||
SINPUT_TOUCHSTYLE_DOUBLE,
|
||||
SINPUT_TOUCHSTYLE_MAX,
|
||||
} SInput_TouchStyleType;
|
||||
|
||||
typedef enum
|
||||
{
|
||||
SINPUT_MISCSTYLE_NONE,
|
||||
SINPUT_MISCSTYLE_1,
|
||||
SINPUT_MISCSTYLE_2,
|
||||
SINPUT_MISCSTYLE_3,
|
||||
SINPUT_MISCSTYLE_4,
|
||||
SINPUT_MISCSTYLE_MAX,
|
||||
} SInput_MiscStyleType;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
Uint16 analog_style;
|
||||
Uint16 bumper_style;
|
||||
Uint16 trigger_style;
|
||||
Uint16 paddle_style;
|
||||
Uint16 meta_style;
|
||||
Uint16 touch_style;
|
||||
Uint16 misc_style;
|
||||
} SDL_SInputStyles_t;
|
@@ -171,6 +171,7 @@
|
||||
#define USB_PRODUCT_HANDHELDLEGEND_PROGCC 0x10df
|
||||
#define USB_PRODUCT_HANDHELDLEGEND_GCULTIMATE 0x10dd
|
||||
#define USB_PRODUCT_BONZIRICHANNEL_FIREBIRD 0x10e0
|
||||
#define USB_PRODUCT_VOIDGAMING_PS4FIREBIRD 0x10e5
|
||||
|
||||
// USB usage pages
|
||||
#define USB_USAGEPAGE_GENERIC_DESKTOP 0x0001
|
||||
|
Reference in New Issue
Block a user