How-To: Rebindable Keys

Goal: give the player a working key-rebinding list, and decide how every bound key prints - full name, platform glyph, or abbreviation.

Prerequisites
Enhanced Input, and an Input Mapping Context whose actions you want rebindable. How-To: Use the Ready-Made Collections builds the list; this page is what fills and styles it.

1. Mark which actions are rebindable

An action appears in the rebind list only if it carries a UPlayerMappableKeySettings on its mapping - Enhanced Input's own mechanism. There is no second list of "rebindable actions" for you to keep in step: the decision lives on the mapping, next to the binding it governs.

Open the Input Mapping Context, expand the mapping, and under Setting Behavior choose a Player Mappable Key Settings class, then give it a Name (this is the stable identity - see the warning below) and a Display Name and Display Category (which is how the list groups rows).

The mapping Name is permanent
UPlayerMappableKeySettings::Name is the key Enhanced Input saves a rebind under, the name CriticalMappingNames matches against, and the name a conflict warning reports. Renaming it discards every rebind a player has already made for that action.
Verify
The action's mapping shows a Player Mappable Key Settings object with a non-empty Name.

2. Build the rows

K2_RegisterKeybindingSettings(LocalPlayer, Collection, bGamepad) builds one row per rebindable action and adds them to the collection you hand it. Call it once per device. The two input builders already do this - reach for it directly only when you want the list somewhere else.

In your registry Blueprint: Event K2_RegisterInputSettings (LocalPlayer) -> Create Collection (Outer = self, DevName = KeyboardBindings, DisplayName = "Keybindings") -> K2 Register Keybinding Settings (Local Player = the event pin, Collection = the new collection, Gamepad = false) -> K2 Register Setting (the collection).

Repeat with a second collection, DevName GamepadBindings, Gamepad = true.

Rows are device-scoped, and that is load-bearing
An action bound on both devices yields two independent rows. Enhanced Input does not separate them for you: it hands every mapping of an action a slot from a single counter, so "Attack" on LMB and on the pad's X button ends up slot First (mouse) and slot Second (pad). A row that assumed "primary = slot First" would let the gamepad row overwrite the keyboard binding. UCrimsonSettingKeyboardInput addresses everything by BUTTON INDEX - 0 primary, 1 secondary - and resolves the slot each one means per device.
Verify
The collection lists your rebindable actions, grouped by their Display Category. Rebind one, Apply, restart - the binding survives, because SaveChanges() persists the Enhanced Input user settings alongside everything else.

3. Author the row widget

The row class is UCrimsonSettingsListEntrySetting_KeyboardInput. Subclass it as a Widget Blueprint and give it these binds:

Widget nameRequired?Purpose
Button_PrimaryKeyYesThe primary key pill. Clicking it starts listening for a new key.
Button_SecondaryKeyYesThe secondary pill.
Button_ClearYesUnbinds. Tooltip comes from ClearButtonTooltip.
Button_ResetToDefaultYesRestores the mapping's authored key. Tooltip from ResetButtonTooltip.
ActionWidget_PrimaryKeyOptionalGlyph slot for the primary pill on keyboard and mouse rows.
ActionWidget_SecondaryKeyOptionalGlyph slot for the secondary pill on keyboard and mouse rows.
ActionWidget_PrimaryKey_GamepadOptionalGlyph slot for the primary pill on gamepad rows.
ActionWidget_SecondaryKey_GamepadOptionalGlyph slot for the secondary pill on gamepad rows.

All four glyph slots are BindWidgetOptional and typed UCommonActionWidget, so a project places whatever UCommonActionWidget subclass it likes and this plugin never learns about it. The row hands the pair matching its own device the row's UInputAction and collapses the other pair. What a key looks like is therefore your decision, not the plugin's.

Four slots, not two
A keybind row is device-scoped; a glyph widget is not. The input tabs list keyboard rows and gamepad rows over the same actions, and a gamepad row has to draw pad art while the player is editing it with a mouse. UCommonActionWidget on its own resolves for whatever device the player is currently holding, which is the wrong question here - so the pair a row does not edit is collapsed, and the pair it does edit should be pinned to that device.
A plain UCommonActionWidget gets three things wrong here
It resolves an action to its first mapped key, so one placed in a secondary slot mirrors the primary. It follows the current input device, so a gamepad row reads as keyboard art while the player is on a mouse. And it resolves keys through the mapping contexts applied right now - which Enhanced Input's input-mode filtering strips while a menu is open, so gameplay bindings resolve to no key at all on this screen.

Subclass UCommonActionWidget once and fix all three there, then place your subclass in the four slots. It needs: a key-slot property, so a widget in a secondary slot asks for the second key rather than the first; an input-type override, so the two unsuffixed widgets are pinned to mouse and keyboard and the two _Gamepad ones to gamepad regardless of what the player is holding; and a fallback that reads the Enhanced Input user settings rather than the applied mapping contexts. The last one is the fix for the menu case: UEnhancedInputLocalPlayerSubsystem::GetUserSettings() -> UEnhancedInputUserSettings::GetActiveKeyProfile() gives you FPlayerKeyMapping entries whose GetSlot(), GetCurrentKey() and GetAssociatedInputAction() answer the question without any applied mapping context, and no input mode filters that profile.
Chords come along for free
This plugin rebinds plain keys. Chords (modifier + key) are an extension point: UCrimsonSettingKeyboardInput exposes the virtual hooks OnBindingApplied, OnBindingResetToDefault, DoesMappingConflict, OnConflictingBindingCleared, GetKeyTextForButton and IsMappingCustomized, the list entry exposes BeginKeyCapture, PushModalPanel, GatherConflictingActions, GetPendingKeyDisplayText, ApplyPendingBinding and ClearPendingConflicts, and UCrimsonSettingRegistry::KeybindingSettingClass selects your subclass. (CrimsonCore - requires all Crimson plugins) UCrimsonCoreSettingKeyboardInput and UCrimsonCoreSettingsListEntry_KeyboardInput are the reference: they store chords through the input plugin and draw the modifier glyphs ahead of the key.

4. Choose how keys print

UCrimsonSettingsDeveloperSettings::KeybindDisplayMode decides how every keybind pill in the project reads. It is one project setting rather than a per-row property, so the screen cannot disagree with itself - and the rows are authored assets a consumer would otherwise edit one at a time.

Project Settings -> Crimson -> Crimson Settings: the Keybind Display and Critical Bindings categories.
ModeEditor labelThe pill shows
NormalFull NamesThe key's full name, chord included - Shift+Right Mouse Button. Longest, but unambiguous.
GlyphsPlatform GlyphsA platform glyph, drawn by the row's action widget. The shipped default - an icon is read faster than a name and survives a narrow pill. Falls back to abbreviated text wherever a glyph cannot be drawn.
ShortAbbreviatedThe abbreviated name - Shift+RMB. Fits a narrow pill without truncating.

Short mode asks GetAbbreviatedKeyName(Key), which returns the configured override when the key has one and otherwise falls through to the engine's own short name (FKey::GetDisplayName(bLongDisplayName=false)). That fallback is already right for letters, digits and the mouse buttons - KeyAbbreviations exists for the keys where it disappoints, which is the gamepad triggers, bumpers and stick clicks: the engine renders those at almost full length, exactly where a narrow pill runs out of room.

The table ships populated
23 entries: mouse buttons and wheel, the triggers and their axis twins, shoulders, stick clicks, the four face buttons written for both conventions, the D-pad, and Select / Start. It is a starting point, not a list you have to maintain - replace the whole array in DefaultGame.ini if you disagree with any of it.
Glyphs mode needs a glyph slot
In Glyphs mode the pill's text is cleared and the action widget is shown; in every other mode - and for an unbound key, an unresolvable action, a key whose platform data carries no art, or the critical UNBOUND state - the action widget is collapsed and the pill shows text. The row asks the widget's own GetIcon() whether it resolved anything before choosing glyph over text, so a missing icon is never an empty box. A row set to Glyphs with no bind for the device it edits logs one warning per row class and falls back to Short.
Verify
Switch the mode in Project Settings and reopen the screen. Full Names prints Right Mouse Button; Abbreviated prints RMB; Platform Glyphs draws the icon.

5. Warn about cleared critical bindings

CriticalMappingNames lists the mappings the game genuinely needs - the ones a player who clears them is probably about to file a bug about. Names match UPlayerMappableKeySettings::Name. It ships empty, so nothing warns until a project opts in.

Project Settings -> Crimson -> Crimson Settings -> Critical Bindings -> Critical Mapping Names. Add one entry per mapping name. The panel writes DefaultGame.ini for you.

A listed row's primary key button (button index 0 only) warns while that row's own device has no key at all - ShouldWarnUnbound() is IsCriticalMapping() && IsUnboundOnThisDevice(). The button shows CriticalUnboundText (UNBOUND when the row class leaves it empty) with CriticalUnboundTooltip, and SetWarningState(true) plays the row's Anim_Warning.

Device-scoped on purpose
An action bound on the keyboard but not the pad is unbound as far as a pad player is concerned, so the gamepad row is the one with something to say about it. The keyboard row for the same action stays quiet.

What the warning looks like is content, not code. UCrimsonSettingsButtonBase only sequences the animations; Anim_Warning is authored on your Widget Blueprint. Warning replaces idle only, so a button warning about a missing binding still highlights normally when the player reaches for it.

Verify
Clear a critical binding on one device. That row's primary pill reads UNBOUND and plays its warning animation; the same action's row on the other device is unaffected.

See also

  • How-To: Use the Ready-Made Collections - the two input tabs that already carry a rebind list.
  • API Reference -> Input & rebinding - the full UCrimsonSettingKeyboardInput surface, and what the four glyph slots expect.