"Jump would be easier on J than on Space." When a player feels that way, key rebinding lets them change it themselves. Changing a binding is also called rebinding.
The key name changing on the settings screen is not the finish line. Being able to jump with the new key after closing the screen, and keeping that key after relaunching the game, are all part of one feature.
This article uses a settings screen that changes jump from Space to J as its subject. Get one row working, then extend it to your game's controls.
What You'll Learn
- The relationship between the initial binding and the player's changed binding
- Why the change target is registered with User Settings
- Capturing the pressed key, changing the binding, and displaying the current key
- Saving changes, cancelling, and restoring the default
- Layer the player's change on top of the initial binding
- Preparation and registering the row to change
- Build the key-selection settings screen
- Open the screen and return to game controls
- Read and display the current key
- Change to the chosen key and save
- Test display, behavior, and saving in order
- Add a restore-defaults button
- Checks when it does not work
- Bonus: thinking about adding more actions
- Summary
Layer the player's change on top of the initial binding
In Enhanced Input, an Input Action (IA) is the action "jump" and an Input Mapping Context (IMC) holds the binding "jump on Space".
To that we add Enhanced Input User Settings , the player's settings. The Space the developer chose stays as the default and the J the player chose sits on top as an override. Think of sticky notes for changes layered over the original table.
| Responsibility | What it remembers here |
|---|---|
| IA_PracticeJump | The action "jump" |
| IMC_PlayerControls | The initial binding, Space |
| User Settings | This player uses J |
The Blueprint that performs the jump still receives IA_PracticeJump. You do not rewire the Jump node whenever the key changes.

With that division, "save the player's change" and "restore the default" can also be handled separately from the jump behavior.
Preparation and registering the row to change
We use Enhanced Input User Settings from UE 5.3 onward. This is for people who know Blueprint variables and functions and basic UMG element placement.
We continue with the practice project from the Enhanced Input introduction. Confirm the following.
- BP_InputPractice runs as the player and jumps with Space
- IMC_PlayerControls has exactly one Space Bar binding for IA_PracticeJump
- The InputSubsystem variable holds the player's Enhanced Input Local Player Subsystem
- BeginPlay enables IMC_PlayerControls and IMC_Common
We handle just the jump slot. J is unused in Enhanced Input Basics, which makes the change easy to spot. If you switched to drive mode, return to walking first.
1. Enable User Settings
Stop Play, open Enhanced Input from "Edit" → "Project Settings", and turn on Enable User Settings . Save the change, save any open assets, and restart the editor.
User Settings is the entry point that holds and saves per-player changes. Where Enhanced Input Basics' InputSubsystem managed "the control table in use", this handles "the settings this player chose".
2. Name the jump row
Open IMC_PlayerControls and expand IA_PracticeJump's Space Bar row.
- Set Setting Behavior to
Override Settings - Choose "Player Mappable Key Settings" from the picker and expand its fields
- Set Name to
JumpKeyand Display Name toJump
Override Settings means "use the settings prepared on this key row". Player Mappable means a binding the player can change.
Name is what you search for later to find the change target. It separates the "Jump" shown on screen from the JumpKey the logic looks for. It does not automatically find the IA's asset name, so keep using JumpKey from here.

Leave the other key rows alone. Save and close.
3. Register this control table with the settings entry point
In BP_InputPractice, create Get User Settings from Get InputSubsystem. Promote the output to a variable named InputUserSettings .

Rebuild BeginPlay's white wire in this order.
- Set InputSubsystem
- Set InputUserSettings
- Check InputUserSettings with
Is Valid - From the Is Valid side,
Register Input Mapping Context - The existing Add Mapping Context adding IMC_PlayerControls
- The existing Add Mapping Context adding IMC_Common
Register's Target is Get InputUserSettings and the IMC is IMC_PlayerControls. Add's Target is the same Get InputSubsystem as in Enhanced Input Basics. On the Is Not Valid side, Print String User Settings unavailable and stop there.

Register handles registering the change target and Add handles enabling the control table . They look similar but do different jobs. Going through Register makes the change target JumpKey available in User Settings.
Compile and Play, confirming no errors and that Space still jumps. The key has not changed yet. The side that accepts changes is now prepared.
Build the key-selection settings screen
Stop Play, create a Widget Blueprint, and name it WBP_KeySettings . If UMG is new to you, the Widget Blueprint introduction covers Designer versus Graph.
In the Designer, place a Vertical Box at the center of a Canvas Panel and stack these elements. Aim for about 400 width so text and buttons fit.
| Element | Name | Display / settings |
|---|---|---|
| Text | For the heading | Jump key |
| Input Key Selector | JumpKeySelector | The key-choosing element. Is Variable on |
| Text | StatusText | Empty at first. Is Variable on |
| Button + Text | CloseButton | Close |
Input Key Selector waits for the next key when clicked and displays the chosen key. You get a button and input capture without building them. Changing and saving the game's binding, though, is the job of the logic we wire next.
Configure JumpKeySelector as follows.
- Allow Gamepad Keys: off
- Allow Modifier Keys: off
- Key Selection Text:
Press a key - No Key Specified Text:
Not set - Escape Keys: add BackSpace

In this exercise, Backspace cancels while waiting for a change. Esc ends Play in the editor, so we use a different key that is easy to test. This is not a practice binding Backspace to jump.
Create these variables on WBP_KeySettings.
| Variable | Type | Purpose |
|---|---|---|
| InputUserSettings | Enhanced Input User Settings Object Reference | The party we read and write settings on. Instance Editable and Expose on Spawn on |
| bRefreshingKey | Boolean, default false | The marker while logic is fixing the display |
Expose on Spawn lets you pass a value when creating the Widget. Later BP_InputPractice passes the InputUserSettings it fetched. After setting the variables, compile and save the Widget.
Open the screen and return to game controls
First make the assembled screen openable from the game. Route input to the UI while rebinding and return it to the character on close.
1. Open with the K key
Create a Digital (Bool) IA_OpenKeySettings in the InputPractice folder. Leave Triggers empty and bind it to K in IMC_Common. The key that opens the settings screen is separate from the jump row we are changing.
In BP_InputPractice, call Create Widget from IA_OpenKeySettings' Started with Class WBP_KeySettings.
- Owning Player: Get Player Controller (Player Index = 0)
- Input User Settings: Get InputUserSettings
Owning Player is the player using this screen. The Controller you pass is also used when switching input between the UI and the game.
Promote Create Widget's Return Value to a variable named KeySettingsWidget . Wire white exec in this order.
- Create Widget → Set KeySettingsWidget
- Add to Viewport (Target is Get KeySettingsWidget)
- Set Input Mode UI Only
- Set Show Mouse Cursor = true

Set Input Mode UI Only's Player Controller is Get Player Controller's output and In Widget to Focus is Get KeySettingsWidget. Set Mouse Lock Mode to Do Not Lock and turn Flush Input on in versions that have it. Set Show Mouse Cursor uses the same Controller as Target.
Turn on Is Focusable in WBP_KeySettings' Class Defaults. UI Only routes input to the UI while the settings screen is in use.

2. Return control with the close button
In WBP_KeySettings, add CloseButton's On Clicked. Wire white exec to Remove From Parent (Target = self) → Set Input Mode Game Only → Set Show Mouse Cursor = false .
Pass Get Owning Player to Game Only's Player Controller and turn Flush Input on. The cursor's Target is the same Get Owning Player. That returns to game controls without carrying over held key states.

Removing the screen alone leaves the input mode at UI Only. Pair closing the screen with returning input to the game.
Compile and Play, then open the screen with K. At this stage the key field can still read "Not set". If "Close" returns control and Space jumps, entering and leaving the screen works. Next we display the actual key in that field.
Read and display the current key
Writing Space every time the settings screen opens would show Space even to someone who already changed it to J. Display the current key, not the default.
Create the RefreshJumpKey function
Create a function RefreshJumpKey on WBP_KeySettings with no inputs or return values.
First, place Find Mappings in Row from Get InputUserSettings with Mapping Name JumpKey. What comes back is the set of bindings belonging to that name. Create To Array from its output to get it as an array.
Since we have only the one Space slot, check whether the array's Length equals 1 .

From the function entry, wire Set bRefreshingKey = true, then a Branch with that comparison as Condition.
On the Branch's False side, Set Is Enabled = false on JumpKeySelector and Set Text on StatusText to Check the JumpKey registration . Finish with Set bRefreshingKey = false. We confirm there is one slot before reading array index 0.

What we read from the binding is Current Key, what the player uses now. Default Key is the initial value from the IMC, so we do not use it here.
An Input Chord bundles a key together with modifiers such as Shift. We handle single keys like J and Space here, but wrap them in that form when passing to the Selector.

Handle the True side in this order.
- Call
Set Is Enabledwith JumpKeySelector as Target, set to true - Pass the array Get (Index = 0) to
Break Player Key Mapping - Pass Current Key to
Make Input Chord's Key. Shift/Ctrl/Alt/Cmd all false - Call
Set Selected Keywith JumpKeySelector as Target, passing Make Input Chord's output to In Selected Key - Finish with Set bRefreshingKey = false
Get, Break, and Make pass values. White exec runs from the Branch through Set Is Enabled, Set Selected Key, and Set bRefreshingKey.

bRefreshingKey is the marker preventing repeated processing when the display fix is received again as a key change. We use it in the next section.
Call RefreshJumpKey from Event Construct in the event graph. Now the key display is built from the current settings whenever the screen is constructed. Compile and Play, and confirm the field opened with K changes from "Not set" to Space.
Change to the chosen key and save
Select JumpKeySelector in the Designer and add On Key Selected from Details' Events. That is the event you receive when a key is chosen.
1. Do not start the change while refreshing the display
Wire On Key Selected to a Branch with Get bRefreshingKey as Condition. Leave the True side unconnected and continue from False into the key change.

That separates RefreshJumpKey's display updates from the player's chosen change.
2. Pass the chosen key and the change target
Pass the event's Selected Key to Break Input Chord . We wrapped a value for display earlier; now we unwrap it and take the Key.
Place Map Player Key with Target Get InputUserSettings. In Args is the input bundling which slot changes to which key. Create Make Map Player Key Args from that pin and fill in the following.
| Field | Setting |
|---|---|
| Mapping Name | JumpKey |
| Slot | First |
| New Key | Break Input Chord's Key |
| Hardware Device Id | None |
| Profile Id fields | Leave blank |
| Create Matching Slot If Needed | Off |
| Defer On Settings Changed Broadcast | Off |
A Slot is a place prepared for a key on the same action. We change only jump's first, so we use First. This is not logic that adds slots. Device identification and multiple profiles stay at their defaults here.

Wire white exec from the previous Branch's False into Map Player Key. Confirm that you pass Break Input Chord's Key rather than Selected Key directly into New Key.

3. On success, save and re-read the display
Map Player Key's Failure Reason is the container holding reasons the change failed. Zero entries means there were no failure reasons.
Create Get Num Gameplay Tags in Container from Failure Reason and check whether its Return Value equals 0. The node name is long, but what we check is the number of failure reasons. Wire Map Player Key's white output to a Branch with that comparison as Condition.

On True, wire Save Settings → RefreshJumpKey → StatusText's Set Text showing Changed . Save Settings' Target is Get InputUserSettings and Set Text's Target is StatusText.

On False, do not save; wire RefreshJumpKey → StatusText's Set Text showing Could not change it. Check the mapping name and slot . That returns the key the Selector temporarily chose to the key the settings actually hold.

Map Player Key changes the running binding and Save Settings stores it for the next launch. Closing the screen and continuing the same session makes a missing save easy to overlook, so we relaunch and check later.
Test display, behavior, and saving in order

Compile and save everything, Play, and click the game window.
- Confirm Space jumps, land, and press K
- The settings screen shows Space
- Click the key field and press and release J. "Changed" and J appear
- Press "Close". J jumps and Space no longer does
- Reopen with K and J is still shown
- Click the key field and cancel with Backspace. Staying at J confirms cancelling works
Next, end Play and start it again. Also close the editor, reopen the project, and confirm both J on the settings screen and jumping with J.
Check both that the display persists and that the key actually works . Saved settings load when User Settings initializes, and the Register at launch prepares the same JumpKey entry.
Add a restore-defaults button
Add a Button to the settings screen named ResetButton with the label "Restore defaults".
Call Reset All Player Keys In Row from On Clicked. Target is Get InputUserSettings and In Args is Make Map Player Key Args. Set Mapping Name to JumpKey and leave the rest at defaults.

That node restores the specified action row to its initial binding. Our JumpKey has one slot, so it returns to Space. It is not logic that clears the settings for every action.
Check Failure Reason for 0 entries the same way as before and split with a Branch.
- True: Save Settings → RefreshJumpKey → StatusText showing
Restored defaults - False: RefreshJumpKey → StatusText showing
Could not restore defaults
Change to J, press this button, and confirm the Space display and jumping with Space. Space after relaunching means the restore was saved too.
The structure of keeping the original table and layering the player's change pays off here. You do not need to remember "what the default was" as a separate string on the screen.
Checks when it does not work
First isolate whether you are stuck at "cannot read settings", "cannot change", "does not reach game input", or "does not save".
| Symptom | Where to check |
|---|---|
| User Settings unavailable appears | Whether you enabled Enable User Settings and restarted, and whether Get User Settings' Target is InputSubsystem |
| Check the JumpKey registration appears | The Space row's Override Settings, Name = JumpKey, and that Register ran. Also whether you created extra key rows under JumpKey |
| Create Widget has no Input User Settings input | Whether the Widget's variable has Instance Editable and Expose on Spawn on, and whether you compiled |
| Selected Key will not connect to New Key | Whether you extracted just the Key with Break Input Chord |
| "Could not change it" appears | Whether Mapping Name is JumpKey and Slot is First, and whether you changed before registering |
| It shows J but does not jump | Whether you are in walk mode, whether "Close" returned Game Only, and whether IA_PracticeJump calls Jump |
| Reopening shows Space | Whether RefreshJumpKey uses Current Key rather than Default Key |
| It reverts after a relaunch | Whether Save Settings runs after a successful Map, and whether reset logic runs at launch |
| The display refreshes repeatedly | Whether bRefreshingKey toggles around Set Selected Key and stops things on the On Key Selected side |
To investigate further, stringify Map's or Reset's Failure Reason and send it to Print String and Output Log to trace the reason.
Bonus: thinking about adding more actions
What if the same key is chosen?
We tested with the free key J. Binding W from movement or K from opening the settings to jump would conflict. Calling Map Player Key does not automatically tidy things up for your game.
| Policy | How you show it to the player |
|---|---|
| Allow duplicates | The same key serves several actions |
| Reject duplicates | Tell them "that key is used for movement" |
| Swap them | Move the existing action to the previous key |
Whether both actions run on the same key also involves IMC priority and input-consuming settings. Comparing against other bindings before changing and rejecting duplicates is the easiest to follow at first. Reserving the settings-open key and the cancel key is another approach.
Keep Slots and devices separate
A Slot is the place for holding, say, "Space and J as two candidates" for jump. First and Second do not inherently mean keyboard and gamepad.
To make gamepad bindings changeable too, decide which action, slot, and device you target and align the displayed row with the target passed to Map. Registering several slots under the same JumpKey also means revisiting the Length = 1 check when reading. The gamepad support article is the next entry point.
Apply Settings and saving are not the same
Enhanced Input User Settings' Apply Settings is for applying your own input settings and announcing updates after applying. By default it broadcasts OnSettingsApplied.
Our key change uses Map Player Key, saving uses Save Settings, and re-reading the screen uses RefreshJumpKey, each with its own role. Do not assume "the new key will not save unless Apply is called".
Setting names matter after release too
A Name like JumpKey ties saved settings to the current action. Changing it casually later can break the correspondence with earlier settings.
As you add actions, organize what each row changes: movement, jump, attack. The flow you built on the first row, "read the current value, choose again, verify the result, and save", is reusable for every row.
Summary
Key rebinding connects a screen that waits for keys with settings that hold the player's binding. Input Key Selector receives the key and you change the JumpKey slot registered with User Settings.
When finishing, do not judge success by the display alone; confirm the jump after closing the screen and the key after relaunching. Once one row works end to end, adding more actions uses the same flow.
Reference: User Settings, Registering a mapping context, Map Player Key, Input Key Selector, What Apply Settings does.