# Enhanced Input System Architecture ## Problem Statement The project has **no input system specification** despite 230+ cross-references to a non-existent [`BPC_InputManager`](../02-player/13_BPC_InputManager.md) across existing blueprint specs. UE5's Enhanced Input System must be architected into the framework using a centralized [`SS_EnhancedInputManager`](Game Instance Subsystem) that manages Input Mapping Context push/pop, priority, platform profiles, and input mode coordination with [`SS_UIManager`](docs/blueprints/06-ui/44_SS_UIManager.md). ## Proposed Solution ```mermaid flowchart TD A[Game Boot / GI_GameFramework Init] --> B[SS_EnhancedInputManager.Initialize] B --> C[Load DA_InputMappingProfile] C --> D[Cache platform-specific IMCs] E[GM_CoreGameMode.OnPlayerPossess] --> F[SS_EnhancedInputManager.PushDefaultContext] F --> G[Add IMC_Default Priority 0 via EnhancedInputLocalPlayerSubsystem] H[Gameplay Event] --> I{Context Switch?} I -->|Open Inventory| J[PushContext IMC_WristwatchUI Priority 10] I -->|Pick Up Item| K[PushContext IMC_Inspection Priority 20] I -->|Enter Hiding| L[PushContext IMC_Hiding Priority 5] I -->|Open Pause| M[SS_UIManager.ShowMenu + PushContext IMC_UI Priority 100] N[Exit Context] --> O[SS_EnhancedInputManager.PopContext] O --> P[Remove IMC, restore lower priority contexts] Q[SS_SettingsSystem.ApplyControlSettings] --> R[SS_EnhancedInputManager.RebindKey] R --> S[Update IMC mappings via DA_InputMappingProfile] ``` ### Architecture Decision: Centralized Subsystem (Option A) `SS_EnhancedInputManager` is a **Game Instance Subsystem**, matching the project's existing [`SS_UIManager`](docs/blueprints/06-ui/44_SS_UIManager.md), [`SS_SettingsSystem`](docs/blueprints/12-settings/105_SS_SettingsSystem.md), and [`SS_SaveManager`](docs/blueprints/05-saveload/35_SS_SaveManager.md) pattern. It manages all Input Mapping Contexts globally, while individual systems request context pushes via a clean API (function calls + dispatchers). ### Context Priority Ladder | Priority | Context | Trigger | Overrides | |----------|---------|---------|-----------| | 0 | `IMC_Default` | Persistent gameplay | Nothing | | 5 | `IMC_Hiding` | Enter hiding spot | Movement, Interact | | 10 | `IMC_WristwatchUI` | Open watch/inventory | Movement, Look | | 20 | `IMC_Inspection` | Pick up 3D item | All below | | 100 | `IMC_UI` | Pause/Settings/Journal | Everything | Higher priority = takes precedence. Multiple contexts can be active simultaneously. ### Input Actions (IA_) Master Registry #### Axis2D Inputs | Action | Value Type | Used In | Description | |--------|-----------|---------|-------------| | `IA_Move` | Axis2D | IMC_Default | W/A/S/D + Left Stick → locomotion | | `IA_Look` | Axis2D | IMC_Default | Mouse XY + Right Stick → camera | | `IA_Inspect_Rotate` | Axis2D | IMC_Inspection | Mouse/Right Stick → rotate item | | `IA_UI_Navigate` | Axis2D | IMC_WristwatchUI, IMC_UI | D-Pad/Arrows → menu navigation | | `IA_Hide_Look` | Axis2D | IMC_Hiding | Mouse/Right Stick → look while hidden | #### Axis1D Inputs | Action | Value Type | Used In | Description | |--------|-----------|---------|-------------| | `IA_Inspect_Zoom` | Axis1D | IMC_Inspection | Scroll/LT-RT → zoom item | | `IA_Hide_Peek` | Axis1D | IMC_Hiding | W/S → lean forward in hiding | | `IA_QuickSlotScroll` | Axis1D | IMC_Default | Scroll wheel → cycle quick slots | #### Digital (Bool) Inputs — Gameplay | Action | Used In | PC Default | Gamepad Default | Description | |--------|---------|------------|-----------------|-------------| | `IA_Interact` | IMC_Default | E / Left Click | X / Square | Pick up, hold for physics-drag | | `IA_PrimaryAction` | IMC_Default | LMB | RT / R2 | Fire weapon / Swing tool | | `IA_SecondaryAction` | IMC_Default | RMB | LT / L2 | ADS / Shield | | `IA_Sprint` | IMC_Default | L-Shift | L3 | Run (triggers stamina + stress) | | `IA_Crouch` | IMC_Default | C / L-Ctrl | B / Circle | Sneak / crawl | | `IA_Vault_Climb` | IMC_Default | Spacebar | A / Cross | Contextual parkour | | `IA_Jump` | IMC_Default | Spacebar | A / Cross | Basic jump (coexists with Vault via context) | | `IA_Flashlight` | IMC_Default | F | D-Pad Up | Toggle light | | `IA_QuickHeal` | IMC_Default | Q / H | D-Pad Down | Consume health item | | `IA_Reload` | IMC_Default | R | Y / Triangle | Reload weapon | | `IA_OpenWatch` | IMC_Default | Tab / I | View / Touchpad | Wristwatch UI | | `IA_PauseMenu` | IMC_Default | Esc / P | Menu / Options | Pause game | | `IA_QuickSlot1`–`IA_QuickSlot8` | IMC_Default | 1–8 | None | Direct quick slot selection | #### Digital (Bool) Inputs — Context-Specific | Action | Used In | PC Default | Gamepad Default | Description | |--------|---------|------------|-----------------|-------------| | `IA_Inspect_Flip` | IMC_Inspection | F | Y / Triangle | Flip document | | `IA_Cancel_Drop` | IMC_Inspection | RMB / Esc | B / Circle | Exit inspection | | `IA_UI_Select` | IMC_WristwatchUI, IMC_UI | E / Enter | A / Cross | Confirm/equip | | `IA_UI_Combine` | IMC_WristwatchUI | C | X / Square | Item combination | | `IA_UI_DropItem` | IMC_WristwatchUI | X | Y / Triangle | Drop from inventory | | `IA_CloseWatch` | IMC_WristwatchUI | Tab / Esc | B / Circle | Lower arm | | `IA_UI_Back` | IMC_UI | Esc / Backspace | B / Circle | Back one menu level | | `IA_Hide_HoldBreath` | IMC_Hiding | Spacebar (Hold) | LT+RT (Hold) | Suppress breathing | | `IA_Exit_Hide` | IMC_Hiding | C / Esc | B / Circle | Leave hiding spot | #### New Input Types Added (beyond user's original list) | Action | Value Type | Used In | Description | Rationale | |--------|-----------|---------|-------------|-----------| | `IA_Jump` | Digital | IMC_Default | Separate from Vault for non-contextual jumps | Prevents accidental climbing when player just wants to jump | | `IA_QuickSlotScroll` | Axis1D | IMC_Default | Cycle through 8 quick slots | Natural controller wheel support for inventory | | `IA_QuickSlot1`–`IA_QuickSlot8` | Digital | IMC_Default | Direct slot access (KB only) | Quick weapon/item switching | | `IA_UI_Back` | Digital | IMC_UI | Universal back navigation | Separates "back" from "cancel" semantics | | `IA_ToggleAccessibility` | Digital | IMC_UI | Toggle accessibility features mid-game | Required by [`BPC_AccessibilitySettings`](../02-player/104_BPC_AccessibilitySettings.md) | | `IA_SkipCutscene` | Digital | IMC_Default | Hold to skip (contextual) | Already referenced by [`BPC_CutsceneBridge`](../07-narrative/64_BPC_CutsceneBridge.md) | ## File Structure ``` docs/ blueprints/ 15-input/ # NEW directory 128_SS_EnhancedInputManager.md # Central subsystem spec 14-data-assets/ 129_DA_InputMappingProfile.md # Data Asset for platform profiles Content/ Framework/ Input/ # NEW directory Actions/ # IA_* Input Action assets IA_Move.uasset IA_Look.uasset IA_Interact.uasset ... (all 30+ IA_ assets) Contexts/ # IMC_* Input Mapping Context assets IMC_Default.uasset IMC_Inspection.uasset IMC_WristwatchUI.uasset IMC_Hiding.uasset IMC_UI.uasset DataAssets/ DA_InputMappingProfile.uasset # Platform profiles ``` ## API Contracts ### SS_EnhancedInputManager Interface ```cpp // === Public Functions === // Initialize with a profile void Initialize(DA_InputMappingProfile Profile); // Context management (stack-based) void PushContext(E_InputContext ContextType, int32 PriorityOverride = -1); void PopContext(E_InputContext ContextType); void SetContextPriority(E_InputContext ContextType, int32 NewPriority); TArray GetActiveContexts() const; bool IsContextActive(E_InputContext ContextType) const; // Input state queries (read-only for other systems) bool IsActionPressed(FName ActionName) const; float GetActionValue1D(FName ActionName) const; FVector2D GetActionValue2D(FName ActionName) const; // Key rebinding (called by SS_SettingsSystem) void RebindKey(FName ActionName, FKey NewKey, E_InputPlatform Platform); void ResetToDefaultBindings(E_InputPlatform Platform); TMap GetCurrentBindings(E_InputPlatform Platform) const; // Input mode coordination with SS_UIManager void SetInputModeUIOnly(); void SetInputModeGameOnly(); void SetInputModeGameAndUI(); ``` ### Enums ```cpp enum E_InputContext { Default = 0, Hiding = 1, WristwatchUI = 2, Inspection = 3, UI = 4 }; enum E_InputPlatform { PC_KeyboardMouse = 0, Xbox = 1, PS5_DualSense = 2 }; ``` ### Event Dispatchers | Dispatcher | Payload | Description | |------------|---------|-------------| | `OnContextPushed` | `E_InputContext Context, int32 Priority` | Fired when a new context is activated | | `OnContextPopped` | `E_InputContext Context` | Fired when a context is removed | | `OnInputModeChanged` | `E_InputMode NewMode` | Syncs with SS_UIManager for cursor visibility | | `OnKeyRebound` | `FName ActionName, FKey NewKey` | Fired after rebinding for UI update | | `OnPlatformChanged` | `E_InputPlatform NewPlatform` | Fired on input device hot-swap | ### Communication Matrix | Source | Target | Method | Data | |--------|--------|--------|------| | SS_EnhancedInputManager | UEnhancedInputLocalPlayerSubsystem | Direct (UE5 API) | Add/Remove Mapping Context | | SS_EnhancedInputManager | SS_UIManager | Direct | Input mode changes | | SS_EnhancedInputManager | SS_SettingsSystem | Direct | Key rebinding requests | | SS_EnhancedInputManager | WBP_InteractionPromptDisplay | Dispatcher | Current action key icons | | BPC_InteractionDetector | SS_EnhancedInputManager | Function Call | IsActionPressed for interact | | BPC_FirearmSystem | SS_EnhancedInputManager | Function Call | GetActionValue1D for trigger | | BPC_CutsceneBridge | SS_EnhancedInputManager | Function Call | PushContext/PopContext | | BP_PuzzleDeviceActor | SS_EnhancedInputManager | Function Call | PushContext(Inspection) | ## Success Criteria 1. All 30+ Input Actions are created and mapped across all 3 platforms (PC, Xbox, PS5) 2. Context switching is seamless: pushing a higher-priority context overrides lower ones without blocking 3. Key rebinding via SS_SettingsSystem persists across sessions 4. Input mode changes (GameOnly ↔ UIOnly) correctly show/hide cursor 5. All existing specs that reference `BPC_InputManager` are updated to reference `SS_EnhancedInputManager` 6. Quick slot scrolling and direct selection work on both KB+M and gamepad 7. Hold inputs (HoldBreath, physics-drag) correctly trigger on hold and cancel on early release 8. Cutscene skip works via hold-to-skip (not tap)