$npx -y skills add quodsoler/unreal-engine-skills --skill ue-input-systemUse this skill when implementing player input with Unreal Engine's Enhanced Input system. Also use when the user mentions 'Enhanced Input', 'input', 'input action', 'InputAction', 'mapping context', 'InputMappingContext', 'input binding', 'key binding', 'input trigger', 'input mo
| 1 | # UE Enhanced Input System |
| 2 | |
| 3 | You are an expert in Unreal Engine's Enhanced Input system. |
| 4 | |
| 5 | ## Context Check |
| 6 | |
| 7 | Read `.agents/ue-project-context.md` before proceeding. Confirm: |
| 8 | |
| 9 | - `EnhancedInput` plugin is listed as enabled |
| 10 | - Target platforms (affects which modifiers are needed per platform) |
| 11 | - Whether CommonUI is in use (it manages input mode switching automatically) |
| 12 | - Whether the project still uses legacy input (migration may be needed) |
| 13 | |
| 14 | ## Information Gathering |
| 15 | |
| 16 | Ask the developer: what actions are needed and their value types (Bool/Axis1D/Axis2D/Axis3D), which platforms, any complex input requirements (hold-to-charge, double-tap, combos, chord shortcuts), and whether multiple input modes are required (gameplay vs UI vs vehicle). |
| 17 | |
| 18 | --- |
| 19 | |
| 20 | ## Enhanced Input Setup |
| 21 | |
| 22 | ### Plugin and Module |
| 23 | |
| 24 | `.uproject`: add `{ "Name": "EnhancedInput", "Enabled": true }` to Plugins. |
| 25 | |
| 26 | `Build.cs`: add `"EnhancedInput"` to `PublicDependencyModuleNames`. |
| 27 | |
| 28 | `DefaultInput.ini`: |
| 29 | ```ini |
| 30 | [/Script/Engine.InputSettings] |
| 31 | DefaultPlayerInputClass=/Script/EnhancedInput.EnhancedPlayerInput |
| 32 | DefaultInputComponentClass=/Script/EnhancedInput.EnhancedInputComponent |
| 33 | ``` |
| 34 | |
| 35 | ### UInputAction Asset |
| 36 | |
| 37 | `UInputAction : UDataAsset`. Create one per logical player action. Key properties (from `InputAction.h`): |
| 38 | |
| 39 | ```cpp |
| 40 | EInputActionValueType ValueType = EInputActionValueType::Boolean; |
| 41 | // Boolean | Axis1D (float) | Axis2D (FVector2D) | Axis3D (FVector) |
| 42 | |
| 43 | EInputActionAccumulationBehavior AccumulationBehavior |
| 44 | = EInputActionAccumulationBehavior::TakeHighestAbsoluteValue; |
| 45 | // TakeHighestAbsoluteValue — highest magnitude wins across all mappings to this action |
| 46 | // Cumulative — all mapping values sum (W + S cancel each other for WASD) |
| 47 | |
| 48 | bool bConsumeInput = true; // blocks lower-priority Enhanced Input mappings to same keys |
| 49 | |
| 50 | TArray<TObjectPtr<UInputTrigger>> Triggers; // applied AFTER per-mapping triggers |
| 51 | TArray<TObjectPtr<UInputModifier>> Modifiers; // applied AFTER per-mapping modifiers |
| 52 | ``` |
| 53 | |
| 54 | ### UInputMappingContext Asset |
| 55 | |
| 56 | `UInputMappingContext : UDataAsset`. Maps physical keys to actions. |
| 57 | |
| 58 | - `DefaultKeyMappings.Mappings` — `TArray<FEnhancedActionKeyMapping>` of key-to-action entries |
| 59 | - `MappingProfileOverrides` — per-profile key overrides for player remapping support |
| 60 | - `RegistrationTrackingMode`: `Untracked` (default, first Remove wins) or `CountRegistrations` (IMC stays until Remove called N times, safe when multiple systems share it) |
| 61 | |
| 62 | --- |
| 63 | |
| 64 | ## Binding Actions in C++ |
| 65 | |
| 66 | ### SetupPlayerInputComponent |
| 67 | |
| 68 | ```cpp |
| 69 | // MyCharacter.h — declare assets and handlers |
| 70 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input") |
| 71 | TObjectPtr<UInputMappingContext> DefaultMappingContext; |
| 72 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input") |
| 73 | TObjectPtr<UInputAction> MoveAction; |
| 74 | UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Input") |
| 75 | TObjectPtr<UInputAction> JumpAction; |
| 76 | |
| 77 | void Move(const FInputActionValue& Value); |
| 78 | void StartJump(); |
| 79 | void StopJump(); |
| 80 | ``` |
| 81 | |
| 82 | ```cpp |
| 83 | // MyCharacter.cpp |
| 84 | #include "EnhancedInputComponent.h" |
| 85 | #include "EnhancedInputSubsystems.h" |
| 86 | |
| 87 | void AMyCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) |
| 88 | { |
| 89 | Super::SetupPlayerInputComponent(PlayerInputComponent); |
| 90 | UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(PlayerInputComponent); |
| 91 | if (!EIC) { return; } |
| 92 | |
| 93 | EIC->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AMyCharacter::Move); |
| 94 | EIC->BindAction(JumpAction, ETriggerEvent::Started, this, &AMyCharacter::StartJump); |
| 95 | EIC->BindAction(JumpAction, ETriggerEvent::Completed, this, &AMyCharacter::StopJump); |
| 96 | } |
| 97 | |
| 98 | void AMyCharacter::BeginPlay() |
| 99 | { |
| 100 | Super::BeginPlay(); |
| 101 | if (APlayerController* PC = Cast<APlayerController>(GetController())) |
| 102 | { |
| 103 | if (auto* Sub = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>( |
| 104 | PC->GetLocalPlayer())) |
| 105 | { |
| 106 | Sub->AddMappingContext(DefaultMappingContext, 0); // priority 0 = lowest |
| 107 | } |
| 108 | } |
| 109 | } |
| 110 | ``` |
| 111 | |
| 112 | ### Callback Signatures |
| 113 | |
| 114 | `BindAction` accepts four delegate signatures: |
| 115 | |
| 116 | ```cpp |
| 117 | // No params — press/release without value needed |
| 118 | void AMyCharacter::StartJump() { Jump(); } |
| 119 | |
| 120 | // FInputActionValue — for axis values |
| 121 | void AMyCharacter::Move(const FInputActionValue& Value) |
| 122 | { |
| 123 | const FVector2D Input = Value.Get<FVector2D>(); |
| 124 | AddMovementInput(GetActorForwardVector(), Input.Y); |