diff --git a/Docs/Getting-Gamepad-USB-Device-Name.md b/Docs/Getting-Gamepad-USB-Device-Name.md new file mode 100644 index 00000000..ca368803 --- /dev/null +++ b/Docs/Getting-Gamepad-USB-Device-Name.md @@ -0,0 +1,117 @@ +# Getting the Gamepad USB Device Name + +Unreal exposes `UInputDeviceSubsystem::GetMostRecentlyUsedHardwareDevice()`, which +returns an `FHardwareDeviceIdentifier`. In stock Unreal this is nearly useless: on +Windows it toggles between `"WindowsApplication"` (KBM) and `"XInputController"` +(any XInput pad); on Linux it returns nothing meaningful at all. It cannot +distinguish a DualSense from an Xbox pad. + +The USB-reported device name (e.g. `"Sony Interactive Entertainment Wireless +Controller"`) is what we want to surface. This document describes the changes +required on each platform to put that name into `FHardwareDeviceIdentifier`. + +## How `FHardwareDeviceIdentifier` Gets Populated + +Input drivers wrap their `MessageHandler->OnControllerButton/Analog` calls in an +`FInputDeviceScope` (stack-allocated, thread-local stack of pointers). The scope +carries `InputDeviceName` (driver class) and `HardwareDeviceIdentifier` (physical +device string). When the input event reaches `UInputDeviceSubsystem`, those two +fields are copied into the `FHardwareDeviceIdentifier` record for that user. + +So the fix on each platform is the same shape: **at device-connect time, cache +the USB device-name string; in the per-event scope, pass it as the +`HardwareDeviceIdentifier`.** + +## Windows: Patch the GameInput Plugin + +Location: `Engine/Plugins/Runtime/GameInput/Source/GameInputBase/`. + +The Microsoft GameInput SDK already exposes the data we need on every device via +`GameInputDeviceInfo::displayName` (a `wchar_t*`). The plugin reads it for log +lines (`GameInputUtils.cpp:18-23`) but does not propagate it. + +Steps: + +1. **Cache at connect.** Add `FString CachedDisplayName` to + `FGameInputDeviceContainer`. In its constructor / device-info init path + (`GameInputDeviceContainer.cpp:44`, where `Info` is in scope), set: + ```cpp + CachedDisplayName = FString(Info->displayName); + ``` + `TCHAR == wchar_t` on Windows, so the conversion is direct. Lifetime matches + the container — cleared automatically on disconnect. + +2. **Make the container reachable from `FGameInputEventParams`.** The processor + already gets a `Device` pointer; add a `Container` pointer so + `GetHardwareDeviceIdentifierName` can read the cached string. + +3. **Return it from `GetHardwareDeviceIdentifierName`** + (`GameInputDeviceProcessor.cpp:61`). After the existing + `bOverrideHardwareDeviceIdString` block, before the family-bucket switch: + ```cpp + if (Params.Container && !Params.Container->CachedDisplayName.IsEmpty()) + { + return Params.Container->CachedDisplayName; + } + ``` + The override path still wins (explicit dev intent); the family-bucket + fallback handles devices with empty `displayName`. + +Total: ~10 lines plus the field. All inside `#if GAME_INPUT_SUPPORT`. + +The user must enable the GameInput plugin and disable the default `XInputDevice` +plugin (otherwise both drivers will dispatch events for the same pad). + +## Linux: Patch `LinuxApplication.cpp` + +Location: `Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxApplication.cpp`. + +SDL already provides the device name via `SDL_GameControllerName()`. The Linux +path calls it once for a log line in `AddGameController` (line 2175) and then +discards it. The Linux path also does not push an `FInputDeviceScope` at all +around its controller events — that's the second half of why +`GetMostRecentlyUsedHardwareDevice` is useless on Linux. + +Steps: + +1. **Store the name.** Add `FString DeviceName` to `SDLControllerState`. In + `AddGameController` (~line 2175), assign: + ```cpp + ControllerState.DeviceName = UTF8_TO_TCHAR(SDL_GameControllerName(Controller)); + ``` + +2. **Wrap controller-event dispatch in a scope.** Around the + `MessageHandler->OnControllerButton*/OnControllerAnalog` block (starting + ~line 518): + ```cpp + FInputDeviceScope Scope( + nullptr, + FName("LinuxApplication"), + ControllerState.DeviceId.GetId(), + ControllerState.DeviceName); + // ... existing dispatch ... + ``` + Use `"LinuxApplication"` for `InputDeviceName` to mirror the Windows + convention. + +Total: ~12 lines. No third-party dependencies, no engine plugins, no per-device +config tables. + +## What This Does Not Solve + +- **Stock XInput on Windows.** If we keep the default `XInputDevice` plugin, + events continue to come through `XInputInterface.cpp` with a fixed + `"XInputController"` identifier. XInput itself does not expose VID/PID or + device strings. Recovering the name there requires correlating the XInput + slot with a Raw Input HID via the `IG_xx` token in the Raw Input device path, + then calling `HidD_GetProductString` — a separate, more involved patch. + GameInput is the cleaner answer on Windows. + +- **XInput-wrapped pads under GameInput.** A DualSense routed through Steam + Input or DS4Windows will surface as the wrapper's display name (e.g. ViGEm), + not as the underlying physical device. This is a property of the wrapper, not + fixable from our side. + +- **`displayName` is not a stable identifier.** It is a human-readable name + whose exact text varies by OS version, driver, and USB descriptor. Use it for + prompt-set selection and logging. Do not use it as a save-game key. diff --git a/EnginePatches/EnginePatch b/EnginePatches/EnginePatch index cc99f821..e508eeb2 100644 --- a/EnginePatches/EnginePatch +++ b/EnginePatches/EnginePatch @@ -43,35 +43,6 @@ // If we're rendering offscreen, use the "dummy" SDL video driver if (FParse::Param(FCommandLine::Get(), TEXT("RenderOffScreen")) && !getenv("SDL_VIDEODRIVER")) { ---- Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxWindow.cpp.orig 2026-04-12 22:58:34.538334467 -0400 -+++ Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxWindow.cpp 2026-04-12 22:48:15.848291098 -0400 -@@ -235,7 +235,26 @@ - - // The SDL window doesn't need to be reshaped. - // the size of the window you input is the sizeof the client. -+ -+ // Under XWayland, non-override-redirect popup windows don't receive input -+ // events from the compositor. SDL already sets override_redirect for -+ // tooltips and popup menus, but other borderless child windows (like -+ // notification popups and dialogs) also need it. We temporarily enable -+ // the SDL hint to force override_redirect for these windows. -+ bool bForceOverrideRedirect = !Definition->HasOSWindowBorder -+ && InParent.IsValid() -+ && !(WindowStyle & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)); -+ if (bForceOverrideRedirect) -+ { -+ SDL_SetHint(SDL_HINT_X11_FORCE_OVERRIDE_REDIRECT, "1"); -+ } -+ - HWnd = SDL_CreateWindow( TCHAR_TO_ANSI( *Definition->Title ), X, Y, ClientWidth, ClientHeight, WindowStyle ); -+ -+ if (bForceOverrideRedirect) -+ { -+ SDL_SetHint(SDL_HINT_X11_FORCE_OVERRIDE_REDIRECT, "0"); -+ } - // produce a helpful message for common driver errors - if (HWnd == nullptr) - { --- Engine/Source/Runtime/Core/Private/Unix/UnixPlatformStackWalk.cpp.orig 2026-04-12 22:58:34.349328955 -0400 +++ Engine/Source/Runtime/Core/Private/Unix/UnixPlatformStackWalk.cpp 2026-04-12 23:05:56.395187515 -0400 @@ -15,6 +15,7 @@ @@ -79,7 +50,7 @@ #include "HAL/PlatformProcess.h" #include "HAL/PlatformTime.h" +#include "Modules/ModuleManager.h" - #include "AutoRTFM/AutoRTFM.h" + #include "AutoRTFM.h" #include @@ -1060,3 +1061,69 @@ diff --git a/EnginePatches/Old-Patches.md b/EnginePatches/Old-Patches.md new file mode 100644 index 00000000..76124a15 --- /dev/null +++ b/EnginePatches/Old-Patches.md @@ -0,0 +1,47 @@ +# Old Patches + +Patches that were once part of `EnginePatch` but are no longer needed. +Kept here for reference in case the underlying issue resurfaces. + +## LinuxWindow.cpp — force override_redirect for borderless child windows + +Removed when the engine was upgraded to UE 5.7, which uses SDL3. SDL3 has +better Wayland support, so this workaround is believed to be unnecessary. +The original purpose was to make Unreal play better with Wayland: under +XWayland, non-override-redirect popup windows don't receive input events +from the compositor. SDL already sets override_redirect for tooltips and +popup menus, but other borderless child windows (notification popups, +dialogs) also needed it, so we temporarily enabled +`SDL_HINT_X11_FORCE_OVERRIDE_REDIRECT` around the `SDL_CreateWindow` call. + +```diff +--- Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxWindow.cpp.orig 2026-04-12 22:58:34.538334467 -0400 ++++ Engine/Source/Runtime/ApplicationCore/Private/Linux/LinuxWindow.cpp 2026-04-12 22:48:15.848291098 -0400 +@@ -235,7 +235,26 @@ + + // The SDL window doesn't need to be reshaped. + // the size of the window you input is the sizeof the client. ++ ++ // Under XWayland, non-override-redirect popup windows don't receive input ++ // events from the compositor. SDL already sets override_redirect for ++ // tooltips and popup menus, but other borderless child windows (like ++ // notification popups and dialogs) also need it. We temporarily enable ++ // the SDL hint to force override_redirect for these windows. ++ bool bForceOverrideRedirect = !Definition->HasOSWindowBorder ++ && InParent.IsValid() ++ && !(WindowStyle & (SDL_WINDOW_TOOLTIP | SDL_WINDOW_POPUP_MENU)); ++ if (bForceOverrideRedirect) ++ { ++ SDL_SetHint(SDL_HINT_X11_FORCE_OVERRIDE_REDIRECT, "1"); ++ } ++ + HWnd = SDL_CreateWindow( TCHAR_TO_ANSI( *Definition->Title ), X, Y, ClientWidth, ClientHeight, WindowStyle ); ++ ++ if (bForceOverrideRedirect) ++ { ++ SDL_SetHint(SDL_HINT_X11_FORCE_OVERRIDE_REDIRECT, "0"); ++ } + // produce a helpful message for common driver errors + if (HWnd == nullptr) + { +``` diff --git a/UnrealEngine-5.5.4-release.zip b/UnrealEngine-5.5.4-release.zip deleted file mode 100644 index f32033b9..00000000 --- a/UnrealEngine-5.5.4-release.zip +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:1f2327f5104d4dad26dac639804d4603194b7ae6f57b5df5c348a65d0c3b64c1 -size 655101165 diff --git a/UnrealEngine-5.7.4-release.zip b/UnrealEngine-5.7.4-release.zip new file mode 100644 index 00000000..46d47ab7 --- /dev/null +++ b/UnrealEngine-5.7.4-release.zip @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:c2db07679703ae809ab887d02eb4da8d617b191b316a508892e30262e3ccf082 +size 709315911