mirror of
https://github.com/sinbad/StevesUEHelpers.git
synced 2025-02-23 09:35:25 +00:00
Improve input image behaviour when there are multiple device mappings.
Add a device preference, which defaults to automatic (gamepad, then either mouse or keyboard depending if its a button or an axis). Also change the ordering so that multiple mappings for the same device list the first mapping as a preference.
This commit is contained in:
parent
5ba7a841e4
commit
0cd30059f5
@ -8,6 +8,7 @@
|
||||
#include "GameFramework/PlayerController.h"
|
||||
#include "GameFramework/PlayerInput.h"
|
||||
#include "StevesUI/KeySprite.h"
|
||||
#include "StevesUI/StevesUI.h"
|
||||
|
||||
//PRAGMA_DISABLE_OPTIMIZATION
|
||||
|
||||
@ -126,15 +127,19 @@ FFocusSystem* UStevesGameSubsystem::GetFocusSystem()
|
||||
return &FocusSystem;
|
||||
}
|
||||
|
||||
UPaperSprite* UStevesGameSubsystem::GetInputImageSprite(EInputBindingType BindingType, FName ActionOrAxis,
|
||||
FKey Key, int PlayerIdx, const UUiTheme* Theme)
|
||||
UPaperSprite* UStevesGameSubsystem::GetInputImageSprite(EInputBindingType BindingType,
|
||||
FName ActionOrAxis,
|
||||
FKey Key,
|
||||
EInputImageDevicePreference DevicePreference,
|
||||
int PlayerIdx,
|
||||
const UUiTheme* Theme)
|
||||
{
|
||||
switch(BindingType)
|
||||
{
|
||||
case EInputBindingType::Action:
|
||||
return GetInputImageSpriteFromAction(ActionOrAxis, PlayerIdx, Theme);
|
||||
return GetInputImageSpriteFromAction(ActionOrAxis, DevicePreference, PlayerIdx, Theme);
|
||||
case EInputBindingType::Axis:
|
||||
return GetInputImageSpriteFromAxis(ActionOrAxis, PlayerIdx, Theme);
|
||||
return GetInputImageSpriteFromAxis(ActionOrAxis, DevicePreference, PlayerIdx, Theme);
|
||||
case EInputBindingType::Key:
|
||||
return GetInputImageSpriteFromKey(Key, PlayerIdx, Theme);
|
||||
default:
|
||||
@ -146,48 +151,46 @@ UPaperSprite* UStevesGameSubsystem::GetInputImageSprite(EInputBindingType Bindin
|
||||
TArray<FInputActionKeyMapping> GS_TempActionMap;
|
||||
TArray<FInputAxisKeyMapping> GS_TempAxisMap;
|
||||
|
||||
UPaperSprite* UStevesGameSubsystem::GetInputImageSpriteFromAction(const FName& Name, int PlayerIdx, const UUiTheme* Theme)
|
||||
UPaperSprite* UStevesGameSubsystem::GetInputImageSpriteFromAction(const FName& Name,
|
||||
EInputImageDevicePreference DevicePreference,
|
||||
int PlayerIdx,
|
||||
const UUiTheme* Theme)
|
||||
{
|
||||
|
||||
// Look up the key for this action
|
||||
UInputSettings* Settings = UInputSettings::GetInputSettings();
|
||||
GS_TempActionMap.Empty();
|
||||
Settings->GetActionMappingByName(Name, GS_TempActionMap);
|
||||
const bool WantGamepad = LastInputWasGamePad(PlayerIdx);
|
||||
for (auto && ActionMap : GS_TempActionMap)
|
||||
|
||||
// For default, prefer keyboard for buttons
|
||||
if (DevicePreference == EInputImageDevicePreference::Auto)
|
||||
DevicePreference = EInputImageDevicePreference::Gamepad_Keyboard_Mouse;
|
||||
|
||||
const auto Preferred = GetPreferedActionOrAxisMapping<FInputActionKeyMapping>(GS_TempActionMap, Name, DevicePreference, LastInputWasGamePad(PlayerIdx));
|
||||
if (Preferred)
|
||||
{
|
||||
if (ActionMap.Key.IsGamepadKey() == WantGamepad)
|
||||
{
|
||||
return GetInputImageSpriteFromKey(ActionMap.Key, PlayerIdx, Theme);
|
||||
}
|
||||
}
|
||||
// if we fell through, didn't find a mapping which matched our gamepad preference
|
||||
if (GS_TempActionMap.Num())
|
||||
{
|
||||
return GetInputImageSpriteFromKey(GS_TempActionMap[0].Key, PlayerIdx, Theme);
|
||||
return GetInputImageSpriteFromKey(Preferred->Key, PlayerIdx, Theme);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
UPaperSprite* UStevesGameSubsystem::GetInputImageSpriteFromAxis(const FName& Name, int PlayerIdx, const UUiTheme* Theme)
|
||||
UPaperSprite* UStevesGameSubsystem::GetInputImageSpriteFromAxis(const FName& Name,
|
||||
EInputImageDevicePreference DevicePreference,
|
||||
int PlayerIdx,
|
||||
const UUiTheme* Theme)
|
||||
{
|
||||
// Look up the key for this axis
|
||||
UInputSettings* Settings = UInputSettings::GetInputSettings();
|
||||
GS_TempAxisMap.Empty();
|
||||
Settings->GetAxisMappingByName(Name, GS_TempAxisMap);
|
||||
const bool WantGamepad = LastInputWasGamePad(PlayerIdx);
|
||||
for (auto && AxisMap : GS_TempAxisMap)
|
||||
|
||||
// For default, prefer mouse for axes
|
||||
if (DevicePreference == EInputImageDevicePreference::Auto)
|
||||
DevicePreference = EInputImageDevicePreference::Gamepad_Mouse_Keyboard;
|
||||
|
||||
const auto Preferred = GetPreferedActionOrAxisMapping<FInputAxisKeyMapping>(GS_TempAxisMap, Name, DevicePreference, LastInputWasGamePad(PlayerIdx));
|
||||
if (Preferred)
|
||||
{
|
||||
if (AxisMap.Key.IsGamepadKey() == WantGamepad)
|
||||
{
|
||||
return GetInputImageSpriteFromKey(AxisMap.Key, PlayerIdx, Theme);
|
||||
}
|
||||
return GetInputImageSpriteFromKey(Preferred->Key, PlayerIdx, Theme);
|
||||
}
|
||||
// if we fell through, didn't find a mapping which matched our gamepad preference
|
||||
if (GS_TempAxisMap.Num())
|
||||
{
|
||||
return GetInputImageSpriteFromKey(GS_TempAxisMap[0].Key, PlayerIdx, Theme);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
@ -72,7 +72,7 @@ void UInputImage::UpdateImage()
|
||||
auto GS = GetStevesGameSubsystem(GetWorld());
|
||||
if (GS)
|
||||
{
|
||||
auto Sprite = GS->GetInputImageSprite(BindingType, ActionOrAxisName, Key, PlayerIndex, CustomTheme);
|
||||
auto Sprite = GS->GetInputImageSprite(BindingType, ActionOrAxisName, Key, DevicePreference, PlayerIndex, CustomTheme);
|
||||
if (Sprite)
|
||||
{
|
||||
// Match size is needed incase size has changed
|
||||
|
@ -122,7 +122,7 @@ public:
|
||||
if (GS)
|
||||
{
|
||||
// Can only support default theme, no way to edit theme in decorator config
|
||||
auto Sprite = GS->GetInputImageSprite(BindingType, ActionOrAxisName, Key, PlayerIndex);
|
||||
auto Sprite = GS->GetInputImageSprite(BindingType, ActionOrAxisName, Key, EInputImageDevicePreference::Auto, PlayerIndex);
|
||||
if (Sprite && Brush.GetResourceObject() != Sprite)
|
||||
{
|
||||
UStevesGameSubsystem::SetBrushFromAtlas(&Brush, Sprite, true);
|
||||
@ -214,7 +214,7 @@ protected:
|
||||
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.PlayerIndex);
|
||||
Params.InitialSprite = GS->GetInputImageSprite(Params.BindingType, Params.ActionOrAxisName, Params.Key, EInputImageDevicePreference::Auto, Params.PlayerIndex);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -1,6 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "CoreMinimal.h"
|
||||
#include "StevesHelperCommon.h"
|
||||
|
||||
class UWidget;
|
||||
class SWidget;
|
||||
@ -24,3 +25,55 @@ UWidget* FindWidgetFromSlate(SWidget* SW, UWidget* Parent);
|
||||
* @param Widget A UWidget
|
||||
*/
|
||||
void SetWidgetFocusProperly(UWidget* Widget);
|
||||
|
||||
template <typename T>
|
||||
const T* GetPreferedActionOrAxisMapping(const TArray<T>& AllMappings, const FName& Name,
|
||||
EInputImageDevicePreference DevicePreference,
|
||||
bool bLastInputWasGamepad)
|
||||
{
|
||||
const T* MouseMapping = nullptr;
|
||||
const T* KeyboardMapping = nullptr;
|
||||
const T* GamepadMapping = nullptr;
|
||||
for (const T& ActionMap : AllMappings)
|
||||
{
|
||||
// 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 (ActionMap.Key.IsGamepadKey())
|
||||
{
|
||||
GamepadMapping = &ActionMap;
|
||||
}
|
||||
else if (ActionMap.Key.IsMouseButton())
|
||||
{
|
||||
MouseMapping = &ActionMap;
|
||||
}
|
||||
else
|
||||
{
|
||||
KeyboardMapping = &ActionMap;
|
||||
}
|
||||
}
|
||||
|
||||
const T* Preferred = nullptr;
|
||||
if (GamepadMapping && bLastInputWasGamepad)
|
||||
{
|
||||
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;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
return Preferred;
|
||||
}
|
||||
|
@ -161,29 +161,48 @@ public:
|
||||
* @param BindingType The type of input binding to look up
|
||||
* @param ActionOrAxis The name of the action or axis, if BindingType is looking for that
|
||||
* @param Key The explicit key you want to display, if the BindingType is set to custom key
|
||||
* @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 PlayerIndex The player index to look up the binding for
|
||||
* @param Theme Optional explicit theme, if blank use the default theme
|
||||
* @return
|
||||
*/
|
||||
UFUNCTION(BlueprintCallable)
|
||||
UPaperSprite* GetInputImageSprite(EInputBindingType BindingType, FName ActionOrAxis, FKey Key, int PlayerIndex = 0, const UUiTheme* Theme = nullptr);
|
||||
UPaperSprite* GetInputImageSprite(EInputBindingType BindingType,
|
||||
FName ActionOrAxis,
|
||||
FKey Key,
|
||||
EInputImageDevicePreference DevicePreference,
|
||||
int PlayerIndex = 0,
|
||||
const UUiTheme* Theme = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Get an input button / key image from an action
|
||||
* @param Name The name of the 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 PlayerIndex The player index to look up the binding for
|
||||
* @param Theme Optional explicit theme, if blank use the default theme
|
||||
* @return
|
||||
*/
|
||||
UPaperSprite* GetInputImageSpriteFromAction(const FName& Name, int PlayerIndex = 0, const UUiTheme* Theme = nullptr);
|
||||
UPaperSprite* GetInputImageSpriteFromAction(const FName& Name,
|
||||
EInputImageDevicePreference DevicePreference =
|
||||
EInputImageDevicePreference::Gamepad_Keyboard_Mouse,
|
||||
int PlayerIndex = 0,
|
||||
const UUiTheme* Theme = nullptr);
|
||||
/**
|
||||
* @brief Get an input image from an axis
|
||||
* @param Name The name of the axis
|
||||
* @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 PlayerIndex The player index to look up the binding for
|
||||
* @param Theme Optional explicit theme, if blank use the default theme
|
||||
* @return
|
||||
*/
|
||||
UPaperSprite* GetInputImageSpriteFromAxis(const FName& Name, int PlayerIndex = 0, const UUiTheme* Theme = nullptr);
|
||||
UPaperSprite* GetInputImageSpriteFromAxis(const FName& Name,
|
||||
EInputImageDevicePreference DevicePreference =
|
||||
EInputImageDevicePreference::Gamepad_Mouse_Keyboard,
|
||||
int PlayerIndex = 0,
|
||||
const UUiTheme* Theme = nullptr);
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get an input image for a specific key
|
||||
|
@ -49,3 +49,15 @@ enum class EInputBindingType : uint8
|
||||
Key = 2
|
||||
};
|
||||
|
||||
/// What order of preference should we return input images where an action/axis has multiple mappings
|
||||
UENUM(BlueprintType)
|
||||
enum class EInputImageDevicePreference : uint8
|
||||
{
|
||||
/// For actions, use Gamepad_Keyboard_Mouse, for axes, use Gamepad_Mouse_Keyboard
|
||||
Auto,
|
||||
/// Gamepad first, then keyboard, then mouse - this is usually best for actions (buttons)
|
||||
Gamepad_Keyboard_Mouse UMETA(DisplayName="Prefer Gamepad (if active), then keyboard, then mouse"),
|
||||
/// Gamepad first, then mouse, then keyboard - this is usually best for axes
|
||||
Gamepad_Mouse_Keyboard UMETA(DisplayName="Prefer Gamepad (if active), then mouse, then keyboard")
|
||||
};
|
||||
|
||||
|
@ -23,6 +23,10 @@ protected:
|
||||
UPROPERTY(EditAnywhere)
|
||||
FName ActionOrAxisName;
|
||||
|
||||
/// Where there are multiple mappings, which to prefer
|
||||
UPROPERTY(EditAnywhere)
|
||||
EInputImageDevicePreference DevicePreference = EInputImageDevicePreference::Auto;
|
||||
|
||||
/// If BindingType is Key, the key
|
||||
UPROPERTY(EditAnywhere)
|
||||
FKey Key;
|
||||
|
@ -28,6 +28,16 @@ key that we'll need an image for.
|
||||
|
||||
You can leave this blank if you set Binding Type to "Key".
|
||||
|
||||
### Device Preference
|
||||
|
||||
When using an Action or Axis Name, which device to prefer to show the image for
|
||||
where there are multiple mappings. The default is "Auto", which means:
|
||||
|
||||
1. Gamepad, if the last used device was gamepad
|
||||
2. If an Action (button/key), prefer Keyboard over Mouse buttons
|
||||
3. If an Axis, prefer Mouse over Keyboard
|
||||
|
||||
|
||||
### Key
|
||||
|
||||
If you don't want the InputImage to look up an action, but want to manually specify
|
||||
|
Loading…
x
Reference in New Issue
Block a user