Input & Interaction
Grids overlays support two input modes: passthrough (Alt-key) and exclusive capture. The mode determines whether game input (movement, camera, etc.) is blocked while interacting with an overlay.
Input Modes
Passthrough Mode (Alt-Key)
The default mode. Overlays are visible but non-interactive. Holding Alt enables cursor-based interaction while keeping game input active in the background. Best for HUD elements, notifications, and overlays where you want quick peek-and-interact.
| State | Behavior |
|---|---|
| Alt released (default) | Mouse captured by game, cursor hidden, overlays are HitTestInvisible (visible but non-interactive) |
| Alt held | Cursor appears, overlays become Visible (interactive), game also receives input |
| Alt + Right-click | Line trace from cursor → checks for IContextMenuProvider on hit actor → opens context menu overlay |
Exclusive Capture Mode
For modal overlays like menus, dialogs, and search UIs where typing shouldn't move the character. When an overlay captures input exclusively, the player controller switches to UI-only input mode — all keyboard and mouse input goes to the overlay, none reaches the game.
| State | Behavior |
|---|---|
| Overlay opens with capture | Cursor appears, game input fully blocked, overlay receives all input |
| Overlay closes / releases capture | Game input restored, cursor hidden |
When to use: Any overlay with text fields, search boxes, chat input, or complex interactions where WASD/mouse should not affect the game.
Using Input Capture
From C++ (creating overlays)
UWebOverlay* Overlay = Sys->CreateOverlay("my-menu", Url, 100);
Overlay->SetInteractive(true);
Overlay->SetCapturesInput(true); // Blocks game input while this overlay is active
From JavaScript/TypeScript (at runtime)
import { grids } from '@grids/overlay-sdk';
// Request exclusive input capture (blocks game input)
grids.captureInput();
// Release exclusive input (game input restored)
grids.releaseInput();
The capture state is tracked globally by UWebOverlaySubsystem. If any visible and interactive overlay has bCapturesInput = true, the player controller switches to UI-only input mode. When the last capturing overlay is hidden, closed, or releases capture, game input is automatically restored.
Choosing the Right Mode
| Overlay Type | Mode | Example |
|---|---|---|
| HUD / status display | Passthrough | Health bar, minimap |
| Notifications | Passthrough | Toast messages |
| Context menus | Passthrough | Right-click menus (quick select) |
| Asset browser / menus | Exclusive capture | Tab menu with search box |
| Chat / text input | Exclusive capture | In-game chat overlay |
| Settings / dialogs | Exclusive capture | Configuration panels |
Implementation Details
Alt-Key System
The Alt-key logic lives in AGridsPlayerController:
- Key down — Show mouse cursor, switch to
GameAndUIinput mode - Key up — Dismiss context menus, hide cursor, restore
GameOnlyinput mode - Right-click while Alt held — Perform a line trace, check if the hit actor implements
IContextMenuProvider, and open the context menu overlay viaUContextMenuManager
Exclusive Capture System
Input capture is managed by the overlay subsystem with a delegate pattern:
UWebOverlay::SetCapturesInput(true)marks the overlay as input-capturingUWebOverlaySubsystem::UpdateInputCaptureState()checks if any overlay is capturingOnInputCaptureChangeddelegate fires, notifyingAGridsPlayerController- Controller switches to
FInputModeUIOnly(capture) orFInputModeGameOnly(release)
Input Mapping
The system uses Unreal's Enhanced Input System:
- IMC_Default — Standard gameplay input (movement, camera, actions)
- IMC_MouseLook — Separate context for when cursor is active during Alt hold
Overlay Focus vs Input Capture
These are two separate concepts:
| Method | Effect |
|---|---|
grids.requestFocus() / releaseFocus() | Toggles Slate hit-test visibility (whether clicks reach the overlay). Game input continues. |
grids.captureInput() / releaseInput() | Blocks/restores game input entirely. The overlay acts as a modal dialog. |
You can combine both: requestFocus() makes the overlay interactive, captureInput() additionally blocks game input.
Build Mode Controls
Pressing B enters build mode. While build mode is active, a translucent preview follows the crosshair and left-click places a block at the previewed location and rotation. Rotation is fully 3-axis and synced to the server + persisted on placement.
Rotation keys
| Key | Action |
|---|---|
| R | Rotate the active axis by + snap (default +15°) |
| Shift + R | Rotate the active axis by − snap |
| X | Select the Pitch (X) axis for subsequent R presses |
| Y | Select the Roll (Y) axis |
| Z | Select the Yaw (Z) axis (default) |
| [ | Decrease snap size — cycles through 1°, 5°, 15°, 45°, 90° |
| ] | Increase snap size |
| Shift (hold) | Temporarily switch to free rotate — each R press rotates by 1° regardless of snap |
| Backspace | Reset rotation to (0, 0, 0) |
Rotation keys are only active during placement (no block selected). If you've clicked a placed block to select it, rotation keys are disabled so they don't conflict with the selection editor. Press another shape button or build:deselect to return to placement mode.
Rotation UI
The build-editor overlay's rotation panel (bottom-center of the viewport during placement) mirrors every key in clickable form:
- An axis selector (X / Y / Z) that highlights the active axis
- Live readouts of Pitch / Yaw / Roll in degrees
- − / + step buttons that respect the current snap size
- A snap selector (1° / 5° / 15° / 45° / 90° / free) that switches increments
- A reset button that zeroes all three axes
All overlay buttons call through to the same C++ entry points as the keys, so there is only ever one source of truth for placement rotation.
Multiplayer and persistence
Rotation is included in every block placement message:
AGridsCharacter::ServerRequestBlockPlacealready accepts anFRotator— the previewed rotation is sent with the placement RPC.AReplicatedBlock::BlockRotationis replicated (DOREPLIFETIME) with anOnRep_BlockTransformthat applies the authoritative rotation to late-joiners and recovers from any dropped initial-spawn transform.UGridAuthoritySubsystem::SaveBlocknow accepts the full rotator and POSTsrotation_yaw,rotation_pitch,rotation_rollto the edge API. A legacyrotationfield (== yaw) is also sent for backwards compatibility.- On zone server startup,
AGridsServerGameMode::LoadBlocksFromDbreads all three axes (falling back to legacyrotationwhen the new fields are absent) and spawns blocks with the exact rotation they had.