From 5770e87cb22137c81c883534bd129ea03106a137 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Fri, 2 Sep 2022 13:57:59 -0700
Subject: [PATCH] Fixed regression handling touchpad input with PS5 controllers
using the original shipping firmware
---
src/joystick/hidapi/SDL_hidapi_ps5.c | 114 +++++++++++++++------------
1 file changed, 65 insertions(+), 49 deletions(-)
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index 172d5e60a26..771911c2c02 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -109,14 +109,19 @@ typedef struct
Uint8 rgucAccelX[2]; /* 21 */
Uint8 rgucAccelY[2]; /* 23 */
Uint8 rgucAccelZ[2]; /* 25 */
- Uint8 rgucUnknown1[4]; /* 27 */
- Uint8 ucTouchpadCounter1; /* 31 - high bit clear + counter */
- Uint8 rgucTouchpadData1[3]; /* 32 - X/Y, 12 bits per axis */
- Uint8 ucTouchpadCounter2; /* 35 - high bit clear + counter */
- Uint8 rgucTouchpadData2[3]; /* 36 - X/Y, 12 bits per axis */
+ Uint8 rgucTimer1[4]; /* 27 - 32 bit little endian */
+ Uint8 ucBatteryTemp; /* 31 */
+ Uint8 ucTouchpadCounter1; /* 32 - high bit clear + counter */
+ Uint8 rgucTouchpadData1[3]; /* 33 - X/Y, 12 bits per axis */
+ Uint8 ucTouchpadCounter2; /* 36 - high bit clear + counter */
+ Uint8 rgucTouchpadData2[3]; /* 37 - X/Y, 12 bits per axis */
+ Uint8 rgucUnknown1[8]; /* 40 */
+ Uint8 rgucTimer2[4]; /* 48 - 32 bit little endian */
+ Uint8 ucBatteryLevel; /* 52 */
+ Uint8 ucConnectState; /* 53 - 0x08 = USB, 0x01 = headphone */
/* There's more unknown data at the end, and a 32-bit CRC on Bluetooth */
-} PS5StatePacketV1_t;
+} PS5StatePacket_t;
typedef struct
{
@@ -135,19 +140,14 @@ typedef struct
Uint8 rgucAccelX[2]; /* 21 */
Uint8 rgucAccelY[2]; /* 23 */
Uint8 rgucAccelZ[2]; /* 25 */
- Uint8 rgucTimer1[4]; /* 27 - 32 bit little endian */
- Uint8 ucBatteryTemp; /* 31 */
- Uint8 ucTouchpadCounter1; /* 32 - high bit clear + counter */
- Uint8 rgucTouchpadData1[3]; /* 33 - X/Y, 12 bits per axis */
- Uint8 ucTouchpadCounter2; /* 36 - high bit clear + counter */
- Uint8 rgucTouchpadData2[3]; /* 37 - X/Y, 12 bits per axis */
- Uint8 rgucUnknown1[8]; /* 40 */
- Uint8 rgucTimer2[4]; /* 48 - 32 bit little endian */
- Uint8 ucBatteryLevel; /* 52 */
- Uint8 ucConnectState; /* 53 - 0x08 = USB, 0x01 = headphone */
+ Uint8 rgucUnknown1[4]; /* 27 */
+ Uint8 ucTouchpadCounter1; /* 31 - high bit clear + counter */
+ Uint8 rgucTouchpadData1[3]; /* 32 - X/Y, 12 bits per axis */
+ Uint8 ucTouchpadCounter2; /* 35 - high bit clear + counter */
+ Uint8 rgucTouchpadData2[3]; /* 36 - X/Y, 12 bits per axis */
/* There's more unknown data at the end, and a 32-bit CRC on Bluetooth */
-} PS5StatePacketV2_t;
+} PS5StatePacketAlt_t;
typedef struct
{
@@ -198,6 +198,7 @@ typedef struct {
SDL_HIDAPI_Device *device;
SDL_Joystick *joystick;
SDL_bool is_bluetooth;
+ SDL_bool use_alternate_report;
SDL_bool effects_supported;
SDL_bool sensors_supported;
SDL_bool touchpad_supported;
@@ -221,6 +222,7 @@ typedef struct {
{
PS5SimpleStatePacket_t simple;
PS5StatePacketCommon_t state;
+ PS5StatePacket_t full_state;
Uint8 data[64];
} last_state;
} SDL_DriverPS5_Context;
@@ -250,6 +252,16 @@ static SDL_bool HIDAPI_DriverPS5_HasTouchpad(Uint16 vendor_id, Uint16 product_id
return SDL_TRUE;
}
+static SDL_bool HIDAPI_DriverPS5_UseAlternateReport(Uint16 vendor_id, Uint16 product_id)
+{
+ /* The Hori Fighting Stick Alpha reports touchpad at a different offset than the PS5 controller */
+ if (vendor_id == USB_VENDOR_HORI && product_id == USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5) {
+ return SDL_TRUE;
+ }
+
+ return SDL_FALSE;
+}
+
static int HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size);
static void
@@ -553,11 +565,11 @@ HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device)
SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context;
SDL_bool led_reset_complete = SDL_FALSE;
- if (ctx->firmware_version <= 0x204) {
+ if (ctx->use_alternate_report) {
/* We don't know how to check the timer, just assume it's complete for now */
led_reset_complete = SDL_TRUE;
} else {
- const PS5StatePacketV2_t *packet = (PS5StatePacketV2_t *)ctx->last_state.data;
+ const PS5StatePacket_t *packet = &ctx->last_state.full_state;
/* Check the timer to make sure the Bluetooth connection LED animation is complete */
const Uint32 connection_complete = 10200000;
@@ -730,6 +742,10 @@ HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick)
}
}
+ if (HIDAPI_DriverPS5_UseAlternateReport(device->vendor_id, device->product_id)) {
+ ctx->use_alternate_report = SDL_TRUE;
+ }
+
if (HIDAPI_DriverPS5_CanRumble(device->vendor_id, device->product_id)) {
ctx->effects_supported = SDL_TRUE;
}
@@ -1116,30 +1132,7 @@ HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL_hid_device
}
static void
-HIDAPI_DriverPS5_HandleStatePacketV1(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketV1_t *packet)
-{
- static const float TOUCHPAD_SCALEX = 1.0f / 1920;
- static const float TOUCHPAD_SCALEY = 1.0f / 1070;
- Uint8 touchpad_state;
- int touchpad_x, touchpad_y;
-
- if (ctx->report_touchpad) {
- touchpad_state = ((packet->ucTouchpadCounter1 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED;
- touchpad_x = packet->rgucTouchpadData1[0] | (((int)packet->rgucTouchpadData1[1] & 0x0F) << 8);
- touchpad_y = (packet->rgucTouchpadData1[1] >> 4) | ((int)packet->rgucTouchpadData1[2] << 4);
- SDL_PrivateJoystickTouchpad(joystick, 0, 0, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f);
-
- touchpad_state = ((packet->ucTouchpadCounter2 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED;
- touchpad_x = packet->rgucTouchpadData2[0] | (((int)packet->rgucTouchpadData2[1] & 0x0F) << 8);
- touchpad_y = (packet->rgucTouchpadData2[1] >> 4) | ((int)packet->rgucTouchpadData2[2] << 4);
- SDL_PrivateJoystickTouchpad(joystick, 0, 1, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f);
- }
-
- SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
-}
-
-static void
-HIDAPI_DriverPS5_HandleStatePacketV2(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketV2_t *packet)
+HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet)
{
static const float TOUCHPAD_SCALEX = 1.0f / 1920;
static const float TOUCHPAD_SCALEY = 1.0f / 1070;
@@ -1181,6 +1174,29 @@ HIDAPI_DriverPS5_HandleStatePacketV2(SDL_Joystick *joystick, SDL_hid_device *dev
SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
}
+static void
+HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketAlt_t *packet)
+{
+ static const float TOUCHPAD_SCALEX = 1.0f / 1920;
+ static const float TOUCHPAD_SCALEY = 1.0f / 1070;
+ Uint8 touchpad_state;
+ int touchpad_x, touchpad_y;
+
+ if (ctx->report_touchpad) {
+ touchpad_state = ((packet->ucTouchpadCounter1 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED;
+ touchpad_x = packet->rgucTouchpadData1[0] | (((int) packet->rgucTouchpadData1[1] & 0x0F) << 8);
+ touchpad_y = (packet->rgucTouchpadData1[1] >> 4) | ((int) packet->rgucTouchpadData1[2] << 4);
+ SDL_PrivateJoystickTouchpad(joystick, 0, 0, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f);
+
+ touchpad_state = ((packet->ucTouchpadCounter2 & 0x80) == 0) ? SDL_PRESSED : SDL_RELEASED;
+ touchpad_x = packet->rgucTouchpadData2[0] | (((int) packet->rgucTouchpadData2[1] & 0x0F) << 8);
+ touchpad_y = (packet->rgucTouchpadData2[1] >> 4) | ((int) packet->rgucTouchpadData2[2] << 4);
+ SDL_PrivateJoystickTouchpad(joystick, 0, 1, touchpad_state, touchpad_x * TOUCHPAD_SCALEX, touchpad_y * TOUCHPAD_SCALEY, touchpad_state ? 1.0f : 0.0f);
+ }
+
+ SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
+}
+
static SDL_bool
HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
{
@@ -1210,10 +1226,10 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
HIDAPI_DriverPS5_HandleSimpleStatePacket(joystick, device->dev, ctx, (PS5SimpleStatePacket_t *)&data[1]);
} else {
HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, device->dev, ctx, (PS5StatePacketCommon_t *)&data[1]);
- if (ctx->firmware_version <= 0x204) {
- HIDAPI_DriverPS5_HandleStatePacketV1(joystick, device->dev, ctx, (PS5StatePacketV1_t *)&data[1]);
+ if (ctx->use_alternate_report) {
+ HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[1]);
} else {
- HIDAPI_DriverPS5_HandleStatePacketV2(joystick, device->dev, ctx, (PS5StatePacketV2_t *)&data[1]);
+ HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[1]);
}
}
break;
@@ -1226,10 +1242,10 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
HIDAPI_DriverPS5_CheckPendingLEDReset(device);
}
HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, device->dev, ctx, (PS5StatePacketCommon_t *)&data[2]);
- if (ctx->firmware_version <= 0x204) {
- HIDAPI_DriverPS5_HandleStatePacketV1(joystick, device->dev, ctx, (PS5StatePacketV1_t *)&data[2]);
+ if (ctx->use_alternate_report) {
+ HIDAPI_DriverPS5_HandleStatePacketAlt(joystick, device->dev, ctx, (PS5StatePacketAlt_t *)&data[2]);
} else {
- HIDAPI_DriverPS5_HandleStatePacketV2(joystick, device->dev, ctx, (PS5StatePacketV2_t *)&data[2]);
+ HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2]);
}
break;
default: