Table of Contents
Events
Reading events
Two functions read events:
(win:process-events window-system &key (timeout 0)) => count
(win:poll-event window-system event) => boolean
process-events reads what the window system sent, answers what needs an
answer, and queues the events. It returns how many events it queued.
timeout is how long it may wait for something to arrive:
timeout |
Behaviour |
|---|---|
0, the default |
Does not wait. Handles what has arrived and returns. Use this in a loop that renders every frame. |
a positive real, such as 0.05 |
Waits at most that many seconds. Use this on an event thread, so it can still notice that it should stop. |
nil |
Waits until something arrives. |
poll-event copies the oldest queued event into event and returns true,
or returns false if no event is queued. It never waits and never
allocates.
Make the event struct once, with make-event, and reuse it:
(let ((event (win:make-event)))
(loop
(win:process-events window-system :timeout 0.05)
(loop while (win:poll-event window-system event)
do (handle event))))
Call process-events regularly, from one thread. The window system expects
answers, such as replies to its pings, and held keys repeat only while it
runs. See Threads.
Events wait in a queue until they are polled. The queue grows when events come in faster than they are polled, and it keeps its size afterwards. Poll them all every time.
The event struct
An event is a struct with one field per thing an event can say. Which
fields mean something depends on its type. The others are nil, 0,
0.0 or empty. A program reads events; backends write them. The readers'
setf writers are exported for backends, and for tests that stand in for
one.
| Reader | Type | Set for |
|---|---|---|
event-type |
event-type |
Every event. |
event-window |
window |
Every event: the window it concerns. |
event-width, event-height |
(integer 0) |
:resize: the new size in units. |
event-scale |
scale |
:resize: the new scale. 1 for other events. |
event-key |
key or nil |
:key-press, :key-release: the physical key. |
event-symbol |
key or nil |
:key-press, :key-release: the logical key. |
event-scancode |
(integer 0) |
:key-press, :key-release: the platform's code for the key. |
event-repeat-p |
boolean |
:key-press: true when the key repeats because it is held. |
event-text |
string |
:text: the text typed or chosen in an input method. :preedit: the text being composed. |
event-caret-start, event-caret-end |
(integer 0) or nil |
:preedit: the input method's caret in the text being composed, or nil. |
event-delete-before, event-delete-after |
(integer 0) |
:delete-surrounding: how many characters to delete before and after the caret. |
event-button |
button or nil |
:button-press, :button-release. |
event-x, event-y |
single-float |
Pointer, button and scroll events: the pointer's position in units, from the window's top left. |
event-dx, event-dy |
single-float |
:pointer-motion: how far the pointer moved, in units; while the pointer is captured, the device's own motion. |
event-scroll-x, event-scroll-y |
single-float |
:scroll: how far, in steps, positive right and down. |
(event-modifier-p event modifier) says whether a modifier was held, for
key, pointer, button and scroll events, and (event-modifiers event) is
the mask of them all, in modifier-bit bits. See
Keyboard.
The text is reused. The string event-text returns belongs to the
event and is overwritten by the next poll-event into it. Copy it to keep
it, (copy-seq (win:event-text event)), or copy the whole event:
(win:copy-event event kept) ; every field of EVENT into KEPT, made with MAKE-EVENT
copy-event copies every field of one event into another, its text into
the other's own string, and returns the other: to keep an event past the
next poll-event, or to hand it on, as a queue of events does. It
allocates nothing unless the text is longer than the other's string has
room for.
An event struct belongs to the thread that polls into it.
Event types
Windows
| Type | Meaning | Fields |
|---|---|---|
:resize |
The window system proposes a new size, a new scale, or both. The first :resize reports the first size. |
width, height, scale |
:close |
The user asked to close the window, for example with its close button, or the window system dismissed a popup. The window stays open until you destroy it. | |
:focus-in |
The window gained the keyboard. | |
:focus-out |
The window lost the keyboard. |
A :resize event is an announcement. It does not mean the window has the
new size yet: see Resizing and Scaling. When
several resizes arrive before you poll, the window's pending size is the
latest, so act on window-pending-size rather than on each event.
:close is a request. Ask the user to save their work, or ignore it, or
destroy the window. For a popup the window system dismissed,
popup-dismissed-p is true: destroy it. See Popups.
Keyboard
| Type | Meaning | Fields |
|---|---|---|
:key-press |
A key went down, or repeated because it is held. | key, symbol, scancode, repeat-p, modifiers |
:key-release |
A key came up. | key, symbol, scancode, modifiers |
:text |
Text was typed, or chosen in an input method. | text |
Keyboard events go to the window that has the keyboard focus, between
:focus-in and :focus-out. See Keyboard.
Input methods
| Type | Meaning | Fields |
|---|---|---|
:preedit |
The text an input method is composing, to show at the caret; "" when nothing is composed. |
text, caret-start, caret-end |
:delete-surrounding |
Delete characters around the caret. | delete-before, delete-after |
They come only while the window takes text from an input method, after
start-text-input. See Input Methods.
Pointer
| Type | Meaning | Fields |
|---|---|---|
:pointer-enter |
The pointer came into the window. | x, y, modifiers |
:pointer-leave |
The pointer left the window. | x, y (where it was last), modifiers |
:pointer-motion |
The pointer moved over the window. | x, y, dx, dy, modifiers |
:button-press |
A button went down. | button, x, y, modifiers |
:button-release |
A button came up. | button, x, y, modifiers |
:scroll |
A wheel turned or a touchpad scrolled. | scroll-x, scroll-y, x, y, modifiers |
Pointer events go to the window under the pointer, between
:pointer-enter and :pointer-leave. See Pointer.
A dispatch loop
(defun handle (event)
(case (win:event-type event)
(:close
(setf *running* nil))
(:key-press
(cond ((and (win:event-modifier-p event :control)
(eq (win:event-symbol event) :z))
(undo))
((eq (win:event-key event) :escape)
(setf *running* nil))))
(:text
(insert-text (copy-seq (win:event-text event))))
(:pointer-motion
(hover (win:event-x event) (win:event-y event)))
(:button-press
(when (eq (win:event-button event) :left)
(click (win:event-x event) (win:event-y event))))
(:scroll
(scroll-by (win:event-scroll-y event)))))
With several windows, event-window says which window an event is about.