# Input

> Presses latched once per frame and handed to exactly one tick, and why a held key must not cross the board.

The simulation runs at a fixed 120 Hz. The window runs at whatever the display
does. Those do not divide evenly, so a rendered frame may owe the simulation
zero ticks, or one, or three.

A press has to reach exactly one of them. Drop it and the game eats inputs.
Repeat it and one tap crosses three lanes.

<GameSource file="src/platform/input.zig" decl="Latch" />

`poll` runs once per rendered frame, before the tick loop. `take` hands the
latched presses to one tick and clears them.

## Why the fields are booleans and not key states

`IsKeyPressed` is true on the frame a key goes down and false while it is held.
That is the behaviour the game wants. A held `D` should move one lane, not slide
across the board at a hundred lanes a second.

The simulation says so in its own type:

<GameSource file="src/sim/sim.zig" decl="Input" />

And a test holds the compiler to it:

<GameSource file="src/sim/tests.zig" decl="a held direction moves exactly one lane" />

## A frame that owes no ticks

If a frame produces no ticks, `take` is never called and the latch keeps its
presses for the next frame. A tap between two ticks is remembered rather than
lost.

If a frame produces three ticks, the first gets the press and the other two get
nothing. That is what `take` clearing itself buys.

## Touch

The same poll reads the mouse, and splits the window down the middle.

Tapping the left half steers left, tapping the right half steers right, and
either counts as the confirm that starts a run. That is the whole control scheme
on a phone, and it needed four lines because the simulation already thought in
lanes rather than in keys.

## What the platform layer does not do

Mute is a keypress, and it never reaches the simulation:

```zig
if (rl.IsKeyPressed(rl.KEY_M)) self.audio.toggleMute();
```

Muting is not a rule of the game. Nothing in `sim/` knows sound exists, and
adding a key for it would have been the first crack in that.
