Added support for the NACON Revolution 5 Pro controller

(cherry picked from commit f0e47f8ee07410e29dcba8a13c91f3e2ef3c92b1)
This commit is contained in:
Sam Lantinga 2023-11-27 12:09:31 -08:00
parent bbcf40e811
commit 8d47e3bb82
5 changed files with 84 additions and 5 deletions

View file

@ -141,6 +141,8 @@ static const ControllerDescription_t arrControllers[] = {
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2303 ), k_eControllerType_XInputPS4Controller, NULL }, // Qanba Obsidian Arcade Joystick
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2500 ), k_eControllerType_PS4Controller, NULL }, // Qanba Dragon
{ MAKE_CONTROLLER_ID( 0x2c22, 0x2503 ), k_eControllerType_XInputPS4Controller, NULL }, // Qanba Dragon Arcade Joystick
{ MAKE_CONTROLLER_ID( 0x3285, 0x0d16 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution 5 Pro (PS4 mode with dongle)
{ MAKE_CONTROLLER_ID( 0x3285, 0x0d17 ), k_eControllerType_PS4Controller, NULL }, // NACON Revolution 5 Pro (PS4 mode wired)
{ MAKE_CONTROLLER_ID( 0x7545, 0x0104 ), k_eControllerType_PS4Controller, NULL }, // Armor 3 or Level Up Cobra - At least one variant has gyro
{ MAKE_CONTROLLER_ID (0x9886, 0x0024 ), k_eControllerType_XInputPS4Controller, NULL }, // Astro C40 in Xbox 360 mode
{ MAKE_CONTROLLER_ID( 0x9886, 0x0025 ), k_eControllerType_PS4Controller, NULL }, // Astro C40
@ -154,6 +156,8 @@ static const ControllerDescription_t arrControllers[] = {
{ MAKE_CONTROLLER_ID( 0x0f0d, 0x0184 ), k_eControllerType_PS5Controller, NULL }, // Hori Fighting Stick α
{ 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( 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
{ 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

View file

@ -128,6 +128,7 @@ typedef struct
SDL_HIDAPI_Device *device;
SDL_Joystick *joystick;
SDL_bool is_dongle;
SDL_bool is_nacon_dongle;
SDL_bool official_controller;
SDL_bool sensors_supported;
SDL_bool lightbar_supported;
@ -401,6 +402,11 @@ static SDL_bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
}
ctx->effects_supported = (ctx->lightbar_supported || ctx->vibration_supported);
if (device->vendor_id == USB_VENDOR_NACON_ALT &&
device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS4_WIRELESS) {
ctx->is_nacon_dongle = SDL_TRUE;
}
if (device->vendor_id == USB_VENDOR_PDP &&
(device->product_id == USB_PRODUCT_VICTRIX_FS_PRO ||
device->product_id == USB_PRODUCT_VICTRIX_FS_PRO_V2)) {
@ -426,7 +432,7 @@ static SDL_bool HIDAPI_DriverPS4_InitDevice(SDL_HIDAPI_Device *device)
} else {
HIDAPI_DisconnectBluetoothDevice(device->serial);
}
if (ctx->is_dongle && serial[0] == '\0') {
if ((ctx->is_dongle || ctx->is_nacon_dongle) && serial[0] == '\0') {
/* Not yet connected */
return SDL_TRUE;
}
@ -1085,6 +1091,21 @@ static SDL_bool HIDAPI_DriverPS4_IsPacketValid(SDL_DriverPS4_Context *ctx, Uint8
return SDL_TRUE;
}
if (ctx->is_nacon_dongle && size >= (1 + sizeof(PS4StatePacket_t))) {
/* The report timestamp doesn't change when the controller isn't connected */
PS4StatePacket_t *packet = (PS4StatePacket_t *)&data[1];
if (SDL_memcmp(packet->rgucTimestamp, ctx->last_state.rgucTimestamp, sizeof(packet->rgucTimestamp)) == 0) {
return SDL_FALSE;
}
if (ctx->last_state.rgucAccelX[0] == 0 && ctx->last_state.rgucAccelX[1] == 0 &&
ctx->last_state.rgucAccelY[0] == 0 && ctx->last_state.rgucAccelY[1] == 0 &&
ctx->last_state.rgucAccelZ[0] == 0 && ctx->last_state.rgucAccelZ[1] == 0) {
/* We don't have any state to compare yet, go ahead and copy it */
SDL_memcpy(&ctx->last_state, &data[1], sizeof(PS4StatePacket_t));
return SDL_FALSE;
}
}
/* In the case of a DS4 USB dongle, bit[2] of byte 31 indicates if a DS4 is actually connected (indicated by '0').
* For non-dongle, this bit is always 0 (connected).
* This is usually the ID over USB, but the DS4v2 that started shipping with the PS4 Slim will also send this
@ -1197,7 +1218,7 @@ static SDL_bool HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
}
}
if (ctx->is_dongle) {
if (ctx->is_dongle || ctx->is_nacon_dongle) {
if (packet_count == 0) {
if (device->num_joysticks > 0) {
/* Check to see if it looks like the device disconnected */
@ -1219,7 +1240,7 @@ static SDL_bool HIDAPI_DriverPS4_UpdateDevice(SDL_HIDAPI_Device *device)
}
}
if (size < 0 && device->num_joysticks > 0) {
if (packet_count == 0 && size < 0 && device->num_joysticks > 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}

View file

@ -217,6 +217,7 @@ typedef struct
{
SDL_HIDAPI_Device *device;
SDL_Joystick *joystick;
SDL_bool is_nacon_dongle;
SDL_bool use_alternate_report;
SDL_bool sensors_supported;
SDL_bool lightbar_supported;
@ -246,6 +247,7 @@ typedef struct
{
PS5SimpleStatePacket_t simple;
PS5StatePacketCommon_t state;
PS5StatePacketAlt_t alt_state;
PS5StatePacket_t full_state;
Uint8 data[64];
} last_state;
@ -483,10 +485,17 @@ static SDL_bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
}
ctx->use_alternate_report = SDL_TRUE;
if (device->vendor_id == USB_VENDOR_NACON_ALT &&
(device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRED ||
device->product_id == USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS)) {
/* This doesn't report vibration capability, but it can do rumble */
ctx->vibration_supported = SDL_TRUE;
}
} else if (device->vendor_id == USB_VENDOR_RAZER &&
(device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRED ||
device->product_id == USB_PRODUCT_RAZER_WOLVERINE_V2_PRO_PS5_WIRELESS)) {
/* The Razer Wolverine V2 Pro doesn't respond to the detection protocol, but has a touchpad and sensors, but no vibration */
/* The Razer Wolverine V2 Pro doesn't respond to the detection protocol, but has a touchpad and sensors and no vibration */
ctx->sensors_supported = SDL_TRUE;
ctx->touchpad_supported = SDL_TRUE;
ctx->use_alternate_report = SDL_TRUE;
@ -494,6 +503,11 @@ static SDL_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 = SDL_TRUE;
}
device->joystick_type = joystick_type;
device->type = SDL_CONTROLLER_TYPE_PS5;
if (device->vendor_id == USB_VENDOR_SONY) {
@ -505,6 +519,11 @@ static SDL_bool HIDAPI_DriverPS5_InitDevice(SDL_HIDAPI_Device *device)
}
HIDAPI_SetDeviceSerial(device, serial);
if (ctx->is_nacon_dongle) {
/* We don't know if this is connected yet, wait for reports */
return SDL_TRUE;
}
/* Prefer the USB device over the Bluetooth device */
if (device->is_bluetooth) {
if (HIDAPI_HasConnectedUSBDevice(device->serial)) {
@ -1378,6 +1397,20 @@ static SDL_bool HIDAPI_DriverPS5_IsPacketValid(SDL_DriverPS5_Context *ctx, Uint8
{
switch (data[0]) {
case k_EPS5ReportIdState:
if (ctx->is_nacon_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 SDL_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) {
/* 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 SDL_FALSE;
}
}
return SDL_TRUE;
case k_EPS5ReportIdBluetoothState:
@ -1471,7 +1504,22 @@ static SDL_bool HIDAPI_DriverPS5_UpdateDevice(SDL_HIDAPI_Device *device)
}
}
if (size < 0 && device->num_joysticks > 0) {
if (ctx->is_nacon_dongle) {
if (packet_count == 0) {
if (device->num_joysticks > 0) {
/* Check to see if it looks like the device disconnected */
if (SDL_TICKS_PASSED(now, ctx->last_packet + BLUETOOTH_DISCONNECT_TIMEOUT_MS)) {
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}
}
} else {
if (device->num_joysticks == 0) {
HIDAPI_JoystickConnected(device, NULL);
}
}
}
if (packet_count == 0 && size < 0 && device->num_joysticks > 0) {
/* Read error, device is disconnected */
HIDAPI_JoystickDisconnected(device, device->joysticks[0]);
}

View file

@ -162,6 +162,7 @@ SDL_bool HIDAPI_SupportsPlaystationDetection(Uint16 vendor, Uint16 product)
case USB_VENDOR_MADCATZ:
return SDL_TRUE;
case USB_VENDOR_NACON:
case USB_VENDOR_NACON_ALT:
return SDL_TRUE;
case USB_VENDOR_PDP:
return SDL_TRUE;

View file

@ -38,6 +38,7 @@
#define USB_VENDOR_MADCATZ 0x0738
#define USB_VENDOR_MICROSOFT 0x045e
#define USB_VENDOR_NACON 0x146b
#define USB_VENDOR_NACON_ALT 0x3285
#define USB_VENDOR_NINTENDO 0x057e
#define USB_VENDOR_NVIDIA 0x0955
#define USB_VENDOR_PDP 0x0e6f
@ -69,6 +70,10 @@
#define USB_PRODUCT_HORI_FIGHTING_STICK_ALPHA_PS5 0x0184
#define USB_PRODUCT_LOGITECH_F310 0xc216
#define USB_PRODUCT_LOGITECH_CHILLSTREAM 0xcad1
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS4_WIRELESS 0x0d16
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS4_WIRED 0x0d17
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRELESS 0x0d18
#define USB_PRODUCT_NACON_REVOLUTION_5_PRO_PS5_WIRED 0x0d19
#define USB_PRODUCT_NINTENDO_GAMECUBE_ADAPTER 0x0337
#define USB_PRODUCT_NINTENDO_N64_CONTROLLER 0x2019
#define USB_PRODUCT_NINTENDO_SEGA_GENESIS_CONTROLLER 0x201e