// 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 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> 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 ContextStack; /** Whether UI input mode is currently active. */ bool bCurrentUIMode = false; /** Cached Enhanced Input subsystem. */ UPROPERTY() TObjectPtr 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; };