Input

Purpose

Input turns device observations into semantic actions and, when requested, ordered physical/text records. Games consume an immutable tick view without polling native devices or taking ownership of another consumer’s records.

Interface

Types below are in CE::Input unless another namespace is shown.

Types and operations

API and purpose

System
Device IDs, bindings, capture/focus support and complete poll publication. Adapter publication; adapter catalogue.

Actions::Bindings, Actions::Chord, Actions::AxisOptions
Register buttons, simultaneous chords and scaled/gated axes on the platform owner. Bindings; binding task.

Actions::ContextDefinition, Actions::ContextSubmission, Actions::Context
Attach reusable bindings for independent consumers from any producer, retaining one move-only lease per consumer. Action contexts; Controller tutorial.

Actions::Id, Actions::BindingId, Control
Distinguish game meaning, one registration and a physical device/control pair. Control identities and tokens.

Tick, Actions::View
Read direct or context-local button/axis state, observed duration and ordered records during update. Tick input; context views.

PollSnapshot, Actions::Snapshot
Retain complete immutable poll results across later polling. Poll snapshots; ordered records.

GamepadAvailability, GamepadAvailabilityChanged
Read the current convenience-slot state and subscribe to changes after complete polls. Gamepad availability and seed.

Capture::Lease, Routing::Lease
Keep a record channel requested or a particular keyboard-focus request alive. Capture; routing.

Controls for bindings

Pass these Engine enums directly with the corresponding device ID when binding buttons, chords or axes.

Enum or constants

Purpose and details

KeyboardKey

Letter/digit positions, editing/navigation keys, F1–F25, keypad and left/right modifiers; pair with keyboard_id(). Identities, headers and binding examples.

MouseButton

Left, Right, Middle, Extra1–Extra5; pair with mouse_id(). Mouse binding path.

GamepadControl

Named buttons, D-pad, sticks, triggers and optional sensor axes; pair with gamepad_id(). A/B/X/Y describe Xbox-style positions. Availability depends on the backend/device. Names and limits.

MouseControl

Absolute X/Y, one-poll WheelUp/WheelDown button pulses, and relative DeltaX, DeltaY, ScrollX, ScrollY, paired with mouse_id(). Axis behavior; constant declarations.

AxisKind

Absolute retains the final value; Relative accumulates changes. Set through Actions::AxisOptions. Axis mapping and observation.

Keyboard positions do not supply localized text. Unknown is not bindable; standard enums are converted by Control, while adapters normalize native codes. The control guide explains this distinction and lists the headers without repeating every key here.

Capture, records and routing values

Enum or value

Purpose and details

Capture::Channel

State is always collected; Events requests physical records; Text requests committed Unicode scalars. Channel activation and leases.

Routing::KeyboardPolicy

Exclusive gates keyboard gameplay; PassThrough also permits it. Focus does not activate capture. Focus and routing.

DeviceKind, Events::ButtonPhase, Modifiers

Identify record source, press/release/repeat and modifier flags. Record interpretation.

Events::Record, Events::Payload

Ordered button, axis, pointer, scroll or committed-text payload with target/epoch metadata. Record ownership; target filtering.

PollingPolicy, PollingOptions

Lockstep, Finite, Unlimited capacity and minimum spacing between completed polls. Backlog and scheduling.

Usage

Bind physical controls during platform initialization, then read semantic actions through the update’s immutable Input::Tick. A reusable controller retains its own action context so local action IDs and bindings do not collide with another controller’s.

        ---
config:
  theme: base
  themeVariables:
    fontFamily: system-ui, sans-serif
    fontSize: 14px
  flowchart:
    htmlLabels: true
    curve: linear
    nodeSpacing: 22
    rankSpacing: 38
    padding: 12
---
flowchart LR
    accTitle: Input · simple gameplay actions
    accDescr: Local names omit Input::; ambiguous nested namespaces remain qualified. Arrows point toward dependencies. Application roles are rounded; named API operations have rounded corners. Dashed arrows mark optional choices.
    k0(["Application<br/>init_platform()"]):::app
    k1["System"]:::focal
    k2["Actions::<br/>Bindings"]:::focal
    k3["Control"]:::focal
    k4["KeyboardKey"]:::focal
    k5["PollSnapshot"]:::focal
    k6(["Application<br/>update()"]):::app
    k7["Tick"]:::focal
    k8["Actions::<br/>ButtonTickState"]:::focal
    k0 --> k1
    k1 --> k2
    k2 --> k3
    k3 --> k4
    k1 --> k5
    k6 --> k7
    k7 --> k8
    classDef focal fill:#e7f3ef,stroke:#387d6b,color:#153d33,stroke-width:1.2px
    classDef neighbor fill:#f0f3f8,stroke:#8c9bb1,color:#35445b,stroke-width:1px
    classDef app fill:#fff2df,stroke:#c09452,color:#674515,stroke-dasharray:5 3
    classDef system fill:#eaf0fc,stroke:#617fab,color:#263f69,stroke-width:1.2px
    linkStyle default stroke:#7e8fa7,stroke-width:1.2px

    

Local names omit Input:: where unambiguous. Explore this diagram and its other views →

Explore the full application path, UI capture and focus, or engine input dependencies.

Choose what to consume

Reader’s task

API path

Setup and ownership

Read a few game-wide actions

Input::Actions::Bindings → tick.input.button(id)

Register direct bindings on platform; retain tokens and remove them during cleanup. Bind input.

Reuse a player/controller mapping

Input::Actions::ContextDefinition → Input::Actions::Context → tick.input.actions(context)

Acquire action_contexts() on platform once; attach from the consumer’s owner and retain one lease per controller. Controller tutorial.

Feed a menu or text editor

Input::Capture::Lease and Input::Routing::Lease → tick records

Request Events/Text separately from keyboard focus. Read ordered records on the UI owner, preferably through a toolkit session.

Retain a complete native poll

Input::PollSnapshot

Acquire after publication on platform; the immutable handle can cross threads and survive later polls.

React to convenience-gamepad availability

Input::gamepad_availability_changed_event plus gamepad_availability()

Subscribe and read the seed together on platform; select queued delivery for a simulation-owned target. Availability contract.

Actions, capture and focus are independent

Actions describe gameplay meaning. Capture requests activate ordered physical or committed-text records; they do not consume a private queue. Focus chooses a record recipient and may gate keyboard gameplay. Focusing alone does not request Events or Text, and action-context lifetime does not establish UI focus.

Keep capture/focus leases while their UI consumer is active. Each poll latches those requests once, so a mid-poll change takes effect on the next poll and cannot reassign records already captured. Multiple consumers can inspect the same immutable record batch. See capture and routing.

Uses

Dependency

Input’s use

Platform::Window

A concrete adapter borrows a compatible live window while native callbacks are attached. Display.

Input::Actions::Bindings

Evaluate direct and context-local mappings into immutable action snapshots.

Input::Capture::Collector, Input::Routing::Manager

Collect supported records and latch focus/capture for one complete poll.

Events::EventBus::Publisher

Publish optional gamepad observations through a weak route. Runtime selects its Context bus; standalone input opts in. Events.

Used by

Consumer

What it reads or requests

Runtime::GameRuntime

Poll on platform and transfer complete polling intervals to immutable tick input. Runtime.

Application controllers

Read direct or context-local actions from Game::TickContext without querying live devices.

UI::TGUI::Session, UI::RmlUi::Session

Request supported record/focus capabilities and feed widgets during their update. GUI.

Standalone host or custom adapter

Drive complete polling/publication explicitly when Runtime is absent. Adapter publication.

Contracts

Directly bind and unbind controls on the platform owner. For runtime consumers, obtain action_contexts() there once and retain its endpoint; attach definitions or reset context leases on the consumer’s owner. Each context has independent local action IDs, and accepted changes take effect at the next poll. Button edges/counts and observed hold durations describe the consumed polling interval; they do not schedule updates or replace tick.delta_seconds. Relative axes accumulate changes, whereas absolute axes retain their final value. For direct actions, button_simulation_seconds() maps observed down-time proportion onto the selected simulation delta when that is the desired movement policy.

Records preserve collection order and committed text comes from the backend’s text input, not inferred key names. Readers may inspect the same record batch. Capture activation and focus are latched at poll start; requests cannot retroactively reroute already captured records. Exclusive keyboard focus gates keyboard gameplay input while leaving other devices available. A superseded focus lease cannot clear a newer request.

Lifecycle

Runtime::Context may own input or explicitly borrow it. Borrowed input must survive runtime cleanup/context lifetime and detach from a still-live window. Register bindings during game initialization, retain their IDs and remove them during cleanup, including partial initialization. Context leases release their mappings when their controller leaves; the endpoint remains safe after input destruction but rejects new attachments. Keep capture/focus leases only while their consumer needs them. Lease state and delivered immutable snapshots can survive adapter destruction; they do not retain a native window.

Shutdown discards pending, unpublished input after simulation stops. It does not perform an extra game update to consume those records. Already delivered handles remain valid.

Execution

Polling, native callback collection, direct binding changes and publication run on the platform owner. Runtime transfers complete batches to simulation. Update reads the tick’s borrowed view during that hook; copy owned data for longer use. Context attachment/removal, capture and routing requests support concurrent callers, with exclusive access when moving/resetting each individual lease. Delivered records are read-only. GUI widgets are called on their UI/simulation owner, never from a native callback.

Integration

After binding application actions during init_platform(), an update can select direction and speed without referring to physical keys:

const float direction = (tick.input.button(move_right).held() ? 1.0f : 0.0f)
                      - (tick.input.button(move_left).held() ? 1.0f : 0.0f);
position.x += direction * speed * static_cast<float>(tick.delta_seconds);

Here position, speed and the action IDs belong to the game. Held-state movement is a policy that moves for the whole selected update when the button ends held; a tap released before consumption contributes no movement in this example. For proportional contribution from observed taps, use tick.button_simulation_seconds(action) and multiply its result by speed instead of multiplying held() by delta. For a menu or editor, route ordered records through a toolkit session instead of deriving text from these actions. See binding actions and GUI construction.

A reusable controller instead reads tick.input.actions(its_context).button(id). The Controller tutorial puts those local IDs and the context lease into one class; Character consumes its commands, including runtime player joins and departures.

Limits and further reading

Backend capabilities determine whether Events, committed Text and focus routing are available. The GLFW backend does not promise composition/preedit, clipboard editing or a complete IME/editor protocol. Read actions, snapshots, polling, records and focus, timing and the input interface.