CommonUI: unbound action matches an unresolvable brush entry, drawing a wrong key glyph (5.8 regression)

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]

Steps to Reproduce
Add an entry to CommonInput_KeyboardMouse’s InputBrushDataMap keyed to a layout-specific character key (e.g. ², present on AZERTY). On a machine whose active layout does not register it, view a gamepad-bound/keyboard-unbound action on keyboard — 5.7 draws no glyph, 5.8 draws that entry’s brush.

[Attachment Removed]

Hi,

Thanks for reporting this, I ended up going with your first suggestion since it’s a bit more contained. That fix should be checked in now at CL#57024006.

Best,

Cody

[Attachment Removed]

Thanks for following up so quickly! Issue can be closed now.

[Attachment Removed]