keyboard: add keypressed() and keyreleased() functions

This commit is contained in:
Lephe 2023-07-24 14:08:23 +02:00
parent 16259deb20
commit 6d86c54507
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
4 changed files with 86 additions and 1 deletions

View file

@ -207,6 +207,9 @@ typedef struct {
/* Parameters for the standard repeat function */
int rep_standard_first, rep_standard_next;
/* State of keys that have changes since the last flip monitoring reset. */
GALIGNED(4) uint8_t state_flips[12];
} keydev_t;
/* keydev_std(): Standard keyboard input device
@ -274,6 +277,17 @@ void keydev_set_async_filter(keydev_t *d, keydev_async_filter_t filter);
/* keydev_keydown(): Check if a key is down according to generated events */
bool keydev_keydown(keydev_t *d, int key);
/* keydev_keypressed(): Check if a key was pressed
This compares to the state at the time of the last keydev_clear_flips(). */
bool keydev_keypressed(keydev_t *d, int key);
/* keydev_keyreleased(): Check if a key was released
This compares to the state at the time of the last keydev_clear_flips(). */
bool keydev_keyreleased(keydev_t *d, int key);
/* keydev_clear_flips(): Reset flip info used by keypressed()/keyreleased() */
void keydev_clear_flips(keydev_t *d);
/* keydev_transform(): Obtain current transform parameters */
keydev_transform_t keydev_transform(keydev_t *d);

View file

@ -60,6 +60,24 @@ extern "C" {
* clearevents() reads all pending events from the input queue.
Games are often also interested in whether keys were pressed or released
_since the last frame_. gint doesn't know what a frame is, but you can track
key state flips by using cleareventflips() before reading events and
keypressed() and keyreleased() afterwards.
* keypressed() checks if the specified key is currently down and was up at
the time of the last cleareventflips().
* keyreleased() checks if the specified key is currently up and was down at
the time of the last cleareventflips().
A typical game loop might look like. cleareventflisps() must be called
_before_ clearevents().
cleareventflips();
clearevents(); // or pollevent(), waitevent()
if(keydown(KEY_RIGHT)) move();
if(keypressed(KEY_F6)) open_inventory();
The previous functions are quite low-level. GUI programs that look like the
system applications will prefer using a GetKey()-like functions that return
a single key press at a time, heeds for releases, for SHIFT and ALPHA
@ -162,6 +180,12 @@ key_event_t waitevent(volatile int *timeout);
/* clearevents(): Read all events waiting in the queue */
void clearevents(void);
/* cleareventflips(): Set the time reference for keypressed()/keyreleased()
The two functions keypressed() and keyreleased() will use the keyboard state
at the time this function was called to determine whether any given key was
just pressed or jut released. */
void cleareventflips(void);
//---
// Key state functions
//---
@ -181,6 +205,16 @@ int keydown_all(int key1, ...);
sequence should be terminated by a 0 integer. */
int keydown_any(int key1, ...);
/* keypressed(): Check if a key was just pressed
This function returns non-zero if the specified key is currently down, *and*
it was up at the time of the last call to cleareventflips(). */
int keypressed(int key);
/* keyreleased(): Check if a key was just released
This function returns non-zero if the specified key is currently up, *and*
it was down at the time of the last call to cleareventflips(). */
int keyreleased(int key);
//---
// High-level functions
//---

View file

@ -179,6 +179,7 @@ key_event_t keydev_unqueue_event(keydev_t *d)
if(ev.type == KEYEV_DOWN)
{
d->state_queue[row] |= col;
d->state_flips[row] ^= col;
/* Mark this key as the currently repeating one */
if(d->rep_key == 0 && can_repeat(d, ev.key))
{
@ -191,6 +192,7 @@ key_event_t keydev_unqueue_event(keydev_t *d)
else if(ev.type == KEYEV_UP)
{
d->state_queue[row] &= ~col;
d->state_flips[row] ^= col;
/* End the current repeating streak */
if(d->rep_key == ev.key)
{
@ -219,6 +221,27 @@ bool keydev_keydown(keydev_t *d, int key)
__attribute__((alias("keydev_keydown")))
bool _WEAK_keydev_keydown(keydev_t *d, int key);
bool keydev_keypressed(keydev_t *d, int key)
{
int row = (key >> 4);
int col = 0x80 >> (key & 0x7);
return (d->state_queue[row] & col) && (d->state_flips[row] & col);
}
bool keydev_keyreleased(keydev_t *d, int key)
{
int row = (key >> 4);
int col = 0x80 >> (key & 0x7);
return !(d->state_queue[row] & col) && (d->state_flips[row] & col);
}
void keydev_clear_flips(keydev_t *d)
{
memset(d->state_flips, 0, sizeof d->state_flips);
}
//---
// Event transforms
//---

View file

@ -102,12 +102,26 @@ void clearevents(void)
while(pollevent().type != KEYEV_NONE);
}
/* keydown(): Current key state */
void cleareventflips(void)
{
keydev_clear_flips(&keysc_dev);
}
int keydown(int key)
{
return keydev_keydown(&keysc_dev, key);
}
int keypressed(int key)
{
return keydev_keypressed(&keysc_dev, key);
}
int keyreleased(int key)
{
return keydev_keyreleased(&keysc_dev, key);
}
//---
// Driver initialization
//---