Skip to content

Commit 94f17d6

Browse files
authored
Add support for whammy and tilt on PS4/5 guitars
PS4/5 controllers put device specific data into a specific region in the report, so we have to extract it separately. No known guitars use the right stick on the guitar, so to keep things working similarly to PS3, i have opted to map whammy and tilt the same way as the PS3 rb guitars.
1 parent b3f4eba commit 94f17d6

File tree

4 files changed

+91
-2
lines changed

4 files changed

+91
-2
lines changed

src/joystick/hidapi/SDL_hidapi_ps4.c

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,7 @@ typedef struct
9898
Uint8 rgucTouchpadData1[3];
9999
Uint8 ucTouchpadCounter2;
100100
Uint8 rgucTouchpadData2[3];
101+
Uint8 rgucDeviceSpecific[12];
101102
} PS4StatePacket_t;
102103

103104
typedef struct
@@ -146,6 +147,9 @@ typedef struct
146147
bool vibration_supported;
147148
bool touchpad_supported;
148149
bool effects_supported;
150+
bool guitar_whammy_supported;
151+
bool guitar_tilt_supported;
152+
bool guitar_effects_selector_supported;
149153
HIDAPI_PS4_EnhancedReportHint enhanced_report_hint;
150154
bool enhanced_reports;
151155
bool enhanced_mode;
@@ -347,6 +351,7 @@ static bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
347351
if (size == 48 && data[2] == 0x27) {
348352
Uint8 capabilities = data[4];
349353
Uint8 device_type = data[5];
354+
Uint8 device_specific_capabilities = data[24];
350355
Uint16 gyro_numerator = LOAD16(data[10], data[11]);
351356
Uint16 gyro_denominator = LOAD16(data[12], data[13]);
352357
Uint16 accel_numerator = LOAD16(data[14], data[15]);
@@ -374,6 +379,15 @@ static bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
374379
break;
375380
case 0x01:
376381
joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
382+
if (device_specific_capabilities & 0x01) {
383+
ctx->guitar_effects_selector_supported = true;
384+
}
385+
if (device_specific_capabilities & 0x02) {
386+
ctx->guitar_tilt_supported = true;
387+
}
388+
if (device_specific_capabilities & 0x04) {
389+
ctx->guitar_whammy_supported = true;
390+
}
377391
break;
378392
case 0x02:
379393
joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
@@ -716,6 +730,10 @@ static void HIDAPI_DriverPS4_SetEnhancedModeAvailable(SDL_DriverPS4_Context *ctx
716730
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, (float)(1000 / ctx->report_interval));
717731
}
718732

733+
if (ctx->guitar_tilt_supported) {
734+
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, (float)(1000 / ctx->report_interval));
735+
}
736+
719737
if (ctx->official_controller) {
720738
ctx->report_battery = true;
721739
}
@@ -983,7 +1001,7 @@ static bool HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device
9831001

9841002
HIDAPI_DriverPS4_UpdateEnhancedModeOnApplicationUsage(ctx);
9851003

986-
if (!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) {
1004+
if ((!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) && !ctx->guitar_tilt_supported) {
9871005
return SDL_Unsupported();
9881006
}
9891007

@@ -1154,6 +1172,30 @@ static void HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_d
11541172
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, data, 3);
11551173
}
11561174

1175+
if (ctx->guitar_whammy_supported) {
1176+
axis = ((int)packet->rgucDeviceSpecific[1] * 257) - 32768;
1177+
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
1178+
}
1179+
1180+
if (ctx->guitar_effects_selector_supported) {
1181+
// Align pickup selector mappings with PS3 instruments
1182+
static const Sint16 effects_mappings[] = {24576, 11008, -1792, -13568, -26880};
1183+
if (packet->rgucDeviceSpecific[0] < SDL_arraysize(effects_mappings)) {
1184+
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, effects_mappings[packet->rgucDeviceSpecific[0]]);
1185+
}
1186+
}
1187+
1188+
if (ctx->guitar_tilt_supported) {
1189+
float sensor_data[3];
1190+
sensor_data[0] = ((float)packet->rgucDeviceSpecific[2] / 255) * SDL_STANDARD_GRAVITY;
1191+
sensor_data[1] = 0;
1192+
sensor_data[2] = 0;
1193+
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, sensor_data, SDL_arraysize(sensor_data));
1194+
1195+
// Align tilt mappings with PS3 instruments
1196+
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, packet->rgucDeviceSpecific[2] > 0xF0);
1197+
}
1198+
11571199
SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
11581200
}
11591201

src/joystick/hidapi/SDL_hidapi_ps5.c

Lines changed: 45 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,7 @@ typedef struct
156156
Uint8 rgucTouchpadData1[3]; // 32 - X/Y, 12 bits per axis
157157
Uint8 ucTouchpadCounter2; // 35 - high bit clear + counter
158158
Uint8 rgucTouchpadData2[3]; // 36 - X/Y, 12 bits per axis
159+
Uint8 rgucDeviceSpecific[8]; // 40
159160

160161
// There's more unknown data at the end, and a 32-bit CRC on Bluetooth
161162
} PS5StatePacketAlt_t;
@@ -232,6 +233,9 @@ typedef struct
232233
bool playerled_supported;
233234
bool touchpad_supported;
234235
bool effects_supported;
236+
bool guitar_whammy_supported;
237+
bool guitar_tilt_supported;
238+
bool guitar_effects_selector_supported;
235239
HIDAPI_PS5_EnhancedReportHint enhanced_report_hint;
236240
bool enhanced_reports;
237241
bool enhanced_mode;
@@ -448,6 +452,7 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
448452
if (size == 48 && data[2] == 0x28) {
449453
Uint8 capabilities = data[4];
450454
Uint8 capabilities2 = data[20];
455+
Uint8 device_specific_capabilities = data[24];
451456
Uint8 device_type = data[5];
452457

453458
#ifdef DEBUG_PS5_PROTOCOL
@@ -475,6 +480,15 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
475480
break;
476481
case 0x01:
477482
joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
483+
if (device_specific_capabilities & 0x01) {
484+
ctx->guitar_effects_selector_supported = true;
485+
}
486+
if (device_specific_capabilities & 0x02) {
487+
ctx->guitar_tilt_supported = true;
488+
}
489+
if (device_specific_capabilities & 0x04) {
490+
ctx->guitar_whammy_supported = true;
491+
}
478492
break;
479493
case 0x02:
480494
joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
@@ -836,6 +850,11 @@ static void HIDAPI_DriverPS5_SetEnhancedModeAvailable(SDL_DriverPS5_Context *ctx
836850
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate);
837851
}
838852

853+
if (ctx->guitar_tilt_supported) {
854+
float update_rate = 250.0f;
855+
SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate);
856+
}
857+
839858
ctx->report_battery = true;
840859

841860
HIDAPI_UpdateDeviceProperties(ctx->device);
@@ -1127,7 +1146,7 @@ static bool HIDAPI_DriverPS5_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device
11271146

11281147
HIDAPI_DriverPS5_UpdateEnhancedModeOnApplicationUsage(ctx);
11291148

1130-
if (!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) {
1149+
if ((!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) && !ctx->guitar_tilt_supported) {
11311150
return SDL_Unsupported();
11321151
}
11331152

@@ -1432,6 +1451,7 @@ static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hi
14321451
static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
14331452
bool touchpad_down;
14341453
int touchpad_x, touchpad_y;
1454+
Sint16 axis;
14351455

14361456
if (ctx->report_touchpad) {
14371457
touchpad_down = ((packet->ucTouchpadCounter1 & 0x80) == 0);
@@ -1447,6 +1467,30 @@ static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hi
14471467

14481468
HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, dev, ctx, (PS5StatePacketCommon_t *)packet, timestamp);
14491469

1470+
if (ctx->guitar_whammy_supported) {
1471+
axis = ((int)packet->rgucDeviceSpecific[1] * 257) - 32768;
1472+
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
1473+
}
1474+
1475+
if (ctx->guitar_effects_selector_supported) {
1476+
// Align pickup selector mappings with PS3 instruments
1477+
static const Sint16 effects_mappings[] = {24576, 11008, -1792, -13568, -26880};
1478+
if (packet->rgucDeviceSpecific[0] < SDL_arraysize(effects_mappings)) {
1479+
SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, effects_mappings[packet->rgucDeviceSpecific[0]]);
1480+
}
1481+
}
1482+
1483+
if (ctx->guitar_tilt_supported) {
1484+
float sensor_data[3];
1485+
sensor_data[0] = ((float)packet->rgucDeviceSpecific[2] / 255) * SDL_STANDARD_GRAVITY;
1486+
sensor_data[1] = 0;
1487+
sensor_data[2] = 0;
1488+
SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, sensor_data, SDL_arraysize(sensor_data));
1489+
1490+
// Align tilt mappings with PS3 instruments
1491+
SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, packet->rgucDeviceSpecific[2] > 0xF0);
1492+
}
1493+
14501494
SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
14511495
}
14521496

src/joystick/hidapi/SDL_hidapijoystick.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ bool HIDAPI_SupportsPlaystationDetection(Uint16 vendor, Uint16 product)
174174
}
175175

176176
switch (vendor) {
177+
case USB_VENDOR_CRKD:
178+
return true;
177179
case USB_VENDOR_DRAGONRISE:
178180
return true;
179181
case USB_VENDOR_HORI:

src/joystick/usb_ids.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
#define USB_VENDOR_ASTRO 0x9886
3131
#define USB_VENDOR_ASUS 0x0b05
3232
#define USB_VENDOR_BACKBONE 0x358a
33+
#define USB_VENDOR_CRKD 0x3651
3334
#define USB_VENDOR_GAMESIR 0x3537
3435
#define USB_VENDOR_DRAGONRISE 0x0079
3536
#define USB_VENDOR_FLYDIGI_V1 0x04b4

0 commit comments

Comments
 (0)