mirror of
https://github.com/sinbad/StevesUEHelpers.git
synced 2025-02-23 17:45:23 +00:00
Merge branch 'enhanced-input'
This commit is contained in:
commit
46e1a18187
@ -1,5 +1,9 @@
|
|||||||
#include "StevesGameSubsystem.h"
|
#include "StevesGameSubsystem.h"
|
||||||
|
|
||||||
|
#include "EngineUtils.h"
|
||||||
|
#include "EnhancedInputSubsystems.h"
|
||||||
#include "StevesGameViewportClientBase.h"
|
#include "StevesGameViewportClientBase.h"
|
||||||
|
#include "StevesPluginSettings.h"
|
||||||
#include "StevesUEHelpers.h"
|
#include "StevesUEHelpers.h"
|
||||||
#include "Engine/AssetManager.h"
|
#include "Engine/AssetManager.h"
|
||||||
#include "Engine/GameInstance.h"
|
#include "Engine/GameInstance.h"
|
||||||
@ -20,6 +24,7 @@ void UStevesGameSubsystem::Initialize(FSubsystemCollectionBase& Collection)
|
|||||||
CreateInputDetector();
|
CreateInputDetector();
|
||||||
InitTheme();
|
InitTheme();
|
||||||
InitForegroundCheck();
|
InitForegroundCheck();
|
||||||
|
NotifyEnhancedInputMappingsChanged();
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,6 +63,50 @@ void UStevesGameSubsystem::DestroyInputDetector()
|
|||||||
#endif
|
#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<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()
|
void UStevesGameSubsystem::InitTheme()
|
||||||
{
|
{
|
||||||
DefaultUiTheme = LoadObject<UUiTheme>(nullptr, *DefaultUiThemePath, nullptr);
|
DefaultUiTheme = LoadObject<UUiTheme>(nullptr, *DefaultUiThemePath, nullptr);
|
||||||
@ -224,6 +273,42 @@ UPaperSprite* UStevesGameSubsystem::GetInputImageSpriteFromAxis(const FName& Nam
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UPaperSprite* UStevesGameSubsystem::GetInputImageSpriteFromEnhancedInputAction(UInputAction* Action,
|
||||||
|
EInputImageDevicePreference DevicePreference,
|
||||||
|
int PlayerIdx,
|
||||||
|
APlayerController* PC,
|
||||||
|
UUiTheme* Theme)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (const UEnhancedInputLocalPlayerSubsystem* Subsystem = ULocalPlayer::GetSubsystem<UEnhancedInputLocalPlayerSubsystem>(PC->GetLocalPlayer()))
|
||||||
|
{
|
||||||
|
const TArray<FKey> 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<UDataTable> UStevesGameSubsystem::GetGamepadImages(int PlayerIndex, const UUiTheme* Theme)
|
TSoftObjectPtr<UDataTable> UStevesGameSubsystem::GetGamepadImages(int PlayerIndex, const UUiTheme* Theme)
|
||||||
{
|
{
|
||||||
// TODO: determine type of controller
|
// TODO: determine type of controller
|
||||||
|
4
Source/StevesUEHelpers/Private/StevesPluginSettings.cpp
Normal file
4
Source/StevesUEHelpers/Private/StevesPluginSettings.cpp
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
// Fill out your copyright notice in the Description page of Project Settings.
|
||||||
|
|
||||||
|
|
||||||
|
#include "StevesPluginSettings.h"
|
@ -1,5 +1,9 @@
|
|||||||
#include "StevesUEHelpers.h"
|
#include "StevesUEHelpers.h"
|
||||||
|
|
||||||
|
#include "ISettingsModule.h"
|
||||||
|
#include "ISettingsSection.h"
|
||||||
|
#include "StevesPluginSettings.h"
|
||||||
|
|
||||||
#define LOCTEXT_NAMESPACE "FStevesUEHelpers"
|
#define LOCTEXT_NAMESPACE "FStevesUEHelpers"
|
||||||
|
|
||||||
DEFINE_LOG_CATEGORY(LogStevesUEHelpers)
|
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
|
// 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"))
|
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()
|
void FStevesUEHelpers::ShutdownModule()
|
||||||
|
@ -16,7 +16,9 @@ TSharedRef<SWidget> UInputImage::RebuildWidget()
|
|||||||
GS->OnInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged);
|
GS->OnInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged);
|
||||||
GS->OnButtonInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged);
|
GS->OnButtonInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged);
|
||||||
GS->OnAxisInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged);
|
GS->OnAxisInputModeChanged.AddUniqueDynamic(this, &UInputImage::OnInputModeChanged);
|
||||||
|
GS->OnEnhancedInputMappingsChanged.AddUniqueDynamic(this, &UInputImage::OnEnhancedInputMappingsChanged);
|
||||||
}
|
}
|
||||||
|
|
||||||
UpdateImage();
|
UpdateImage();
|
||||||
|
|
||||||
return Ret;
|
return Ret;
|
||||||
@ -35,6 +37,11 @@ void UInputImage::OnInputModeChanged(int ChangedPlayerIdx, EInputMode InputMode)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UInputImage::OnEnhancedInputMappingsChanged()
|
||||||
|
{
|
||||||
|
MarkImageDirty();
|
||||||
|
}
|
||||||
|
|
||||||
void UInputImage::SetCustomTheme(UUiTheme* Theme)
|
void UInputImage::SetCustomTheme(UUiTheme* Theme)
|
||||||
{
|
{
|
||||||
CustomTheme = Theme;
|
CustomTheme = Theme;
|
||||||
@ -94,18 +101,51 @@ void UInputImage::SetFromKey(FKey K)
|
|||||||
UpdateImage();
|
UpdateImage();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UInputImage::SetFromInputAction(UInputAction* Action)
|
||||||
|
{
|
||||||
|
BindingType = EInputBindingType::EnhancedInputAction;
|
||||||
|
InputAction = Action;
|
||||||
|
UpdateImage();
|
||||||
|
}
|
||||||
|
|
||||||
void UInputImage::UpdateImage()
|
void UInputImage::UpdateImage()
|
||||||
{
|
{
|
||||||
auto GS = GetStevesGameSubsystem(GetWorld());
|
auto GS = GetStevesGameSubsystem(GetWorld());
|
||||||
if (GS)
|
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 (Sprite)
|
||||||
{
|
{
|
||||||
|
if (bHiddenBecauseBlank)
|
||||||
|
{
|
||||||
|
SetVisibility(OldVisibility);
|
||||||
|
bHiddenBecauseBlank = false;
|
||||||
|
}
|
||||||
// Match size is needed incase size has changed
|
// 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
|
// Need to make it update region in case inside a scale box or something else that needs to adjust
|
||||||
SetBrushFromAtlasInterface(Sprite, true);
|
SetBrushFromAtlasInterface(Sprite, true);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (IsVisible())
|
||||||
|
{
|
||||||
|
bHiddenBecauseBlank = true;
|
||||||
|
OldVisibility = GetVisibility();
|
||||||
|
SetVisibility(ESlateVisibility::Hidden);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
bIsDirty = false;
|
bIsDirty = false;
|
||||||
DelayUpdate = 0;
|
DelayUpdate = 0;
|
||||||
@ -114,7 +154,7 @@ void UInputImage::UpdateImage()
|
|||||||
void UInputImage::MarkImageDirty()
|
void UInputImage::MarkImageDirty()
|
||||||
{
|
{
|
||||||
bIsDirty = true;
|
bIsDirty = true;
|
||||||
DelayUpdate = 0.5f;
|
DelayUpdate = 0.1f;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Tickables
|
// Tickables
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
#include "StevesHelperCommon.h"
|
#include "StevesHelperCommon.h"
|
||||||
#include "StevesUEHelpers.h"
|
#include "StevesUEHelpers.h"
|
||||||
#include "Fonts/FontMeasure.h"
|
#include "Fonts/FontMeasure.h"
|
||||||
|
#include "Kismet/GameplayStatics.h"
|
||||||
#include "Misc/DefaultValueHelper.h"
|
#include "Misc/DefaultValueHelper.h"
|
||||||
#include "Widgets/Layout/SScaleBox.h"
|
#include "Widgets/Layout/SScaleBox.h"
|
||||||
#include "Widgets/Images/SImage.h"
|
#include "Widgets/Images/SImage.h"
|
||||||
@ -18,6 +19,8 @@ struct FRichTextInputImageParams
|
|||||||
FName ActionOrAxisName;
|
FName ActionOrAxisName;
|
||||||
/// If BindingType is Key, the key
|
/// If BindingType is Key, the key
|
||||||
FKey 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
|
/// Player index, if binding type is action or axis
|
||||||
int PlayerIndex;
|
int PlayerIndex;
|
||||||
/// Where there are multiple mappings, which to prefer
|
/// Where there are multiple mappings, which to prefer
|
||||||
@ -38,6 +41,8 @@ protected:
|
|||||||
FName ActionOrAxisName;
|
FName ActionOrAxisName;
|
||||||
/// If BindingType is Key, the key
|
/// If BindingType is Key, the key
|
||||||
FKey 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
|
/// Player index, if binding type is action or axis
|
||||||
int PlayerIndex = 0;
|
int PlayerIndex = 0;
|
||||||
/// Where there are multiple mappings, which to prefer
|
/// Where there are multiple mappings, which to prefer
|
||||||
@ -66,6 +71,7 @@ public:
|
|||||||
ActionOrAxisName = InParams.ActionOrAxisName;
|
ActionOrAxisName = InParams.ActionOrAxisName;
|
||||||
DevicePreference = InParams.DevicePreference;
|
DevicePreference = InParams.DevicePreference;
|
||||||
Key = InParams.Key;
|
Key = InParams.Key;
|
||||||
|
InputAction = InParams.InputAction;
|
||||||
PlayerIndex = InParams.PlayerIndex;
|
PlayerIndex = InParams.PlayerIndex;
|
||||||
Decorator = InParams.Decorator;
|
Decorator = InParams.Decorator;
|
||||||
RequestedWidth = Width;
|
RequestedWidth = Width;
|
||||||
@ -77,7 +83,7 @@ public:
|
|||||||
// We will need to do the work to update the brush from the main thread later
|
// We will need to do the work to update the brush from the main thread later
|
||||||
|
|
||||||
// We can use static methods though
|
// We can use static methods though
|
||||||
if (InParams.InitialSprite)
|
if (IsValid(InParams.InitialSprite))
|
||||||
UStevesGameSubsystem::SetBrushFromAtlas(&Brush, InParams.InitialSprite, true);
|
UStevesGameSubsystem::SetBrushFromAtlas(&Brush, InParams.InitialSprite, true);
|
||||||
TimeUntilNextSpriteCheck = 0.25f;
|
TimeUntilNextSpriteCheck = 0.25f;
|
||||||
|
|
||||||
@ -128,7 +134,19 @@ public:
|
|||||||
if (GS)
|
if (GS)
|
||||||
{
|
{
|
||||||
// Can only support default theme, no way to edit theme in decorator config
|
// 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)
|
if (Sprite && Brush.GetResourceObject() != Sprite)
|
||||||
{
|
{
|
||||||
UStevesGameSubsystem::SetBrushFromAtlas(&Brush, Sprite, true);
|
UStevesGameSubsystem::SetBrushFromAtlas(&Brush, Sprite, true);
|
||||||
@ -175,7 +193,8 @@ public:
|
|||||||
{
|
{
|
||||||
return RunParseResult.MetaData.Contains(TEXT("key")) ||
|
return RunParseResult.MetaData.Contains(TEXT("key")) ||
|
||||||
RunParseResult.MetaData.Contains(TEXT("action")) ||
|
RunParseResult.MetaData.Contains(TEXT("action")) ||
|
||||||
RunParseResult.MetaData.Contains(TEXT("axis"));
|
RunParseResult.MetaData.Contains(TEXT("axis")) ||
|
||||||
|
RunParseResult.MetaData.Contains(TEXT("eaction"));
|
||||||
}
|
}
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
@ -191,6 +210,8 @@ protected:
|
|||||||
Params.Key = EKeys::AnyKey;
|
Params.Key = EKeys::AnyKey;
|
||||||
Params.Decorator = Decorator;
|
Params.Decorator = Decorator;
|
||||||
|
|
||||||
|
auto GS = GetStevesGameSubsystem(Decorator->GetWorld());
|
||||||
|
|
||||||
if (const FString* PlayerStr = RunInfo.MetaData.Find(TEXT("player")))
|
if (const FString* PlayerStr = RunInfo.MetaData.Find(TEXT("player")))
|
||||||
{
|
{
|
||||||
int PTemp;
|
int PTemp;
|
||||||
@ -212,6 +233,15 @@ protected:
|
|||||||
Params.BindingType = EInputBindingType::Axis;
|
Params.BindingType = EInputBindingType::Axis;
|
||||||
Params.ActionOrAxisName = **AxisStr;
|
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")))
|
if (const FString* PreferStr = RunInfo.MetaData.Find(TEXT("prefer")))
|
||||||
{
|
{
|
||||||
@ -240,11 +270,21 @@ protected:
|
|||||||
// Look up the initial sprite here
|
// Look up the initial sprite here
|
||||||
// The Slate widget can't do it in Construct because World pointer doesn't work (thread issues?)
|
// 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
|
// Also annoying: can't keep Brush on this class because this method is const. UGH
|
||||||
auto GS = GetStevesGameSubsystem(Decorator->GetWorld());
|
|
||||||
if (GS)
|
if (GS)
|
||||||
{
|
{
|
||||||
// Can only support default theme, no way to edit theme in decorator config
|
if (Params.BindingType == EInputBindingType::EnhancedInputAction && !Params.InputAction.IsNull())
|
||||||
Params.InitialSprite = GS->GetInputImageSprite(Params.BindingType, Params.ActionOrAxisName, Params.Key, Params.DevicePreference, Params.PlayerIndex);
|
{
|
||||||
|
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
|
else
|
||||||
{
|
{
|
||||||
|
@ -49,3 +49,67 @@ void SetWidgetFocusProperly(UWidget* Widget)
|
|||||||
Widget->SetFocus();
|
Widget->SetFocus();
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const FKey* GetPreferedKeyMapping(const TArray<FKey>& 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;
|
||||||
|
}
|
||||||
|
@ -89,3 +89,10 @@ const T* GetPreferedActionOrAxisMapping(const TArray<T>& AllMappings, const FNam
|
|||||||
}
|
}
|
||||||
return Preferred;
|
return Preferred;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
const FKey* GetPreferedKeyMapping(const TArray<FKey>& AllKeys,
|
||||||
|
EInputImageDevicePreference DevicePreference,
|
||||||
|
EInputMode LastInputDevice,
|
||||||
|
EInputMode LastButtonInputDevice,
|
||||||
|
EInputMode LastAxisInputDevice);
|
||||||
|
@ -8,11 +8,13 @@
|
|||||||
#include "StevesHelperCommon.h"
|
#include "StevesHelperCommon.h"
|
||||||
#include "StevesTextureRenderTargetPool.h"
|
#include "StevesTextureRenderTargetPool.h"
|
||||||
#include "StevesUI/FocusSystem.h"
|
#include "StevesUI/FocusSystem.h"
|
||||||
|
#include "StevesUI/InputImage.h"
|
||||||
#include "StevesUI/UiTheme.h"
|
#include "StevesUI/UiTheme.h"
|
||||||
|
|
||||||
#include "StevesGameSubsystem.generated.h"
|
#include "StevesGameSubsystem.generated.h"
|
||||||
|
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInputModeChanged, int, PlayerIndex, EInputMode, InputMode);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInputModeChanged, int, PlayerIndex, EInputMode, InputMode);
|
||||||
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FOnEnhancedInputMappingsChanged);
|
||||||
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWindowForegroundChanged, bool, bFocussed);
|
DECLARE_DYNAMIC_MULTICAST_DELEGATE_OneParam(FOnWindowForegroundChanged, bool, bFocussed);
|
||||||
|
|
||||||
/// Entry point for all the top-level features of the helper system
|
/// 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 Initialize(FSubsystemCollectionBase& Collection) override;
|
||||||
virtual void Deinitialize() override;
|
virtual void Deinitialize() override;
|
||||||
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
DECLARE_DELEGATE_TwoParams(FInternalInputModeChanged, int /* PlayerIndex */, EInputMode)
|
DECLARE_DELEGATE_TwoParams(FInternalInputModeChanged, int /* PlayerIndex */, EInputMode)
|
||||||
/**
|
/**
|
||||||
@ -160,6 +161,12 @@ public:
|
|||||||
/// last axis moved was still mouse, you'd get this event later
|
/// last axis moved was still mouse, you'd get this event later
|
||||||
UPROPERTY(BlueprintAssignable)
|
UPROPERTY(BlueprintAssignable)
|
||||||
FOnInputModeChanged OnAxisInputModeChanged;
|
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
|
/// Event raised when the game window's foreground status changes
|
||||||
UPROPERTY(BlueprintAssignable)
|
UPROPERTY(BlueprintAssignable)
|
||||||
@ -209,6 +216,21 @@ public:
|
|||||||
int PlayerIndex = 0,
|
int PlayerIndex = 0,
|
||||||
const UUiTheme* Theme = nullptr);
|
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
|
* @brief Get an input button / key image from an action
|
||||||
* @param Name The name of the action
|
* @param Name The name of the action
|
||||||
@ -266,4 +288,16 @@ public:
|
|||||||
*/
|
*/
|
||||||
FStevesTextureRenderTargetPoolPtr GetTextureRenderTargetPool(FName Name, bool bAutoCreate = true);
|
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<UInputAction> FindEnhancedInputAction(const FString& Name);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -41,12 +41,14 @@ enum class EGamePauseChange : uint8
|
|||||||
UENUM(BlueprintType)
|
UENUM(BlueprintType)
|
||||||
enum class EInputBindingType : uint8
|
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,
|
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,
|
Axis = 1,
|
||||||
/// A manually specified FKey (which can be key, button, axis)
|
/// 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
|
/// What order of preference should we return input images where an action/axis has multiple mappings
|
||||||
|
23
Source/StevesUEHelpers/Public/StevesPluginSettings.h
Normal file
23
Source/StevesUEHelpers/Public/StevesPluginSettings.h
Normal 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, LongPackageName))
|
||||||
|
TArray<FDirectoryPath> EnhancedInputActionSearchDirectories;
|
||||||
|
|
||||||
|
UStevesPluginSettings() {}
|
||||||
|
|
||||||
|
};
|
@ -22,6 +22,10 @@ protected:
|
|||||||
/// If BindingType is Action/Axis, the name of it
|
/// If BindingType is Action/Axis, the name of it
|
||||||
UPROPERTY(EditAnywhere)
|
UPROPERTY(EditAnywhere)
|
||||||
FName ActionOrAxisName;
|
FName ActionOrAxisName;
|
||||||
|
|
||||||
|
/// If binding type is EnhancedInputAction, a reference to an enhanced input action
|
||||||
|
UPROPERTY(EditAnywhere) // can't be inside #if
|
||||||
|
TSoftObjectPtr<UInputAction> InputAction;
|
||||||
|
|
||||||
/// Where there are multiple mappings, which to prefer
|
/// Where there are multiple mappings, which to prefer
|
||||||
UPROPERTY(EditAnywhere)
|
UPROPERTY(EditAnywhere)
|
||||||
@ -42,6 +46,8 @@ protected:
|
|||||||
bool bSubbedToInputEvents = false;
|
bool bSubbedToInputEvents = false;
|
||||||
bool bIsDirty = true;
|
bool bIsDirty = true;
|
||||||
float DelayUpdate = 0;
|
float DelayUpdate = 0;
|
||||||
|
bool bHiddenBecauseBlank;
|
||||||
|
ESlateVisibility OldVisibility;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -57,6 +63,10 @@ public:
|
|||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
virtual void SetFromKey(FKey K);
|
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
|
/// Get the binding type that we'll use to populate the image
|
||||||
UFUNCTION(BlueprintCallable)
|
UFUNCTION(BlueprintCallable)
|
||||||
virtual EInputBindingType GetBindingType() const { return BindingType; }
|
virtual EInputBindingType GetBindingType() const { return BindingType; }
|
||||||
@ -96,5 +106,7 @@ protected:
|
|||||||
|
|
||||||
UFUNCTION()
|
UFUNCTION()
|
||||||
void OnInputModeChanged(int ChangedPlayerIdx, EInputMode InputMode);
|
void OnInputModeChanged(int ChangedPlayerIdx, EInputMode InputMode);
|
||||||
|
UFUNCTION()
|
||||||
|
void OnEnhancedInputMappingsChanged();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
@ -25,10 +25,11 @@ public class StevesUEHelpers : ModuleRules
|
|||||||
"CoreUObject",
|
"CoreUObject",
|
||||||
"Engine",
|
"Engine",
|
||||||
"InputCore",
|
"InputCore",
|
||||||
|
"EnhancedInput",
|
||||||
"Slate",
|
"Slate",
|
||||||
"SlateCore",
|
"SlateCore",
|
||||||
"UMG",
|
"UMG",
|
||||||
"Paper2D"
|
"Paper2D",
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -17,10 +17,15 @@ InputImage requires a [UiTheme](UiTheme.md) to operate, which links to the image
|
|||||||
### Binding Type
|
### Binding Type
|
||||||
|
|
||||||
|
|
||||||
* "Action" if the image should display the current mapping for an input action
|
* "Enhanced Input Action" to specify an [Enhanced Input](https://docs.unrealengine.com/5.1/en-US/enhanced-input-in-unreal-engine/) action
|
||||||
* "Axis" to look up an input axis
|
* "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)
|
* "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
|
### Action or Axis Name
|
||||||
|
|
||||||
The name of the input action or axis that should be looked up to determine the
|
The name of the input action or axis that should be looked up to determine the
|
||||||
|
@ -33,13 +33,21 @@ related to input controls. There are various options:
|
|||||||
|
|
||||||
## Adding input images to rich text
|
## 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"/>`
|
`<input action="TheActionName"/>`
|
||||||
|
|
||||||
This displays the image for a bound action input, as configured in project settings.
|
This displays the image for a bound action input, as configured in project settings.
|
||||||
|
|
||||||
### Input Axes
|
### Legacy Input Axes
|
||||||
|
|
||||||
`<input axis="TheAxisName"/>`
|
`<input axis="TheAxisName"/>`
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user