Files
UE5-Modular-Game-Framework/docs/blueprints/15-input/128_SS_EnhancedInputManager.md
Lefteris Notas 14441c000c Add haptics example documentation for Project Void controller feedback
- Introduced comprehensive guide for setting up controller haptics and force feedback.
- Detailed directory structure for haptic profiles and creation steps for DA_HapticProfile instances.
- Included platform-specific configurations for Xbox and PS5 DualSense adaptive triggers.
- Outlined wiring of BPC_HapticsController to various gameplay systems and events.
- Provided accessibility integration options and testing checklist for haptic functionality.
2026-05-22 17:16:34 +03:00

330 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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)
- **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<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 |
| `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 18 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.*