Let a caller take keystrokes without owning the event loop
akbasic's GET and GETKEY ask "is there a keystroke waiting, yes or no" and must not require the interpreter to pump SDL events itself. akgl_controller_poll_key drains one key per call from a fixed 32-entry ring that akgl_controller_handle_event fills, so the host keeps pumping and the embedded interpreter reads at its own pace. akgl_controller_flush_keys discards a backlog. The recording happens before the control-map scan, not after: that scan returns as soon as a binding claims the event, so recording afterwards would have dropped exactly the keys a game also acts on. A full buffer refuses the newest keystroke rather than overwriting the oldest, so a caller reading a line gets what was typed first. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -13,6 +13,16 @@
|
||||
#define AKGL_MAX_CONTROL_MAPS 8
|
||||
#define AKGL_MAX_CONTROLS 32
|
||||
|
||||
/**
|
||||
* @brief Keystrokes akgl_controller_handle_event() will hold for a poller.
|
||||
*
|
||||
* The Commodore keyboard buffer this serves held ten. Thirty-two is enough that
|
||||
* a program which polls once per frame never loses a key to a fast typist, and
|
||||
* small enough that the buffer stays a fixed-size object in the library's data
|
||||
* segment.
|
||||
*/
|
||||
#define AKGL_CONTROLLER_KEY_BUFFER 32
|
||||
|
||||
/** @brief Maps one SDL input to pressed and released callbacks. */
|
||||
typedef struct {
|
||||
uint32_t event_on;
|
||||
@@ -117,4 +127,39 @@ akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_default(int controlmapid, cha
|
||||
* @throws AKERR_NULLPOINTER When the corresponding validation or operation fails.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_open_gamepads(void);
|
||||
|
||||
/**
|
||||
* @brief Take the oldest waiting keystroke, if there is one.
|
||||
*
|
||||
* The rest of this header is built around the host pumping SDL events into
|
||||
* akgl_controller_handle_event(), which suits a game loop and does not suit an
|
||||
* embedded interpreter asking "is there a key waiting, yes or no" without
|
||||
* owning the event loop itself. Every key press that reaches
|
||||
* akgl_controller_handle_event() is recorded in a fixed ring buffer first,
|
||||
* whether or not a control map claims it, and this drains that buffer one
|
||||
* keystroke per call.
|
||||
*
|
||||
* When no key is waiting the call still succeeds: @p available is set to
|
||||
* `false` and @p keycode to 0. The caller polls, it does not block.
|
||||
*
|
||||
* A full buffer drops the *newest* keystroke rather than the oldest, so what
|
||||
* was typed first is what is read first. This runs on whichever thread pumps
|
||||
* events; it is not synchronized.
|
||||
*
|
||||
* @param keycode Output destination populated with the SDL keycode, or 0.
|
||||
* @param available Output destination set to `true` when a keystroke was taken.
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
* @throws AKERR_NULLPOINTER When the corresponding validation or operation fails.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_poll_key(int *keycode, bool *available);
|
||||
|
||||
/**
|
||||
* @brief Discard every keystroke waiting in the buffer.
|
||||
*
|
||||
* For a caller that has been ignoring input and does not want a backlog acted
|
||||
* on the moment it starts polling again.
|
||||
*
|
||||
* @return `NULL` on success, otherwise an error context owned by the caller.
|
||||
*/
|
||||
akerr_ErrorContext AKERR_NOIGNORE *akgl_controller_flush_keys(void);
|
||||
#endif // _CONTROLLER_H_
|
||||
|
||||
Reference in New Issue
Block a user