Keyboard state and the key constants that name it.
Read a key through the snapshot App.Input contains --
input.devices.key_pressed(KeySpace) -- rather than through the packed
bytes. set_source! and set_text! are the other half: they let a run
drive its own keyboard, which is what a scripted demo or a headless test
needs.
A code with a named key decodes to that key, so a value that came from
the host -- a Devices.Event -- pattern-matches on KeyA exactly as
one written in the app does. A code in range with no name is Raw.
Check if a key was pressed at least once since the previous input. An
interval event: a key tapped between two cycles is pressed and released
in the next input and held in neither. Coalesced per key; the ordered
record with every press is Devices.Snapshot.events. Pass host
directly.
NoExitKey stops any key from ending it; App.default starts with
ExitKey(KeyEscape). The exit key ends the app directly, before
update! sees the press, whatever App.Config.with_close_request
chose. The window's close button follows with_close_request and is
unaffected by this.
Legal in init!, update!, and tasks; refused in render!.
Hand keyboard state to a scripted source, or back to the hardware keyboard.
What the app reads is unchanged: input.devices still holds packed key
state and Keys.key_pressed still reports edges, so widget code cannot
tell a scripted key from a struck one. That is the point -- a recorded
demo or a headless test exercises the real input path rather than a
parallel fake one.
The source installed on one cycle is what the host samples for the next,
the same way Mouse.set_source! places the pointer.
Legal in init!, update!, and tasks; refused in render!.
Codepoints for a string, ready for Keys.set_text!.
Keys.typing("hi") is the two codepoints a keyboard would have queued
had those two characters been typed, so the layout-dependent text channel
is scripted with text rather than with key codes.
Enter text as though it had been typed on the next frame.
Text is a separate channel from key state: it follows the active keyboard
layout, so a scripted key code cannot produce it and this cannot produce
key state. An app that reads both wants Keys.set_source! as well.
The codepoints arrive on the next cycle's input.devices.text_input and
are gone the cycle after, the way a real keyboard's characters arrive on
one frame and not the next. At most 32 codepoints are delivered per
input; a longer script has the excess discarded and
text_input_overflow set, exactly as for hardware input.
Legal in init!, update!, and tasks; refused in render!.
Where keyboard state comes from: the hardware, or a script.
Virtual names the keys held down on the next frame, and only those.
The host runs the same derivation over a scripted source that it runs
over hardware, so a key that appears in one frame's list and not the
previous one is pressed, and one that disappears is released. Hardware
edges are shut out entirely while a script is the source.