From 3572be39980c9c3941b9f60ee1b5ccb9830b7087 Mon Sep 17 00:00:00 2001 From: Sam Lantinga Date: Thu, 4 Sep 2025 18:20:26 -0700 Subject: [PATCH] Improved detection of FlyDigi controllers --- src/joystick/SDL_gamepad.c | 13 +--- src/joystick/hidapi/SDL_hidapi_flydigi.c | 81 +++++++++++++++++------- src/joystick/hidapi/SDL_hidapi_flydigi.h | 38 +++++++++++ 3 files changed, 98 insertions(+), 34 deletions(-) create mode 100644 src/joystick/hidapi/SDL_hidapi_flydigi.h diff --git a/src/joystick/SDL_gamepad.c b/src/joystick/SDL_gamepad.c index c5ef232b31..ce9c870e46 100644 --- a/src/joystick/SDL_gamepad.c +++ b/src/joystick/SDL_gamepad.c @@ -29,6 +29,7 @@ #include "SDL_gamepad_db.h" #include "controller_type.h" #include "usb_ids.h" +#include "hidapi/SDL_hidapi_flydigi.h" #include "hidapi/SDL_hidapi_nintendo.h" #include "../events/SDL_events_c.h" @@ -913,19 +914,9 @@ static GamepadMapping_t *SDL_CreateMappingForHIDAPIGamepad(SDL_GUID guid) SDL_strlcat(mapping_string, "paddle1:b13,paddle2:b12,paddle3:b15,paddle4:b14,misc2:b11,misc3:b16,misc4:b17", sizeof(mapping_string)); } else if (SDL_IsJoystickFlydigiController(vendor, product)) { SDL_strlcat(mapping_string, "paddle1:b11,paddle2:b12,paddle3:b13,paddle4:b14,", sizeof(mapping_string)); - switch (guid.data[15]) { - case 20: - case 21: - case 22: - case 23: - case 28: - case 80: - case 81: - case 85: - case 105: + if (guid.data[15] >= SDL_FLYDIGI_VADER2) { // Vader series of controllers have C/Z buttons SDL_strlcat(mapping_string, "misc2:b15,misc3:b16,", sizeof(mapping_string)); - break; } } else if (vendor == USB_VENDOR_8BITDO && product == USB_PRODUCT_8BITDO_ULTIMATE2_WIRELESS) { SDL_strlcat(mapping_string, "paddle1:b12,paddle2:b11,paddle3:b14,paddle4:b13,", sizeof(mapping_string)); diff --git a/src/joystick/hidapi/SDL_hidapi_flydigi.c b/src/joystick/hidapi/SDL_hidapi_flydigi.c index 565f03b70d..55048f6083 100644 --- a/src/joystick/hidapi/SDL_hidapi_flydigi.c +++ b/src/joystick/hidapi/SDL_hidapi_flydigi.c @@ -25,6 +25,7 @@ #include "../SDL_sysjoystick.h" #include "SDL_hidapijoystick_c.h" #include "SDL_hidapi_rumble.h" +#include "SDL_hidapi_flydigi.h" #ifdef SDL_JOYSTICK_HIDAPI_FLYDIGI @@ -147,70 +148,104 @@ static void UpdateDeviceIdentity(SDL_HIDAPI_Device *device) } } - if (ctx->deviceID == 0) { + Uint8 controller_type = SDL_FLYDIGI_UNKNOWN; + switch (ctx->deviceID) { + case 19: + controller_type = SDL_FLYDIGI_APEX2; + break; + case 24: + case 26: + case 29: + controller_type = SDL_FLYDIGI_APEX3; + break; + case 84: + controller_type = SDL_FLYDIGI_APEX4; + break; + case 20: + case 21: + case 23: + controller_type = SDL_FLYDIGI_VADER2; + break; + case 22: + controller_type = SDL_FLYDIGI_VADER2_PRO; + break; + case 28: + controller_type = SDL_FLYDIGI_VADER3; + break; + case 80: + case 81: + controller_type = SDL_FLYDIGI_VADER3_PRO; + break; + case 85: + case 91: + case 105: + controller_type = SDL_FLYDIGI_VADER4_PRO; + break; + default: // Try to guess from the name of the controller if (SDL_strstr(device->name, "VADER") != NULL) { if (SDL_strstr(device->name, "VADER2") != NULL) { - ctx->deviceID = 20; + controller_type = SDL_FLYDIGI_VADER2; } else if (SDL_strstr(device->name, "VADER3") != NULL) { - ctx->deviceID = 28; + controller_type = SDL_FLYDIGI_VADER3; } else if (SDL_strstr(device->name, "VADER4") != NULL) { - ctx->deviceID = 85; + controller_type = SDL_FLYDIGI_VADER4; } } else if (SDL_strstr(device->name, "APEX") != NULL) { if (SDL_strstr(device->name, "APEX2") != NULL) { - ctx->deviceID = 19; + controller_type = SDL_FLYDIGI_APEX2; } else if (SDL_strstr(device->name, "APEX3") != NULL) { - ctx->deviceID = 24; + controller_type = SDL_FLYDIGI_APEX3; } else if (SDL_strstr(device->name, "APEX4") != NULL) { - ctx->deviceID = 84; + controller_type = SDL_FLYDIGI_APEX4; + } else if (SDL_strstr(device->name, "APEX5") != NULL) { + controller_type = SDL_FLYDIGI_APEX5; } } + break; } - device->guid.data[15] = ctx->deviceID; + device->guid.data[15] = controller_type; // This is the previous sensor default of 125hz. // Override this in the switch statement below based on observed sensor packet rate. ctx->sensor_timestamp_step_ns = SDL_NS_PER_SECOND / 125; - switch (ctx->deviceID) { - case 19: + switch (controller_type) { + case SDL_FLYDIGI_APEX2: HIDAPI_SetDeviceName(device, "Flydigi Apex 2"); break; - case 24: - case 26: - case 29: + case SDL_FLYDIGI_APEX3: HIDAPI_SetDeviceName(device, "Flydigi Apex 3"); break; - case 84: + case SDL_FLYDIGI_APEX4: // The Apex 4 controller has sensors, but they're only reported when gyro mouse is enabled HIDAPI_SetDeviceName(device, "Flydigi Apex 4"); break; - case 20: - case 21: - case 23: + case SDL_FLYDIGI_APEX5: + HIDAPI_SetDeviceName(device, "Flydigi Apex 5"); + break; + case SDL_FLYDIGI_VADER2: // The Vader 2 controller has sensors, but they're only reported when gyro mouse is enabled HIDAPI_SetDeviceName(device, "Flydigi Vader 2"); ctx->has_cz = true; break; - case 22: + case SDL_FLYDIGI_VADER2_PRO: HIDAPI_SetDeviceName(device, "Flydigi Vader 2 Pro"); ctx->has_cz = true; break; - case 28: + case SDL_FLYDIGI_VADER3: HIDAPI_SetDeviceName(device, "Flydigi Vader 3"); ctx->has_cz = true; break; - case 80: - case 81: + case SDL_FLYDIGI_VADER3_PRO: HIDAPI_SetDeviceName(device, "Flydigi Vader 3 Pro"); ctx->has_cz = true; ctx->sensors_supported = true; ctx->accelScale = SDL_STANDARD_GRAVITY / 256.0f; ctx->sensor_timestamp_step_ns = ctx->wireless ? SENSOR_INTERVAL_VADER4_PRO_DONGLE_NS : SENSOR_INTERVAL_VADER_PRO4_WIRED_NS; break; - case 85: - case 105: + case SDL_FLYDIGI_VADER4: + case SDL_FLYDIGI_VADER4_PRO: HIDAPI_SetDeviceName(device, "Flydigi Vader 4 Pro"); ctx->has_cz = true; ctx->sensors_supported = true; diff --git a/src/joystick/hidapi/SDL_hidapi_flydigi.h b/src/joystick/hidapi/SDL_hidapi_flydigi.h new file mode 100644 index 0000000000..42d6ef7ee2 --- /dev/null +++ b/src/joystick/hidapi/SDL_hidapi_flydigi.h @@ -0,0 +1,38 @@ +/* + Simple DirectMedia Layer + Copyright (C) 1997-2024 Sam Lantinga + + This software is provided 'as-is', without any express or implied + warranty. In no event will the authors be held liable for any damages + arising from the use of this software. + + Permission is granted to anyone to use this software for any purpose, + including commercial applications, and to alter it and redistribute it + freely, subject to the following restrictions: + + 1. The origin of this software must not be misrepresented; you must not + claim that you wrote the original software. If you use this software + in a product, an acknowledgment in the product documentation would be + appreciated but is not required. + 2. Altered source versions must be plainly marked as such, and must not be + misrepresented as being the original software. + 3. This notice may not be removed or altered from any source distribution. +*/ + +// These are values used in the controller type byte of the controller GUID + +typedef enum +{ + SDL_FLYDIGI_UNKNOWN, + SDL_FLYDIGI_APEX2 = (1 << 0), + SDL_FLYDIGI_APEX3, + SDL_FLYDIGI_APEX4, + SDL_FLYDIGI_APEX5, + SDL_FLYDIGI_VADER2 = (1 << 4), + SDL_FLYDIGI_VADER2_PRO, + SDL_FLYDIGI_VADER3, + SDL_FLYDIGI_VADER3_PRO, + SDL_FLYDIGI_VADER4, + SDL_FLYDIGI_VADER4_PRO, +} SDL_FlyDigiControllerType; +