# 128 — Enhanced Input Manager (`SS_EnhancedInputManager`)

> **⚡ C++ Status: Full Implementation** — `Source/PG_Framework/Public/Input/SS_EnhancedInputManager.h` provides the complete context stack management: Push/Pop context with priority ordering, input mode coordination, key rebinding, and action value queries. **Auto-created** by UE's subsystem system — no BP child needed. Access from any BP: `Get Game Instance → Get Subsystem(SS_EnhancedInputManager)`. You still need to create 22 IA_* + 5 IMC_* assets in the editor. See `docs/developer/cpp-integration-guide.md` for usage patterns.
>
> ---

## 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), [`BPC_PlatformServiceAbstraction`](docs/blueprints/01-core/150_BPC_PlatformServiceAbstraction.md) (central platform detection — replaces own platform enum)
- **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` *(deprecated — use EPlatformFamily from BPC_PlatformServiceAbstraction. This enum is kept for DA_InputMappingProfile compatibility but all runtime selection uses the unified enum)*
| Value | Description |
|-------|-------------|
| `PC_KeyboardMouse = 0` | Keyboard + Mouse (maps to `PC_Win64`, `PC_Linux`, `Mac`) |
| `Xbox = 1` | Xbox Series X\|S / Xbox One (maps to `Xbox_Series` or `Xbox_One`) |
| `PS5_DualSense = 2` | PlayStation 5 DualSense (maps to `PS5` or `PS5_Pro`) |

---

## 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<E_InputContext, Int32>` | `{Default:0, Hiding:5, WristwatchUI:10, Inspection:20, UI:100}` | `Config` | Default priority table |

### Internal (Private)
| Variable | Type | Default | Category | Description |
|----------|------|---------|----------|-------------|
| `ActiveContexts` | `TArray<S_ActiveContext>` | `Empty` | `State` | Currently pushed contexts (stack, highest first) |
| `CurrentBindings` | `TMap<E_InputPlatform, TArray<S_KeyBinding>>` | `Empty` | `State` | Current key bindings per platform |
| `DefaultBindings` | `TMap<E_InputPlatform, TArray<S_KeyBinding>>` | `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<E_InputContext>`
- **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<FName, FKey>`
- **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")` |
| `BPC_HapticsController` (148) | `Function Call` | `SS_EnhancedInputManager::GetControllerPlatform()` — for platform detection |
| `BPC_PlatformServiceAbstraction` (150) | `Function Call / Bind OnPlatformReady` | `GetDefaultInputProfile()` — selects correct DA_InputMappingProfile for detected platform |
| `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.*