WB_Hotkeys redesigned to use enhanced input. Amazing!

This commit is contained in:
2026-04-17 02:18:30 -04:00
parent 26399a6a15
commit ae1ad7640d
10 changed files with 169 additions and 11 deletions

View File

@@ -0,0 +1,84 @@
#include "LuprexUserWidget.h"
#include "EnhancedInputComponent.h"
#include "InputAction.h"
UlxUserWidget::UlxUserWidget(const FObjectInitializer& ObjectInitializer)
: Super(ObjectInitializer)
{
}
void UlxUserWidget::NativeOnInitialized()
{
Super::NativeOnInitialized();
BackupInputComponent();
}
void UlxUserWidget::BackupInputComponent()
{
SavedEnhancedActionEventBindings.Reset();
UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(InputComponent);
if (!EIC) return;
const TArray<EventBinding>& Live = EIC->GetActionEventBindings();
SavedEnhancedActionEventBindings.Reserve(Live.Num());
for (const EventBinding& Binding : Live)
{
SavedEnhancedActionEventBindings.Add(Binding->Clone());
}
}
void UlxUserWidget::DisableEventBinding(const UInputAction* InputAction)
{
UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(InputComponent);
if (!EIC) return;
TArray<EventBinding>& Bindings = GetMutableActionEventBindings(EIC);
Bindings.RemoveAll([InputAction](const EventBinding& B)
{
return B->GetAction() == InputAction;
});
}
void UlxUserWidget::RestoreInputBinding(const UInputAction* InputAction)
{
DisableEventBinding(InputAction);
UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(InputComponent);
if (!EIC) return;
TArray<EventBinding>& Live = GetMutableActionEventBindings(EIC);
for (const EventBinding& Saved : SavedEnhancedActionEventBindings)
{
if (Saved->GetAction() == InputAction)
{
Live.Add(Saved->Clone());
}
}
}
void UlxUserWidget::RedirectInputAction(const UInputAction* From, const UInputAction* To)
{
DisableEventBinding(From);
UEnhancedInputComponent* EIC = Cast<UEnhancedInputComponent>(InputComponent);
if (!EIC) return;
for (const EventBinding& Saved : SavedEnhancedActionEventBindings)
{
if (Saved->GetAction() == To)
{
TSharedPtr<FEnhancedInputActionEventBinding> Clone(Saved->Clone().Release());
EIC->BindActionInstanceLambda(From, Saved->GetTriggerEvent(),
[Clone](const FInputActionInstance& Data)
{
Clone->Execute(Data);
});
}
}
}
TArray<UlxUserWidget::EventBinding>& UlxUserWidget::GetMutableActionEventBindings(UEnhancedInputComponent* EIC)
{
return const_cast<TArray<EventBinding>&>(EIC->GetActionEventBindings());
}

View File

@@ -0,0 +1,50 @@
#pragma once
#include "CoreMinimal.h"
#include "Blueprint/UserWidget.h"
#include "EnhancedInputComponent.h"
#include "LuprexUserWidget.generated.h"
UCLASS(BlueprintType, Blueprintable)
class INTEGRATION_API UlxUserWidget : public UUserWidget
{
GENERATED_BODY()
public:
using EventBinding = TUniquePtr<FEnhancedInputActionEventBinding>;
UlxUserWidget(const FObjectInitializer& ObjectInitializer);
virtual void NativeOnInitialized() override;
// Clone every enhanced-input action binding currently on InputComponent
// into SavedEnhancedActionEventBindings, so bindings can later be removed
// from the component and reinstated without losing their delegates.
void BackupInputComponent();
// Remove every live event binding whose action is InputAction.
// No-op if there are none, or if InputComponent isn't enhanced.
UFUNCTION(BlueprintCallable, Category="Luprex|Widget Enhanced Input")
void DisableEventBinding(const UInputAction* InputAction);
// Replace any live bindings for InputAction with fresh clones of every
// saved binding for that action. Leaves the backup array intact so this
// can be called repeatedly.
UFUNCTION(BlueprintCallable, Category="Luprex|Widget Enhanced Input")
void RestoreInputBinding(const UInputAction* InputAction);
// Install live bindings on From that, when fired, dispatch through a
// clone of each saved binding for To. Clears any pre-existing live
// bindings on From first. Backup array is untouched.
UFUNCTION(BlueprintCallable, Category="Luprex|Widget Enhanced Input")
void RedirectInputAction(const UInputAction* From, const UInputAction* To);
// Cloned bindings captured from InputComponent after construction.
TArray<EventBinding> SavedEnhancedActionEventBindings;
private:
// Strip the synthetic const off UEnhancedInputComponent::GetActionEventBindings
// to get direct mutable access to the protected array. Well-defined because
// the underlying object is not const; only the getter's return type is.
static TArray<EventBinding>& GetMutableActionEventBindings(UEnhancedInputComponent* EIC);
};

View File

@@ -243,6 +243,20 @@ FKey UlxUtilityLibrary::GetKeyByNameString(const FString &Name)
return Key.IsValid() ? Key : FKey();
}
UInputAction *UlxUtilityLibrary::FindInputActionByName(const UInputMappingContext *MappingContext, const FString &Name)
{
if (!MappingContext) return nullptr;
FName Target(*Name);
for (const FEnhancedActionKeyMapping &Mapping : MappingContext->GetMappings())
{
if (Mapping.Action && Mapping.Action->GetFName() == Target)
{
return const_cast<UInputAction *>(Mapping.Action.Get());
}
}
return nullptr;
}
FVector UlxUtilityLibrary::GetActorForwardVelocity(const AActor *Actor, double Speed, bool bSnapToXY)
{
if (!Actor) return FVector::ZeroVector;

View File

@@ -159,6 +159,13 @@ public:
UFUNCTION(BlueprintPure, Category = "Input|Key")
static FKey GetKeyByNameString(const FString &Name);
// Find an InputAction within an InputMappingContext, matched by asset
// name (e.g. "IA_Jump"). Returns nullptr if the mapping context is
// null or no action with the given name is mapped.
//
UFUNCTION(BlueprintPure, Category = "Input")
static UInputAction *FindInputActionByName(const UInputMappingContext *MappingContext, const FString &Name);
// Get the actor's forward vector multiplied by a speed.
// If SnapToXY is true, the forward vector is projected
// onto the XY plane and renormalized before scaling.