SDL: Added support for the Razer Raiju V5 Pro in wireless mode (d264c)

From d264c27468e04307896c86a8fc2243548406ab9d Mon Sep 17 00:00:00 2001
From: Sam Lantinga <[EMAIL REDACTED]>
Date: Tue, 13 Jan 2026 16:23:05 -0800
Subject: [PATCH] Added support for the Razer Raiju V5 Pro in wireless mode

(cherry picked from commit 54fdeb9e79550a03feac1b6fbe1fee1cb5166fe6)
---
 src/joystick/controller_list.h       |  3 ++-
 src/joystick/hidapi/SDL_hidapi_ps5.c | 32 ++++++++++++++++++----------
 src/joystick/usb_ids.h               |  3 ++-
 3 files changed, 25 insertions(+), 13 deletions(-)

diff --git a/src/joystick/controller_list.h b/src/joystick/controller_list.h
index 2980f82dc2b33..5cf4e2c4055b5 100644
--- a/src/joystick/controller_list.h
+++ b/src/joystick/controller_list.h
@@ -159,7 +159,8 @@ static const ControllerDescription_t arrControllers[] = {
 	{ MAKE_CONTROLLER_ID( 0x1532, 0x100b ), k_eControllerType_PS5Controller, NULL },	// Razer Wolverine V2 Pro (Wired)
 	{ MAKE_CONTROLLER_ID( 0x1532, 0x100c ), k_eControllerType_PS5Controller, NULL },	// Razer Wolverine V2 Pro (Wireless)
 	{ MAKE_CONTROLLER_ID( 0x1532, 0x1012 ), k_eControllerType_PS5Controller, NULL },	// Razer Kitsune
-	{ MAKE_CONTROLLER_ID( 0x1532, 0x1024 ), k_eControllerType_PS5Controller, NULL },	// Razer Raiju V3 Pro
+	{ MAKE_CONTROLLER_ID( 0x1532, 0x1024 ), k_eControllerType_PS5Controller, NULL },	// Razer Raiju V5 Pro (PS5 mode wired)
+	{ MAKE_CONTROLLER_ID( 0x1532, 0x1026 ), k_eControllerType_PS5Controller, NULL },	// Razer Raiju V5 Pro (PS5 mode with dongle)
 	{ MAKE_CONTROLLER_ID( 0x3285, 0x0d18 ), k_eControllerType_PS5Controller, NULL },	// NACON Revolution 5 Pro (PS5 mode with dongle)
 	{ MAKE_CONTROLLER_ID( 0x3285, 0x0d19 ), k_eControllerType_PS5Controller, NULL },	// NACON Revolution 5 Pro (PS5 mode wired)
 	{ MAKE_CONTROLLER_ID( 0x358a, 0x0104 ), k_eControllerType_PS5Controller, NULL },	// Backbone One PlayStation Edition for iOS
diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c
index 5e6d7cf979334..526d6a37069ba 100644
--- a/src/joystick/hidapi/SDL_hidapi_ps5.c
+++ b/src/joystick/hidapi/SDL_hidapi_ps5.c
@@ -230,7 +230,7 @@ typedef struct
 {
     SDL_HIDAPI_Device *device;
     SDL_Joystick *joystick;
-    bool is_nacon_dongle;
+    bool is_dongle;
     bool use_alternate_report;
     bool sensors_supported;
     bool lightbar_supported;
@@ -516,7 +516,8 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
             ctx->use_alternate_report = true;
         } else if (device->vendor_id == USB_VENDOR_RAZER &&
                    (device->product_id == USB_PRODUCT_RAZER_KITSUNE ||
-                    device->product_id == USB_PRODUCT_RAZER_RAIJU_V3_PRO)) {
+                    device->product_id == USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRED ||
+                    device->product_id == USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRELESS)) {
             // The Razer Kitsune and Raiju don't respond to the detection protocol, but have a touchpad
             joystick_type = SDL_JOYSTICK_TYPE_ARCADE_STICK;
             ctx->touchpad_supported = true;
@@ -525,9 +526,13 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
     }
     ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported || ctx->playerled_supported);
 
-    if (device->vendor_id == USB_VENDOR_NACON_ALT &&
-        device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS) {
-        ctx->is_nacon_dongle = true;
+    if ((device->vendor_id == USB_VENDOR_NACON_ALT &&
+         device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS) ||
+        (device->vendor_id == USB_VENDOR_RAZER &&
+         (device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS ||
+          device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS ||
+          device->product_id == USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRELESS))) {
+        ctx->is_dongle = true;
     }
 
     device->joystick_type = joystick_type;
@@ -541,7 +546,7 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
     }
     HIDAPI_SetDeviceSerial(device, serial);
 
-    if (ctx->is_nacon_dongle) {
+    if (ctx->is_dongle) {
         // We don't know if this is connected yet, wait for reports
         return true;
     }
@@ -965,6 +970,10 @@ static bool HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystic
     joystick->nhats = 1;
     joystick->firmware_version = ctx->firmware_version;
 
+    if (ctx->is_dongle) {
+        joystick->connection_state = SDL_JOYSTICK_CONNECTION_WIRELESS;
+    }
+
     SDL_AddHintCallback(SDL_HINT_JOYSTICK_ENHANCED_REPORTS,
                         SDL_PS5EnhancedReportsChanged, ctx);
     SDL_AddHintCallback(SDL_HINT_JOYSTICK_HIDAPI_PS5_PLAYER_LED,
@@ -1465,15 +1474,16 @@ static bool HIDAPI_DriverPS5_IsPacketValid(SDL_DriverPS5_Context *ctx, Uint8 *da
 {
     switch (data[0]) {
     case k_EPS5ReportIdState:
-        if (ctx->is_nacon_dongle && size >= (1 + sizeof(PS5StatePacketAlt_t))) {
+        if (ctx->is_dongle && size >= (1 + sizeof(PS5StatePacketAlt_t))) {
             // The report timestamp doesn't change when the controller isn't connected
             PS5StatePacketAlt_t *packet = (PS5StatePacketAlt_t *)&data[1];
             if (SDL_memcmp(packet->rgucPacketSequence, ctx->last_state.state.rgucPacketSequence, sizeof(packet->rgucPacketSequence)) == 0) {
                 return false;
             }
-            if (ctx->last_state.alt_state.rgucAccelX[0] == 0 && ctx->last_state.alt_state.rgucAccelX[1] == 0 &&
-                ctx->last_state.alt_state.rgucAccelY[0] == 0 && ctx->last_state.alt_state.rgucAccelY[1] == 0 &&
-                ctx->last_state.alt_state.rgucAccelZ[0] == 0 && ctx->last_state.alt_state.rgucAccelZ[1] == 0) {
+            if (ctx->last_state.state.rgucPacketSequence[0] == 0 &&
+                ctx->last_state.state.rgucPacketSequence[1] == 0 &&
+                ctx->last_state.state.rgucPacketSequence[2] == 0 &&
+                ctx->last_state.state.rgucPacketSequence[3] == 0) {
                 // We don't have any state to compare yet, go ahead and copy it
                 SDL_memcpy(&ctx->last_state, &data[1], sizeof(PS5StatePacketAlt_t));
                 return false;
@@ -1572,7 +1582,7 @@ static bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
         }
     }
 
-    if (ctx->is_nacon_dongle) {
+    if (ctx->is_dongle) {
         if (packet_count == 0) {
             if (device->num_joysticks > 0) {
                 // Check to see if it looks like the device disconnected
diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h
index f0daf382ff54f..29c9fc379af8e 100644
--- a/src/joystick/usb_ids.h
+++ b/src/joystick/usb_ids.h
@@ -124,7 +124,8 @@
 #define USB_PRODUCT_RAZER_PANTHERA                        0x0401
 #define USB_PRODUCT_RAZER_PANTHERA_EVO                    0x1008
 #define USB_PRODUCT_RAZER_RAIJU                           0x1000
-#define USB_PRODUCT_RAZER_RAIJU_V3_PRO                    0x1024
+#define USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRED          0x1024
+#define USB_PRODUCT_RAZER_RAIJU_V3_PRO_PS5_WIRELESS       0x1026
 #define USB_PRODUCT_RAZER_TOURNAMENT_EDITION_USB          0x1007
 #define USB_PRODUCT_RAZER_TOURNAMENT_EDITION_BLUETOOTH    0x100a
 #define USB_PRODUCT_RAZER_ULTIMATE_EDITION_USB            0x1004