Files

233 lines
8.1 KiB
C++

// Copyright Epic Games, Inc. All Rights Reserved.
// UE5 Modular Game Framework — SS_EnhancedInputManager (128)
// Sole authority for Push/Pop input context, key rebinding, and input mode changes.
// In C++, directly wraps UEnhancedInputLocalPlayerSubsystem with priority-based
// context stack management.
#pragma once
#include "CoreMinimal.h"
#include "Subsystems/GameInstanceSubsystem.h"
#include "GameplayTagContainer.h"
#include "InputAction.h"
#include "SS_EnhancedInputManager.generated.h"
class UInputMappingContext;
class UInputAction;
class UEnhancedInputLocalPlayerSubsystem;
/**
* Input context priority ladder.
* Higher priority contexts override lower priority for conflicting inputs.
*/
UENUM(BlueprintType)
enum class EInputContextPriority : uint8
{
Default = 0 UMETA(DisplayName = "Default (0)"),
Hiding = 5 UMETA(DisplayName = "Hiding (5)"),
Wristwatch = 10 UMETA(DisplayName = "Wristwatch UI (10)"),
Inspection = 20 UMETA(DisplayName = "Inspection (20)"),
UI = 100 UMETA(DisplayName = "UI (100)"),
};
/**
* Mapping context entry in the stack.
*/
USTRUCT(BlueprintType)
struct PG_FRAMEWORK_API FInputContextEntry
{
GENERATED_BODY()
UPROPERTY(BlueprintReadOnly)
TObjectPtr<UInputMappingContext> Context = nullptr;
UPROPERTY(BlueprintReadOnly)
EInputContextPriority Priority = EInputContextPriority::Default;
UPROPERTY(BlueprintReadOnly)
FGameplayTag ContextTag; // For identification: Framework.Input.Context.Default, etc.
bool operator==(const FInputContextEntry& Other) const
{
return Context == Other.Context;
}
};
// Delegates
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnContextPushed, FGameplayTag, ContextTag, EInputContextPriority, Priority);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnContextPopped, FGameplayTag, ContextTag, EInputContextPriority, Priority);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnInputModeChanged, bool, bUIMode, bool, bShowCursor);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FOnKeyRebound, FGameplayTag, ActionTag, FKey, NewKey);
/**
* SS_EnhancedInputManager — Input Context Stack Authority.
*
* Manages all Enhanced Input Mapping Contexts with priority-based ordering.
* Systems call PushContext/PopContext instead of directly touching the
* Enhanced Input subsystem. Coordinates input mode (game/UI) with SS_UIManager.
*
* C++ gives us direct UEnhancedInputLocalPlayerSubsystem access — no
* "Get Enhanced Input Local Player Subsystem" node chains.
*/
UCLASS()
class PG_FRAMEWORK_API USS_EnhancedInputManager : public UGameInstanceSubsystem
{
GENERATED_BODY()
public:
USS_EnhancedInputManager();
// ========================================================================
// Lifecycle
// ========================================================================
virtual void Initialize(FSubsystemCollectionBase& Collection) override;
virtual void Deinitialize() override;
// ========================================================================
// Context Stack Management
// ========================================================================
/**
* Push an input mapping context onto the stack.
* Higher priority contexts override lower for conflicting inputs.
* Duplicate protection — if the context is already active, it's moved to top.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Input")
void PushContext(UInputMappingContext* Context, EInputContextPriority Priority, FGameplayTag ContextTag);
/**
* Remove an input mapping context from the stack.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Input")
void PopContext(UInputMappingContext* Context);
/**
* Pop a context by its GameplayTag identifier.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Input")
void PopContextByTag(FGameplayTag ContextTag);
/**
* Clear ALL contexts from the stack (e.g., on level transition).
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Input")
void ClearAllContexts();
/**
* Returns whether a context is currently active on the stack.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Input")
bool IsContextActive(FGameplayTag ContextTag) const;
/**
* Returns the currently highest-priority active context.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Input")
FGameplayTag GetTopContext() const;
// ========================================================================
// Input Mode Coordination
// ========================================================================
/**
* Switch between game input mode and UI input mode.
* Coordinates cursor visibility and input blocking with SS_UIManager.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Input")
void SetInputMode(bool bUIMode, bool bShowCursor = true, bool bLockMouseToViewport = false);
/** Returns whether UI input mode is active. */
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Input")
bool IsUIMode() const { return bCurrentUIMode; }
// ========================================================================
// Key Rebinding
// ========================================================================
/**
* Rebind a key for a specific input action.
* Persists via SS_SettingsSystem.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Input")
void RebindKey(UInputAction* Action, FKey NewKey, bool bSaveToDisk = true);
/**
* Reset all key bindings to defaults.
*/
UFUNCTION(BlueprintCallable, Category = "Framework|Input")
void ResetAllBindings();
/**
* Get the current key bound to an input action.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Input")
FKey GetBoundKey(UInputAction* Action) const;
// ========================================================================
// Query
// ========================================================================
/**
* Check if a specific input action is currently being pressed.
* Use this instead of raw Enhanced Input queries.
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Input")
bool IsActionPressed(UInputAction* Action) const;
/**
* Get the current value of an input action (0.0 to 1.0 for digital, axis value for analog).
*/
UFUNCTION(BlueprintCallable, BlueprintPure, Category = "Framework|Input")
float GetActionValue(UInputAction* Action) const;
// ========================================================================
// Configuration
// ========================================================================
/** Default input mapping contexts (loaded on initialize). */
UPROPERTY(EditAnywhere, BlueprintReadOnly, Category = "Framework|Input|Config")
TArray<TObjectPtr<UInputMappingContext>> DefaultContexts;
// ========================================================================
// Event Dispatchers
// ========================================================================
UPROPERTY(BlueprintAssignable, Category = "Framework|Input|Events")
FOnContextPushed OnContextPushed;
UPROPERTY(BlueprintAssignable, Category = "Framework|Input|Events")
FOnContextPopped OnContextPopped;
UPROPERTY(BlueprintAssignable, Category = "Framework|Input|Events")
FOnInputModeChanged OnInputModeChanged;
UPROPERTY(BlueprintAssignable, Category = "Framework|Input|Events")
FOnKeyRebound OnKeyRebound;
protected:
// ========================================================================
// Internal State
// ========================================================================
/** Ordered context stack (highest priority at the end/newest). */
TArray<FInputContextEntry> ContextStack;
/** Whether UI input mode is currently active. */
bool bCurrentUIMode = false;
/** Cached Enhanced Input subsystem. */
UPROPERTY()
TObjectPtr<UEnhancedInputLocalPlayerSubsystem> EnhancedInputSubsystem;
// ========================================================================
// Internal Methods
// ========================================================================
/** Re-sorts the context stack by priority and re-applies to the subsystem. */
void RebuildContextStack();
/** Gets the Enhanced Input subsystem, caching it if needed. */
UEnhancedInputLocalPlayerSubsystem* GetEnhancedInputSubsystem() const;
};