From 4d79f9662f0093c6d8a1cde2785dd59ee14be950 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 5 Nov 2020 15:02:54 -0800 Subject: [PATCH] Added initial support for the Sony PS5 Controller --- include/SDL_gamecontroller.h | 3 +- src/joystick/SDL_gamecontrollerdb.h | 4 + src/joystick/SDL_joystick.c | 18 ++- src/joystick/SDL_joystick_c.h | 3 + src/joystick/controller_type.h | 3 + src/joystick/hidapi/SDL_hidapi_ps4.c | 208 +++++++++++++++++++++++---- src/joystick/usb_ids.h | 1 + 7 files changed, 211 insertions(+), 29 deletions(-) diff --git a/include/SDL_gamecontroller.h b/include/SDL_gamecontroller.h index a0984bbcb..2eca81208 100644 --- a/include/SDL_gamecontroller.h +++ b/include/SDL_gamecontroller.h @@ -65,7 +65,8 @@ typedef enum SDL_CONTROLLER_TYPE_PS3, SDL_CONTROLLER_TYPE_PS4, SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO, - SDL_CONTROLLER_TYPE_VIRTUAL + SDL_CONTROLLER_TYPE_VIRTUAL, + SDL_CONTROLLER_TYPE_PS5 } SDL_GameControllerType; typedef enum diff --git a/src/joystick/SDL_gamecontrollerdb.h b/src/joystick/SDL_gamecontrollerdb.h index 59ae79682..bb4286bf9 100644 --- a/src/joystick/SDL_gamecontrollerdb.h +++ b/src/joystick/SDL_gamecontrollerdb.h @@ -240,6 +240,7 @@ static const char *s_ControllerMappings [] = "030000004c050000a00b000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000004c050000cc09000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", + "030000004c050000e60c000000000000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,", "03000000d62000006dca000000000000,PowerA Pro Ex,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", "03000000d62000009557000000000000,Pro Elite PS3 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", @@ -423,6 +424,7 @@ static const char *s_ControllerMappings [] = "030000004c050000c405000000000000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000004c050000c405000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", + "030000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000008f0e00000300000000000000,Piranha xtreme,a:b2,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,leftshoulder:b6,leftstick:b10,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,rightstick:b11,righttrigger:b5,rightx:a3,righty:a2,start:b9,x:b3,y:b0,", "030000008916000000fd000000000000,Razer Onza TE,a:b0,b:b1,back:b9,dpdown:b12,dpleft:b13,dpright:b14,dpup:b11,guide:b10,leftshoulder:b4,leftstick:b6,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b7,righttrigger:a5,rightx:a3,righty:a4,start:b8,x:b2,y:b3,", "03000000321500000204000000010000,Razer Panthera (PS3),a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:b6,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:b7,rightx:a2,righty:a3,start:b9,x:b0,y:b3,", @@ -658,6 +660,8 @@ static const char *s_ControllerMappings [] = "050000004c050000cc09000000010000,PS4 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "050000004c050000cc09000000810000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,", "050000004c050000cc09000001800000,PS4 Controller,a:b0,b:b1,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b10,leftshoulder:b4,leftstick:b11,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b12,righttrigger:a5,rightx:a3,righty:a4,start:b9,x:b3,y:b2,", + "030000004c050000e60c000011010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", + "050000004c050000e60c000000010000,PS5 Controller,a:b1,b:b2,back:b8,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b12,leftshoulder:b4,leftstick:b10,lefttrigger:a3,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b11,righttrigger:a4,rightx:a2,righty:a5,start:b9,x:b0,y:b3,", "030000004c050000da0c000011010000,Playstation Controller,a:b2,b:b1,back:b8,leftshoulder:b6,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b5,start:b9,x:b3,y:b0,", "03000000c62400000053000000010000,PowerA,a:b0,b:b1,back:b6,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b4,leftstick:b9,lefttrigger:a2,leftx:a0,lefty:a1,rightshoulder:b5,rightstick:b10,righttrigger:a5,rightx:a3,righty:a4,start:b7,x:b2,y:b3,", "03000000300f00001211000011010000,QanBa Arcade JoyStick,a:b2,b:b0,back:b10,dpdown:h0.4,dpleft:h0.8,dpright:h0.2,dpup:h0.1,guide:b8,leftshoulder:b5,lefttrigger:b4,leftx:a0,lefty:a1,rightshoulder:b7,righttrigger:b6,start:b9,x:b1,y:b3,", diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index a3e51996b..c4904f185 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -1763,6 +1763,9 @@ SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 produc case k_eControllerType_PS4Controller: type = SDL_CONTROLLER_TYPE_PS4; break; + case k_eControllerType_PS5Controller: + type = SDL_CONTROLLER_TYPE_PS5; + break; case k_eControllerType_SwitchProController: case k_eControllerType_SwitchInputOnlyController: type = SDL_CONTROLLER_TYPE_NINTENDO_SWITCH_PRO; @@ -1777,16 +1780,23 @@ SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 produc } SDL_bool -SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor, Uint16 product) +SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id) { - EControllerType eType = GuessControllerType(vendor, product); + EControllerType eType = GuessControllerType(vendor_id, product_id); + return (eType == k_eControllerType_PS5Controller); +} + +SDL_bool +SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id) +{ + EControllerType eType = GuessControllerType(vendor_id, product_id); return (eType == k_eControllerType_SwitchInputOnlyController); } SDL_bool -SDL_IsJoystickSteamController(Uint16 vendor, Uint16 product) +SDL_IsJoystickSteamController(Uint16 vendor_id, Uint16 product_id) { - EControllerType eType = GuessControllerType(vendor, product); + EControllerType eType = GuessControllerType(vendor_id, product_id); return (eType == k_eControllerType_SteamController || eType == k_eControllerType_SteamControllerV2); } diff --git a/src/joystick/SDL_joystick_c.h b/src/joystick/SDL_joystick_c.h index 02bf2b5a9..301e0c94f 100644 --- a/src/joystick/SDL_joystick_c.h +++ b/src/joystick/SDL_joystick_c.h @@ -61,6 +61,9 @@ extern char *SDL_CreateJoystickName(Uint16 vendor, Uint16 product, const char *v extern SDL_GameControllerType SDL_GetJoystickGameControllerTypeFromGUID(SDL_JoystickGUID guid, const char *name); extern SDL_GameControllerType SDL_GetJoystickGameControllerType(const char *name, Uint16 vendor, Uint16 product, int interface_number, int interface_class, int interface_subclass, int interface_protocol); +/* Function to return whether a joystick is a PS5 controller */ +extern SDL_bool SDL_IsJoystickPS5(Uint16 vendor_id, Uint16 product_id); + /* Function to return whether a joystick is a Nintendo Switch Pro controller */ extern SDL_bool SDL_IsJoystickNintendoSwitchProInputOnly(Uint16 vendor_id, Uint16 product_id); diff --git a/src/joystick/controller_type.h b/src/joystick/controller_type.h index 9a091d31c..cf079f799 100644 --- a/src/joystick/controller_type.h +++ b/src/joystick/controller_type.h @@ -54,6 +54,7 @@ typedef enum k_eControllerType_SwitchInputOnlyController = 42, k_eControllerType_MobileTouch = 43, k_eControllerType_XInputSwitchController = 44, // Client-side only, used to mark Switch-compatible controllers as not supporting Switch controller protocol + k_eControllerType_PS5Controller = 45, k_eControllerType_LastController, // Don't add game controllers below this enumeration - this enumeration can change value // Keyboards and Mice @@ -175,6 +176,8 @@ static const ControllerDescription_t arrControllers[] = { { MAKE_CONTROLLER_ID( 0x0f0d, 0x0123 ), k_eControllerType_PS4Controller, NULL }, // HORI Wireless Controller Light (Japan only) - only over bt- over usb is xbox and pid 0x0124 { MAKE_CONTROLLER_ID( 0x146b, 0x0d13 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution 3 + { MAKE_CONTROLLER_ID( 0x054c, 0x0ce6 ), k_eControllerType_PS5Controller, NULL }, // Sony PS5 Controller + { 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 { MAKE_CONTROLLER_ID( 0x0079, 0x18d4 ), k_eControllerType_XBox360Controller, NULL }, // GPD Win 2 X-Box Controller diff --git a/src/joystick/hidapi/SDL_hidapi_ps4.c b/src/joystick/hidapi/SDL_hidapi_ps4.c index 173e1ed12..b044b9b80 100644 --- a/src/joystick/hidapi/SDL_hidapi_ps4.c +++ b/src/joystick/hidapi/SDL_hidapi_ps4.c @@ -78,6 +78,19 @@ typedef struct Uint8 rgucTrackpadData2[ 3 ]; } PS4StatePacket_t; +typedef struct +{ + Uint8 ucLeftJoystickX; + Uint8 ucLeftJoystickY; + Uint8 ucRightJoystickX; + Uint8 ucRightJoystickY; + Uint8 ucTriggerLeft; + Uint8 ucTriggerRight; + Uint8 ucCounter; + Uint8 rgucButtonsAndHat[ 3 ]; + Uint8 rgucUnknown[ 53 ]; +} PS5StatePacket_t; + typedef struct { Uint8 ucRumbleRight; @@ -95,6 +108,7 @@ typedef struct } DS4EffectsState_t; typedef struct { + SDL_bool is_PS5; SDL_bool is_dongle; SDL_bool is_bluetooth; SDL_bool audio_supported; @@ -108,10 +122,40 @@ typedef struct { Uint8 led_blue; Uint8 volume; Uint32 last_volume_check; - PS4StatePacket_t last_state; + union + { + PS4StatePacket_t PS4; + PS5StatePacket_t PS5; + } last_state; } SDL_DriverPS4_Context; +/* Define this if you want to log all packets from the controller */ +/*#define DEBUG_PS4_PROTOCOL*/ +#define DEBUG_PS4_PROTOCOL + +#ifdef DEBUG_PS4_PROTOCOL +static void +DumpPacket(const char *prefix, Uint8 *data, int size) +{ + int i; + char *buffer; + size_t length = SDL_strlen(prefix) + 11*(USB_PACKET_LENGTH/8) + (5*USB_PACKET_LENGTH) + 1 + 1; + + buffer = (char *)SDL_malloc(length); + SDL_snprintf(buffer, length, prefix, size); + for (i = 0; i < size; ++i) { + if ((i % 8) == 0) { + SDL_snprintf(&buffer[SDL_strlen(buffer)], length - SDL_strlen(buffer), "\n%.2d: ", i); + } + SDL_snprintf(&buffer[SDL_strlen(buffer)], length - SDL_strlen(buffer), " 0x%.2x", data[i]); + } + SDL_strlcat(buffer, "\n", length); + SDL_Log("%s", buffer); + SDL_free(buffer); +} +#endif /* DEBUG_PS4_PROTOCOL */ + /* Public domain CRC implementation adapted from: http://home.thep.lu.se/~bjorn/crc/crc32_simple.c */ @@ -136,14 +180,18 @@ static Uint32 crc32(Uint32 crc, const void *data, int count) static SDL_bool HIDAPI_DriverPS4_IsSupportedDevice(const char *name, SDL_GameControllerType type, Uint16 vendor_id, Uint16 product_id, Uint16 version, int interface_number, int interface_class, int interface_subclass, int interface_protocol) { - return (type == SDL_CONTROLLER_TYPE_PS4); + return (type == SDL_CONTROLLER_TYPE_PS4 || type == SDL_CONTROLLER_TYPE_PS5); } static const char * HIDAPI_DriverPS4_GetDeviceName(Uint16 vendor_id, Uint16 product_id) { if (vendor_id == USB_VENDOR_SONY) { - return "PS4 Controller"; + if (SDL_IsJoystickPS5(vendor_id, product_id)) { + return "PS5 Controller"; + } else { + return "PS4 Controller"; + } } return NULL; } @@ -291,6 +339,14 @@ HIDAPI_DriverPS4_OpenJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) } } + /* Special handling for PS5 controller */ + ctx->is_PS5 = SDL_IsJoystickPS5(device->vendor_id, device->product_id); + if (ctx->is_PS5) { + /* Don't know how these work yet... */ + ctx->audio_supported = SDL_FALSE; + ctx->rumble_supported = SDL_FALSE; + } + /* Initialize player index (needed for setting LEDs) */ ctx->player_index = SDL_JoystickGetPlayerIndex(joystick); @@ -368,7 +424,9 @@ HIDAPI_DriverPS4_RumbleJoystick(SDL_HIDAPI_Device *device, SDL_Joystick *joystic static SDL_bool HIDAPI_DriverPS4_HasJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystick) { - return SDL_TRUE; + SDL_DriverPS4_Context *ctx = (SDL_DriverPS4_Context *)device->context; + + return ctx->rumble_supported; } static int @@ -381,16 +439,15 @@ HIDAPI_DriverPS4_SetJoystickLED(SDL_HIDAPI_Device *device, SDL_Joystick *joystic ctx->led_green = green; ctx->led_blue = blue; - /* FIXME: Is there a better way to send this without sending another rumble packet? */ return HIDAPI_DriverPS4_RumbleJoystick(device, joystick, ctx->rumble_left, ctx->rumble_right); } static void -HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet) +HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS4StatePacket_t *packet, int size) { Sint16 axis; - if (ctx->last_state.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) { + if (ctx->last_state.PS4.rgucButtonsHatAndCounter[0] != packet->rgucButtonsHatAndCounter[0]) { { Uint8 data = (packet->rgucButtonsHatAndCounter[0] >> 4); @@ -445,7 +502,7 @@ HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_ } } - if (ctx->last_state.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) { + if (ctx->last_state.PS4.rgucButtonsHatAndCounter[1] != packet->rgucButtonsHatAndCounter[1]) { Uint8 data = packet->rgucButtonsHatAndCounter[1]; SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); @@ -465,7 +522,7 @@ HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_ packet->ucTriggerRight = (data & 0x08) && packet->ucTriggerRight == 0 ? 255 : packet->ucTriggerRight; } - if (ctx->last_state.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) { + if (ctx->last_state.PS4.rgucButtonsHatAndCounter[2] != packet->rgucButtonsHatAndCounter[2]) { Uint8 data = (packet->rgucButtonsHatAndCounter[2] & 0x03); SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); @@ -485,23 +542,119 @@ HIDAPI_DriverPS4_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_ axis = ((int)packet->ucRightJoystickY * 257) - 32768; SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); - if (packet->ucBatteryLevel & 0x10) { - joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED; - } else { - /* Battery level ranges from 0 to 10 */ - int level = (packet->ucBatteryLevel & 0xF); - if (level == 0) { - joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY; - } else if (level <= 2) { - joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW; - } else if (level <= 7) { - joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM; + if (size >= 30) { + if (packet->ucBatteryLevel & 0x10) { + joystick->epowerlevel = SDL_JOYSTICK_POWER_WIRED; } else { - joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL; + /* Battery level ranges from 0 to 10 */ + int level = (packet->ucBatteryLevel & 0xF); + if (level == 0) { + joystick->epowerlevel = SDL_JOYSTICK_POWER_EMPTY; + } else if (level <= 2) { + joystick->epowerlevel = SDL_JOYSTICK_POWER_LOW; + } else if (level <= 7) { + joystick->epowerlevel = SDL_JOYSTICK_POWER_MEDIUM; + } else { + joystick->epowerlevel = SDL_JOYSTICK_POWER_FULL; + } } } - SDL_memcpy(&ctx->last_state, packet, sizeof(ctx->last_state)); + SDL_memcpy(&ctx->last_state.PS4, packet, SDL_min(size, sizeof(ctx->last_state.PS4))); +} + +static void +HIDAPI_DriverPS5_HandleStatePacket(SDL_Joystick *joystick, hid_device *dev, SDL_DriverPS4_Context *ctx, PS5StatePacket_t *packet) +{ + Sint16 axis; + + if (ctx->last_state.PS5.rgucButtonsAndHat[0] != packet->rgucButtonsAndHat[0]) { + { + Uint8 data = (packet->rgucButtonsAndHat[0] >> 4); + + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_X, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_A, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_B, (data & 0x04) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_Y, (data & 0x08) ? SDL_PRESSED : SDL_RELEASED); + } + { + Uint8 data = (packet->rgucButtonsAndHat[0] & 0x0F); + SDL_bool dpad_up = SDL_FALSE; + SDL_bool dpad_down = SDL_FALSE; + SDL_bool dpad_left = SDL_FALSE; + SDL_bool dpad_right = SDL_FALSE; + + switch (data) { + case 0: + dpad_up = SDL_TRUE; + break; + case 1: + dpad_up = SDL_TRUE; + dpad_right = SDL_TRUE; + break; + case 2: + dpad_right = SDL_TRUE; + break; + case 3: + dpad_right = SDL_TRUE; + dpad_down = SDL_TRUE; + break; + case 4: + dpad_down = SDL_TRUE; + break; + case 5: + dpad_left = SDL_TRUE; + dpad_down = SDL_TRUE; + break; + case 6: + dpad_left = SDL_TRUE; + break; + case 7: + dpad_up = SDL_TRUE; + dpad_left = SDL_TRUE; + break; + default: + break; + } + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_DOWN, dpad_down); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_UP, dpad_up); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_RIGHT, dpad_right); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_DPAD_LEFT, dpad_left); + } + } + + if (ctx->last_state.PS5.rgucButtonsAndHat[1] != packet->rgucButtonsAndHat[1]) { + Uint8 data = packet->rgucButtonsAndHat[1]; + + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSHOULDER, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSHOULDER, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_BACK, (data & 0x10) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_START, (data & 0x20) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_LEFTSTICK, (data & 0x40) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_RIGHTSTICK, (data & 0x80) ? SDL_PRESSED : SDL_RELEASED); + } + + if (ctx->last_state.PS5.rgucButtonsAndHat[2] != packet->rgucButtonsAndHat[2]) { + Uint8 data = (packet->rgucButtonsAndHat[2] & 0x03); + + SDL_PrivateJoystickButton(joystick, SDL_CONTROLLER_BUTTON_GUIDE, (data & 0x01) ? SDL_PRESSED : SDL_RELEASED); + SDL_PrivateJoystickButton(joystick, 15, (data & 0x02) ? SDL_PRESSED : SDL_RELEASED); + } + + axis = ((int)packet->ucTriggerLeft * 257) - 32768; + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERLEFT, axis); + axis = ((int)packet->ucTriggerRight * 257) - 32768; + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_TRIGGERRIGHT, axis); + axis = ((int)packet->ucLeftJoystickX * 257) - 32768; + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTX, axis); + axis = ((int)packet->ucLeftJoystickY * 257) - 32768; + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_LEFTY, axis); + axis = ((int)packet->ucRightJoystickX * 257) - 32768; + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTX, axis); + axis = ((int)packet->ucRightJoystickY * 257) - 32768; + SDL_PrivateJoystickAxis(joystick, SDL_CONTROLLER_AXIS_RIGHTY, axis); + + SDL_memcpy(&ctx->last_state.PS5, packet, sizeof(ctx->last_state.PS5)); } static SDL_bool @@ -520,13 +673,20 @@ HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device) } while ((size = hid_read_timeout(device->dev, data, sizeof(data), 0)) > 0) { +#ifdef DEBUG_PS4_PROTOCOL + DumpPacket("PS4 packet: size = %d", data, size); +#endif switch (data[0]) { case k_EPS4ReportIdUsbState: - HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1]); + if (ctx->is_PS5 && size > 10) { + HIDAPI_DriverPS5_HandleStatePacket(joystick, device->dev, ctx, (PS5StatePacket_t *)&data[1]); + } else { + HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[1], size - 1); + } break; case k_EPS4ReportIdBluetoothState: /* Bluetooth state packets have two additional bytes at the beginning */ - HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[3]); + HIDAPI_DriverPS4_HandleStatePacket(joystick, device->dev, ctx, (PS4StatePacket_t *)&data[3], size - 3); break; default: #ifdef DEBUG_JOYSTICK diff --git a/src/joystick/usb_ids.h b/src/joystick/usb_ids.h index 624c35e0a..976273078 100644 --- a/src/joystick/usb_ids.h +++ b/src/joystick/usb_ids.h @@ -42,6 +42,7 @@ #define USB_PRODUCT_SONY_DS4 0x05c4 #define USB_PRODUCT_SONY_DS4_DONGLE 0x0ba0 #define USB_PRODUCT_SONY_DS4_SLIM 0x09cc +#define USB_PRODUCT_SONY_DS5 0x0ce6 #define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_1 0x02e3 #define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2 0x0b00 #define USB_PRODUCT_XBOX_ONE_ELITE_SERIES_2_BLUETOOTH 0x0b05