FKey::IsSameResolvedKey compares GetVirtualKey(), which returns a default-constructed FKey for any key without registered FKeyDetails. An action with no key for the current input type therefore compares equal to any brush entry whose key is also unresolvable, and that entry’s brush is drawn. 5.7 compared key names and matched nothing.
Introduced by CL 48876192 — “CommonUI: Fix not properly resolving the new virtual keys” (2025/12/02). Still present in //UE5/Main#10 and //UE6/Main.
File Engine/Plugins/Runtime/CommonUI/Source/CommonInput/Private/CommonInputBaseTypes.cpp
Conditions
1. An action bound on gamepad and unbound on keyboard, as Lyra ships in DT_SaveActions (Apply, CancelChanges: Gamepad_FaceButton_Left/Top, no keyboard key). GetInputTypeInfo(MouseAndKeyboard) returns KeyboardInputTypeInfo with an empty key, and CommonUI::GetIconForInputActions adds it to the lookup without a validity check.
2. An InputBrushDataMap entry whose key has no registered FKeyDetails. FWindowsPlatformInput::GetKeyMap names layout-specific keys after the character they print (FString::Chr), and registers them only for the layout active when InitKeyMappings runs — so a brush map covering more than one keyboard layout contains entries unresolvable on a given machine.
Potential fix: check for InKey.IsValid()
TryGetInputBrushFromDataMap (~line 34):
return InKey.IsValid() && KeyBrushPair.Key.IsSameResolvedKey(InKey); TryGetInputBrushFromKeySets (~line 62), inner predicate:
return Key.IsValid() && BrushKey.IsSameResolvedKey(Key);
Neither can regress CL 48876192: Virtual_Gamepad_Accept/Back are registered keys and pass IsValid(). Optionally also skip invalid keys in CommonUI::GetIconForInputActions, which currently adds them unconditionally — that would fix it at the source rather than at both lookups.
It would also be possible to fix by modifying IsSameResolvedKey() to fall back to name identity when resolution fails:
bool FKey::IsSameResolvedKey(const FKey& Other) const
{
const FKey ThisVirtual = GetVirtualKey();
const FKey OtherVirtual = Other.GetVirtualKey();
if (!ThisVirtual.IsValid() || !OtherVirtual.IsValid())
{
return KeyName == Other.KeyName;
}
return ThisVirtual == OtherVirtual;
}
or modify GetVirtualKey() to return *this instead of FKey() in case of invalid KeyDetails:
// current
return (KeyDetails.IsValid() ? KeyDetails->GetVirtualKey() : FKey());
// proposed
return (KeyDetails.IsValid() ? KeyDetails->GetVirtualKey() : *this);
[Attachment Removed]