From 0aea6933dc74a727c3507e769b25400204c65ef8 Mon Sep 17 00:00:00 2001 From: Steve Streeting Date: Tue, 7 Mar 2023 16:34:39 +0000 Subject: [PATCH] Workaround for the problem that EnhancedInput does not tell you when contexts / mappings change --- .../Private/StevesGameSubsystem.cpp | 12 ++++++++++ .../Private/StevesUI/InputImage.cpp | 24 +++++++++++++++++-- .../Public/StevesGameSubsystem.h | 15 ++++++++++++ .../Public/StevesUI/InputImage.h | 4 ++++ 4 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp b/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp index 1aabaab..1ed1ba4 100644 --- a/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp +++ b/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp @@ -22,6 +22,7 @@ void UStevesGameSubsystem::Initialize(FSubsystemCollectionBase& Collection) CreateInputDetector(); InitTheme(); InitForegroundCheck(); + NotifyEnhancedInputMappingsChanged(); #endif } @@ -60,6 +61,17 @@ void UStevesGameSubsystem::DestroyInputDetector() #endif } +void UStevesGameSubsystem::NotifyEnhancedInputMappingsChanged() +{ + // delay to ensure there's a tick in between which updates the mappings, it's not synchronous + auto DelayedFunc = [this]() + { + OnEnhancedInputMappingsChanged.Broadcast(); + }; + FTimerHandle TempHandle; + GetWorld()->GetTimerManager().SetTimer(TempHandle, FTimerDelegate::CreateLambda(DelayedFunc), 0.05, false); +} + void UStevesGameSubsystem::InitTheme() { DefaultUiTheme = LoadObject(nullptr, *DefaultUiThemePath, nullptr); diff --git a/Source/StevesUEHelpers/Private/StevesUI/InputImage.cpp b/Source/StevesUEHelpers/Private/StevesUI/InputImage.cpp index 208ce7a..5ddeff0 100644 --- a/Source/StevesUEHelpers/Private/StevesUI/InputImage.cpp +++ b/Source/StevesUEHelpers/Private/StevesUI/InputImage.cpp @@ -12,12 +12,13 @@ TSharedRef UInputImage::RebuildWidget() auto GS = GetStevesGameSubsystem(GetWorld()); if (GS && !bSubbedToInputEvents) { + bSubbedToInputEvents = true; GS->OnInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged); GS->OnButtonInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged); GS->OnAxisInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged); + GS->OnEnhancedInputMappingsChanged.AddUniqueDynamic(this, &UInputImage::OnEnhancedInputMappingsChanged); } - bSubbedToInputEvents = true; UpdateImage(); return Ret; @@ -36,6 +37,11 @@ void UInputImage::OnInputModeChanged(int ChangedPlayerIdx, EInputMode InputMode) } } +void UInputImage::OnEnhancedInputMappingsChanged() +{ + MarkImageDirty(); +} + void UInputImage::SetCustomTheme(UUiTheme* Theme) { CustomTheme = Theme; @@ -120,10 +126,24 @@ void UInputImage::UpdateImage() if (Sprite) { + if (bHiddenBecauseBlank) + { + SetVisibility(OldVisibility); + bHiddenBecauseBlank = false; + } // Match size is needed incase size has changed // Need to make it update region in case inside a scale box or something else that needs to adjust SetBrushFromAtlasInterface(Sprite, true); } + else + { + if (IsVisible()) + { + bHiddenBecauseBlank = true; + OldVisibility = GetVisibility(); + SetVisibility(ESlateVisibility::Hidden); + } + } } bIsDirty = false; DelayUpdate = 0; @@ -132,7 +152,7 @@ void UInputImage::UpdateImage() void UInputImage::MarkImageDirty() { bIsDirty = true; - DelayUpdate = 0.5f; + DelayUpdate = 0.1f; } // Tickables diff --git a/Source/StevesUEHelpers/Public/StevesGameSubsystem.h b/Source/StevesUEHelpers/Public/StevesGameSubsystem.h index 2536377..3d44bb0 100644 --- a/Source/StevesUEHelpers/Public/StevesGameSubsystem.h +++ b/Source/StevesUEHelpers/Public/StevesGameSubsystem.h @@ -14,6 +14,7 @@ #include "StevesGameSubsystem.generated.h" DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInputModeChanged, int, PlayerIndex, EInputMode, InputMode); +DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnEnhancedInputMappingsChanged); DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWindowForegroundChanged, bool, bFocussed); /// Entry point for all the top-level features of the helper system @@ -160,6 +161,12 @@ public: /// last axis moved was still mouse, you'd get this event later UPROPERTY(BlueprintAssignable) FOnInputModeChanged OnAxisInputModeChanged; + + /// Event raised justr after the Enhanced Input mappings have changed + /// Right now, this has to be user-triggered via NotifyEnhancedInputMappingsChanged, because the Enhanced Input + /// plugin provides NO events to monitor it (sigh) + UPROPERTY(BlueprintAssignable) + FOnEnhancedInputMappingsChanged OnEnhancedInputMappingsChanged; /// Event raised when the game window's foreground status changes UPROPERTY(BlueprintAssignable) @@ -277,4 +284,12 @@ public: */ FStevesTextureRenderTargetPoolPtr GetTextureRenderTargetPool(FName Name, bool bAutoCreate = true); + /** + * Notify this subsystem that changes have been made to the Enhanced Input mappings, e.g. adding or removing a context. + * Unfortunately, the Enhanced Input plugin currently provides NO WAY for us to monitor context changes automatically, + * so we need the user to tell us when they make a change. + * This call is however slightly delayed before being acted upon, because EI defers the rebuild of mappings until the next tick. + */ + void NotifyEnhancedInputMappingsChanged(); + }; diff --git a/Source/StevesUEHelpers/Public/StevesUI/InputImage.h b/Source/StevesUEHelpers/Public/StevesUI/InputImage.h index c460ded..7fe960c 100644 --- a/Source/StevesUEHelpers/Public/StevesUI/InputImage.h +++ b/Source/StevesUEHelpers/Public/StevesUI/InputImage.h @@ -46,6 +46,8 @@ protected: bool bSubbedToInputEvents = false; bool bIsDirty = true; float DelayUpdate = 0; + bool bHiddenBecauseBlank; + ESlateVisibility OldVisibility; public: @@ -104,5 +106,7 @@ protected: UFUNCTION() void OnInputModeChanged(int ChangedPlayerIdx, EInputMode InputMode); + UFUNCTION() + void OnEnhancedInputMappingsChanged(); };