SDL: Added detection of the joystick type for third party PS4 and PS5 controllers

From 17d7d03adf6aeb090f5689e6aa0f31d690a3e39f Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Mon, 26 Sep 2022 08:12:35 -0700
Subject: [PATCH] Added detection of the joystick type for third party PS4 and
 PS5 controllers

---
 src/joystick/hidapi/SDL_hidapi_ps4.c | 30 ++++++++++++++++++++++++++++
 src/joystick/hidapi/SDL_hidapi_ps5.c | 27 +++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c
index 04c3d4031f0..d1c422cd0b8 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps4.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps4.c
@@ -239,6 +239,7 @@ HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
     Uint8 data[USB_PACKET_LENGTH];
     int size;
     char serial[18];
+    SDL_JoystickType joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
 
     ctx = (SDL_DriverPS4_Context *)SDL_calloc(1, sizeof(*ctx));
     if (!ctx) {
@@ -315,6 +316,7 @@ HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
     } else if ((size = ReadFeatureReport(device->dev, k_ePS4FeatureReportIdCapabilities, data, sizeof(data))) == 48 &&
                data[2] == 0x27) {
         Uint8 capabilities = data[4];
+        Uint8 device_type = data[5];
 
 #ifdef DEBUG_PS4_PROTOCOL
         HIDAPI_DumpPacket("PS4 capabilities: size = %d", data, size);
@@ -331,6 +333,33 @@ HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
         if ((capabilities & 0x40) != 0) {
             ctx->touchpad_supported = SDL_TRUE;
         }
+
+        switch (device_type) {
+        case 0x00:
+            joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
+            break;
+        case 0x01:
+            joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
+            break;
+        case 0x02:
+            joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
+            break;
+        case 0x04:
+            joystick_type = SDL_JOYSTICK_TYPE_DANCE_PAD;
+            break;
+        case 0x06:
+            joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
+            break;
+        case 0x07:
+            joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
+            break;
+        case 0x08:
+            joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
+            break;
+        default:
+            joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
+            break;
+        }
     } else if (device->vendor_id == USB_VENDOR_RAZER) {
         /* The Razer Raiju doesn't respond to the detection protocol, but has a touchpad and vibration */
         ctx->vibration_supported = SDL_TRUE;
@@ -338,6 +367,7 @@ HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
     }
     ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported);
 
+    device->joystick_type = joystick_type;
     device->type = SDL_CONTROLLER_TYPE_PS4;
     if (device->vendor_id == USB_VENDOR_SONY) {
         HIDAPI_SetDeviceName(device, "PS4 Controller");
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index 6f26c3b91f2..5f72d56c06e 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -340,6 +340,7 @@ HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
     Uint8 data[USB_PACKET_LENGTH*2];
     int size;
     char serial[18];
+    SDL_JoystickType joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
 
     ctx = (SDL_DriverPS5_Context *)SDL_calloc(1, sizeof(*ctx));
     if (!ctx) {
@@ -422,6 +423,7 @@ HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
                data[2] == 0x28) {
         Uint8 capabilities = data[4];
         Uint8 capabilities2 = data[20];
+        Uint8 device_type = data[5];
 
 #ifdef DEBUG_PS5_PROTOCOL
         HIDAPI_DumpPacket("PS5 capabilities: size = %d", data, size);
@@ -442,10 +444,35 @@ HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
             ctx->playerled_supported = SDL_TRUE;
         }
 
+        switch (device_type) {
+        case 0x00:
+            joystick_type = SDL_JOYSTICK_TYPE_GAMECONTROLLER;
+            break;
+        case 0x01:
+            joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
+            break;
+        case 0x02:
+            joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
+            break;
+        case 0x06:
+            joystick_type = SDL_JOYSTICK_TYPE_WHEEL;
+            break;
+        case 0x07:
+            joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
+            break;
+        case 0x08:
+            joystick_type = SDL_JOYSTICK_TYPE_FLIGHT_STICK;
+            break;
+        default:
+            joystick_type = SDL_JOYSTICK_TYPE_UNKNOWN;
+            break;
+        }
+
         ctx->use_alternate_report = SDL_TRUE;
     }
     ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported || ctx->playerled_supported);
 
+    device->joystick_type = joystick_type;
     device->type = SDL_CONTROLLER_TYPE_PS5;
     if (device->vendor_id == USB_VENDOR_SONY) {
         HIDAPI_SetDeviceName(device, "PS5 Controller");