> ## Documentation Index
> Fetch the complete documentation index at: https://docs.eucaengine.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Input

> Bind keys to actions and manage the input-context stack — and see honestly why binding needs an ActionMap the bare host doesn't register, while the context stack works headless out of the box.

Euca's input layer (`euca-input`) is pure data: an `InputState` snapshot (pressed / just-pressed keys, mouse,
scroll, gamepad), an `ActionMap` binding `InputKey`s to named actions, and an `InputContextStack` (`Gameplay`
/ `Menu` / `Editor`) that decides which bindings are active. The mental model: every input endpoint mutates one
of those **resources** — so an endpoint works only where its resource is present. This page walks the bind and
context flow, and shows exactly how to tell a no-op from a real effect; every command is real and runnable
against a [local server](/quickstart), with output from one.

<Warning>
  **The headless host registers `InputState` and `InputContextStack`, but no `ActionMap`.** So the context
  stack works out of the box (push/pop take effect), while `/input/bind` returns `ok:true` and stores nothing —
  there's no `ActionMap` to write to. Key bindings are a client / windowed-host concern; a host that wants them
  registers an `ActionMap` itself. The honest evidence is below.
</Warning>

## Bind a key (and prove whether it stuck)

`/input/bind` validates `key` and `action`, then writes to the `ActionMap` **only if one exists**. On the bare
headless host there's no `ActionMap`, so the call returns success but `/input/list` stays empty — that
contrast is how you know:

```bash theme={null}
curl -s -X POST http://localhost:3917/input/bind \
  -H 'Content-Type: application/json' -d '{"key":"W","action":"move_forward"}'
# {"ok":true,"message":"Bound 'W' to 'move_forward'"}   ← ok, but nothing was stored

curl -s http://localhost:3917/input/list
# {"bindings":[],"count":0}   ← no ActionMap registered, so the bind no-op'd
```

Validation still runs locally — a request missing `key` or `action` is rejected before it ever touches the map:

```bash theme={null}
curl -s -X POST http://localhost:3917/input/bind -H 'Content-Type: application/json' -d '{"key":"W"}'
# {"ok":false,"message":"Missing 'key' or 'action'"}

curl -s -X POST http://localhost:3917/input/unbind -H 'Content-Type: application/json' -d '{"key":"W"}'
# {"ok":false,"message":"No binding for 'W'"}   ← unbind reads the map; absent map → nothing to remove
```

## Push and pop a context (works headless)

The headless host carries an `InputContextStack`, initialized with a base `Gameplay` context, so push and pop
both take effect. Push a `menu` context and it pops right back:

```bash theme={null}
curl -s -X POST http://localhost:3917/input/context/push \
  -H 'Content-Type: application/json' -d '{"context":"menu"}'
# {"ok":true,"message":"Pushed context 'menu'"}

curl -s -X POST http://localhost:3917/input/context/pop
# {"ok":true,"message":"Popped context: Menu"}   ← the pushed 'menu' pops off
```

`/input/context/pop` refuses only when you'd pop the **base** context — pop again with just `Gameplay` left and
you get `{"ok":false,"message":"Cannot pop last context"}`. The stack guards its floor; it never empties.

## What a host that registers the resources gets

The data and operations all exist in `euca-input`; they just need the resources present:

* **Bindings** — `ActionMap::bind` maps an `InputKey` (`Key(name)`, `MouseLeft`/`MouseRight`/`MouseMiddle`,
  gamepad buttons/axes) to a named action; `active_actions` / `just_started_actions` query them. With an
  `ActionMap` registered, the bind above would appear in `/input/list` as
  `{"key":"W","action":"move_forward"}`.
* **Context stack** — push/pop `Gameplay` / `Menu` / `Editor` to switch which bindings apply.
* **Gamepad** — `GamepadState` tracks axes and buttons per gamepad id.
* **Snapshots** — `InputSnapshot::capture()` / `apply_to()` for server-side [networked](/concepts/networking)
  replay.

## Endpoints

| Method | Path                  | Description                                                         |
| ------ | --------------------- | ------------------------------------------------------------------- |
| `POST` | `/input/bind`         | Bind a key/button to a named action (no-ops without an `ActionMap`) |
| `POST` | `/input/unbind`       | Remove a binding (reports "no binding" without an `ActionMap`)      |
| `GET`  | `/input/list`         | List current bindings (empty without an `ActionMap`)                |
| `POST` | `/input/context/push` | Push an input context (works headless; the stack is registered)     |
| `POST` | `/input/context/pop`  | Pop the top context; refuses only when you'd pop the base context   |

## Status

* **Shipped** — `ActionMap` bindings, the context stack, the gamepad abstraction, and input snapshots, all as
  headless serializable data in `euca-input`.
* **Host-dependent** — The headless host registers an `InputContextStack` (so context push/pop work) but no
  `ActionMap`, so `/input/bind` accepts calls and stores nothing (verified above). A windowed or input-aware
  host registers an `ActionMap`, after which the bind endpoints take effect.

<Card title="Input endpoints" icon="keyboard" href="/api-reference/introduction" horizontal>
  Bind, unbind, list, and context endpoints with request and response schemas.
</Card>
