|
@@ -30,6 +30,9 @@
|
|
|
|
|
|
#ifdef SDL_JOYSTICK_HIDAPI_SINPUT
|
|
|
|
|
|
+/*****************************************************************************************************/
|
|
|
+// This protocol is documented at:
|
|
|
+// https://docs.handheldlegend.com/s/sinput/doc/sinput-hid-protocol-TkPYWlDMAg
|
|
|
/*****************************************************************************************************/
|
|
|
|
|
|
// Define this if you want to log all packets from the controller
|
|
@@ -83,6 +86,39 @@
|
|
|
#define SINPUT_REPORT_IDX_TOUCH2_Y 43
|
|
|
#define SINPUT_REPORT_IDX_TOUCH2_P 45
|
|
|
|
|
|
+#define SINPUT_BUTTON_IDX_SOUTH 0
|
|
|
+#define SINPUT_BUTTON_IDX_EAST 1
|
|
|
+#define SINPUT_BUTTON_IDX_WEST 2
|
|
|
+#define SINPUT_BUTTON_IDX_NORTH 3
|
|
|
+#define SINPUT_BUTTON_IDX_DPAD_UP 4
|
|
|
+#define SINPUT_BUTTON_IDX_DPAD_DOWN 5
|
|
|
+#define SINPUT_BUTTON_IDX_DPAD_LEFT 6
|
|
|
+#define SINPUT_BUTTON_IDX_DPAD_RIGHT 7
|
|
|
+#define SINPUT_BUTTON_IDX_LEFT_STICK 8
|
|
|
+#define SINPUT_BUTTON_IDX_RIGHT_STICK 9
|
|
|
+#define SINPUT_BUTTON_IDX_LEFT_BUMPER 10
|
|
|
+#define SINPUT_BUTTON_IDX_RIGHT_BUMPER 11
|
|
|
+#define SINPUT_BUTTON_IDX_LEFT_TRIGGER 12
|
|
|
+#define SINPUT_BUTTON_IDX_RIGHT_TRIGGER 13
|
|
|
+#define SINPUT_BUTTON_IDX_LEFT_PADDLE1 14
|
|
|
+#define SINPUT_BUTTON_IDX_RIGHT_PADDLE1 15
|
|
|
+#define SINPUT_BUTTON_IDX_START 16
|
|
|
+#define SINPUT_BUTTON_IDX_BACK 17
|
|
|
+#define SINPUT_BUTTON_IDX_GUIDE 18
|
|
|
+#define SINPUT_BUTTON_IDX_CAPTURE 19
|
|
|
+#define SINPUT_BUTTON_IDX_LEFT_PADDLE2 20
|
|
|
+#define SINPUT_BUTTON_IDX_RIGHT_PADDLE2 21
|
|
|
+#define SINPUT_BUTTON_IDX_TOUCHPAD1 22
|
|
|
+#define SINPUT_BUTTON_IDX_TOUCHPAD2 23
|
|
|
+#define SINPUT_BUTTON_IDX_POWER 24
|
|
|
+#define SINPUT_BUTTON_IDX_MISC4 25
|
|
|
+#define SINPUT_BUTTON_IDX_MISC5 26
|
|
|
+#define SINPUT_BUTTON_IDX_MISC6 27
|
|
|
+#define SINPUT_BUTTON_IDX_MISC7 28
|
|
|
+#define SINPUT_BUTTON_IDX_MISC8 29
|
|
|
+#define SINPUT_BUTTON_IDX_MISC9 30
|
|
|
+#define SINPUT_BUTTON_IDX_MISC10 31
|
|
|
+
|
|
|
#define SINPUT_REPORT_IDX_COMMAND_RESPONSE_ID 1
|
|
|
#define SINPUT_REPORT_IDX_COMMAND_RESPONSE_BULK 2
|
|
|
|
|
@@ -160,6 +196,7 @@ typedef struct
|
|
|
bool right_analog_stick_supported;
|
|
|
bool left_analog_trigger_supported;
|
|
|
bool right_analog_trigger_supported;
|
|
|
+ bool dpad_supported;
|
|
|
bool touchpad_supported;
|
|
|
|
|
|
Uint8 touchpad_count; // 2 touchpads maximum
|
|
@@ -257,6 +294,17 @@ static void ProcessSDLFeaturesResponse(SDL_HIDAPI_Device *device, Uint8 *data)
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ // Convert DPAD to hat
|
|
|
+ const 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
|
|
@@ -281,7 +329,7 @@ static bool RetrieveSDLFeatures(SDL_HIDAPI_Device *device)
|
|
|
{
|
|
|
int written = 0;
|
|
|
|
|
|
- // Attempt to send the SDL features get command.
|
|
|
+ // Attempt to send the SDL features get command.
|
|
|
for (int attempt = 0; attempt < 8; ++attempt) {
|
|
|
const Uint8 featuresGetCommand[SINPUT_DEVICE_REPORT_COMMAND_SIZE] = { SINPUT_DEVICE_REPORT_ID_OUTPUT_CMDDAT, SINPUT_DEVICE_COMMAND_FEATURES };
|
|
|
// This write will occasionally return -1, so ignore failure here and try again
|
|
@@ -295,7 +343,7 @@ static bool RetrieveSDLFeatures(SDL_HIDAPI_Device *device)
|
|
|
if (written < SINPUT_DEVICE_REPORT_COMMAND_SIZE) {
|
|
|
SDL_SetError("SInput device SDL Features GET command could not write");
|
|
|
return false;
|
|
|
- }
|
|
|
+ }
|
|
|
|
|
|
int read = 0;
|
|
|
|
|
@@ -380,7 +428,7 @@ static bool HIDAPI_DriverSInput_InitDevice(SDL_HIDAPI_Device *device)
|
|
|
if (!RetrieveSDLFeatures(device)) {
|
|
|
return false;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return HIDAPI_JoystickConnected(device, NULL);
|
|
|
}
|
|
|
|
|
@@ -447,6 +495,10 @@ static bool HIDAPI_DriverSInput_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joys
|
|
|
|
|
|
joystick->naxes = axes;
|
|
|
|
|
|
+ if (ctx->dpad_supported) {
|
|
|
+ joystick->nhats = 1;
|
|
|
+ }
|
|
|
+
|
|
|
if (ctx->accelerometer_supported) {
|
|
|
SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 1000.0f / ctx->polling_rate_ms);
|
|
|
}
|
|
@@ -522,7 +574,7 @@ static Uint32 HIDAPI_DriverSInput_GetJoystickCapabilities(SDL_HIDAPI_Device *dev
|
|
|
if (ctx->joystick_rgb_supported) {
|
|
|
caps |= SDL_JOYSTICK_CAP_RGB_LED;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
return caps;
|
|
|
}
|
|
|
|
|
@@ -594,6 +646,24 @@ static void HIDAPI_DriverSInput_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+ if (ctx->dpad_supported) {
|
|
|
+ Uint8 hat = SDL_HAT_CENTERED;
|
|
|
+
|
|
|
+ if (data[SINPUT_REPORT_IDX_BUTTONS_0] & (1 << SINPUT_BUTTON_IDX_DPAD_UP)) {
|
|
|
+ hat |= SDL_HAT_UP;
|
|
|
+ }
|
|
|
+ if (data[SINPUT_REPORT_IDX_BUTTONS_0] & (1 << SINPUT_BUTTON_IDX_DPAD_DOWN)) {
|
|
|
+ hat |= SDL_HAT_DOWN;
|
|
|
+ }
|
|
|
+ if (data[SINPUT_REPORT_IDX_BUTTONS_0] & (1 << SINPUT_BUTTON_IDX_DPAD_LEFT)) {
|
|
|
+ hat |= SDL_HAT_LEFT;
|
|
|
+ }
|
|
|
+ if (data[SINPUT_REPORT_IDX_BUTTONS_0] & (1 << SINPUT_BUTTON_IDX_DPAD_RIGHT)) {
|
|
|
+ hat |= SDL_HAT_RIGHT;
|
|
|
+ }
|
|
|
+ SDL_SendJoystickHat(timestamp, joystick, 0, hat);
|
|
|
+ }
|
|
|
+
|
|
|
// Analog inputs map to a signed Sint16 range of -32768 to 32767 from the device.
|
|
|
// Use an axis index because not all gamepads will have the same axis inputs.
|
|
|
Uint8 axis_idx = 0;
|
|
@@ -609,7 +679,7 @@ static void HIDAPI_DriverSInput_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
|
|
|
SDL_SendJoystickAxis(timestamp, joystick, axis_idx, axis);
|
|
|
++axis_idx;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Right Analog Stick
|
|
|
axis = 0; // Reset axis value for joystick
|
|
|
if (ctx->right_analog_stick_supported) {
|
|
@@ -629,7 +699,7 @@ static void HIDAPI_DriverSInput_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
|
|
|
SDL_SendJoystickAxis(timestamp, joystick, axis_idx, axis);
|
|
|
++axis_idx;
|
|
|
}
|
|
|
-
|
|
|
+
|
|
|
// Right Analog Trigger
|
|
|
axis = SDL_MIN_SINT16; // Reset axis value for trigger
|
|
|
if (ctx->right_analog_trigger_supported) {
|
|
@@ -670,7 +740,7 @@ static void HIDAPI_DriverSInput_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
|
|
|
|
|
|
if (state > 0) {
|
|
|
SDL_SendJoystickPowerInfo(joystick, state, percent);
|
|
|
- }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
// Extract the IMU timestamp delta (in microseconds)
|
|
@@ -710,7 +780,7 @@ static void HIDAPI_DriverSInput_HandleStatePacket(SDL_Joystick *joystick, SDL_Dr
|
|
|
|
|
|
// Process Gyroscope
|
|
|
if (ctx->gyroscope_supported) {
|
|
|
-
|
|
|
+
|
|
|
gyro = EXTRACTSINT16(data, SINPUT_REPORT_IDX_IMU_GYRO_Y);
|
|
|
imu_values[2] = -(float)gyro * ctx->gyroScale; // Y-axis rotation
|
|
|
|