Finish implementing IsKeyUsedByPlayerController

This commit is contained in:
2025-05-27 16:30:49 -04:00
parent 40da211985
commit 23194ac0e5
9 changed files with 140 additions and 168 deletions

Binary file not shown.

Binary file not shown.

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#include "CommonTypes.generated.h"
namespace CommonTypes { namespace CommonTypes {
// Array of tangible IDs. // Array of tangible IDs.
using IdArray = TArray<int64>; using IdArray = TArray<int64>;
@@ -10,3 +12,47 @@ namespace CommonTypes {
// Array of std::string_view // Array of std::string_view
using StringViewVec = TArray<std::string_view>; using StringViewVec = TArray<std::string_view>;
} }
UENUM(BlueprintType)
enum class ElxLuaValueType : uint8 {
End,
String,
Name,
Float,
Boolean,
Vector
};
/////////////////////////////////////////////////////////////////
//
// A variety of boolean-like results that can be conveniently
// be used in conjunction with 'ExpandEnumAsExecs' to create
// branching functions.
//
/////////////////////////////////////////////////////////////////
UENUM(BlueprintType)
enum class ElxSuccessOrError : uint8 {
Success,
Error,
};
UENUM(BlueprintType)
enum class ElxFoundOrNotFound : uint8 {
Found,
NotFound,
};
UENUM(BlueprintType)
enum class ElxUsedOrNotUsed : uint8 {
Used,
NotUsed,
};
UENUM(BlueprintType)
enum class ElxSuccessOrWrongType : uint8 {
Success,
WrongType,
};

View File

@@ -13,6 +13,7 @@ public class Integration : ModuleRules
"CoreUObject", "CoreUObject",
"Engine", "Engine",
"InputCore", "InputCore",
"SlateCore",
"Sockets", "Sockets",
"Networking", "Networking",
"EnhancedInput", "EnhancedInput",

View File

@@ -15,40 +15,6 @@ class UlxLuaValues;
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
UENUM(BlueprintType)
enum class ElxLuaValueType : uint8 {
End,
String,
Name,
Float,
Boolean,
Vector
};
/////////////////////////////////////////////////////////////////
//
// A general-purpose 'success or error' type.
//
/////////////////////////////////////////////////////////////////
UENUM(BlueprintType)
enum class ElxSuccessOrError : uint8 {
Success,
Error,
};
UENUM(BlueprintType)
enum class ElxFoundOrNotFound : uint8 {
Found,
NotFound,
};
UENUM(BlueprintType)
enum class ElxSuccessOrWrongType : uint8 {
Success,
WrongType,
};
///////////////////////////////////////////////////////////////// /////////////////////////////////////////////////////////////////
// //
// This is a little parser that parses Lua function 'prototypes'. // This is a little parser that parses Lua function 'prototypes'.

View File

@@ -1,56 +0,0 @@
#include "StoreFNameInputModifier.h"
#include "EnhancedPlayerInput.h"
#include "LuprexGameModeBase.h"
static const int ENCODE_LIMIT = 0x00FFFFFF;
FInputActionValue UPassFNameAsAxis3D::ModifyRaw_Implementation(const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime)
{
// Internally, an FName is stored as three integers:
// ComparisonIndex, DisplayIndex, and Number. These numbers
// are only valid within a single unreal process, but that's OK.
// We copy these three numbers into an Axis3D.
//
// Yes, that's ugly. It would be nicer if FName was one
// of the types explicitly allowed in an FInputActionValue.
// Maybe some day!
//
// Integers larger than ENCODE_LIMIT cannot be losslessly
// converted to float. Such numbers should never occur in
// practice: the string table should not contain that many
// strings!
//
uint32 cidx = FNameToStore.GetComparisonIndex().ToUnstableInt();
uint32 didx = FNameToStore.GetDisplayIndex().ToUnstableInt();
uint32 nidx = FNameToStore.GetNumber();
// Make sure the three integers will fit into three floats without rounding or overflow.
if ((cidx > ENCODE_LIMIT) || (didx > ENCODE_LIMIT) || (nidx > ENCODE_LIMIT))
{
UE_LOG(LogLuprexIntegration, Error, TEXT("Name cannot be converted to FInputActionValue: %s"), *FNameToStore.ToString());
return FInputActionValue(FVector());
}
return FInputActionValue(FVector(cidx, didx, nidx));
}
FName UPassFNameAsAxis3D::DecodeFNameFromAxis3D(const FVector &Vec)
{
uint32 cidx = static_cast<uint32>(Vec.X);
uint32 didx = static_cast<uint32>(Vec.Y);
uint32 nidx = static_cast<uint32>(Vec.Z);
FName Result(FNameEntryId::FromUnstableInt(cidx), FNameEntryId::FromUnstableInt(didx), nidx);
FName Inverse(FNameEntryId::FromUnstableInt(didx), FNameEntryId::FromUnstableInt(cidx), nidx);
if ((double(cidx) != Vec.X) || (double(didx) != Vec.Y) || (double(nidx) != Vec.Z) ||
(cidx > ENCODE_LIMIT) || (didx > ENCODE_LIMIT) || (nidx > ENCODE_LIMIT) ||
(!Result.IsValid()) || (!Inverse.IsValid()))
{
UE_LOG(LogLuprexIntegration, Error, TEXT("FVector is not an encoded FName."));
return NAME_None;
}
return Result;
}

View File

@@ -1,54 +0,0 @@
#pragma once
#include "CoreMinimal.h"
#include "InputModifiers.h"
#include "StoreFNameInputModifier.generated.h"
/**
* @brief Allows you to pass an FName into an event handler.
*
* This modifier allows you to type an FName directly into an input mapping in
* the InputMappingContext editor, and have that FName passed through to an
* enhanced input handler.
*
* This modifier has an FName UPROPERTY which is editable in the InputMappingContext
* editor. At runtime, it encodes the FName as an Axis3D. In the event handler,
* the Axis3D can be decoded back into an FName using DecodeFNameFromAxis3D.
*
* One use for this modifier is when you want to know exactly which
* keyboard key triggered an EnhancedInput event. You can put the key's FName
* into the InputMappingContext, and it will get passed through to the event
* handler.
*
*/
UCLASS()
class INTEGRATION_API UPassFNameAsAxis3D : public UInputModifier
{
GENERATED_BODY()
public:
/**
* @brief The FName to be encoded into the FInputActionValue.
*
* This property can be configured in the Input Mapping Context editor
* for each specific mapping.
*
*/
UPROPERTY(EditAnywhere, BlueprintReadWrite, Category = "Modifier Settings")
FName FNameToStore;
protected:
virtual FInputActionValue ModifyRaw_Implementation(const UEnhancedPlayerInput* PlayerInput, FInputActionValue CurrentValue, float DeltaTime) override;
/**
* @brief Decodes an FName that was passed by the PassFnameAsAxis3D modifier.
*
* This function is used in an enhanced input event, where the PassFNameAsAxis3D
* modifier was used to pass an FName into the event. The value shows up as
* an Axis3D, which much be decoded back into an FName.
*
*/
UFUNCTION(BlueprintPure, Category = "Input|Enhanced")
static FName DecodeFNameFromAxis3D(const FVector& Encoded);
};

View File

@@ -9,7 +9,7 @@
#include "Blueprint/UserWidget.h" #include "Blueprint/UserWidget.h"
#include "Components/GridPanel.h" #include "Components/GridPanel.h"
#include "InputMappingContext.h" #include "InputMappingContext.h"
#include "EnhancedInputComponent.h"
#define LOCTEXT_NAMESPACE "Luprex Utility" #define LOCTEXT_NAMESPACE "Luprex Utility"
@@ -212,20 +212,80 @@ void UlxUtilityLibrary::GetPositionOfGridPanelMiddleCell(UGridPanel *GridPanel,
} }
} }
void UlxUtilityLibrary::MapAllKeyboardKeysToOneInputAction(UInputMappingContext *IMC, UInputAction *Action) ElxUsedOrNotUsed UlxUtilityLibrary::IsKeyUsedByMappingContext(const FKeyEvent &KeyEvent, const UInputMappingContext *MappingContext)
{ {
TArray<FKey> AllKeys; FKey Key = KeyEvent.GetKey();
EKeys::GetAllKeys(AllKeys);
// Map every keyboard key to the provided LuaAction if (!MappingContext)
for (const FKey& Key : AllKeys)
{ {
if ((Key.IsValid()) && return ElxUsedOrNotUsed::NotUsed;
(Key.IsBindableInBlueprints()) && }
(Key.GetMenuCategory() == EKeys::NAME_KeyboardCategory) &&
(!Key.IsModifierKey())) for (const FEnhancedActionKeyMapping& Mapping : MappingContext->GetMappings())
{ {
IMC->MapKey(Action, Key); if (Mapping.Key == Key)
{
return ElxUsedOrNotUsed::Used;
} }
} }
return ElxUsedOrNotUsed::NotUsed;
}
class UEnhancedPlayerInputExposed : public UEnhancedPlayerInput
{
public:
const TArray<FEnhancedActionKeyMapping>& GetEnhancedActionMappings() const { return UEnhancedPlayerInput::GetEnhancedActionMappings(); }
};
ElxUsedOrNotUsed UlxUtilityLibrary::IsKeyUsedByPlayerController(const FKeyEvent &KeyEvent, bool IncludeEscapeAndFkeys, const APlayerController *PlayerController, const UObject *Context)
{
if (PlayerController == nullptr) PlayerController = Context->GetWorld()->GetFirstPlayerController();
FKey Key = KeyEvent.GetKey();
UEnhancedPlayerInput *PlayerInput = Cast<UEnhancedPlayerInput>(PlayerController->PlayerInput);
if (PlayerInput == nullptr)
{
return ElxUsedOrNotUsed::NotUsed;
}
UEnhancedPlayerInputExposed *Exposed = static_cast<UEnhancedPlayerInputExposed *>(PlayerInput);
for (const FInputActionKeyMapping& ActionMapping : Exposed->ActionMappings)
{
if (ActionMapping.Key == Key)
{
return ElxUsedOrNotUsed::Used; // Found a match in legacy Action Mappings.
}
}
for (const FInputAxisKeyMapping& AxisMapping : Exposed->AxisMappings)
{
if (AxisMapping.Key == Key)
{
return ElxUsedOrNotUsed::Used; // Found a match in legacy Axis Mappings.
}
}
for (const FEnhancedActionKeyMapping& Mapping : Exposed->GetEnhancedActionMappings())
{
if (Mapping.Key == Key)
{
return ElxUsedOrNotUsed::Used; // Found a match in the active, flattened mappings.
}
}
if (IncludeEscapeAndFkeys)
{
if (Key == EKeys::Escape ||
Key == EKeys::F1 || Key == EKeys::F2 || Key == EKeys::F3 ||
Key == EKeys::F4 || Key == EKeys::F5 || Key == EKeys::F6 ||
Key == EKeys::F7 || Key == EKeys::F8 || Key == EKeys::F9 ||
Key == EKeys::F10 || Key == EKeys::F11 || Key == EKeys::F12)
{
return ElxUsedOrNotUsed::Used;
}
}
return ElxUsedOrNotUsed::NotUsed;
} }

View File

@@ -4,7 +4,8 @@
#include "CoreMinimal.h" #include "CoreMinimal.h"
#include "Kismet/KismetSystemLibrary.h" #include "Kismet/KismetSystemLibrary.h"
#include "Input/Events.h"
#include "CommonTypes.h"
#include "UtilityLibrary.generated.h" #include "UtilityLibrary.generated.h"
class UEnhancedInputLocalPlayerSubsystem; class UEnhancedInputLocalPlayerSubsystem;
@@ -132,13 +133,21 @@ public:
UFUNCTION(BlueprintPure, Category="Widget") UFUNCTION(BlueprintPure, Category="Widget")
static void GetPositionOfGridPanelMiddleCell(UGridPanel *GridPanel, FVector2D &UpperLeftXY, FVector2D &LowerRightXY); static void GetPositionOfGridPanelMiddleCell(UGridPanel *GridPanel, FVector2D &UpperLeftXY, FVector2D &LowerRightXY);
// Create a mapping context that maps all keyboard keys to a single input action. // Check if a given key is used by the mapping context.
// //
// This mapping context is usually meant to be used in conjunction with a UFUNCTION(BlueprintCallable, Category = "Input", meta = (ExpandEnumAsExecs="ReturnValue"))
// hand-crafted mapping context, to act as a catch-all that catches all static ElxUsedOrNotUsed IsKeyUsedByMappingContext(const FKeyEvent &KeyEvent, const UInputMappingContext *MappingContext);
// keys that aren't mapped in the hand-crafted mapping.
//
UFUNCTION(BlueprintCallable, Category="Input", meta=(WorldContext="WorldContextObject"))
static void MapAllKeyboardKeysToOneInputAction(UInputMappingContext *IMC, UInputAction *Action);
// Check if a given key is used by the player controller.
//
// If you pass in a null pointer for the player controller, then this
// function will use the first player controller by default.
//
// If 'Include Escape and FKeys' is checked, then the escape key
// and the function keys are also considered to be 'used' by the
// player controller. It is generally a good idea to treat these
// keys as reserved for play-in-editor.
//
UFUNCTION(BlueprintCallable, Category = "Input", meta = (WorldContext="Context", ExpandEnumAsExecs="ReturnValue", IncludeEscapeAndFkeys="true"))
static ElxUsedOrNotUsed IsKeyUsedByPlayerController(const FKeyEvent &KeyEvent, bool IncludeEscapeAndFkeys, const APlayerController *PlayerController, const UObject *Context);
}; };