From 3e7e6a2ae48182bfb84ad2aa630588251aecd7f0 Mon Sep 17 00:00:00 2001 From: jyelon Date: Mon, 4 May 2026 15:27:28 -0400 Subject: [PATCH] More progress on prompt --- Content/Widgets/WB_Hotkey_Image.uasset | 4 +- Content/Widgets/WB_Hotkeys.uasset | 4 +- Content/Widgets/XUserWidget.uasset | 3 - Source/Integration/Common.h | 6 +- Source/Integration/PlayerControllerBase.cpp | 31 -------- Source/Integration/PlayerControllerBase.h | 11 --- Source/Integration/PromptWidget.cpp | 78 +++++++++++++++++---- Source/Integration/PromptWidget.h | 30 +++++--- Source/Integration/UtilityLibrary.cpp | 22 ++++++ Source/Integration/UtilityLibrary.h | 5 ++ 10 files changed, 121 insertions(+), 73 deletions(-) delete mode 100644 Content/Widgets/XUserWidget.uasset diff --git a/Content/Widgets/WB_Hotkey_Image.uasset b/Content/Widgets/WB_Hotkey_Image.uasset index 8f666b7b..1a66f36a 100644 --- a/Content/Widgets/WB_Hotkey_Image.uasset +++ b/Content/Widgets/WB_Hotkey_Image.uasset @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9eb7d9a6a4c4ce3800e850970235feff856cf6b6b7c57c4cd52f8150b79a37df -size 93798 +oid sha256:a00d2efc8527f8098b87ce787da061302f1881018b6b9b5f549648d96b74f22d +size 49505 diff --git a/Content/Widgets/WB_Hotkeys.uasset b/Content/Widgets/WB_Hotkeys.uasset index ffe11e0a..fc3ecc3d 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:3e43bb530169a8f2b69b9d5ccb2bb49d5e3934753f31913963e49737d7f952e7 -size 291795 +oid sha256:44c375d755465c9ca6a741bcdcfb88db842c4525c4c5e38442c4eed208e7fa4c +size 292603 diff --git a/Content/Widgets/XUserWidget.uasset b/Content/Widgets/XUserWidget.uasset deleted file mode 100644 index 9a2f4879..00000000 --- a/Content/Widgets/XUserWidget.uasset +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:fbaec08329c774ce3440bf05b965a06d9353be5eea6f703dec05a61350b01b1f -size 24857 diff --git a/Source/Integration/Common.h b/Source/Integration/Common.h index 214ce8c1..d3d3e2f5 100644 --- a/Source/Integration/Common.h +++ b/Source/Integration/Common.h @@ -127,14 +127,14 @@ enum class ElxLuaSyntaxCheck : uint8 { //////////////////////////////////////////////////////////// // -// ElxInputMode +// ElxControllerType // -// The three input modes recognized by the game. +// The three types of controller recognized by luprex. // //////////////////////////////////////////////////////////// UENUM(BlueprintType) -enum class ElxInputMode : uint8 { +enum class ElxControllerType : uint8 { KeyboardMouse, XboxGamepad, PlayStationGamepad, diff --git a/Source/Integration/PlayerControllerBase.cpp b/Source/Integration/PlayerControllerBase.cpp index 3d0f3214..a2271439 100644 --- a/Source/Integration/PlayerControllerBase.cpp +++ b/Source/Integration/PlayerControllerBase.cpp @@ -248,25 +248,6 @@ void AlxPlayerControllerBase::BuildInputStack(TArray& InputSta } } -static ElxInputMode DetectInputMode(const ULocalPlayer *LocalPlayer) -{ - UInputDeviceSubsystem *IDS = GEngine->GetEngineSubsystem(); - if (!IDS) return ElxInputMode::KeyboardMouse; - - FHardwareDeviceIdentifier Device = IDS->GetMostRecentlyUsedHardwareDevice(LocalPlayer->GetPlatformUserId()); - if (Device.PrimaryDeviceType != EHardwareDevicePrimaryType::Gamepad) - { - return ElxInputMode::KeyboardMouse; - } - - FString DeviceName = Device.HardwareDeviceIdentifier.ToString(); - if (DeviceName.Contains(TEXT("PS4")) || DeviceName.Contains(TEXT("PS5")) || DeviceName.Contains(TEXT("PlayStation"))) - { - return ElxInputMode::PlayStationGamepad; - } - return ElxInputMode::XboxGamepad; -} - void AlxPlayerControllerBase::UpdateInputMode() { // Get all the various objects we need to be able to manipulate @@ -323,13 +304,6 @@ void AlxPlayerControllerBase::UpdateInputMode() GameViewportClient->SetIgnoreInput(false); - ElxInputMode NewInputMode = DetectInputMode(LocalPlayer); - if (NewInputMode != CurrentInputMode) - { - CurrentInputMode = NewInputMode; - OnInputModeChanged.Broadcast(CurrentInputMode); - } - // We always put keyboard focus on whatever user widget is in // front. If the front widget doesn't want keyboard focus, // then we put keyboard focus on the viewport. @@ -346,11 +320,6 @@ void AlxPlayerControllerBase::UpdateInputMode() } } -ElxInputMode AlxPlayerControllerBase::GetInputMode(const UObject *Context) -{ - return FromContext(Context)->CurrentInputMode; -} - void AlxPlayerControllerBase::UpdateLookAt() { UlxTangibleManager *TM = GetGameInstance()->GetSubsystem(); diff --git a/Source/Integration/PlayerControllerBase.h b/Source/Integration/PlayerControllerBase.h index 0b91b745..7cabde8b 100644 --- a/Source/Integration/PlayerControllerBase.h +++ b/Source/Integration/PlayerControllerBase.h @@ -7,8 +7,6 @@ #include "UObject/ObjectKey.h" #include "PlayerControllerBase.generated.h" -DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FlxInputModeChanged, ElxInputMode, NewMode); - class UlxRootCanvasPanel; class UWidget; @@ -43,12 +41,6 @@ public: // Called by GameMode each tick. void UpdateLookAt(); - UFUNCTION(BlueprintPure, meta = (WorldContext = "Context"), Category = "Luprex|Input Mode") - static ElxInputMode GetInputMode(const UObject *Context); - - UPROPERTY(BlueprintAssignable, Category = "Luprex|Input Mode") - FlxInputModeChanged OnInputModeChanged; - // Called by GameMode each tick. GCs dead requests and will // eventually reconcile focus, pointer, and capture state. void UpdateInputMode(); @@ -97,7 +89,4 @@ public: UlxRootCanvasPanel *RootCanvas = nullptr; bool MustCallLookAtChanged = false; - - UPROPERTY() - ElxInputMode CurrentInputMode = ElxInputMode::KeyboardMouse; }; diff --git a/Source/Integration/PromptWidget.cpp b/Source/Integration/PromptWidget.cpp index f5d04800..2bf6c98a 100644 --- a/Source/Integration/PromptWidget.cpp +++ b/Source/Integration/PromptWidget.cpp @@ -1,5 +1,10 @@ #include "PromptWidget.h" +#include "UtilityLibrary.h" #include "PlayerControllerBase.h" +#include "Engine/Engine.h" +#include "GameFramework/InputDeviceSubsystem.h" +#include "InputAction.h" +#include "InputMappingContext.h" #include "Widgets/SOverlay.h" #include "Widgets/Images/SImage.h" #include "Widgets/Text/STextBlock.h" @@ -57,25 +62,30 @@ int32 UlxPromptWidget::ChooseIcon(bool Playstation, FKey Key) const void UlxPromptWidget::ChooseAppearance(int32 &OutIcon, FString &OutGlyph) { - UWorld* World = GetWorld(); - APlayerController* PC = World ? World->GetFirstPlayerController() : nullptr; - AlxPlayerControllerBase* LPC = Cast(PC); - - ElxInputMode Mode = LPC ? LPC->CurrentInputMode : ElxInputMode::KeyboardMouse; - - FKey Key = (Mode == ElxInputMode::KeyboardMouse) ? KeyboardKey : GamepadKey; - - OutIcon = ChooseIcon(Mode == ElxInputMode::PlayStationGamepad, Key); + FKey Key = (ControllerType == ElxControllerType::KeyboardMouse) ? KeyboardKey : GamepadKey; + OutIcon = ChooseIcon(ControllerType == ElxControllerType::PlayStationGamepad, Key); if (OutIcon == 0) OutGlyph = Key.GetDisplayName().ToString(); else OutGlyph = TEXT(""); } +void UlxPromptWidget::OnHardwareDeviceChanged(const FPlatformUserId UserId, const FInputDeviceId DeviceId) +{ + ElxControllerType Type = UlxUtilityLibrary::DetectControllerType(GetOwningLocalPlayer()); + if (ControllerType != Type) + { + ControllerType = Type; + SynchronizeProperties(); + } +} + FBox2f UlxPromptWidget::GetIconUVs(int32 IconIndex) { const float ColWidth = 1.0f / 4.0f; const float RowHeight = 1.0f / 8.0f; - float U = (IconIndex % 4) * ColWidth; - float V = (IconIndex / 4) * RowHeight; + int32 Col = IconIndex % 4; + int32 Row = IconIndex / 4; + float U = Col * ColWidth; + float V = Row * RowHeight; return FBox2f(FVector2f(U, V), FVector2f(U + ColWidth, V + RowHeight)); } @@ -151,13 +161,50 @@ void UlxPromptWidget::SetKeys(FKey InGamepadKey, FKey InKeyboardKey) } } +void UlxPromptWidget::SetKeysFromBindings(const UInputMappingContext* InputMappingContext, const UInputAction* EnhancedInputAction) +{ + check(InputMappingContext); + check(EnhancedInputAction); + + FKey NewFirstKey; + FKey NewGamepadKey; + FKey NewKeyboardKey; + + for (const FEnhancedActionKeyMapping& Mapping : InputMappingContext->GetMappings()) + { + if (Mapping.Action != EnhancedInputAction) continue; + FKey Key = Mapping.Key; + if (Key.IsDigital()) + { + if (!NewFirstKey.IsValid()) NewFirstKey = Mapping.Key; + if (Key.IsTouch()) { /* not supported */ } + else if (Key.IsGesture()) { /* not supported */ } + else if (Key.IsGamepadKey()) { if (!NewGamepadKey.IsValid()) NewGamepadKey = Key; } + else { if (!NewKeyboardKey.IsValid()) NewKeyboardKey = Key; } + } + } + + if (!NewGamepadKey.IsValid()) NewGamepadKey = NewFirstKey; + if (!NewKeyboardKey.IsValid()) NewKeyboardKey = NewFirstKey; + SetKeys(NewGamepadKey, NewKeyboardKey); +} + TSharedRef UlxPromptWidget::RebuildWidget() { + if (!IsDesignTime()) + { + ControllerType = UlxUtilityLibrary::DetectControllerType(GetOwningLocalPlayer()); + if (UInputDeviceSubsystem* IDS = GEngine->GetEngineSubsystem()) + { + IDS->OnInputHardwareDeviceChanged.AddDynamic(this, &UlxPromptWidget::OnHardwareDeviceChanged); + } + } + int32 Icon = 0; FString Glyph; ChooseAppearance(Icon, Glyph); - MyBrush.SetResourceObject(ButtonAtlas); + MyBrush.SetResourceObject(ButtonAtlas.Get()); MyBrush.ImageSize = Size; MyBrush.SetUVRegion(GetIconUVs(Icon)); @@ -184,6 +231,13 @@ TSharedRef UlxPromptWidget::RebuildWidget() void UlxPromptWidget::ReleaseSlateResources(bool bReleaseChildren) { Super::ReleaseSlateResources(bReleaseChildren); + if (!IsDesignTime()) + { + if (UInputDeviceSubsystem* IDS = GEngine->GetEngineSubsystem()) + { + IDS->OnInputHardwareDeviceChanged.RemoveDynamic(this, &UlxPromptWidget::OnHardwareDeviceChanged); + } + } MyOverlay.Reset(); MyImage.Reset(); MyScaleBox.Reset(); diff --git a/Source/Integration/PromptWidget.h b/Source/Integration/PromptWidget.h index 34b5933d..0887f115 100644 --- a/Source/Integration/PromptWidget.h +++ b/Source/Integration/PromptWidget.h @@ -4,9 +4,13 @@ #include "Common.h" #include "Components/Widget.h" #include "InputCoreTypes.h" +#include "Widgets/SOverlay.h" #include "Widgets/Layout/SScaleBox.h" #include "PromptWidget.generated.h" +class UInputAction; +class UInputMappingContext; + UCLASS(BlueprintType, Blueprintable) class INTEGRATION_API UlxPromptWidget : public UWidget @@ -17,8 +21,14 @@ public: UPROPERTY(EditAnywhere, Category="Prompt") TObjectPtr ButtonAtlas; - UFUNCTION(BlueprintCallable, Category="Prompt") - void SetKeys(FKey InGamepadKey, FKey InKeyboardKey); + UPROPERTY(EditAnywhere, Category="Prompt") + ElxControllerType ControllerType = ElxControllerType::KeyboardMouse; + + UPROPERTY(EditAnywhere, Category="Prompt") + FKey GamepadKey = EKeys::Gamepad_FaceButton_Left; + + UPROPERTY(EditAnywhere, Category="Prompt") + FKey KeyboardKey = EKeys::Z; UPROPERTY(EditAnywhere, Setter, Category="Prompt") FVector2D Size = FVector2D(64, 64); @@ -29,6 +39,12 @@ public: UPROPERTY(EditAnywhere, Setter, Category="Prompt") FLinearColor GlyphColor = FLinearColor::White; +public: + UFUNCTION(BlueprintCallable, Category="Prompt") + void SetKeys(FKey InGamepadKey, FKey InKeyboardKey); + + UFUNCTION(BlueprintCallable, Category="Prompt") + void SetKeysFromBindings(const UInputMappingContext* InputMappingContext, const UInputAction* EnhancedInputAction); UFUNCTION(BlueprintCallable, Category="Prompt") void SetGlyphMargins(FMargin InMargins); @@ -36,21 +52,17 @@ public: UFUNCTION(BlueprintCallable, Category="Prompt") void SetGlyphColor(FLinearColor InColor); - UFUNCTION(BlueprintCallable, Category="Prompt") void SetSize(FVector2D InSize); + UFUNCTION() + void OnHardwareDeviceChanged(const FPlatformUserId UserId, const FInputDeviceId DeviceId); + protected: virtual TSharedRef RebuildWidget() override; virtual void SynchronizeProperties() override; virtual void ReleaseSlateResources(bool bReleaseChildren) override; - UPROPERTY(EditAnywhere, Category="Prompt") - FKey GamepadKey = EKeys::Gamepad_FaceButton_Left; - - UPROPERTY(EditAnywhere, Category="Prompt") - FKey KeyboardKey = EKeys::Z; - private: FSlateBrush MyBrush; TSharedPtr MyOverlay; diff --git a/Source/Integration/UtilityLibrary.cpp b/Source/Integration/UtilityLibrary.cpp index 14d8cb00..387fef74 100644 --- a/Source/Integration/UtilityLibrary.cpp +++ b/Source/Integration/UtilityLibrary.cpp @@ -14,6 +14,8 @@ #include "EnhancedInputComponent.h" #include "Animation/AnimSequenceBase.h" #include "GameFramework/Pawn.h" +#include "GameFramework/InputDeviceSubsystem.h" +#include "GameFramework/InputSettings.h" #define LOCTEXT_NAMESPACE "Luprex Utility" @@ -275,3 +277,23 @@ void UlxUtilityLibrary::ValidateLuaExpr( FlxLockedWrapper w; Status = w.ValidateLuaExpr(Code, ErrorMessage); } + +ElxControllerType UlxUtilityLibrary::DetectControllerType(ULocalPlayer *Player) +{ + UInputDeviceSubsystem *IDS = GEngine->GetEngineSubsystem(); + if (!IDS) return ElxControllerType::KeyboardMouse; + + FHardwareDeviceIdentifier Device = IDS->GetMostRecentlyUsedHardwareDevice(Player->GetPlatformUserId()); + if (Device.PrimaryDeviceType != EHardwareDevicePrimaryType::Gamepad) + { + return ElxControllerType::KeyboardMouse; + } + + FString DeviceName = Device.HardwareDeviceIdentifier.ToString(); + if (DeviceName.Contains(TEXT("PS4")) || DeviceName.Contains(TEXT("PS5")) || DeviceName.Contains(TEXT("PlayStation"))) + { + return ElxControllerType::PlayStationGamepad; + } + return ElxControllerType::XboxGamepad; +} + diff --git a/Source/Integration/UtilityLibrary.h b/Source/Integration/UtilityLibrary.h index dfa0eb93..b995b4f9 100644 --- a/Source/Integration/UtilityLibrary.h +++ b/Source/Integration/UtilityLibrary.h @@ -179,4 +179,9 @@ public: // UFUNCTION(BlueprintCallable, meta = (WorldContext = "context"), Category = "Luprex|Utility") static void ValidateLuaExpr(ElxLuaSyntaxCheck &Status, FString &ErrorMessage, UObject *context, const FString &Code); + + // Determine what type of controller the game is currently using + // + UFUNCTION(BlueprintCallable, category="Luprex|Utility") + static ElxControllerType DetectControllerType(ULocalPlayer *Player); };