From 66020c2ed7fae1d4a87011eddcbb14f6bcc4eb98 Mon Sep 17 00:00:00 2001 From: Nintorch <92302738+Nintorch@users.noreply.github.com> Date: Mon, 9 Mar 2026 23:07:06 +0500 Subject: [PATCH] Small GameInput joystick backend improvements This PR includes small improvements to the GameInput joystick backend: - Device subtypes - Compatibility with DirectInput joystick mappings (if the controller is not a gamepad, i.e. `GAMEINPUT_InternalIsGamepad()` returns `false`) - Fallback to DirectInput/XInput for currently unsupported devices (force feedback ones and the ones that are neither gamepads nor controllers, I'm not sure if that's possible, but maybe racing wheels and other device subtypes would count?) (cherry picked from commit 0138843eb7cb988e571949a0d088244560bf0f6e) --- src/joystick/SDL_joystick.c | 9 +++ src/joystick/gdk/SDL_gameinputjoystick.cpp | 68 +++++++++++++++++----- 2 files changed, 63 insertions(+), 14 deletions(-) diff --git a/src/joystick/SDL_joystick.c b/src/joystick/SDL_joystick.c index 621adbd3f4..457f7e689f 100644 --- a/src/joystick/SDL_joystick.c +++ b/src/joystick/SDL_joystick.c @@ -3327,6 +3327,11 @@ bool SDL_IsJoystickWGI(SDL_GUID guid) return (guid.data[14] == 'w') ? true : false; } +bool SDL_IsJoystickGameInput(SDL_GUID guid) +{ + return (guid.data[14] == 'g') ? true : false; +} + bool SDL_IsJoystickHIDAPI(SDL_GUID guid) { return (guid.data[14] == 'h') ? true : false; @@ -3420,6 +3425,10 @@ static SDL_JoystickType SDL_GetJoystickGUIDType(SDL_GUID guid) return (SDL_JoystickType)guid.data[15]; } + if (SDL_IsJoystickGameInput(guid)) { + return (SDL_JoystickType)guid.data[15]; + } + if (SDL_IsJoystickVIRTUAL(guid)) { return (SDL_JoystickType)guid.data[15]; } diff --git a/src/joystick/gdk/SDL_gameinputjoystick.cpp b/src/joystick/gdk/SDL_gameinputjoystick.cpp index efe6795964..f990262f14 100644 --- a/src/joystick/gdk/SDL_gameinputjoystick.cpp +++ b/src/joystick/gdk/SDL_gameinputjoystick.cpp @@ -84,6 +84,25 @@ static bool GAMEINPUT_InternalIsGamepad(const GameInputDeviceInfo *info) return false; } +static Uint8 GAMEINPUT_GetDeviceSubtype(const GameInputDeviceInfo *info) +{ + GameInputKind supportedInput = info->supportedInput; + if (supportedInput & GameInputKindRacingWheel) { + return SDL_JOYSTICK_TYPE_WHEEL; + } + if (supportedInput & GameInputKindArcadeStick) { + return SDL_JOYSTICK_TYPE_ARCADE_STICK; + } + if (supportedInput & GameInputKindFlightStick) { + return SDL_JOYSTICK_TYPE_FLIGHT_STICK; + } + if (supportedInput & (GameInputKindGamepad | GameInputKindController)) { + return SDL_JOYSTICK_TYPE_GAMEPAD; + } + // Other device subtypes don't have their own GameInputKind enum entries. + return 0; +} + #if GAMEINPUT_API_VERSION >= 1 static int GetSteamVirtualGamepadSlot(const char *device_path) { @@ -105,8 +124,9 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice) Uint16 vendor = 0; Uint16 product = 0; Uint16 version = 0; - const char *manufacturer_string = NULL; const char *product_string = NULL; + Uint8 driver_signature = 'g'; + Uint8 subtype = 0; char tmp[4]; int idx = 0; @@ -128,11 +148,41 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice) vendor = info->vendorId; product = info->productId; //version = (info->firmwareVersion.major << 8) | info->firmwareVersion.minor; + subtype = GAMEINPUT_GetDeviceSubtype(info); - if (SDL_JoystickHandledByAnotherDriver(&SDL_GAMEINPUT_JoystickDriver, vendor, product, version, "")) { +#if GAMEINPUT_API_VERSION >= 1 + if (info->displayName) { + product_string = info->displayName; + } +#else + if (info->displayName) { + product_string = info->displayName->data; + } +#endif + + if (SDL_ShouldIgnoreJoystick(vendor, product, version, product_string) || + SDL_JoystickHandledByAnotherDriver(&SDL_GAMEINPUT_JoystickDriver, vendor, product, version, product_string)) { return true; } +#if defined(SDL_JOYSTICK_DINPUT) && defined(SDL_HAPTIC_DINPUT) + // This joystick backend currently doesn't provide a haptic backend, so fallback to DirectInput for haptic-capable devices. + if (SDL_GetHintBoolean(SDL_HINT_JOYSTICK_DIRECTINPUT, true) && info->forceFeedbackMotorCount > 0 && pDevice->IsForceFeedbackMotorPoweredOn(0)) { + return true; + } +#endif + + if (!GAMEINPUT_InternalIsGamepad(info)) { + if (info->supportedInput & GameInputKindController) { + // Maintain GUID compatibility with DirectInput controller mappings. + driver_signature = 0; + subtype = 0; + } else { + // This joystick backend currently doesn't provide proper reading of other joystick types. + return true; + } + } + for (idx = 0; idx < g_GameInputList.count; ++idx) { elem = g_GameInputList.devices[idx]; if (elem && elem->device == pDevice) { @@ -159,20 +209,10 @@ static bool GAMEINPUT_InternalAddOrFind(IGameInputDevice *pDevice) SDL_strlcat(elem->path, tmp, SDL_arraysize(elem->path)); } -#if GAMEINPUT_API_VERSION >= 1 - if (info->displayName) { - product_string = info->displayName; - } -#else - if (info->displayName) { - product_string = info->displayName->data; - } -#endif - pDevice->AddRef(); elem->device = pDevice; - elem->name = SDL_CreateJoystickName(vendor, product, manufacturer_string, product_string); - elem->guid = SDL_CreateJoystickGUID(bus, vendor, product, version, manufacturer_string, product_string, 'g', 0); + elem->name = SDL_CreateJoystickName(vendor, product, NULL, product_string); + elem->guid = SDL_CreateJoystickGUID(bus, vendor, product, version, NULL, product_string, driver_signature, subtype); elem->device_instance = SDL_GetNextObjectID(); elem->info = info; #if GAMEINPUT_API_VERSION >= 1