# 128 — Enhanced Input Manager (`SS_EnhancedInputManager`) ## Purpose Centralized Game Instance Subsystem that manages all UE5 Enhanced Input operations: Input Mapping Context push/pop with priority stack, platform-specific binding profiles, key rebinding, input mode coordination with [`SS_UIManager`](docs/blueprints/06-ui/44_SS_UIManager.md), and read-only input state queries for gameplay systems. ## Dependencies - **Requires:** [`DA_InputMappingProfile`](docs/blueprints/14-data-assets/129_DA_InputMappingProfile.md) (platform profiles), [`GI_GameFramework`](docs/blueprints/01-core/04_GI_GameFramework.md) (subsystem access) - **Required By:** All gameplay systems that read input (`BPC_InteractionDetector`, `BPC_FirearmSystem`, `BPC_MovementStateSystem`, `BPC_CutsceneBridge`, `BPC_HidingSystem`, `BPC_ActiveItemSystem`, etc.) - **Engine/Plugin Requirements:** Enhanced Input Plugin (UE5 built-in), `UEnhancedInputLocalPlayerSubsystem` ## Class Info | Property | Value | |----------|-------| | **Parent Class** | `UGameInstanceSubsystem` | | **Class Type** | Game Instance Subsystem | | **Asset Path** | `Content/Framework/Core/SS_EnhancedInputManager` | | **Implements Interfaces** | None | --- ## 1. Enums ### `E_InputContext` | Value | Description | |-------|-------------| | `Default = 0` | Core gameplay (IMC_Default, Priority 0) | | `Hiding = 1` | Hiding spot controls (IMC_Hiding, Priority 5) | | `WristwatchUI = 2` | Inventory/watch navigation (IMC_WristwatchUI, Priority 10) | | `Inspection = 3` | 3D item inspection (IMC_Inspection, Priority 20) | | `UI = 4` | Full-screen menus/pause (IMC_UI, Priority 100) | ### `E_InputPlatform` | Value | Description | |-------|-------------| | `PC_KeyboardMouse = 0` | Keyboard + Mouse | | `Xbox = 1` | Xbox Series X\|S / Xbox One | | `PS5_DualSense = 2` | PlayStation 5 DualSense | --- ## 2. Structs ### `S_ActiveContext` | Field | Type | Description | |-------|------|-------------| | `ContextType` | `E_InputContext` | Which context this is | | `Priority` | `Int32` | Current priority (may differ from default if overridden) | | `MappingContext` | `UInputMappingContext` | Reference to the IMC asset | | `TimePushed` | `Float` | Game time when context was added | | `bIsActive` | `Bool` | Whether currently active on the subsystem | ### `S_KeyBinding` | Field | Type | Description | |-------|------|-------------| | `ActionName` | `FName` | IA_ name this binding is for | | `Platform` | `E_InputPlatform` | Platform this binding applies to | | `Key` | `FKey` | Current bound key | | `DefaultKey` | `FKey` | Factory default key (for reset) | | `bIsAxis` | `Bool` | Whether this is an axis binding | --- ## 3. Variables ### Configuration (Set via Initialize) | Variable | Type | Default | Category | Description | |----------|------|---------|----------|-------------| | `InputProfile` | `DA_InputMappingProfile` | `None` | `Config` | Platform profile reference | | `DefaultContextPriority` | `TMap` | `{Default:0, Hiding:5, WristwatchUI:10, Inspection:20, UI:100}` | `Config` | Default priority table | ### Internal (Private) | Variable | Type | Default | Category | Description | |----------|------|---------|----------|-------------| | `ActiveContexts` | `TArray` | `Empty` | `State` | Currently pushed contexts (stack, highest first) | | `CurrentBindings` | `TMap>` | `Empty` | `State` | Current key bindings per platform | | `DefaultBindings` | `TMap>` | `Empty` | `State` | Factory default bindings | | `CurrentInputMode` | `E_InputMode` | `GameOnly` | `State` | Current input mode (synced with SS_UIManager) | | `bIsInitialized` | `Bool` | `false` | `State` | Whether Initialize has been called | | `LocalPlayerSubsystem` | `UEnhancedInputLocalPlayerSubsystem` | `None` | `Cache` | Cached reference to the Enhanced Input subsystem | --- ## 4. Functions ### Public Functions #### `Initialize` → `void` - **Description:** Loads platform profile, caches Enhanced Input subsystem, builds default binding table. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `Profile` | `DA_InputMappingProfile` | Platform profile to load | - **Blueprint Authority:** Any - **Flow:** 1. Set InputProfile = Profile 2. Cache EnhancedInputLocalPlayerSubsystem via GetOwningPlayerController() 3. Populate DefaultBindings for each platform from DA_InputMappingProfile 4. Copy DefaultBindings to CurrentBindings 5. Set bIsInitialized = true 6. Broadcast OnInputManagerInitialized #### `PushContext` → `void` - **Description:** Pushes an Input Mapping Context onto the player's active contexts. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `ContextType` | `E_InputContext` | Which context to push | | `PriorityOverride` | `Int32` | Optional priority override (-1 uses default) | - **Blueprint Authority:** Any - **Flow:** 1. Validate bIsInitialized and LocalPlayerSubsystem 2. If context already active: update priority if changed, return 3. Look up IMC from DA_InputMappingProfile for ContextType 4. Resolve priority: PriorityOverride if >= 0, else DefaultContextPriority[ContextType] 5. Call LocalPlayerSubsystem.AddMappingContext(IMC, Priority) 6. Add S_ActiveContext to ActiveContexts, sorted by priority descending 7. Broadcast OnContextPushed #### `PopContext` → `void` - **Description:** Removes an Input Mapping Context from the player's active contexts. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `ContextType` | `E_InputContext` | Which context to pop | - **Blueprint Authority:** Any - **Flow:** 1. Validate bIsInitialized 2. Find S_ActiveContext by ContextType 3. If not found: log warning, return 4. Call LocalPlayerSubsystem.RemoveMappingContext(IMC) 5. Remove from ActiveContexts 6. Broadcast OnContextPopped #### `SetContextPriority` → `void` - **Description:** Adjusts priority of an active context. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `ContextType` | `E_InputContext` | Target context | | `NewPriority` | `Int32` | New priority value | - **Flow:** Remove and re-add the IMC with new priority. #### `GetActiveContexts` → `TArray` - **Description:** Returns list of currently active context types. Read-only. #### `IsContextActive` → `Bool` - **Description:** Check if a specific context is active. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `ContextType` | `E_InputContext` | Context to check | #### `IsActionPressed` → `Bool` - **Description:** Read-only query: is an action currently pressed? - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `ActionName` | `FName` | IA_ name to check | - **Flow:** Delegates to `UEnhancedInputLocalPlayerSubsystem.IsPressed()` #### `GetActionValue1D` → `Float` - **Description:** Read-only query: current 1D axis value. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `ActionName` | `FName` | IA_ name to query | #### `GetActionValue2D` → `FVector2D` - **Description:** Read-only query: current 2D axis value. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `ActionName` | `FName` | IA_ name to query | #### `RebindKey` → `Bool` - **Description:** Rebinds an action to a new key for the given platform. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `ActionName` | `FName` | IA_ name | | `NewKey` | `FKey` | New key to bind | | `Platform` | `E_InputPlatform` | Which platform | - **Flow:** 1. Update CurrentBindings[Platform] 2. Modify the IMC's key mapping for the action 3. Broadcast OnKeyRebound 4. Return true if successful #### `ResetToDefaultBindings` → `void` - **Description:** Resets all bindings for a platform to defaults. - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `Platform` | `E_InputPlatform` | Which platform to reset | #### `GetCurrentBindings` → `TMap` - **Description:** Returns current key bindings for a platform (for settings UI). - **Parameters:** | Param | Type | Description | |-------|------|-------------| | `Platform` | `E_InputPlatform` | Which platform | #### `SetInputModeUIOnly` → `void` - **Description:** Switches to UI-only input mode (cursor visible, gameplay blocked). - **Flow:** Calls `PC_PlayerController.SetInputMode(UIOnly)` and syncs with `SS_UIManager` #### `SetInputModeGameOnly` → `void` - **Description:** Switches to game-only input mode (cursor hidden). - **Flow:** Calls `PC_PlayerController.SetInputMode(GameOnly)` and syncs with `SS_UIManager` #### `SetInputModeGameAndUI` → `void` - **Description:** Switches to game+UI input mode (cursor visible, game active). - **Flow:** Calls `PC_PlayerController.SetInputMode(GameAndUI)` and syncs with `SS_UIManager` --- ## 5. Event Dispatchers | Dispatcher | Parameters | Bind Access | Description | |------------|-----------|-------------|-------------| | `OnInputManagerInitialized` | — | `Public` | Fired after Initialize completes | | `OnContextPushed` | `E_InputContext Context`, `Int32 Priority` | `Public` | Fired when a new context is activated | | `OnContextPopped` | `E_InputContext Context` | `Public` | Fired when a context is removed | | `OnInputModeChanged` | `E_InputMode NewMode` | `Public` | Fired when input mode changes | | `OnKeyRebound` | `FName ActionName`, `FKey NewKey` | `Public` | Fired after key rebinding | | `OnPlatformChanged` | `E_InputPlatform NewPlatform` | `Public` | Fired on input device hot-swap | --- ## 6. Overridden Events / Custom Events ### Event: `Initialize` (Subsystem) - **Description:** Called by the engine when the subsystem is created. Does nothing — full init deferred to `Initialize(Profile)` to ensure DA is loaded first. - **Flow:** Cache self-reference for `FL_GameUtilities::GetInputManager()` ### Event: `Deinitialize` - **Description:** Cleanup on subsystem destruction. - **Flow:** 1. Pop all active contexts 2. Clear cached references 3. Broadcast final state --- ## 7. Blueprint Graph Logic Flow ```mermaid flowchart TD A[GI_GameFramework.Startup] --> B[SS_EnhancedInputManager.Initialize] B --> C[Load DA_InputMappingProfile] C --> D[Cache EnhancedInputLocalPlayerSubsystem] D --> E[Build DefaultBindings] E --> F[Broadcast OnInitialized] G[PushContext] --> H{Already active?} H -->|Yes| I[Update priority] H -->|No| J[Lookup IMC from DA] J --> K[AddMappingContext Priority] K --> L[ActiveContexts sorted insert] L --> M[Broadcast OnContextPushed] N[PopContext] --> O{Found in ActiveContexts?} O -->|Yes| P[RemoveMappingContext] P --> Q[Remove from array] Q --> R[Broadcast OnContextPopped] S[RebindKey] --> T[Update CurrentBindings map] T --> U[Modify IMC key mapping] U --> V[Broadcast OnKeyRebound] ``` --- ## 8. Communication Matrix | Who Talks | How | What Is Sent | |-----------|-----|-------------| | `SS_EnhancedInputManager` | `Direct (UE5 API)` | `UEnhancedInputLocalPlayerSubsystem::AddMappingContext / RemoveMappingContext` | | `SS_EnhancedInputManager` | `Direct` | `SS_UIManager::OnInputModeChanged` — input mode synchronization | | `SS_EnhancedInputManager` | `Dispatcher` | `OnContextPushed/OnContextPopped` → Any listener (UI, audio, narrative) | | `SS_EnhancedInputManager` | `Direct` | `SS_SettingsSystem::ApplyControlSettings` — key rebinding | | `BPC_InteractionDetector` | `Function Call` | `SS_EnhancedInputManager::IsActionPressed("IA_Interact")` | | `BPC_FirearmSystem` | `Function Call` | `SS_EnhancedInputManager::GetActionValue1D("IA_PrimaryAction")` | | `BPC_MovementStateSystem` | `Function Call` | `SS_EnhancedInputManager::GetActionValue2D("IA_Move")` | | `BPC_CutsceneBridge` | `Function Call` | `SS_EnhancedInputManager::PushContext/PopContext` | | `BPC_HidingSystem` | `Function Call` | `SS_EnhancedInputManager::PushContext(Hiding) / PopContext(Hiding)` | | `BPC_ActiveItemSystem` | `Function Call` | `SS_EnhancedInputManager::IsActionPressed("IA_QuickSlot1")` | | `WBP_PauseMenu` | `Function Call` | `SS_EnhancedInputManager::PushContext(UI) / PopContext(UI)` | | `WBP_InventoryMenu` | `Function Call` | `SS_EnhancedInputManager::PushContext(WristwatchUI)` | | `BP_PuzzleDeviceActor` | `Function Call` | `SS_EnhancedInputManager::PushContext(Inspection)` | | `WBP_InteractionPromptDisplay` | `Dispatcher listener` | `OnKeyRebound` → update displayed key icons | --- ## 9. Validation / Testing Checklist - [ ] Initialize correctly loads DA_InputMappingProfile and caches subsystem - [ ] PushContext adds IMC at correct priority on EnhancedInputLocalPlayerSubsystem - [ ] PopContext removes IMC and restores lower-priority context functionality - [ ] Higher priority context correctly overrides lower priority bindings (e.g., WristwatchUI blocks IA_Move) - [ ] IsActionPressed returns correct state for active context actions - [ ] RebindKey persists for the session and dispatches OnKeyRebound - [ ] ResetToDefaultBindings restores all keys to factory defaults - [ ] SetInputModeUIOnly shows cursor and blocks gameplay inputs - [ ] SetInputModeGameOnly hides cursor and restores gameplay inputs - [ ] Edge case: Pushing same context twice updates priority instead of double-stacking - [ ] Edge case: Popping a non-active context logs warning but doesn't crash - [ ] Edge case: Input mode changes during cutscene (UI opens on top) correctly stacks - [ ] Edge case: Controller hot-swap fires OnPlatformChanged and loads correct profile --- ## 10. Reuse Notes - All gameplay systems should query input state through SS_EnhancedInputManager, never through raw EnhancedInputSubsystem calls - Context priority ladder is configurable via DefaultContextPriority variable - The SS_ prefix matches the existing `SS_UIManager`, `SS_SettingsSystem`, `SS_SaveManager` pattern - Platform-specific IMCs allow controller glyphs (Xbox vs PS5 button icons) to differ - For accessibility: hold-to-toggle actions (e.g., Crouch) can be configured as toggle vs hold via the IMC - Quick Slot 1–8 inputs are Keyboard-only; gamepad uses IA_QuickSlotScroll axis - This subsystem replaces the previously-referenced `BPC_InputManager` — all existing docs must be updated --- *Blueprint Spec: Enhanced Input Manager. Conforms to TEMPLATE.md v1.0 — part of the UE5 Modular Game Framework, INPUT layer.*