From ae1ad7640dd1edf63884823e9db88d75ce604869 Mon Sep 17 00:00:00 2001 From: jyelon Date: Fri, 17 Apr 2026 02:18:30 -0400 Subject: [PATCH] WB_Hotkeys redesigned to use enhanced input. Amazing! --- .../Luprex/InputActions/IA_AnyHotkey.uasset | 3 + Content/Luprex/InputActions/IA_DPadD.uasset | 4 +- Content/Testing/BP_Test.uasset | 4 +- Content/Testing/WB_Test.uasset | 4 +- Content/Widgets/WB_Hotkeys.uasset | 4 +- Source/Integration/LuprexUserWidget.cpp | 84 +++++++++++++++++++ Source/Integration/LuprexUserWidget.h | 50 +++++++++++ Source/Integration/UtilityLibrary.cpp | 14 ++++ Source/Integration/UtilityLibrary.h | 7 ++ luprex/lua/login.lua | 6 +- 10 files changed, 169 insertions(+), 11 deletions(-) create mode 100644 Content/Luprex/InputActions/IA_AnyHotkey.uasset create mode 100644 Source/Integration/LuprexUserWidget.cpp create mode 100644 Source/Integration/LuprexUserWidget.h diff --git a/Content/Luprex/InputActions/IA_AnyHotkey.uasset b/Content/Luprex/InputActions/IA_AnyHotkey.uasset new file mode 100644 index 00000000..bd96ba0a --- /dev/null +++ b/Content/Luprex/InputActions/IA_AnyHotkey.uasset @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:32c86a150e73caba4f1f4732dc0c50ea78e00a587805327cbce994de7d9cebf4 +size 1369 diff --git a/Content/Luprex/InputActions/IA_DPadD.uasset b/Content/Luprex/InputActions/IA_DPadD.uasset index de05c2a5..776f2ffd 100644 --- a/Content/Luprex/InputActions/IA_DPadD.uasset +++ b/Content/Luprex/InputActions/IA_DPadD.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d56ee34a39d0cfc7f3ff8dc6e0e4fa635aba7d7cf006ad49246822291b53c863 -size 1690 +oid sha256:47f852a28e261e09f3bc087bf44edcb7193674ce62bdc5b294712db1609e6347 +size 1349 diff --git a/Content/Testing/BP_Test.uasset b/Content/Testing/BP_Test.uasset index bb5ce1a5..9356c230 100644 --- a/Content/Testing/BP_Test.uasset +++ b/Content/Testing/BP_Test.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:bbcf31978d230e3f317ba105da139139ff3dfe8511a4a083da1d59d0976cc576 -size 56301 +oid sha256:744dec37bf46eb8ac6169f05663feb3b3abb63137c429061db4334f39739a454 +size 54771 diff --git a/Content/Testing/WB_Test.uasset b/Content/Testing/WB_Test.uasset index 1f441356..5728eaca 100644 --- a/Content/Testing/WB_Test.uasset +++ b/Content/Testing/WB_Test.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:919bde37fb2ca9fd98676cc66bd873e94f53b5e1b769253d86d167c3df5b800b -size 34126 +oid sha256:576b1ac0e9360ece80e99a0d2cd9abf7356e4a62a0b42ab95b47ac6050b30e2b +size 44257 diff --git a/Content/Widgets/WB_Hotkeys.uasset b/Content/Widgets/WB_Hotkeys.uasset index 0b0eefad..ae7c4d69 100644 --- a/Content/Widgets/WB_Hotkeys.uasset +++ b/Content/Widgets/WB_Hotkeys.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:afa2f3a5d654905c17c717355e398385856360c5bf75a7904ecd7c54a49db18d -size 311655 +oid sha256:f2b7edf85b8eba116f43ebdc9dcf301f61ea61eb26e24f0d0c9c53ed35fb4619 +size 286136 diff --git a/Source/Integration/LuprexUserWidget.cpp b/Source/Integration/LuprexUserWidget.cpp new file mode 100644 index 00000000..66a2a164 --- /dev/null +++ b/Source/Integration/LuprexUserWidget.cpp @@ -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(InputComponent); + if (!EIC) return; + + const TArray& 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(InputComponent); + if (!EIC) return; + + TArray& Bindings = GetMutableActionEventBindings(EIC); + Bindings.RemoveAll([InputAction](const EventBinding& B) + { + return B->GetAction() == InputAction; + }); +} + +void UlxUserWidget::RestoreInputBinding(const UInputAction* InputAction) +{ + DisableEventBinding(InputAction); + + UEnhancedInputComponent* EIC = Cast(InputComponent); + if (!EIC) return; + + TArray& 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(InputComponent); + if (!EIC) return; + + for (const EventBinding& Saved : SavedEnhancedActionEventBindings) + { + if (Saved->GetAction() == To) + { + TSharedPtr Clone(Saved->Clone().Release()); + EIC->BindActionInstanceLambda(From, Saved->GetTriggerEvent(), + [Clone](const FInputActionInstance& Data) + { + Clone->Execute(Data); + }); + } + } +} + +TArray& UlxUserWidget::GetMutableActionEventBindings(UEnhancedInputComponent* EIC) +{ + return const_cast&>(EIC->GetActionEventBindings()); +} diff --git a/Source/Integration/LuprexUserWidget.h b/Source/Integration/LuprexUserWidget.h new file mode 100644 index 00000000..ce3fd355 --- /dev/null +++ b/Source/Integration/LuprexUserWidget.h @@ -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; + + 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 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& GetMutableActionEventBindings(UEnhancedInputComponent* EIC); +}; diff --git a/Source/Integration/UtilityLibrary.cpp b/Source/Integration/UtilityLibrary.cpp index f9fcf8a2..14d8cb00 100644 --- a/Source/Integration/UtilityLibrary.cpp +++ b/Source/Integration/UtilityLibrary.cpp @@ -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(Mapping.Action.Get()); + } + } + return nullptr; +} + FVector UlxUtilityLibrary::GetActorForwardVelocity(const AActor *Actor, double Speed, bool bSnapToXY) { if (!Actor) return FVector::ZeroVector; diff --git a/Source/Integration/UtilityLibrary.h b/Source/Integration/UtilityLibrary.h index c06819de..dfa0eb93 100644 --- a/Source/Integration/UtilityLibrary.h +++ b/Source/Integration/UtilityLibrary.h @@ -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. diff --git a/luprex/lua/login.lua b/luprex/lua/login.lua index 47aa36ce..f74f21e1 100644 --- a/luprex/lua/login.lua +++ b/luprex/lua/login.lua @@ -40,9 +40,9 @@ function cube.lookmenu(add) end function sphere.lookhotkeys(add) - add("Z", "Sphere Hi", function () dprint("Doing Sphere Hi") end) - add("X", "Sphere Bye", function () dprint("Doing Sphere Bye") end) - add("C", "Sphere Yo", function () dprint("Doing Sphere Yo") end) + add("DPadU", "Sphere Hi", function () dprint("Doing Sphere Hi") end) + add("DPadL", "Sphere Bye", function () dprint("Doing Sphere Bye") end) + add("DPadR", "Sphere Yo", function () dprint("Doing Sphere Yo") end) end