Prechádzať zdrojové kódy

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.
Sanjay Govind 3 dní pred
rodič
commit
94f17d6c61

+ 43 - 1
src/joystick/hidapi/SDL_hidapi_ps4.c

@@ -98,6 +98,7 @@ typedef struct
     Uint8 rgucTouchpadData1[3];
     Uint8 rgucTouchpadData1[3];
     Uint8 ucTouchpadCounter2;
     Uint8 ucTouchpadCounter2;
     Uint8 rgucTouchpadData2[3];
     Uint8 rgucTouchpadData2[3];
+    Uint8 rgucDeviceSpecific[12];
 } PS4StatePacket_t;
 } PS4StatePacket_t;
 
 
 typedef struct
 typedef struct
@@ -146,6 +147,9 @@ typedef struct
     bool vibration_supported;
     bool vibration_supported;
     bool touchpad_supported;
     bool touchpad_supported;
     bool effects_supported;
     bool effects_supported;
+    bool guitar_whammy_supported;
+    bool guitar_tilt_supported;
+    bool guitar_effects_selector_supported;
     HIDAPI_PS4_EnhancedReportHint enhanced_report_hint;
     HIDAPI_PS4_EnhancedReportHint enhanced_report_hint;
     bool enhanced_reports;
     bool enhanced_reports;
     bool enhanced_mode;
     bool enhanced_mode;
@@ -347,6 +351,7 @@ static bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
         if (size == 48 && data[2] == 0x27) {
         if (size == 48 && data[2] == 0x27) {
             Uint8 capabilities = data[4];
             Uint8 capabilities = data[4];
             Uint8 device_type = data[5];
             Uint8 device_type = data[5];
+            Uint8 device_specific_capabilities = data[24];
             Uint16 gyro_numerator = LOAD16(data[10], data[11]);
             Uint16 gyro_numerator = LOAD16(data[10], data[11]);
             Uint16 gyro_denominator = LOAD16(data[12], data[13]);
             Uint16 gyro_denominator = LOAD16(data[12], data[13]);
             Uint16 accel_numerator = LOAD16(data[14], data[15]);
             Uint16 accel_numerator = LOAD16(data[14], data[15]);
@@ -374,6 +379,15 @@ static bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
                 break;
                 break;
             case 0x01:
             case 0x01:
                 joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
                 joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
+                if (device_specific_capabilities & 0x01) {
+                    ctx->guitar_effects_selector_supported = true;
+                }
+                if (device_specific_capabilities & 0x02) {
+                    ctx->guitar_tilt_supported = true;
+                }
+                if (device_specific_capabilities & 0x04) {
+                    ctx->guitar_whammy_supported = true;
+                }
                 break;
                 break;
             case 0x02:
             case 0x02:
                 joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
                 joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
@@ -716,6 +730,10 @@ static void HIDAPI_DriverPS4_SetEnhancedModeAvailable(SDL_DriverPS4_Context *ctx
         SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, (float)(1000 / ctx->report_interval));
         SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, (float)(1000 / ctx->report_interval));
     }
     }
 
 
+    if (ctx->guitar_tilt_supported) {
+        SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, (float)(1000 / ctx->report_interval));
+    }
+
     if (ctx->official_controller) {
     if (ctx->official_controller) {
         ctx->report_battery = true;
         ctx->report_battery = true;
     }
     }
@@ -983,7 +1001,7 @@ static bool HIDAPI_DriverPS4_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device
 
 
     HIDAPI_DriverPS4_UpdateEnhancedModeOnApplicationUsage(ctx);
     HIDAPI_DriverPS4_UpdateEnhancedModeOnApplicationUsage(ctx);
 
 
-    if (!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) {
+    if ((!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) && !ctx->guitar_tilt_supported) {
         return SDL_Unsupported();
         return SDL_Unsupported();
     }
     }
 
 
@@ -1154,6 +1172,30 @@ static void HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_d
         SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, data, 3);
         SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, sensor_timestamp, data, 3);
     }
     }
 
 
+    if (ctx->guitar_whammy_supported) {
+        axis = ((int)packet->rgucDeviceSpecific[1] * 257) - 32768;
+        SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
+    }
+
+    if (ctx->guitar_effects_selector_supported) {
+        // Align pickup selector mappings with PS3 instruments
+        static const Sint16 effects_mappings[] = {24576, 11008, -1792, -13568, -26880};
+        if (packet->rgucDeviceSpecific[0] < SDL_arraysize(effects_mappings)) {
+            SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, effects_mappings[packet->rgucDeviceSpecific[0]]);
+        }
+    }
+
+    if (ctx->guitar_tilt_supported) {
+        float sensor_data[3];
+        sensor_data[0] = ((float)packet->rgucDeviceSpecific[2] / 255) * SDL_STANDARD_GRAVITY;
+        sensor_data[1] = 0;
+        sensor_data[2] = 0;
+        SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, sensor_data, SDL_arraysize(sensor_data));
+
+        // Align tilt mappings with PS3 instruments
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, packet->rgucDeviceSpecific[2] > 0xF0);
+    }
+
     SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
     SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
 }
 }
 
 

+ 45 - 1
src/joystick/hidapi/SDL_hidapi_ps5.c

@@ -156,6 +156,7 @@ typedef struct
     Uint8 rgucTouchpadData1[3];   // 32 - X/Y, 12 bits per axis
     Uint8 rgucTouchpadData1[3];   // 32 - X/Y, 12 bits per axis
     Uint8 ucTouchpadCounter2;     // 35 - high bit clear + counter
     Uint8 ucTouchpadCounter2;     // 35 - high bit clear + counter
     Uint8 rgucTouchpadData2[3];   // 36 - X/Y, 12 bits per axis
     Uint8 rgucTouchpadData2[3];   // 36 - X/Y, 12 bits per axis
+    Uint8 rgucDeviceSpecific[8];  // 40
 
 
     // There's more unknown data at the end, and a 32-bit CRC on Bluetooth
     // There's more unknown data at the end, and a 32-bit CRC on Bluetooth
 } PS5StatePacketAlt_t;
 } PS5StatePacketAlt_t;
@@ -232,6 +233,9 @@ typedef struct
     bool playerled_supported;
     bool playerled_supported;
     bool touchpad_supported;
     bool touchpad_supported;
     bool effects_supported;
     bool effects_supported;
+    bool guitar_whammy_supported;
+    bool guitar_tilt_supported;
+    bool guitar_effects_selector_supported;
     HIDAPI_PS5_EnhancedReportHint enhanced_report_hint;
     HIDAPI_PS5_EnhancedReportHint enhanced_report_hint;
     bool enhanced_reports;
     bool enhanced_reports;
     bool enhanced_mode;
     bool enhanced_mode;
@@ -448,6 +452,7 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
         if (size == 48 && data[2] == 0x28) {
         if (size == 48 && data[2] == 0x28) {
             Uint8 capabilities = data[4];
             Uint8 capabilities = data[4];
             Uint8 capabilities2 = data[20];
             Uint8 capabilities2 = data[20];
+            Uint8 device_specific_capabilities = data[24];
             Uint8 device_type = data[5];
             Uint8 device_type = data[5];
 
 
 #ifdef DEBUG_PS5_PROTOCOL
 #ifdef DEBUG_PS5_PROTOCOL
@@ -475,6 +480,15 @@ static bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
                 break;
                 break;
             case 0x01:
             case 0x01:
                 joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
                 joystick_type = SDL_JOYSTICK_TYPE_GUITAR;
+                if (device_specific_capabilities & 0x01) {
+                    ctx->guitar_effects_selector_supported = true;
+                }
+                if (device_specific_capabilities & 0x02) {
+                    ctx->guitar_tilt_supported = true;
+                }
+                if (device_specific_capabilities & 0x04) {
+                    ctx->guitar_whammy_supported = true;
+                }
                 break;
                 break;
             case 0x02:
             case 0x02:
                 joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
                 joystick_type = SDL_JOYSTICK_TYPE_DRUM_KIT;
@@ -836,6 +850,11 @@ static void HIDAPI_DriverPS5_SetEnhancedModeAvailable(SDL_DriverPS5_Context *ctx
         SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate);
         SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate);
     }
     }
 
 
+    if (ctx->guitar_tilt_supported) {
+        float update_rate = 250.0f;
+        SDL_PrivateJoystickAddSensor(ctx->joystick, SDL_SENSOR_ACCEL, update_rate);
+    }
+
     ctx->report_battery = true;
     ctx->report_battery = true;
 
 
     HIDAPI_UpdateDeviceProperties(ctx->device);
     HIDAPI_UpdateDeviceProperties(ctx->device);
@@ -1127,7 +1146,7 @@ static bool HIDAPI_DriverPS5_SetJoystickSensorsEnabled(SDL_HIDAPI_Device *device
 
 
     HIDAPI_DriverPS5_UpdateEnhancedModeOnApplicationUsage(ctx);
     HIDAPI_DriverPS5_UpdateEnhancedModeOnApplicationUsage(ctx);
 
 
-    if (!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) {
+    if ((!ctx->sensors_supported || (enabled && !ctx->enhanced_mode)) && !ctx->guitar_tilt_supported) {
         return SDL_Unsupported();
         return SDL_Unsupported();
     }
     }
 
 
@@ -1432,6 +1451,7 @@ static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hi
     static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
     static const float TOUCHPAD_SCALEY = 9.34579439e-4f; // 1.0f / 1070
     bool touchpad_down;
     bool touchpad_down;
     int touchpad_x, touchpad_y;
     int touchpad_x, touchpad_y;
+    Sint16 axis;
 
 
     if (ctx->report_touchpad) {
     if (ctx->report_touchpad) {
         touchpad_down = ((packet->ucTouchpadCounter1 & 0x80) == 0);
         touchpad_down = ((packet->ucTouchpadCounter1 & 0x80) == 0);
@@ -1447,6 +1467,30 @@ static void HIDAPI_DriverPS5_HandleStatePacketAlt(SDL_Joystick *joystick, SDL_hi
 
 
     HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, dev, ctx, (PS5StatePacketCommon_t *)packet, timestamp);
     HIDAPI_DriverPS5_HandleStatePacketCommon(joystick, dev, ctx, (PS5StatePacketCommon_t *)packet, timestamp);
 
 
+    if (ctx->guitar_whammy_supported) {
+        axis = ((int)packet->rgucDeviceSpecific[1] * 257) - 32768;
+        SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTX, axis);
+    }
+
+    if (ctx->guitar_effects_selector_supported) {
+        // Align pickup selector mappings with PS3 instruments
+        static const Sint16 effects_mappings[] = {24576, 11008, -1792, -13568, -26880};
+        if (packet->rgucDeviceSpecific[0] < SDL_arraysize(effects_mappings)) {
+            SDL_SendJoystickAxis(timestamp, joystick, SDL_GAMEPAD_AXIS_RIGHTY, effects_mappings[packet->rgucDeviceSpecific[0]]);
+        }
+    }
+
+    if (ctx->guitar_tilt_supported) {
+        float sensor_data[3];
+        sensor_data[0] = ((float)packet->rgucDeviceSpecific[2] / 255) * SDL_STANDARD_GRAVITY;
+        sensor_data[1] = 0;
+        sensor_data[2] = 0;
+        SDL_SendJoystickSensor(timestamp, joystick, SDL_SENSOR_ACCEL, timestamp, sensor_data, SDL_arraysize(sensor_data));
+
+        // Align tilt mappings with PS3 instruments
+        SDL_SendJoystickButton(timestamp, joystick, SDL_GAMEPAD_BUTTON_RIGHT_SHOULDER, packet->rgucDeviceSpecific[2] > 0xF0);
+    }
+
     SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
     SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state));
 }
 }
 
 

+ 2 - 0
src/joystick/hidapi/SDL_hidapijoystick.c

@@ -174,6 +174,8 @@ bool HIDAPI_SupportsPlaystationDetection(Uint16 vendor, Uint16 product)
     }
     }
 
 
     switch (vendor) {
     switch (vendor) {
+    case USB_VENDOR_CRKD:
+        return true;
     case USB_VENDOR_DRAGONRISE:
     case USB_VENDOR_DRAGONRISE:
         return true;
         return true;
     case USB_VENDOR_HORI:
     case USB_VENDOR_HORI:

+ 1 - 0
src/joystick/usb_ids.h

@@ -30,6 +30,7 @@
 #define USB_VENDOR_ASTRO        0x9886
 #define USB_VENDOR_ASTRO        0x9886
 #define USB_VENDOR_ASUS         0x0b05
 #define USB_VENDOR_ASUS         0x0b05
 #define USB_VENDOR_BACKBONE     0x358a
 #define USB_VENDOR_BACKBONE     0x358a
+#define USB_VENDOR_CRKD         0x3651
 #define USB_VENDOR_GAMESIR      0x3537
 #define USB_VENDOR_GAMESIR      0x3537
 #define USB_VENDOR_DRAGONRISE   0x0079
 #define USB_VENDOR_DRAGONRISE   0x0079
 #define USB_VENDOR_FLYDIGI_V1   0x04b4
 #define USB_VENDOR_FLYDIGI_V1   0x04b4