File the keystroke ring's missing modifier state as item 10
akbasic built a line editor on akgl_controller_poll_key() and found the ring carries a keycode and nothing else. No shifted character is reachable, so a BASIC string literal cannot be typed at all. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
47
TODO.md
47
TODO.md
@@ -883,6 +883,11 @@ Doing that turned up **items 5 through 9**, filed below. Four are things `akbasi
|
||||
around to build at all; each workaround is commented at its site over there with the words
|
||||
"filed upstream", so they can be found and deleted when these land.
|
||||
|
||||
Building the *standalone* SDL frontend on top of all that — a real window, a real event pump
|
||||
and a line editor — turned up **item 10**, and re-confirmed items 6 and 7: both workarounds
|
||||
had to be written a second time, in `src/frontend_akgl.c`, because a host that owns a window is
|
||||
exactly the caller they inconvenience.
|
||||
|
||||
These are filed here rather than worked around in `akbasic` because growing `libakgl` to serve
|
||||
a consumer is the wanted outcome. Each entry says what the BASIC verb needs, what the
|
||||
`akgl_*` entry point should look like, and what would cover it.
|
||||
@@ -1099,6 +1104,48 @@ a consumer is the wanted outcome. Each entry says what the BASIC verb needs, wha
|
||||
hand and assert the frame at which the pitch has moved, exactly as `tests/audio.c` already
|
||||
does for the envelope stages.
|
||||
|
||||
10. **The keystroke ring carries a keycode and nothing else, so Shift is invisible.**
|
||||
`akgl_controller_handle_event()` (`src/controller.c:104-105`) pushes `event->key.key` into
|
||||
the ring and drops the rest of the event, and `akgl_controller_poll_key(int *keycode, bool
|
||||
*available)` hands back only that. Item 4 asked for a non-blocking keystroke read and got
|
||||
one; what it did not ask for, and what a *line editor* turns out to need, is which
|
||||
character the keystroke actually produced.
|
||||
|
||||
`akbasic` has now built one — an `INPUT` and a REPL prompt drawn in the window, in
|
||||
`src/sink_akgl.c` — and the consequence is concrete: no shifted character is reachable, so
|
||||
`"`, `!`, `(`, `)`, `:` and `;` cannot be typed at all, and lower case cannot be typed
|
||||
either. A BASIC line editor that cannot type a double quote cannot enter a string literal.
|
||||
The interpreter folds letters to upper case, which is what a C128 does anyway and is the
|
||||
right resolution for letters; it is not a resolution for punctuation, and there is nothing
|
||||
the caller can do about it because the modifier state was discarded two layers down.
|
||||
|
||||
Note this is not solvable by the caller polling `SDL_GetModState()` at read time: by then
|
||||
the key is long released, and the whole point of a ring is that reads are decoupled from
|
||||
events.
|
||||
|
||||
**Fix:** widen the ring entry to carry the modifier state and the composed text SDL already
|
||||
computes. Either
|
||||
|
||||
```c
|
||||
typedef struct akgl_Keystroke {
|
||||
SDL_Keycode key;
|
||||
SDL_Keymod mod;
|
||||
char text[8]; /* UTF-8, from SDL_EVENT_TEXT_INPUT; "" for a non-printing key */
|
||||
} akgl_Keystroke;
|
||||
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_poll_keystroke(akgl_Keystroke *dest, bool *available);
|
||||
```
|
||||
|
||||
alongside the existing `akgl_controller_poll_key()`, which stays as it is so nothing
|
||||
breaks — a game asking "was the up arrow pressed" wants exactly what it already gets.
|
||||
Filling `text` means handling `SDL_EVENT_TEXT_INPUT` as well as `SDL_EVENT_KEY_DOWN`, which
|
||||
is the only correct way to get a character out of SDL anyway: it is what makes a keyboard
|
||||
layout, a compose key and a dead key work, none of which a keycode can express.
|
||||
|
||||
Tests would push a shifted key-down plus its text-input event through
|
||||
`akgl_controller_handle_event()` and assert both the keycode and the composed character
|
||||
come back, mirroring what `tests/controller.c` already does for the plain ring.
|
||||
|
||||
## Carried over
|
||||
|
||||
1. **Make character-to-sprite state bindings release their references symmetrically.**
|
||||
|
||||
Reference in New Issue
Block a user