UE5.1 Enhanced Input System: How can simultaneous key presses be handled properly for character movement?

I'm using the Enhanced Input system for an Unreal Engine 5.1.1 first person shooter project.

The input mapping context Move input action

Unlike the recently depreciated old input system, holding down two opposite directional keys (e.g. keyboard [W] and [S]) will not cancel each other out, rather the last listed key set up in the Input Mapping Context will take priority and move the character in that direction - in this case the character moves backwards when [W] and [S] are held at the same time.

showdebug enhancedinput

Is there a way for multiple key presses for the same Input Action to be processed before it returns a value for use in code? Essentially, I want the FVector2D value to be (0, 0) when all four directional keys are pressed and should cancel each other out.

I tried adding values on top of each other for each call of the move callback, however this doesn't seems to work as the callback only seems to be called once for the last listed key as mentioned earlier.

What is especially strange is that the returned FVector2D contains axial values in both X ([W] & [S]) and Y ([A] & [D]) so multiple keys are clearly being processed, yet for the same axis it seems like the last listed key overwrites the value.

... // Called every frame void AShooterCharacter::Tick(float DeltaTime) { Super::Tick(DeltaTime); // Handle movement: // Prevent speed increase on diagonals CurrentMovementInput = CurrentMovementInput.GetSafeNormal(); // Forward movement (X) AddMovementInput(GetActorForwardVector() * CurrentMovementInput.X); // Strafing movement (Y) AddMovementInput(GetActorRightVector() * CurrentMovementInput.Y); // Reset current movement input ready for next frame CurrentMovementInput = FVector2d::ZeroVector; } // Called to bind functionality to input void AShooterCharacter::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) { Super::SetupPlayerInputComponent(PlayerInputComponent); // Set up input mapping context if (ULocalPlayer* LocalPlayer = Cast<ULocalPlayer>(GetLocalViewingPlayerController()->GetLocalPlayer())) { if (UEnhancedInputLocalPlayerSubsystem* InputSystem = LocalPlayer->GetSubsystem<UEnhancedInputLocalPlayerSubsystem>()) { if (!ShooterInputMappingContext.IsNull()) { InputSystem->AddMappingContext(ShooterInputMappingContext.LoadSynchronous(), 1); } } } // Action bindings UEnhancedInputComponent* Input = Cast<UEnhancedInputComponent>(PlayerInputComponent); Input->BindAction(MoveAction, ETriggerEvent::Triggered, this, &AShooterCharacter::MoveCallback); Input->BindAction(LookAction, ETriggerEvent::Triggered, this, &AShooterCharacter::LookCallback); } void AShooterCharacter::MoveCallback(const FInputActionInstance& Instance) { FVector2D AxisValues = Instance.GetValue().Get<FVector2D>(); // Add onto current movement input so that opposite inputs cancel each other? CurrentMovementInput += AxisValues; } ... 

2 Answers

I think something like this would work:

void AShooterCharacter::MoveCallback(const FInputActionValue& Value, const FName& ActionName) { float XInput = 0.0f; float YInput = 0.0f; // Check which keys are currently pressed for each axis if (Value.GetAxisValue("MoveForward") > 0.0f) { XInput += 1.0f; } if (Value.GetAxisValue("MoveForward") < 0.0f) { XInput -= 1.0f; } if (Value.GetAxisValue("MoveRight") > 0.0f) { YInput += 1.0f; } if (Value.GetAxisValue("MoveRight") < 0.0f) { YInput -= 1.0f; } // Combine the pressed keys for each axis to form the final movement input CurrentMovementInput = FVector2D(XInput, YInput); } 

You can look at this.

This is the C++ implementation in the post I wrote based on its ideas. Note: You need to add the modifier to both of them.

#pragma once #include "CoreMinimal.h" #include "InputModifiers.h" #include "InputModifierMutexKey.generated.h" /** * Mutex Key * If the mutex key is pressed, returns ZeroVector. */ UCLASS(meta = (DisplayName = "MutexKey")) class TEST_API UInputModifierMutexKey : public UInputModifier { GENERATED_BODY() public: UPROPERTY(EditInstanceOnly, BlueprintReadWrite, Category = Settings, meta = (DisplayName = "Key")) FKey Key = EKeys::Invalid; protected: virtual FInputActionValue ModifyRaw_Implementation(const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime) override; }; 
#include "InputModifierMutexKey.h" #include "EnhancedPlayerInput.h" FInputActionValue UInputModifierMutexKey::ModifyRaw_Implementation(const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime) { const APlayerController* PC = PlayerInput->GetOuterAPlayerController(); if (!PC) { return CurrentValue; } FVector Value = CurrentValue.Get<FVector>(); if (Key.IsValid() && PC->IsInputKeyDown(Key)) { Value = FVector::ZeroVector; } return FInputActionValue(CurrentValue.GetValueType(), Value); } 

Your Answer

Sign up or log in

Sign up using Google Sign up using Facebook Sign up using Email and Password

Post as a guest

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

You Might Also Like