# Reacting to events, timers, and messages [Programming guides](README.md) An **event** tells your program something happened, such as a key being pressed. A **handler**, or **event script**, is the indented block that reacts to it. The **header** is its first line, such as `when started():`. The part after `when` is an **event descriptor**: it says what to react to. It belongs in that header, not in an ordinary function call. **Top-level** means outside functions, loops, and other blocks. Pliro first runs the ordinary top-level instructions to prepare the program. This is **setup**, or **initialization**. Then it gives event scripts their turns. Ready scripts wait in a **queue**, like people waiting in line. **Cooperative** means a script lets another ready script take a turn at agreed points, such as a positive `wait`. See the [event-loop example](../concepts/event-loop.md). Event scripts are top-level `when` statements: ```text when started(): say "Ready" broadcast("go") when after(1): say "One second later" when messageReceived("go"): say "Go!" when keyPressed("space"): say "Jump!" when pointerPressed("primary"): say "Pressed at", pointerX(), pointerY() when pointerReleased("primary"): say "Released at", pointerX(), pointerY() when pointerClicked("primary"): say "Clicked at", pointerX(), pointerY() ``` ## Timer and scheduling words A **literal** is a value written directly in the code, such as `1` or `"go"`. An event header that requires a literal cannot use a variable in its place. **Case-sensitive** means `"go"` and `"Go"` are different messages. To **arm** a timer is to start its wait. A **one-shot** timer becomes ready once; it does not repeat. A **deadline** is the earliest time it may run. All `after` timers measure from the same moment after setup. Their **monotonic clock** measures elapsed time without jumping when the computer's time-of-day setting changes. Equal deadlines keep their order in the source file. Becoming ready does not interrupt another script in the middle of an instruction. An **invocation** is one run of a handler. It gets fresh **local variables**, its own names inside the block. **Global variables**, created at program level, are shared. **Dispatch** means delivering an event and queuing the matching work. To **yield** is to hand over a turn. A **persistent handler** keeps a suitable running program ready for future key or pointer input, even when it is doing nothing at that moment. **Cancellation** stops pending work from running. The trigger after `when` must be exactly `started()`, `after(seconds)`, `messageReceived("message")`, `keyPressed("key")`, `pointerPressed("primary")`, `pointerReleased("primary")`, or `pointerClicked("primary")`. `after` requires one direct finite Number literal from 0 through 10 seconds and starts its script exactly once. A positive value below one millisecond is represented as one millisecond. Message and key descriptors require one non-empty text literal written directly in the header. Message matching is exact and case-sensitive. Key names use the same portable normalization as `keyDown`; a handler starts only when the key changes from released to pressed, and operating-system repeats are ignored until key-up. `pointerPressed`, `pointerReleased`, and `pointerClicked` accept only the exact direct literal `"primary"`. A press runs when an eligible primary down occurs inside the logical scene and the host claims that pointer. It carries the [immutable](../concepts/mutation.md) bounded whole-number down point. A real up from the same claimed pointer next runs a release handler, even outside the scene, using a signed 32-bit logical-plane point. If the up is inside, it also runs a separate click handler with the existing bounded release point. Additional or duplicate downs do not start another press or release. `pointerX()` and `pointerY()` report the immutable point owned by that pointer-event task. Event descriptors are valid only directly after a top-level `when`; they are not ordinary callable functions. Periodic timers, pointer move/drag, GPIO-edge, and sprite event descriptors are not implemented yet. Ordinary top-level statements initialize shared globals before event scripts run. Started scripts are queued first. All `after` scripts are then armed once from one shared post-setup monotonic anchor; a zero-delay timer stays behind started work, and equal deadlines retain source order. Ready scripts use deterministic [FIFO](../concepts/event-loop.md) order, one script at a time. Every invocation has fresh local variables but may read and update shared globals. Inside a script, `wait` parks only that script and `broadcast` queues matching message scripts in source order before yielding. A run without persistent descriptors finishes after no ready or sleeping script remains. A `keyPressed`, `pointerPressed`, `pointerReleased`, or `pointerClicked` script keeps a capable run in state `running` while idle; Stop, `exitApp`, failure, or host closure ends it. A runtime without a required keyboard/pointer event capability fails with `E4019`. See [Section 17](../../../pliro-syntax.en.md#17-execution-input-exit-and-safety-limits). Positive `wait` calls and completed input requests are cooperative checkpoints. They keep Stop and graphical event processing responsive and start a fresh instruction-budget slice. In an event script, `wait` parks only the active script. `broadcast` queues exactly matching message scripts and yields the active script so the deterministic FIFO scheduler can continue other ready work. Put a persistent animation loop in `when started():` when other event handlers need to run during its waits; ordinary top-level setup must finish before the event-scheduler phase begins. ```pliro # language: en let running = true while running: if keyDown("space"): exitApp() # Update and draw one frame here. wait(0.04) ``` ## Related entries [Syntax and values](../syntax/README.md) · [Built-ins](../builtins/README.md) · [Programming guides](README.md)