diff --git a/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp b/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp index a36e7bd..c10d477 100644 --- a/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp +++ b/Source/StevesUEHelpers/Private/StevesGameSubsystem.cpp @@ -1,5 +1,9 @@ #include "StevesGameSubsystem.h" + +#include "EngineUtils.h" +#include "EnhancedInputSubsystems.h" #include "StevesGameViewportClientBase.h" +#include "StevesPluginSettings.h" #include "StevesUEHelpers.h" #include "Engine/AssetManager.h" #include "Engine/GameInstance.h" @@ -20,6 +24,7 @@ void UStevesGameSubsystem::Initialize(FSubsystemCollectionBase& Collection) CreateInputDetector(); InitTheme(); InitForegroundCheck(); + NotifyEnhancedInputMappingsChanged(); #endif } @@ -58,6 +63,50 @@ 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); +} + +TSoftObjectPtr UStevesGameSubsystem::FindEnhancedInputAction(const FString& Name) +{ + if (FAssetRegistryModule* AssetRegistryModule = FModuleManager::LoadModulePtr(TEXT("AssetRegistry"))) + { + IAssetRegistry& AssetRegistry = AssetRegistryModule->Get(); + if (auto Settings = GetDefault()) + { + for (const auto& Dir : Settings->EnhancedInputActionSearchDirectories) + { + if (!FPackageName::IsValidPath(Dir.Path)) + { + continue; + } + + TArray Assets; + FString Package = FPaths::Combine(Dir.Path, Name); + if (AssetRegistry.GetAssetsByPackageName(FName(*Package), Assets, true)) + { + for (const FAssetData& Asset : Assets) + { + if (Asset.GetClass() == UInputAction::StaticClass()) + { + return TSoftObjectPtr(Asset.GetSoftObjectPath()); + } + } + } + + } + } + } + return nullptr; +} + void UStevesGameSubsystem::InitTheme() { DefaultUiTheme = LoadObject(nullptr, *DefaultUiThemePath, nullptr); @@ -224,6 +273,42 @@ UPaperSprite* UStevesGameSubsystem::GetInputImageSpriteFromAxis(const FName& Nam return nullptr; } +UPaperSprite* UStevesGameSubsystem::GetInputImageSpriteFromEnhancedInputAction(UInputAction* Action, + EInputImageDevicePreference DevicePreference, + int PlayerIdx, + APlayerController* PC, + UUiTheme* Theme) +{ + + if (const UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem(PC->GetLocalPlayer())) + { + const TArray Keys = Subsystem->QueryKeysMappedToAction(Action); + + // For default, prefer mouse for axes + if (DevicePreference == EInputImageDevicePreference::Auto) + { + if (Action->ValueType == EInputActionValueType::Boolean) + { + DevicePreference = EInputImageDevicePreference::Gamepad_Keyboard_Mouse_Button; + } + else + { + DevicePreference = EInputImageDevicePreference::Gamepad_Mouse_Keyboard; + } + } + const EInputMode LastInput = GetLastInputModeUsed(PlayerIdx); + const EInputMode LastButtonInput = GetLastInputButtonPressed(PlayerIdx); + const EInputMode LastAxisInput = GetLastInputAxisMoved(PlayerIdx); + if (const FKey* PreferredKey = GetPreferedKeyMapping(Keys, DevicePreference, LastInput, LastButtonInput, LastAxisInput)) + { + return GetInputImageSpriteFromKey(*PreferredKey, PlayerIdx, Theme); + } + } + + return nullptr; +} + + TSoftObjectPtr UStevesGameSubsystem::GetGamepadImages(int PlayerIndex, const UUiTheme* Theme) { // TODO: determine type of controller diff --git a/Source/StevesUEHelpers/Private/StevesPluginSettings.cpp b/Source/StevesUEHelpers/Private/StevesPluginSettings.cpp new file mode 100644 index 0000000..cd627bd --- /dev/null +++ b/Source/StevesUEHelpers/Private/StevesPluginSettings.cpp @@ -0,0 +1,4 @@ +// Fill out your copyright notice in the Description page of Project Settings. + + +#include "StevesPluginSettings.h" diff --git a/Source/StevesUEHelpers/Private/StevesUEHelpers.cpp b/Source/StevesUEHelpers/Private/StevesUEHelpers.cpp index 9245b1e..1e61638 100644 --- a/Source/StevesUEHelpers/Private/StevesUEHelpers.cpp +++ b/Source/StevesUEHelpers/Private/StevesUEHelpers.cpp @@ -1,5 +1,9 @@ #include "StevesUEHelpers.h" +#include "ISettingsModule.h" +#include "ISettingsSection.h" +#include "StevesPluginSettings.h" + #define LOCTEXT_NAMESPACE "FStevesUEHelpers" DEFINE_LOG_CATEGORY(LogStevesUEHelpers) @@ -8,6 +12,19 @@ void FStevesUEHelpers::StartupModule() { // This code will execute after your module is loaded into memory; the exact timing is specified in the .uplugin file per-module UE_LOG(LogStevesUEHelpers, Log, TEXT("Steve's UE Helpers Module Started")) + + // register settings + ISettingsModule* SettingsModule = FModuleManager::GetModulePtr("Settings"); + + if (SettingsModule) + { + ISettingsSectionPtr SettingsSection = SettingsModule->RegisterSettings("Project", "Plugins", "StevesUEHelpers", + LOCTEXT("StevesUEHelpersSettingsName", "StevesUEHelpers"), + LOCTEXT("StevesUEHelpersSettingsDescription", "Configure the helpers plug-in."), + GetMutableDefault() + ); + } + } void FStevesUEHelpers::ShutdownModule() diff --git a/Source/StevesUEHelpers/Private/StevesUI/InputImage.cpp b/Source/StevesUEHelpers/Private/StevesUI/InputImage.cpp index 5291725..a7cd89b 100644 --- a/Source/StevesUEHelpers/Private/StevesUI/InputImage.cpp +++ b/Source/StevesUEHelpers/Private/StevesUI/InputImage.cpp @@ -16,7 +16,9 @@ TSharedRef UInputImage::RebuildWidget() GS->OnInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged); GS->OnButtonInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged); GS->OnAxisInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged); + GS->OnEnhancedInputMappingsChanged.AddUniqueDynamic(this, &UInputImage::OnEnhancedInputMappingsChanged); } + UpdateImage(); return Ret; @@ -35,6 +37,11 @@ void UInputImage::OnInputModeChanged(int ChangedPlayerIdx, EInputMode InputMode) } } +void UInputImage::OnEnhancedInputMappingsChanged() +{ + MarkImageDirty(); +} + void UInputImage::SetCustomTheme(UUiTheme* Theme) { CustomTheme = Theme; @@ -94,18 +101,51 @@ void UInputImage::SetFromKey(FKey K) UpdateImage(); } +void UInputImage::SetFromInputAction(UInputAction* Action) +{ + BindingType = EInputBindingType::EnhancedInputAction; + InputAction = Action; + UpdateImage(); +} + void UInputImage::UpdateImage() { auto GS = GetStevesGameSubsystem(GetWorld()); if (GS) { - auto Sprite = GS->GetInputImageSprite(BindingType, ActionOrAxisName, Key, DevicePreference, PlayerIndex, CustomTheme); + UPaperSprite* Sprite = nullptr; + if (BindingType == EInputBindingType::EnhancedInputAction && !InputAction.IsNull()) + { + if (auto IA = InputAction.LoadSynchronous()) + { + Sprite = GS->GetInputImageSpriteFromEnhancedInputAction(IA, DevicePreference, PlayerIndex, GetOwningPlayer(), CustomTheme); + } + } + else + { + Sprite = GS->GetInputImageSprite(BindingType, ActionOrAxisName, Key, DevicePreference, PlayerIndex, CustomTheme); + } + 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; @@ -114,7 +154,7 @@ void UInputImage::UpdateImage() void UInputImage::MarkImageDirty() { bIsDirty = true; - DelayUpdate = 0.5f; + DelayUpdate = 0.1f; } // Tickables diff --git a/Source/StevesUEHelpers/Private/StevesUI/RichTextBlockInputImageDecorator.cpp b/Source/StevesUEHelpers/Private/StevesUI/RichTextBlockInputImageDecorator.cpp index 24420af..556fff2 100644 --- a/Source/StevesUEHelpers/Private/StevesUI/RichTextBlockInputImageDecorator.cpp +++ b/Source/StevesUEHelpers/Private/StevesUI/RichTextBlockInputImageDecorator.cpp @@ -4,6 +4,7 @@ #include "StevesHelperCommon.h" #include "StevesUEHelpers.h" #include "Fonts/FontMeasure.h" +#include "Kismet/GameplayStatics.h" #include "Misc/DefaultValueHelper.h" #include "Widgets/Layout/SScaleBox.h" #include "Widgets/Images/SImage.h" @@ -18,6 +19,8 @@ struct FRichTextInputImageParams FName ActionOrAxisName; /// If BindingType is Key, the key FKey Key; + /// If binding type is EnhancedInputAction, a reference to an enhanced input action + TSoftObjectPtr InputAction; /// Player index, if binding type is action or axis int PlayerIndex; /// Where there are multiple mappings, which to prefer @@ -38,6 +41,8 @@ protected: FName ActionOrAxisName; /// If BindingType is Key, the key FKey Key; + /// If binding type is EnhancedInputAction, a reference to an enhanced input action + TSoftObjectPtr InputAction; /// Player index, if binding type is action or axis int PlayerIndex = 0; /// Where there are multiple mappings, which to prefer @@ -66,6 +71,7 @@ public: ActionOrAxisName = InParams.ActionOrAxisName; DevicePreference = InParams.DevicePreference; Key = InParams.Key; + InputAction = InParams.InputAction; PlayerIndex = InParams.PlayerIndex; Decorator = InParams.Decorator; RequestedWidth = Width; @@ -77,7 +83,7 @@ public: // We will need to do the work to update the brush from the main thread later // We can use static methods though - if (InParams.InitialSprite) + if (IsValid(InParams.InitialSprite)) UStevesGameSubsystem::SetBrushFromAtlas(&Brush, InParams.InitialSprite, true); TimeUntilNextSpriteCheck = 0.25f; @@ -128,7 +134,19 @@ public: if (GS) { // Can only support default theme, no way to edit theme in decorator config - auto Sprite = GS->GetInputImageSprite(BindingType, ActionOrAxisName, Key, DevicePreference, PlayerIndex); + UPaperSprite* Sprite = nullptr; + if (BindingType == EInputBindingType::EnhancedInputAction && !InputAction.IsNull()) + { + if (auto IA = InputAction.LoadSynchronous()) + { + auto PC = UGameplayStatics::GetPlayerController(Decorator->GetWorld(), PlayerIndex); + Sprite = GS->GetInputImageSpriteFromEnhancedInputAction(IA, DevicePreference, PlayerIndex, PC); + } + } + else + { + Sprite = GS->GetInputImageSprite(BindingType, ActionOrAxisName, Key, DevicePreference, PlayerIndex); + } if (Sprite && Brush.GetResourceObject() != Sprite) { UStevesGameSubsystem::SetBrushFromAtlas(&Brush, Sprite, true); @@ -175,7 +193,8 @@ public: { return RunParseResult.MetaData.Contains(TEXT("key")) || RunParseResult.MetaData.Contains(TEXT("action")) || - RunParseResult.MetaData.Contains(TEXT("axis")); + RunParseResult.MetaData.Contains(TEXT("axis")) || + RunParseResult.MetaData.Contains(TEXT("eaction")); } return false; @@ -191,6 +210,8 @@ protected: Params.Key = EKeys::AnyKey; Params.Decorator = Decorator; + auto GS = GetStevesGameSubsystem(Decorator->GetWorld()); + if (const FString* PlayerStr = RunInfo.MetaData.Find(TEXT("player"))) { int PTemp; @@ -212,6 +233,15 @@ protected: Params.BindingType = EInputBindingType::Axis; Params.ActionOrAxisName = **AxisStr; } + else if (const FString* EInputStr = RunInfo.MetaData.Find(TEXT("eaction"))) + { + Params.BindingType = EInputBindingType::EnhancedInputAction; + // Try to find the input action + if (GS) + { + Params.InputAction = GS->FindEnhancedInputAction(*EInputStr); + } + } if (const FString* PreferStr = RunInfo.MetaData.Find(TEXT("prefer"))) { @@ -240,11 +270,21 @@ protected: // Look up the initial sprite here // The Slate widget can't do it in Construct because World pointer doesn't work (thread issues?) // Also annoying: can't keep Brush on this class because this method is const. UGH - auto GS = GetStevesGameSubsystem(Decorator->GetWorld()); if (GS) { - // Can only support default theme, no way to edit theme in decorator config - Params.InitialSprite = GS->GetInputImageSprite(Params.BindingType, Params.ActionOrAxisName, Params.Key, Params.DevicePreference, Params.PlayerIndex); + if (Params.BindingType == EInputBindingType::EnhancedInputAction && !Params.InputAction.IsNull()) + { + if (auto IA = Params.InputAction.LoadSynchronous()) + { + auto PC = UGameplayStatics::GetPlayerController(Decorator->GetWorld(), Params.PlayerIndex); + Params.InitialSprite = GS->GetInputImageSpriteFromEnhancedInputAction(IA, Params.DevicePreference, Params.PlayerIndex, PC); + } + } + else + { + // Can only support default theme, no way to edit theme in decorator config + Params.InitialSprite = GS->GetInputImageSprite(Params.BindingType, Params.ActionOrAxisName, Params.Key, Params.DevicePreference, Params.PlayerIndex); + } } else { diff --git a/Source/StevesUEHelpers/Private/StevesUI/StevesUI.cpp b/Source/StevesUEHelpers/Private/StevesUI/StevesUI.cpp index 28ef663..eef96c7 100644 --- a/Source/StevesUEHelpers/Private/StevesUI/StevesUI.cpp +++ b/Source/StevesUEHelpers/Private/StevesUI/StevesUI.cpp @@ -49,3 +49,67 @@ void SetWidgetFocusProperly(UWidget* Widget) Widget->SetFocus(); } + +const FKey* GetPreferedKeyMapping(const TArray& AllKeys, + EInputImageDevicePreference DevicePreference, + EInputMode LastInputDevice, + EInputMode LastButtonInputDevice, + EInputMode LastAxisInputDevice) +{ + // Same as GetPreferedActionOrAxisMapping, just with key directly + const FKey* MouseMapping = nullptr; + const FKey* KeyboardMapping = nullptr; + const FKey* GamepadMapping = nullptr; + for (const FKey& Key : AllKeys) + { + // notice how we take the LAST one in the list as the final version + // this is because UInputSettings::GetActionMappingByName *reverses* the mapping list from Project Settings + if (Key.IsGamepadKey()) + { + GamepadMapping = &Key; + } + else if (Key.IsMouseButton()) // registers true for mouse axes too + { + MouseMapping = &Key; + } + else + { + KeyboardMapping = &Key; + } + } + + const FKey* Preferred = nullptr; + if (GamepadMapping && LastInputDevice == EInputMode::Gamepad) + { + // Always prefer gamepad if used last + Preferred = GamepadMapping; + } + else + { + switch (DevicePreference) + { + // Auto should be pre-converted to another + case EInputImageDevicePreference::Auto: + UE_LOG(LogStevesUI, Error, TEXT("Device Preference should have been converted before this call")) + break; + case EInputImageDevicePreference::Gamepad_Keyboard_Mouse: + Preferred = KeyboardMapping ? KeyboardMapping : MouseMapping; + break; + case EInputImageDevicePreference::Gamepad_Mouse_Keyboard: + Preferred = MouseMapping ? MouseMapping : KeyboardMapping; + break; + + case EInputImageDevicePreference::Gamepad_Keyboard_Mouse_Button: + // Use the latest button press + Preferred = (MouseMapping && (LastButtonInputDevice == EInputMode::Mouse || !KeyboardMapping)) ? MouseMapping : KeyboardMapping; + break; + case EInputImageDevicePreference::Gamepad_Keyboard_Mouse_Axis: + // Use the latest button press + Preferred = (MouseMapping && (LastAxisInputDevice == EInputMode::Mouse || !KeyboardMapping)) ? MouseMapping : KeyboardMapping; + break; + default: + break; + } + } + return Preferred; +} diff --git a/Source/StevesUEHelpers/Private/StevesUI/StevesUI.h b/Source/StevesUEHelpers/Private/StevesUI/StevesUI.h index 4b8aaee..07145a7 100644 --- a/Source/StevesUEHelpers/Private/StevesUI/StevesUI.h +++ b/Source/StevesUEHelpers/Private/StevesUI/StevesUI.h @@ -89,3 +89,10 @@ const T* GetPreferedActionOrAxisMapping(const TArray& AllMappings, const FNam } return Preferred; } + + +const FKey* GetPreferedKeyMapping(const TArray& AllKeys, + EInputImageDevicePreference DevicePreference, + EInputMode LastInputDevice, + EInputMode LastButtonInputDevice, + EInputMode LastAxisInputDevice); diff --git a/Source/StevesUEHelpers/Public/StevesGameSubsystem.h b/Source/StevesUEHelpers/Public/StevesGameSubsystem.h index 986116f..3f3f7a2 100644 --- a/Source/StevesUEHelpers/Public/StevesGameSubsystem.h +++ b/Source/StevesUEHelpers/Public/StevesGameSubsystem.h @@ -8,11 +8,13 @@ #include "StevesHelperCommon.h" #include "StevesTextureRenderTargetPool.h" #include "StevesUI/FocusSystem.h" +#include "StevesUI/InputImage.h" #include "StevesUI/UiTheme.h" #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 @@ -37,7 +39,6 @@ public: virtual void Initialize(FSubsystemCollectionBase& Collection) override; virtual void Deinitialize() override; - protected: DECLARE_DELEGATE_TwoParams(FInternalInputModeChanged, int /* PlayerIndex */, EInputMode) /** @@ -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) @@ -209,6 +216,21 @@ public: int PlayerIndex = 0, const UUiTheme* Theme = nullptr); + /** + * @brief Get an input button / key / axis image as a sprite based on an enhanced input action + * @param Action The input action + * @param DevicePreference The order of preference for images where multiple devices have mappings. In the case of multiple mappings for the same device, the first one will be used. + * @param PlayerIdx The player index to look up the binding for + * @param PC The player controller to look up the binding for + * @param Theme Optional explicit theme, if blank use the default theme + * @return + */ + UPaperSprite* GetInputImageSpriteFromEnhancedInputAction(UInputAction* Action, + EInputImageDevicePreference DevicePreference, + int PlayerIdx, + APlayerController* PC, + UUiTheme* Theme = nullptr); + /** * @brief Get an input button / key image from an action * @param Name The name of the action @@ -266,4 +288,16 @@ 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(); + + /** Attempt to find an enhanced input action by name in the configured folders. + */ + TSoftObjectPtr FindEnhancedInputAction(const FString& Name); + }; diff --git a/Source/StevesUEHelpers/Public/StevesHelperCommon.h b/Source/StevesUEHelpers/Public/StevesHelperCommon.h index cdcf30e..746905d 100644 --- a/Source/StevesUEHelpers/Public/StevesHelperCommon.h +++ b/Source/StevesUEHelpers/Public/StevesHelperCommon.h @@ -41,12 +41,14 @@ enum class EGamePauseChange : uint8 UENUM(BlueprintType) enum class EInputBindingType : uint8 { - /// A button action, will be looked up based on input mappings + /// A legacy button action, will be looked up based on input mappings Action = 0, - /// An axis action, will be looked up based on input mappings + /// An legacy axis action, will be looked up based on input mappings Axis = 1, /// A manually specified FKey (which can be key, button, axis) - Key = 2 + Key = 2, + /// An EnhancedInput action + EnhancedInputAction = 3 }; /// What order of preference should we return input images where an action/axis has multiple mappings diff --git a/Source/StevesUEHelpers/Public/StevesPluginSettings.h b/Source/StevesUEHelpers/Public/StevesPluginSettings.h new file mode 100644 index 0000000..d8a7748 --- /dev/null +++ b/Source/StevesUEHelpers/Public/StevesPluginSettings.h @@ -0,0 +1,23 @@ +#pragma once + +#include "CoreMinimal.h" + +#include "StevesPluginSettings.generated.h" + +/** +* Settings for the plug-in. +*/ +UCLASS(config=Engine) +class STEVESUEHELPERS_API UStevesPluginSettings + : public UObject +{ + GENERATED_BODY() + +public: + /// Which directories to search for Enhanced Input Actions when referenced just by name in e.g. Rich Text Decorator + UPROPERTY(config, EditAnywhere, Category = StevesUEHelpers, meta = (DisplayName = "Directories to search for Enhanced Input Actions", RelativeToGameContentDir, LongPackageName)) + TArray EnhancedInputActionSearchDirectories; + + UStevesPluginSettings() {} + +}; diff --git a/Source/StevesUEHelpers/Public/StevesUI/InputImage.h b/Source/StevesUEHelpers/Public/StevesUI/InputImage.h index 5cfcff2..7fe960c 100644 --- a/Source/StevesUEHelpers/Public/StevesUI/InputImage.h +++ b/Source/StevesUEHelpers/Public/StevesUI/InputImage.h @@ -22,6 +22,10 @@ protected: /// If BindingType is Action/Axis, the name of it UPROPERTY(EditAnywhere) FName ActionOrAxisName; + + /// If binding type is EnhancedInputAction, a reference to an enhanced input action + UPROPERTY(EditAnywhere) // can't be inside #if + TSoftObjectPtr InputAction; /// Where there are multiple mappings, which to prefer UPROPERTY(EditAnywhere) @@ -42,6 +46,8 @@ protected: bool bSubbedToInputEvents = false; bool bIsDirty = true; float DelayUpdate = 0; + bool bHiddenBecauseBlank; + ESlateVisibility OldVisibility; public: @@ -57,6 +63,10 @@ public: UFUNCTION(BlueprintCallable) virtual void SetFromKey(FKey K); + /// Tell this image to display Enhanced InputAction + UFUNCTION(BlueprintCallable) + virtual void SetFromInputAction(UInputAction* Action); + /// Get the binding type that we'll use to populate the image UFUNCTION(BlueprintCallable) virtual EInputBindingType GetBindingType() const { return BindingType; } @@ -96,5 +106,7 @@ protected: UFUNCTION() void OnInputModeChanged(int ChangedPlayerIdx, EInputMode InputMode); + UFUNCTION() + void OnEnhancedInputMappingsChanged(); }; diff --git a/Source/StevesUEHelpers/StevesUEHelpers.Build.cs b/Source/StevesUEHelpers/StevesUEHelpers.Build.cs index 2ad9cef..f70f5b2 100644 --- a/Source/StevesUEHelpers/StevesUEHelpers.Build.cs +++ b/Source/StevesUEHelpers/StevesUEHelpers.Build.cs @@ -25,10 +25,11 @@ public class StevesUEHelpers : ModuleRules "CoreUObject", "Engine", "InputCore", + "EnhancedInput", "Slate", "SlateCore", "UMG", - "Paper2D" + "Paper2D", } ); diff --git a/doc/InputImage.md b/doc/InputImage.md index 25006d8..bd7a974 100644 --- a/doc/InputImage.md +++ b/doc/InputImage.md @@ -17,10 +17,15 @@ InputImage requires a [UiTheme](UiTheme.md) to operate, which links to the image ### Binding Type -* "Action" if the image should display the current mapping for an input action -* "Axis" to look up an input axis +* "Enhanced Input Action" to specify an [Enhanced Input](https://docs.unrealengine.com/5.1/en-US/enhanced-input-in-unreal-engine/) action +* "Action" if the image should display the current mapping for a legacy input action +* "Axis" to look up a legacy input axis * "Key" to manually specify a key (which can be gamepad or mouse too) +### Enhanced Input Action + +Pick an Enhanced Input action from the asset browser interface. + ### Action or Axis Name The name of the input action or axis that should be looked up to determine the diff --git a/doc/RichTextInputDecorator.md b/doc/RichTextInputDecorator.md index 2715cc0..af689a7 100644 --- a/doc/RichTextInputDecorator.md +++ b/doc/RichTextInputDecorator.md @@ -33,13 +33,21 @@ related to input controls. There are various options: ## Adding input images to rich text -### Input Actions +### Enhanced Input Actions + +`` + +This displays the image for a bound Enhanced Input action. The name of the action +should match the action name, which is relative to one of the directories +you specify in Project Settings > Plugins > StevesUEHelpers. + +### Legacy Input Actions `` This displays the image for a bound action input, as configured in project settings. -### Input Axes +### Legacy Input Axes ``