// Copyright Epic Games, Inc. All Rights Reserved. #include "UI/LyraSimulatedInputWidget.h" #include "EnhancedInputSubsystems.h" #include "LyraLogChannels.h" #include UE_INLINE_GENERATED_CPP_BY_NAME(LyraSimulatedInputWidget) #define LOCTEXT_NAMESPACE "LyraSimulatedInputWidget" ULyraSimulatedInputWidget::ULyraSimulatedInputWidget(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { SetConsumePointerInput(true); } #if WITH_EDITOR const FText ULyraSimulatedInputWidget::GetPaletteCategory() { return LOCTEXT("PalleteCategory", "Input"); } #endif // WITH_EDITOR void ULyraSimulatedInputWidget::NativeConstruct() { // Find initial key, then listen for any changes to control mappings QueryKeyToSimulate(); if (UEnhancedInputLocalPlayerSubsystem* System = GetEnhancedInputSubsystem()) { System->ControlMappingsRebuiltDelegate.AddUniqueDynamic(this, &ULyraSimulatedInputWidget::OnControlMappingsRebuilt); } Super::NativeConstruct(); } void ULyraSimulatedInputWidget::NativeDestruct() { if (UEnhancedInputLocalPlayerSubsystem* System = GetEnhancedInputSubsystem()) { System->ControlMappingsRebuiltDelegate.RemoveAll(this); } Super::NativeDestruct(); } FReply ULyraSimulatedInputWidget::NativeOnTouchEnded(const FGeometry& InGeometry, const FPointerEvent& InGestureEvent) { FlushSimulatedInput(); return Super::NativeOnTouchEnded(InGeometry, InGestureEvent); } UEnhancedInputLocalPlayerSubsystem* ULyraSimulatedInputWidget::GetEnhancedInputSubsystem() const { if (APlayerController* PC = GetOwningPlayer()) { if (ULocalPlayer* LP = GetOwningLocalPlayer()) { return LP->GetSubsystem(); } } return nullptr; } UEnhancedPlayerInput* ULyraSimulatedInputWidget::GetPlayerInput() const { if (UEnhancedInputLocalPlayerSubsystem* System = GetEnhancedInputSubsystem()) { return System->GetPlayerInput(); } return nullptr; } void ULyraSimulatedInputWidget::InputKeyValue(const FVector& Value) { // If we have an associated input action then we can use it if (AssociatedAction) { if (UEnhancedInputLocalPlayerSubsystem* System = GetEnhancedInputSubsystem()) { // We don't want to apply any modifiers or triggers to this action, but they are required for the function signature TArray Modifiers; TArray Triggers; System->InjectInputVectorForAction(AssociatedAction, Value, Modifiers, Triggers); } } // In case there is no associated input action, we can attempt to simulate input on the fallback key else if (UEnhancedPlayerInput* Input = GetPlayerInput()) { if(KeyToSimulate.IsValid()) { FInputKeyParams Params; Params.Delta = Value; Params.Key = KeyToSimulate; Params.NumSamples = 1; Params.DeltaTime = GetWorld()->GetDeltaSeconds(); Params.bIsGamepadOverride = KeyToSimulate.IsGamepadKey(); Input->InputKey(Params); } } else { UE_LOG(LogLyra, Error, TEXT("'%s' is attempting to simulate input but has no player input!"), *GetNameSafe(this)); } } void ULyraSimulatedInputWidget::InputKeyValue2D(const FVector2D& Value) { InputKeyValue(FVector(Value.X, Value.Y, 0.0)); } void ULyraSimulatedInputWidget::FlushSimulatedInput() { if (UEnhancedPlayerInput* Input = GetPlayerInput()) { Input->FlushPressedKeys(); } } void ULyraSimulatedInputWidget::QueryKeyToSimulate() { if (UEnhancedInputLocalPlayerSubsystem* System = GetEnhancedInputSubsystem()) { TArray Keys = System->QueryKeysMappedToAction(AssociatedAction); if(!Keys.IsEmpty() && Keys[0].IsValid()) { KeyToSimulate = Keys[0]; } else { KeyToSimulate = FallbackBindingKey; } } } void ULyraSimulatedInputWidget::OnControlMappingsRebuilt() { QueryKeyToSimulate(); } #undef LOCTEXT_NAMESPACE