SDL: Added support for the DualSense Edge paddles

From 9339085593dc20b1f003f26b3c40615cf04504b0 Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Wed, 7 Dec 2022 14:25:53 -0800
Subject: [PATCH] Added support for the DualSense Edge paddles

---
 src/joystick/SDL_gamecontroller.c    |  4 ++++
 src/joystick/SDL_joystick.c          | 11 +++++++++++
 src/joystick/SDL_joystick_c.h        |  1 +
 src/joystick/hidapi/SDL_hidapi_ps5.c | 27 +++++++++++++++++++++++----
 src/joystick/usb_ids.h               |  1 +
 5 files changed, 40 insertions(+), 4 deletions(-)

diff --git a/src/joystick/SDL_gamecontroller.c b/src/joystick/SDL_gamecontroller.c
index d17ec72c0ff7..b54d7591aa61 100644
--- a/src/joystick/SDL_gamecontroller.c
+++ b/src/joystick/SDL_gamecontroller.c
@@ -638,6 +638,10 @@ static ControllerMapping_t *SDL_CreateMappingForHIDAPIController(SDL_JoystickGUI
             case SDL_CONTROLLER_TYPE_PS5:
                 /* PS5 controllers have a microphone button and an additional touchpad button */
                 SDL_strlcat(mapping_string, "touchpad:b15,misc1:b16,", sizeof(mapping_string));
+                /* DualSense Edge controllers have paddles */
+                if (SDL_IsJoystickDualSenseEdge(vendor, product)) {
+                    SDL_strlcat(mapping_string, "paddle1:b20,paddle2:b19,paddle3:b18,paddle4:b17,", sizeof(mapping_string));
+                }
                 break;
             case SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO:
                 /* Nintendo Switch Pro controllers have a screenshot button */
diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c
index 9ebdb7e160e5..85217b65df89 100644
--- a/src/joystick/SDL_joystick.c
+++ b/src/joystick/SDL_joystick.c
@@ -2166,6 +2166,17 @@ SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id)
     return eType == k_eControllerType_PS5Controller;
 }
 
+SDL_bool
+SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id)
+{
+    if (vendor_id == USB_VENDOR_SONY) {
+        if (product_id == USB_PRODUCT_SONY_DS5_EDGE) {
+            return SDL_TRUE;
+        }
+    }
+    return SDL_FALSE;
+}
+
 SDL_bool
 SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id)
 {
diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h
index 4c901269c87c..76ad2a4730d8 100644
--- a/src/joystick/SDL_joystick_c.h
+++ b/src/joystick/SDL_joystick_c.h
@@ -105,6 +105,7 @@ extern SDL_bool SDL_IsJoystickPS4(Uint16 vendor_id, Uint16 product_id);
 
 /* Function to return whether a joystick is a PS5 controller */
 extern SDL_bool SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id);
+extern SDL_bool SDL_IsJoystickDualSenseEdge(Uint16 vendor_id, Uint16 product_id);
 
 /* Function to return whether a joystick is a Nintendo Switch Pro controller */
 extern SDL_bool SDL_IsJoystickNintendoSwitchPro(Uint16 vendor_id, Uint16 product_id);
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index 75f7083a07e3..feb2f9a39c31 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -45,6 +45,15 @@
                             (((Uint32)(C)) << 16) | \
                             (((Uint32)(D)) << 24))
 
+enum
+{
+    SDL_CONTROLLER_BUTTON_PS5_TOUCHPAD = SDL_CONTROLLER_BUTTON_MISC1 + 1,
+    SDL_CONTROLLER_BUTTON_PS5_LEFT_FUNCTION,
+    SDL_CONTROLLER_BUTTON_PS5_RIGHT_FUNCTION,
+    SDL_CONTROLLER_BUTTON_PS5_LEFT_PADDLE,
+    SDL_CONTROLLER_BUTTON_PS5_RIGHT_PADDLE
+};
+
 typedef enum
 {
     k_EPS5ReportIdState = 0x01,
@@ -820,7 +829,13 @@ static SDL_bool HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joy
     ctx->player_lights = SDL_GetHintBoolean(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED, SDL_TRUE);
 
     /* Initialize the joystick capabilities */
-    joystick->nbuttons = ctx->touchpad_supported ? 17 : 15;
+    if (SDL_IsJoystickDualSenseEdge(device->vendor_id, device->product_id)) {
+        joystick->nbuttons = 21;
+    } else if (ctx->touchpad_supported) {
+        joystick->nbuttons = 17;
+    } else {
+        joystick->nbuttons = 15;
+    }
     joystick->naxes = SDL_CONTROLLER_AXIS_MAX;
     joystick->epowerlevel = device->is_bluetooth ? SDL_JOYSTICK_POWER_UNKNOWN : SDL_JOYSTICK_POWER_WIRED;
     joystick->firmware_version = ctx->firmware_version;
@@ -1054,7 +1069,7 @@ static void HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, SDL
         Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03);
 
         SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(timestamp, joystick, 15, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
+        SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_MISC1, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
     }
 
     axis = ((int)packet->ucTriggerLeft * 257) - 32768;
@@ -1148,8 +1163,12 @@ static void HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL
         Uint8 data = packet->rgucButtonsAndHat[2];
 
         SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(timestamp, joystick, 15, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
-        SDL_PrivateJoystickButton(timestamp, joystick, 16, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
+        SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_MISC1, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED);
+        SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_PS5_TOUCHPAD, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED);
+        SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_PS5_LEFT_FUNCTION, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED);
+        SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_PS5_RIGHT_FUNCTION, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED);
+        SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_PS5_LEFT_PADDLE, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED);
+        SDL_PrivateJoystickButton(timestamp, joystick, SDL_CONTROLLER_BUTTON_PS5_RIGHT_PADDLE, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED);
     }
 
     axis = ((int)packet->ucTriggerLeft * 257) - 32768;
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index 4261a380e951..4cf9d80a9e8d 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -101,6 +101,7 @@
 #define USB_PRODUCT_SONY_DS4_DONGLE                       0x0ba0
 #define USB_PRODUCT_SONY_DS4_SLIM                         0x09cc
 #define USB_PRODUCT_SONY_DS5                              0x0ce6
+#define USB_PRODUCT_SONY_DS5_EDGE                         0x0df2
 #define USB_PRODUCT_VICTRIX_FS_PRO_V2                     0x0207
 #define USB_PRODUCT_XBOX360_XUSB_CONTROLLER               0x02a1 /* XUSB driver software PID */
 #define USB_PRODUCT_XBOX360_WIRED_CONTROLLER              0x028e