Enhanced Input
Enhanced Input is the modern UE input system. It is data-driven: Input Actions define what
a player can do, Input Mapping Contexts map physical keys to actions (with optional
modifiers and triggers on each mapping), and the Enhanced Input Local Player Subsystem
pushes and pops contexts at runtime. Legacy DefaultInput.ini axis/action mappings still
compile but are deprecated and should be avoided in new code.
When to use this skill
- Setting up player controls on a Pawn, Character, or PlayerController.
- Binding movement, look, jump, interact, or any other player action in C++.
- Adding, removing, or reprioritizing mapping contexts at runtime (context switching: on-foot, in-vehicle, UI, etc.).
- Reading analog values from
FInputActionValuein an action handler. - Replacing legacy
BindAxis/BindActioninput bindings.
Mental model
Physical key press → IMC mapping (modifiers applied first, triggers evaluated) → FInputActionValue delivered to handler on matching ETriggerEvent
The system is entirely data-asset-driven. UInputAction and UInputMappingContext are
UDataAsset subclasses created in the Content Browser. C++ code holds UPROPERTY pointers
to them and uses the subsystem and component to wire them up.
Setup checklist
- Verify the Enhanced Input plugin is enabled (on by default in 5.x new projects).
- Add
"EnhancedInput"toPrivateDependencyModuleNamesin yourBuild.cs. - Set defaults in Project Settings → Engine → Input:
Default Player Input Class→EnhancedPlayerInputDefault Input Component Class→EnhancedInputComponent
- Create a
UInputActionasset per action; set the value type (Boolean,Axis1D,Axis2D,Axis3D). - Create a
UInputMappingContextasset; add key→action mappings, plus any per-mapping modifiers/triggers. - On possession/spawn: push the context via the subsystem.
- In
SetupPlayerInputComponent: cast toUEnhancedInputComponent, callBindAction.
Core types
| Type | Role |
|---|---|
UInputAction | Abstract action data asset; carries a ValueType (EInputActionValueType) |
UInputMappingContext | Data asset mapping FKey → UInputAction, with per-mapping UInputModifier[] and UInputTrigger[] |
UEnhancedInputComponent | Input component subclass; BindAction registers C++ delegates |
UEnhancedInputLocalPlayerSubsystem | Per-local-player subsystem; AddMappingContext / RemoveMappingContext |
FInputActionValue | Value delivered to handlers; Get<T>() extracts bool, float, FVector2D, or FVector |
ETriggerEvent | When the handler fires: Started, Triggered, Ongoing, Completed, Canceled |
Adding a mapping context
Push contexts from a point where the local player exists — typically
APlayerController::BeginPlay or APawn::PawnClientRestart:
cpp// In AMyPlayerController::BeginPlay or APawn::PawnClientRestart #include "EnhancedInputSubsystems.h" if (ULocalPlayer* LP = GetLocalPlayer()) // APlayerController has GetLocalPlayer() { auto* Subsys = LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(); if (Subsys && DefaultMappingContext) { Subsys->AddMappingContext(DefaultMappingContext, /*Priority*/ 0); } }
Higher-priority values take precedence when two active contexts map the same key to different
actions. Remove with Subsys->RemoveMappingContext(IMC). A context can be added/removed any
number of times (e.g. entering/leaving a vehicle).
Binding actions in C++
SetupPlayerInputComponent runs on the Pawn after the input component is created. Cast it to
UEnhancedInputComponent (safe once the default class is set in Project Settings):
cpp// AMyCharacter.h #pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "AMyCharacter.generated.h" class UInputAction; class UInputMappingContext; struct FInputActionValue; UCLASS() class MYGAME_API AMyCharacter : public ACharacter { GENERATED_BODY() public: virtual void SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) override; protected: void OnMove(const FInputActionValue& Value); void OnLook(const FInputActionValue& Value); UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input") TObjectPtr<UInputMappingContext> DefaultMappingContext; UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input") TObjectPtr<UInputAction> MoveAction; // Axis2D UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input") TObjectPtr<UInputAction> LookAction; // Axis2D UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input") TObjectPtr<UInputAction> JumpAction; // Boolean };
cpp// AMyCharacter.cpp #include "AMyCharacter.h" #include "EnhancedInputComponent.h" #include "EnhancedInputSubsystems.h" #include "InputActionValue.h" void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); // Push mapping context (Pawn path: via controller's local player) if (APlayerController* PC = Cast<APlayerController>(GetController())) { if (ULocalPlayer* LP = PC->GetLocalPlayer()) { auto* Subsys = LP->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(); if (Subsys && DefaultMappingContext) Subsys->AddMappingContext(DefaultMappingContext, 0); } } auto* EIC = CastChecked<UEnhancedInputComponent>(PlayerInputComponent); // Continuous actions use ETriggerEvent::Triggered (fires every tick while held) EIC->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::OnMove); EIC->BindAction(LookAction, ETriggerEvent::Triggered, this, &AMyCharacter::OnLook); // Jump: Started fires on first press, Completed fires on release EIC->BindAction(JumpAction, ETriggerEvent::Started, this, &ACharacter::Jump); EIC->BindAction(JumpAction, ETriggerEvent::Completed, this, &ACharacter::StopJumping); } void AMyCharacter::OnMove(const FInputActionValue& Value) { const FVector2D Axis = Value.Get<FVector2D>(); // matches IA_Move's Axis2D type AddMovementInput(GetActorForwardVector(), Axis.Y); AddMovementInput(GetActorRightVector(), Axis.X); } void AMyCharacter::OnLook(const FInputActionValue& Value) { const FVector2D Delta = Value.Get<FVector2D>(); AddControllerYawInput(Delta.X); AddControllerPitchInput(Delta.Y); }
Key rules:
- Action
UPROPERTYmembers are assigned in a Blueprint subclass (or in asset defaults). AssignDefaultMappingContext,MoveAction, etc. viaEditAnywhere. CastCheckedasserts in Debug builds if the cast fails — a fast failure on misconfiguration.- The handler signature must exactly match one of the four overloads: no args,
const FInputActionValue&,const FInputActionInstance&, or the dynamic four-param form. BindActionreturns aFEnhancedInputActionEventBinding&if you need to remove the binding later; store the handle or useRemoveBindingByHandle.
Reading FInputActionValue
cpp// Match the value type declared on the UInputAction asset: bool bPressed = Value.Get<bool>(); float Analog = Value.Get<float>(); // Axis1D FVector2D Axis2D = Value.Get<FVector2D>(); // Axis2D FVector Axis3D = Value.Get<FVector>(); // Axis3D
Reading the wrong type silently returns zero (e.g. Get<bool>() on an Axis2D action returns
false). The correct type is whatever EInputActionValueType the action asset declares.
Trigger events — choosing the right one
| Use case | ETriggerEvent |
|---|---|
| Continuous hold (movement, look, accelerate) | Triggered |
| One-shot on press (jump start, fire, interact) | Started |
| One-shot on release (jump release, confirm UI) | Completed |
| Cancel feedback (abort a hold) | Canceled |
| Every frame while held, before threshold met | Ongoing |
Note: Started fires once on the frame the key passes the actuation threshold. Triggered
fires every tick while held. Completed fires the frame the key is released (or the trigger
condition is fully met and then ends).
WASD as an Axis2D — modifier pattern
A single IA_Move (Axis2D) action can be driven by four keyboard keys using per-mapping
modifiers in the IMC:
| Key | Modifiers on the mapping |
|---|---|
| W | Swizzle Input Axis Values (YXZ) — moves X→Y so W contributes +Y |
| S | Swizzle (YXZ) + Negate — contributes −Y |
| A | Negate — contributes −X |
| D | (none) — contributes +X (default) |
At runtime, Enhanced Input accumulates all active mappings for an action per frame (default
TakeHighestAbsoluteValue; Cumulative is the alternative, set on the UInputAction asset).
Gotchas
- Missing
"EnhancedInput"in Build.cs → unresolved symbols for all Enhanced Input classes. - Default input classes not set →
CastChecked<UEnhancedInputComponent>crashes on start;Castreturns null and nothing fires. - Mapping context not added → actions never fire; the subsystem must have the IMC before any key can reach an action.
- Adding context before local player exists →
GetLocalPlayer()returns null; always add fromPawnClientRestart/BeginPlay(after possession), not the constructor. - Value type mismatch →
Get<FVector2D>()on a Boolean action yields(0, 0); align the handler type with the action asset'sValueType. - Legacy bind calls on UEnhancedInputComponent →
BindAxis/BindAction(FName, ...)are deleted (compile error) unlessENHANCED_INPUT_ALLOW_LEGACY_BINDING=1in Build.cs. - Action fires on context add when key is held → default
FModifyContextOptionssetsbIgnoreAllPressedKeysUntilRelease = true; the key must be released and re-pressed. SetbIgnoreAllPressedKeysUntilRelease = falseto override. - Priority conflicts — add
0for most contexts; reserve higher values for overlay contexts (e.g. UI) that must win over gameplay.
Legacy input (you will still encounter it)
Older projects use DefaultInput.ini axis/action mappings and BindAxis/BindAction(FName, ...) on UInputComponent. These still compile in 5.8 but cannot coexist cleanly with
UEnhancedInputComponent (legacy binds are explicitly deleted on the enhanced component by
default). Migrate by replacing axis/action map entries with UInputAction + UInputMappingContext assets, and replacing BindAxis/BindAction(FName, ...) calls with
UEnhancedInputComponent::BindAction.
Version notes
- Enhanced Input shipped in UE 4.27 as a plugin and became the default system in UE 5.1.
In UE 5.7 the
Mappingsproperty onUInputMappingContextis deprecated (markedUE_DEPRECATED(5.7)) in favour of the newDefaultKeyMappingsstruct; use the editor asset instead of editing theMappingsarray in C++. FModifyContextOptions(the options struct forAddMappingContext) and input mode filtering viaFGameplayTagContainerare 5.3+ additions.
References & source material
Engine source (UE 5.8, plugin path prefix:
Engine/Plugins/EnhancedInput/Source/EnhancedInput/Public/):
InputAction.h—UInputAction:55 (UDataAssetsubclass),EInputActionValueType(InputActionValue.h:10,Boolean/Axis1D/Axis2D/Axis3D),EInputActionAccumulationBehavior:24,FInputActionInstance:207 (GetValue():259,GetTriggerEvent():256).InputActionValue.h—FInputActionValue:23;Get<bool>():205,Get<float>():212,Get<FVector2D>():218,Get<FVector>():224;EInputActionValueTypereused here.InputMappingContext.h—UInputMappingContext:87 (UDataAssetsubclass);DefaultKeyMappings:101 (5.7 replacement for deprecatedMappings).EnhancedInputComponent.h—UEnhancedInputComponent:373;BindActiontemplate macroDEFINE_BIND_ACTION:480 (four signature overloads);BindActionValue:553;RemoveBinding:475;BindActionInstanceLambda:539.EnhancedInputSubsystems.h—UEnhancedInputLocalPlayerSubsystem:21 (ULocalPlayerSubsystem+IEnhancedInputSubsystemInterface);AddMappingContext:37;RemoveMappingContext:38.EnhancedInputSubsystemInterface.h—IEnhancedInputSubsystemInterface:103;FModifyContextOptions:47 (bIgnoreAllPressedKeysUntilRelease,bForceImmediately,bNotifyUserSettings);HasMappingContext:368;ClearAllMappings:256.InputTriggers.h—ETriggerEvent:34 (None/Triggered/Started/Ongoing/Canceled/Completed);UInputTrigger:113 (ActuationThreshold:130); concrete triggers:UInputTriggerPressed:279,UInputTriggerReleased:298,UInputTriggerHold:318 (HoldTimeThreshold:334),UInputTriggerTap:365,UInputTriggerPulse:457,UInputTriggerChordAction:494.InputModifiers.h—UInputModifier:16 (ModifyRaw_Implementation); concrete modifiers:UInputModifierDeadZone:170,UInputModifierNegate:253,UInputModifierSwizzleAxis:412 (EInputAxisSwizzle::YXZ),UInputModifierScalar:213,UInputModifierSmooth:275,UInputModifierResponseCurveExponential:306.EnhancedActionKeyMapping.h—FEnhancedActionKeyMapping:37 (Action,Key,Modifiers[],Triggers[]).EnhancedInputDeveloperSettings.h—UEnhancedInputDeveloperSettings:43 (DefaultMappingContexts,bEnableInputModeFiltering,DefaultInputMode).
Official docs (UE 5.8):
- Enhanced Input — https://dev.epicgames.com/documentation/unreal-engine/enhanced-input-in-unreal-engine
- Input overview — https://dev.epicgames.com/documentation/unreal-engine/input-in-unreal-engine
Deep-dive references in this skill:
- references/actions-and-contexts.md —
UInputActionvalue types, accumulation,UInputMappingContextstructure, priority, runtime add/remove. - references/modifiers-and-triggers.md — all built-in modifiers and triggers, authoring custom ones, trigger type semantics.
- references/binding-and-setup.md — full
BindActionoverload set, lambda bindings, removing bindings, theFInputActionInstancehandler, per-project class defaults, world-subsystem input for non-player actors.


