Rich text input decorator can now reference enhanced input actions

This commit is contained in:
Steve Streeting 2023-03-07 18:10:25 +00:00
parent 0aea6933dc
commit e9fd6cb254
9 changed files with 156 additions and 14 deletions

View File

@ -1,7 +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"
@ -72,6 +74,39 @@ void UStevesGameSubsystem::NotifyEnhancedInputMappingsChanged()
GetWorld()->GetTimerManager().SetTimer(TempHandle, FTimerDelegate::CreateLambda(DelayedFunc), 0.05, false);
}
TSoftObjectPtr<UInputAction> UStevesGameSubsystem::FindEnhancedInputAction(const FString& Name)
{
if (FAssetRegistryModule* AssetRegistryModule = FModuleManager::LoadModulePtr<FAssetRegistryModule>(TEXT("AssetRegistry")))
{
IAssetRegistry& AssetRegistry = AssetRegistryModule->Get();
if (auto Settings = GetDefault<UStevesPluginSettings>())
{
for (const auto& Dir : Settings->EnhancedInputActionSearchDirectories)
{
if (!FPackageName::IsValidPath(Dir.Path))
{
continue;
}
TArray<FAssetData> 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<UInputAction>(Asset.GetSoftObjectPath());
}
}
}
}
}
}
return nullptr;
}
void UStevesGameSubsystem::InitTheme()
{
DefaultUiTheme = LoadObject<UUiTheme>(nullptr, *DefaultUiThemePath, nullptr);

View File

@ -0,0 +1,4 @@
// Fill out your copyright notice in the Description page of Project Settings.
#include "StevesPluginSettings.h"

View File

@ -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<ISettingsModule>("Settings");
if (SettingsModule)
{
ISettingsSectionPtr SettingsSection = SettingsModule->RegisterSettings("Project", "Plugins", "StevesUEHelpers",
LOCTEXT("StevesUEHelpersSettingsName", "StevesUEHelpers"),
LOCTEXT("StevesUEHelpersSettingsDescription", "Configure the helpers plug-in."),
GetMutableDefault<UStevesPluginSettings>()
);
}
}
void FStevesUEHelpers::ShutdownModule()

View File

@ -114,10 +114,12 @@ void UInputImage::UpdateImage()
if (GS)
{
UPaperSprite* Sprite = nullptr;
if (BindingType == EInputBindingType::EnhancedInputAction)
if (BindingType == EInputBindingType::EnhancedInputAction && !InputAction.IsNull())
{
auto IA = InputAction.LoadSynchronous();
Sprite = GS->GetInputImageSpriteFromEnhancedInputAction(IA, DevicePreference, PlayerIndex, GetOwningPlayer(), CustomTheme);
if (auto IA = InputAction.LoadSynchronous())
{
Sprite = GS->GetInputImageSpriteFromEnhancedInputAction(IA, DevicePreference, PlayerIndex, GetOwningPlayer(), CustomTheme);
}
}
else
{

View File

@ -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<UInputAction> 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<UInputAction> 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
{

View File

@ -225,7 +225,11 @@ public:
* @param Theme Optional explicit theme, if blank use the default theme
* @return
*/
UPaperSprite* GetInputImageSpriteFromEnhancedInputAction(UInputAction* Action, EInputImageDevicePreference DevicePreference, int PlayerIdx, APlayerController* PC, UUiTheme* Theme);
UPaperSprite* GetInputImageSpriteFromEnhancedInputAction(UInputAction* Action,
EInputImageDevicePreference DevicePreference,
int PlayerIdx,
APlayerController* PC,
UUiTheme* Theme = nullptr);
/**
* @brief Get an input button / key image from an action
@ -292,4 +296,8 @@ public:
*/
void NotifyEnhancedInputMappingsChanged();
/** Attempt to find an enhanced input action by name in the configured folders.
*/
TSoftObjectPtr<UInputAction> FindEnhancedInputAction(const FString& Name);
};

View File

@ -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))
TArray<FDirectoryPath> EnhancedInputActionSearchDirectories;
UStevesPluginSettings() {}
};

View File

@ -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

View File

@ -33,13 +33,21 @@ related to input controls. There are various options:
## Adding input images to rich text
### Input Actions
### Enhanced Input Actions
`<input eaction="IA_MyAction"/>`
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
`<input action="TheActionName"/>`
This displays the image for a bound action input, as configured in project settings.
### Input Axes
### Legacy Input Axes
`<input axis="TheAxisName"/>`