Upgrade to unreal 5.7.4

This commit is contained in:
2026-05-05 16:26:49 -04:00
parent 3be98f3617
commit e16e0978b0
5 changed files with 168 additions and 33 deletions

View File

@@ -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.

View File

@@ -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 <link.h>
@@ -1060,3 +1061,69 @@

View File

@@ -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)
{
```

Binary file not shown.

BIN
UnrealEngine-5.7.4-release.zip LFS Normal file

Binary file not shown.