From b2ac758f6173c6b0bced935c082f63d0e448d227 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Mon, 29 Aug 2022 17:33:00 -0700 Subject: [PATCH] Added support for the Hori Fighting Stick Alpha to the HIDAPI driver --- src/hidapi/libusb/hid.c | 3 +- src/joystick/SDL_joystick.c | 3 + src/joystick/controller_type.c | 3 + src/joystick/hidapi/SDL_hidapi_ps4.c | 60 +++++-- src/joystick/hidapi/SDL_hidapi_ps5.c | 242 +++++++++++++++++++++------ src/joystick/usb_ids.h | 3 + 6 files changed, 254 insertions(+), 60 deletions(-) diff --git a/src/hidapi/libusb/hid.c b/src/hidapi/libusb/hid.c index 37d01e34d..6ee1fbe67 100644 --- a/src/hidapi/libusb/hid.c +++ b/src/hidapi/libusb/hid.c @@ -1123,7 +1123,8 @@ static int SDLCALL read_thread(void *param) static void init_xbox360(libusb_device_handle *device_handle, unsigned short idVendor, unsigned short idProduct, struct libusb_config_descriptor *conf_desc) { if ((idVendor == 0x05ac && idProduct == 0x055b) /* Gamesir-G3w */ || - (idVendor == 0x0f0d && idProduct == 0x00dc) /* HORIPAD */) { + (idVendor == 0x0f0d && idProduct == 0x00dc) /* HORIPAD */ || + (idVendor == 0x0f0d && idProduct == 0x011e) /* Hori Fighting Stick α */) { unsigned char data[20]; /* The HORIPAD FPS for Nintendo Switch requires this to enable input reports. diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 117bf4c68..c855f36d9 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -2381,6 +2381,9 @@ static SDL_bool SDL_IsJoystickProductArcadeStick(Uint32 vidpid) MAKE_VIDPID(0x0f0d, 0x008a), /* HORI Real Arcade Pro 4 */ MAKE_VIDPID(0x0f0d, 0x008c), /* Hori Real Arcade Pro 4 */ MAKE_VIDPID(0x0f0d, 0x00aa), /* HORI Real Arcade Pro V Hayabusa in Switch Mode */ + MAKE_VIDPID(0x0f0d, 0x011c), /* Hori Fighting Stick α in PS4 Mode */ + MAKE_VIDPID(0x0f0d, 0x011e), /* Hori Fighting Stick α in PC Mode */ + MAKE_VIDPID(0x0f0d, 0x0184), /* Hori Fighting Stick α in PS5 Mode */ MAKE_VIDPID(0x1532, 0x0a00), /* Razer Atrox Arcade Stick */ MAKE_VIDPID(0x1bad, 0xf03d), /* Street Fighter IV Arcade Stick TE - Chun Li */ MAKE_VIDPID(0x1bad, 0xf502), /* Hori Real Arcade Pro.VX SA */ diff --git a/src/joystick/controller_type.c b/src/joystick/controller_type.c index aba5be33a..5029da09f 100644 --- a/src/joystick/controller_type.c +++ b/src/joystick/controller_type.c @@ -108,6 +108,7 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x0f0d, 0x009c ), k_eControllerType_PS4Controller, NULL }, // HORI TAC PRO mousething { MAKE_CONTROLLER_ID( 0x0f0d, 0x00a0 ), k_eControllerType_PS4Controller, NULL }, // HORI TAC4 mousething { MAKE_CONTROLLER_ID( 0x0f0d, 0x00ee ), k_eControllerType_PS4Controller, NULL }, // Hori mini wired https://www.playstation.com/en-us/explore/accessories/gaming-controllers/mini-wired-gamepad/ + { MAKE_CONTROLLER_ID( 0x0f0d, 0x011c ), k_eControllerType_PS4Controller, NULL }, // Hori Fighting Stick α { MAKE_CONTROLLER_ID( 0x11c0, 0x4001 ), k_eControllerType_PS4Controller, NULL }, // "PS4 Fun Controller" added from user log { MAKE_CONTROLLER_ID( 0x146b, 0x0d01 ), k_eControllerType_PS4Controller, NULL }, // Nacon Revolution Pro Controller - has gyro { MAKE_CONTROLLER_ID( 0x146b, 0x0d02 ), k_eControllerType_PS4Controller, NULL }, // Nacon Revolution Pro Controller v2 - has gyro @@ -140,6 +141,7 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x0c12, 0x0e20 ), k_eControllerType_PS4Controller, NULL }, // Brook Mars Controller - needs FW update to show up as Ps4 controller on PC. Has Gyro but touchpad is a single button. { MAKE_CONTROLLER_ID( 0x054c, 0x0ce6 ), k_eControllerType_PS5Controller, NULL }, // Sony PS5 Controller + { MAKE_CONTROLLER_ID( 0x0f0d, 0x0184 ), k_eControllerType_PS5Controller, NULL }, // Hori Fighting Stick α { MAKE_CONTROLLER_ID( 0x0079, 0x0006 ), k_eControllerType_UnknownNonSteamController, NULL }, // DragonRise Generic USB PCB, sometimes configured as a PC Twin Shock Controller - looks like a DS3 but the face buttons are 1-4 instead of symbols @@ -199,6 +201,7 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x0f0d, 0x001b ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro VX { MAKE_CONTROLLER_ID( 0x0f0d, 0x008c ), k_eControllerType_XBox360Controller, NULL }, // Hori Real Arcade Pro 4 { MAKE_CONTROLLER_ID( 0x0f0d, 0x00db ), k_eControllerType_XBox360Controller, "HORI Slime Controller" }, // Hori Dragon Quest Slime Controller + { MAKE_CONTROLLER_ID( 0x0f0d, 0x011e ), k_eControllerType_XBox360Controller, NULL }, // Hori Fighting Stick α { MAKE_CONTROLLER_ID( 0x1038, 0x1430 ), k_eControllerType_XBox360Controller, "SteelSeries Stratus Duo" }, // SteelSeries Stratus Duo { MAKE_CONTROLLER_ID( 0x1038, 0x1431 ), k_eControllerType_XBox360Controller, "SteelSeries Stratus Duo" }, // SteelSeries Stratus Duo { MAKE_CONTROLLER_ID( 0x1038, 0xb360 ), k_eControllerType_XBox360Controller, NULL }, // SteelSeries Nimbus/Stratus XL diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c index 3d3b617d8..cdabd60bf 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -127,8 +127,11 @@ typedef struct { SDL_bool official_controller; SDL_bool audio_supported; SDL_bool effects_supported; + SDL_bool sensors_supported; + SDL_bool touchpad_supported; SDL_bool enhanced_mode; SDL_bool report_sensors; + SDL_bool report_touchpad; SDL_bool hardware_calibration; IMUCalibrationData calibration[6]; Uint32 last_packet; @@ -202,6 +205,26 @@ static SDL_bool HIDAPI_DriverPS4_CanRumble(Uint16 vendor_id, Uint16 product_id) return SDL_FALSE; } + /* The Hori Fighting Stick Alpha doesn't have any rumble hardware */ + if (vendor_id == USB_VENDOR_HORI && product_id == USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS4) { + return SDL_FALSE; + } + + return SDL_TRUE; +} + +static SDL_bool HIDAPI_DriverPS4_HasSensors(Uint16 vendor_id, Uint16 product_id) +{ + /* The Hori Fighting Stick Alpha doesn't have any gyro or accelerometer */ + if (vendor_id == USB_VENDOR_HORI && product_id == USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS4) { + return SDL_FALSE; + } + + return SDL_TRUE; +} + +static SDL_bool HIDAPI_DriverPS4_HasTouchpad(Uint16 vendor_id, Uint16 product_id) +{ return SDL_TRUE; } @@ -456,9 +479,14 @@ HIDAPI_DriverPS4_SetEnhancedMode(SDL_HIDAPI_Device *device, SDL_Joystick *joysti if (!ctx->enhanced_mode) { ctx->enhanced_mode = SDL_TRUE; - SDL_PrivateJoystickAddTouchpad(joystick, 2); - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f); - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f); + if (ctx->touchpad_supported) { + SDL_PrivateJoystickAddTouchpad(joystick, 2); + ctx->report_touchpad = SDL_TRUE; + } + if (ctx->sensors_supported) { + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f); + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f); + } HIDAPI_DriverPS4_UpdateEffects(device); } @@ -570,6 +598,14 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) ctx->effects_supported = SDL_TRUE; } + if (HIDAPI_DriverPS4_HasSensors(device->vendor_id, device->product_id)) { + ctx->sensors_supported = SDL_TRUE; + } + + if (HIDAPI_DriverPS4_HasTouchpad(device->vendor_id, device->product_id)) { + ctx->touchpad_supported = SDL_TRUE; + } + if (!joystick->serial && device->serial && SDL_strlen(device->serial) == 12) { int i, j; char serial[18]; @@ -835,15 +871,17 @@ HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, } } - 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); + 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); + 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); + } if (ctx->report_sensors) { float data[3]; diff --git a/src/joystick/hidapi/SDL_hidapi_ps5.c b/src/joystick/hidapi/SDL_hidapi_ps5.c index 8a199f2e7..fa8a8ff0f 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps5.c +++ b/src/joystick/hidapi/SDL_hidapi_ps5.c @@ -81,8 +81,53 @@ typedef struct Uint8 ucTriggerLeft; /* 4 */ Uint8 ucTriggerRight; /* 5 */ Uint8 ucCounter; /* 6 */ - Uint8 rgucButtonsAndHat[3]; /* 7 */ - Uint8 ucZero; /* 10 */ + Uint8 rgucButtonsAndHat[4]; /* 7 */ + Uint8 rgucPacketSequence[4]; /* 11 - 32 bit little endian */ + Uint8 rgucGyroX[2]; /* 15 */ + Uint8 rgucGyroY[2]; /* 17 */ + Uint8 rgucGyroZ[2]; /* 19 */ + Uint8 rgucAccelX[2]; /* 21 */ + Uint8 rgucAccelY[2]; /* 23 */ + Uint8 rgucAccelZ[2]; /* 25 */ + +} PS5StatePacketCommon_t; + +typedef struct +{ + Uint8 ucLeftJoystickX; /* 0 */ + Uint8 ucLeftJoystickY; /* 1 */ + Uint8 ucRightJoystickX; /* 2 */ + Uint8 ucRightJoystickY; /* 3 */ + Uint8 ucTriggerLeft; /* 4 */ + Uint8 ucTriggerRight; /* 5 */ + Uint8 ucCounter; /* 6 */ + Uint8 rgucButtonsAndHat[4]; /* 7 */ + Uint8 rgucPacketSequence[4]; /* 11 - 32 bit little endian */ + Uint8 rgucGyroX[2]; /* 15 */ + Uint8 rgucGyroY[2]; /* 17 */ + Uint8 rgucGyroZ[2]; /* 19 */ + 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 */ + + /* There's more unknown data at the end, and a 32-bit CRC on Bluetooth */ +} PS5StatePacketV1_t; + +typedef struct +{ + Uint8 ucLeftJoystickX; /* 0 */ + Uint8 ucLeftJoystickY; /* 1 */ + Uint8 ucRightJoystickX; /* 2 */ + Uint8 ucRightJoystickY; /* 3 */ + Uint8 ucTriggerLeft; /* 4 */ + Uint8 ucTriggerRight; /* 5 */ + Uint8 ucCounter; /* 6 */ + Uint8 rgucButtonsAndHat[4]; /* 7 */ Uint8 rgucPacketSequence[4]; /* 11 - 32 bit little endian */ Uint8 rgucGyroX[2]; /* 15 */ Uint8 rgucGyroY[2]; /* 17 */ @@ -102,7 +147,7 @@ typedef struct Uint8 ucConnectState; /* 53 - 0x08 = USB, 0x01 = headphone */ /* There's more unknown data at the end, and a 32-bit CRC on Bluetooth */ -} PS5StatePacket_t; +} PS5StatePacketV2_t; typedef struct { @@ -153,8 +198,12 @@ typedef struct { SDL_HIDAPI_Device *device; SDL_Joystick *joystick; SDL_bool is_bluetooth; + SDL_bool effects_supported; + SDL_bool sensors_supported; + SDL_bool touchpad_supported; SDL_bool enhanced_mode; SDL_bool report_sensors; + SDL_bool report_touchpad; SDL_bool hardware_calibration; IMUCalibrationData calibration[6]; Uint16 firmware_version; @@ -171,10 +220,35 @@ typedef struct { union { PS5SimpleStatePacket_t simple; - PS5StatePacket_t state; + PS5StatePacketCommon_t state; + Uint8 data[64]; } last_state; } SDL_DriverPS5_Context; +static SDL_bool HIDAPI_DriverPS5_CanRumble(Uint16 vendor_id, Uint16 product_id) +{ + /* The Hori Fighting Stick Alpha doesn't have any rumble hardware */ + if (vendor_id == USB_VENDOR_HORI && product_id == USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5) { + return SDL_FALSE; + } + + return SDL_TRUE; +} + +static SDL_bool HIDAPI_DriverPS5_HasSensors(Uint16 vendor_id, Uint16 product_id) +{ + /* The Hori Fighting Stick Alpha doesn't have any gyro or accelerometer */ + if (vendor_id == USB_VENDOR_HORI && product_id == USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5) { + return SDL_FALSE; + } + + return SDL_TRUE; +} + +static SDL_bool HIDAPI_DriverPS5_HasTouchpad(Uint16 vendor_id, Uint16 product_id) +{ + return SDL_TRUE; +} static int HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joystick, const void *effect, int size); @@ -477,15 +551,26 @@ static void HIDAPI_DriverPS5_CheckPendingLEDReset(SDL_HIDAPI_Device *device) { SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; - const PS5StatePacket_t *packet = &ctx->last_state.state; + SDL_bool led_reset_complete = SDL_FALSE; - /* Check the timer to make sure the Bluetooth connection LED animation is complete */ - const Uint32 connection_complete = 10200000; - Uint32 timer = ((Uint32)packet->rgucTimer1[0] << 0) | - ((Uint32)packet->rgucTimer1[1] << 8) | - ((Uint32)packet->rgucTimer1[2] << 16) | - ((Uint32)packet->rgucTimer1[3] << 24); - if (SDL_TICKS_PASSED(timer, connection_complete)) { + if (ctx->firmware_version <= 0x204) { + /* 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; + + /* Check the timer to make sure the Bluetooth connection LED animation is complete */ + const Uint32 connection_complete = 10200000; + Uint32 timer = ((Uint32)packet->rgucTimer1[0] << 0) | + ((Uint32)packet->rgucTimer1[1] << 8) | + ((Uint32)packet->rgucTimer1[2] << 16) | + ((Uint32)packet->rgucTimer1[3] << 24); + if (SDL_TICKS_PASSED(timer, connection_complete)) { + led_reset_complete = SDL_TRUE; + } + } + + if (led_reset_complete) { HIDAPI_DriverPS5_UpdateEffects(device, k_EDS5EffectLEDReset); ctx->led_reset_state = k_EDS5LEDResetStateComplete; @@ -516,9 +601,14 @@ HIDAPI_DriverPS5_SetEnhancedMode(SDL_HIDAPI_Device *device, SDL_Joystick *joysti if (!ctx->enhanced_mode) { ctx->enhanced_mode = SDL_TRUE; - SDL_PrivateJoystickAddTouchpad(joystick, 2); - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f); - SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f); + if (ctx->touchpad_supported) { + SDL_PrivateJoystickAddTouchpad(joystick, 2); + ctx->report_touchpad = SDL_TRUE; + } + if (ctx->sensors_supported) { + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_GYRO, 250.0f); + SDL_PrivateJoystickAddSensor(joystick, SDL_SENSOR_ACCEL, 250.0f); + } /* Switch into enhanced report mode */ HIDAPI_DriverPS5_UpdateEffects(device, 0); @@ -640,6 +730,18 @@ HIDAPI_DriverPS5_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) } } + if (HIDAPI_DriverPS5_CanRumble(device->vendor_id, device->product_id)) { + ctx->effects_supported = SDL_TRUE; + } + + if (HIDAPI_DriverPS5_HasSensors(device->vendor_id, device->product_id)) { + ctx->sensors_supported = SDL_TRUE; + } + + if (HIDAPI_DriverPS5_HasTouchpad(device->vendor_id, device->product_id)) { + ctx->touchpad_supported = SDL_TRUE; + } + if (!joystick->serial && device->serial && SDL_strlen(device->serial) == 12) { int i, j; char serial[18]; @@ -706,7 +808,7 @@ HIDAPI_DriverPS5_GetJoystickCapabilities(SDL_HIDAPI_Device *device, SDL_Joystick SDL_DriverPS5_Context *ctx = (SDL_DriverPS5_Context *)device->context; Uint32 result = 0; - if (ctx->enhanced_mode) { + if (ctx->enhanced_mode && ctx->effects_supported) { result |= SDL_JOYCAP_LED | SDL_JOYCAP_RUMBLE; } @@ -736,6 +838,10 @@ HIDAPI_DriverPS5_SendJoystickEffect(SDL_HIDAPI_Device *device, SDL_Joystick *joy int *pending_size; int maximum_size; + if (!ctx->effects_supported) { + return SDL_Unsupported(); + } + if (!ctx->enhanced_mode) { HIDAPI_DriverPS5_SetEnhancedMode(device, joystick); } @@ -903,13 +1009,9 @@ HIDAPI_DriverPS5_HandleSimpleStatePacket(SDL_Joystick *joystick, SDL_hid_device } static void -HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacket_t *packet) +HIDAPI_DriverPS5_HandleStatePacketCommon(SDL_Joystick *joystick, SDL_hid_device *dev, SDL_DriverPS5_Context *ctx, PS5StatePacketCommon_t *packet) { - static const float TOUCHPAD_SCALEX = 1.0f / 1920; - static const float TOUCHPAD_SCALEY = 1.0f / 1070; Sint16 axis; - Uint8 touchpad_state; - int touchpad_x, touchpad_y; if (ctx->last_state.state.rgucButtonsAndHat[0] != packet->rgucButtonsAndHat[0]) { { @@ -998,6 +1100,64 @@ HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, axis = ((int)packet->ucRightJoystickY * 257) - 32768; SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); + if (ctx->report_sensors) { + float data[3]; + + data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1])); + data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1])); + data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 2, LOAD16(packet->rgucGyroZ[0], packet->rgucGyroZ[1])); + SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3); + + data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 3, LOAD16(packet->rgucAccelX[0], packet->rgucAccelX[1])); + data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 4, LOAD16(packet->rgucAccelY[0], packet->rgucAccelY[1])); + data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 5, LOAD16(packet->rgucAccelZ[0], packet->rgucAccelZ[1])); + SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3); + } +} + +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) +{ + 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); + } + /* A check of packet->ucBatteryLevel & 0x10 should work as a check for BT vs USB but doesn't * seem to always work. Possibly related to being 100% charged? */ @@ -1018,31 +1178,7 @@ HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, SDL_hid_device *dev, } } - 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); - - if (ctx->report_sensors) { - float data[3]; - - data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 0, LOAD16(packet->rgucGyroX[0], packet->rgucGyroX[1])); - data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 1, LOAD16(packet->rgucGyroY[0], packet->rgucGyroY[1])); - data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 2, LOAD16(packet->rgucGyroZ[0], packet->rgucGyroZ[1])); - SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_GYRO, data, 3); - - data[0] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 3, LOAD16(packet->rgucAccelX[0], packet->rgucAccelX[1])); - data[1] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 4, LOAD16(packet->rgucAccelY[0], packet->rgucAccelY[1])); - data[2] = HIDAPI_DriverPS5_ApplyCalibrationData(ctx, 5, LOAD16(packet->rgucAccelZ[0], packet->rgucAccelZ[1])); - SDL_PrivateJoystickSensor(joystick, SDL_SENSOR_ACCEL, data, 3); - } - - SDL_memcpy(&ctx->last_state.state, packet, sizeof(ctx->last_state.state)); + SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state)); } static SDL_bool @@ -1073,7 +1209,12 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) if (size == 10 || size == 78) { HIDAPI_DriverPS5_HandleSimpleStatePacket(joystick, device->dev, ctx, (PS5SimpleStatePacket_t *)&data[1]); } else { - HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[1]); + 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]); + } else { + HIDAPI_DriverPS5_HandleStatePacketV2(joystick, device->dev, ctx, (PS5StatePacketV2_t *)&data[1]); + } } break; case k_EPS5ReportIdBluetoothState: @@ -1084,7 +1225,12 @@ HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device) if (ctx->led_reset_state == k_EDS5LEDResetStatePending) { HIDAPI_DriverPS5_CheckPendingLEDReset(device); } - HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[2]); + 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]); + } else { + HIDAPI_DriverPS5_HandleStatePacketV2(joystick, device->dev, ctx, (PS5StatePacketV2_t *)&data[2]); + } break; default: #ifdef DEBUG_JOYSTICK diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h index f1cd185dc..752e9a543 100644 --- a/src/joystick/usb_ids.h +++ b/src/joystick/usb_ids.h @@ -28,6 +28,7 @@ #define USB_VENDOR_AMAZON 0x1949 #define USB_VENDOR_APPLE 0x05ac #define USB_VENDOR_GOOGLE 0x18d1 +#define USB_VENDOR_HORI 0x0f0d #define USB_VENDOR_HYPERKIN 0x2e24 #define USB_VENDOR_MICROSOFT 0x045e #define USB_VENDOR_NINTENDO 0x057e @@ -44,6 +45,8 @@ #define USB_PRODUCT_AMAZON_LUNA_CONTROLLER 0x0419 #define USB_PRODUCT_GOOGLE_STADIA_CONTROLLER 0x9400 #define USB_PRODUCT_EVORETRO_GAMECUBE_ADAPTER 0x1846 +#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS4 0x011c +#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184 #define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER 0x0337 #define USB_PRODUCT_NINTENDO_N64_CONTROLLER 0x2019 #define USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER 0x201e