keysc: simpler keyboard device with more consistent repeats

* Stop trying to be smart and generate repeats on the fly; this breaks
  time consistency. Also if repeats are not handled in time this causes
  infinite loops.
* Move rarely-used functions to external files, simplify stuff, get rid
  of internal driver events; saves ~1 kB per add-in overall.
This commit is contained in:
Lephe 2022-04-23 13:34:41 +01:00
parent 0c2935055e
commit e57efb5e37
No known key found for this signature in database
GPG key ID: 1BBA026E13FC0495
10 changed files with 273 additions and 269 deletions

View file

@ -85,7 +85,12 @@ set(SOURCES_COMMON
src/keysc/iokbd.c
src/keysc/keycodes.c
src/keysc/keydev.c
src/keysc/keydev_idle.c
src/keysc/keydev_process_key.c
src/keysc/keydown_all.c
src/keysc/keydown_any.c
src/keysc/keysc.c
src/keysc/scan_frequency.c
# Memory allocator
src/kmalloc/arena_gint.c
src/kmalloc/arena_osheap.c

View file

@ -14,19 +14,6 @@ extern "C" {
/* Size of the buffer event queue */
#define KEYBOARD_QUEUE_SIZE 32
/* keydev_event_t: Change of state in a full row */
typedef struct {
/* Device time for the event */
uint16_t time;
/* Keys that changed state */
uint8_t changed;
/* Row number */
uint8_t row :4;
/* Type of change, either KEYEV_DOWN or KEYEV_UP */
uint8_t kind :4;
} keydev_event_t;
/* Event transforms
Every keyboard input device has a built-in event stream editor that can
@ -84,14 +71,26 @@ typedef struct {
enum {
/* Delayed SHIFT: Pressing then immediately releasing SHIFT when the
keyboard is idle applies SHIFT to the next repeat streak. */
KEYDEV_TR_DELAYED_SHIFT = 0x01,
KEYDEV_TR_DELAYED_SHIFT = 0x01, /* = GETKEY_MOD_SHIFT */
/* Delayed ALPHA: Idem with the ALPHA key */
KEYDEV_TR_DELAYED_ALPHA = 0x02,
KEYDEV_TR_DELAYED_ALPHA = 0x02, /* = GETKEY_MOD_ALPHA */
/* Combination of the delayed modifiers */
KEYDEV_TR_DELAYED_MODS = KEYDEV_TR_DELAYED_SHIFT
| KEYDEV_TR_DELAYED_ALPHA,
/* Instant SHIFT: Each individual event of every repeat streak gets
SHIFT applied if SHIFT is pressed at the time of the repeat. */
KEYDEV_TR_INSTANT_SHIFT = 0x04,
/* Instant ALPHA: Idem with the ALPHA key */
KEYDEV_TR_INSTANT_ALPHA = 0x08,
/* Combination of the instance modifiers */
KEYDEV_TR_INSTANT_MODS = KEYDEV_TR_INSTANT_SHIFT
| KEYDEV_TR_INSTANT_ALPHA,
/* Combination of all modifiers */
KEYDEV_TR_ALL_MODS = KEYDEV_TR_DELAYED_MODS
| KEYDEV_TR_INSTANT_MODS,
/* Repeats: Keys are repeated according to a repeat filter function */
KEYDEV_TR_REPEATS = 0x10,
/* Delete Modifiers: Remove modifier keys from generated events, which
@ -143,31 +142,16 @@ typedef struct {
keydown() are shortcuts for keydev functions using the physical keyboard as
their input. */
typedef struct {
/* Latest state of keys we are aware of. At every processing step, the
different between this and the fresh information is queued and this
is updated. state_now is identical to the real state obtained from
the device unless earlier events failed to be queued, in which case
a difference is maintained so they will be reconsidered later. */
GALIGNED(4) uint8_t state_now[12];
/* State of keys based on produced events. (state_queue + queue) is
always identical to (state_now). When the queue is empty both states
are the same. This is the user's view of the keyboard. */
GALIGNED(4) uint8_t state_queue[12];
/* Current device time in scanning-ticks */
uint time;
/* Last time when repeats were considered */
uint time_repeats;
/* Event queue (circular buffer) */
keydev_event_t queue[KEYBOARD_QUEUE_SIZE];
/* Next event in queue, position after last event in queue */
int8_t queue_next;
int8_t queue_end;
/* Number of events lost because of missing queue space */
uint events_lost;
/* Crafted events waiting to be picked up */
key_event_t out[8];
int out_size;
/* Event transforms */
keydev_transform_t tr;
@ -193,6 +177,19 @@ typedef struct {
/* Delay until next repeat, set by the repeat planner (us) */
int rep_delay;
/* Latest state of keys we are aware of. At every processing step, the
different between this and the fresh information is queued and this
is updated. state_now is identical to the real state obtained from
the device unless earlier events failed to be queued, in which case
a difference is maintained so they will be reconsidered later. */
GALIGNED(4) uint8_t state_now[12];
/* State of keys based on produced events. (state_queue + queue) is
always identical to (state_now). When the queue is empty both states
are the same. This is the user's view of the keyboard. */
GALIGNED(4) uint8_t state_queue[12];
/* Event queue (circular buffer) */
key_event_t queue[KEYBOARD_QUEUE_SIZE];
} keydev_t;
/* keydev_std(): Standard keyboard input device
@ -218,6 +215,12 @@ void keydev_process_state(keydev_t *d, uint8_t state[12]);
devices (such as demo replays) to feed in new events. */
void keydev_process_key(keydev_t *d, int keycode, bool state);
/* keydev_repeat_event(): Generate a repeat event if applicable
At the end of every scan tick, this source will generate a repeat event if
the repeat transform is enabled and the conditions for a repeat are
satisfied. */
key_event_t keydev_repeat_event(keydev_t *d);
/* keydev_tick(): Prepare the next tick
This function maintains time trackers in the device and should be called in
each frame after the scanning is finished and the keydev_process_*()
@ -237,13 +240,6 @@ void keydev_tick(keydev_t *d, uint us);
at the end of every tick. */
key_event_t keydev_unqueue_event(keydev_t *d);
/* keydev_repeat_event(): Generate a repeat event if applicable
At the end of every scan tick (or later if the application is unable to keep
up), this source will generate a repeat event if the repeat transform is
enabled and the conditions for a repeat are satisfied. */
key_event_t keydev_repeat_event(keydev_t *d);
/* keydev_idle(): Check if all keys are released
A list of keys to ignore can be specified as variable arguments. The list
must be terminated by a 0 keycode. */

View file

@ -44,11 +44,10 @@ key_event_t getkey_opt(int opt, volatile int *timeout)
keydev_transform_t tr0 = keydev_transform(d);
key_event_t e;
int o = KEYDEV_TR_REPEATS |
KEYDEV_TR_DELETE_MODIFIERS |
KEYDEV_TR_DELETE_RELEASES |
((opt & GETKEY_MOD_SHIFT) ? KEYDEV_TR_DELAYED_SHIFT : 0) |
((opt & GETKEY_MOD_ALPHA) ? KEYDEV_TR_DELAYED_ALPHA : 0);
int o = KEYDEV_TR_REPEATS +
KEYDEV_TR_DELETE_MODIFIERS +
KEYDEV_TR_DELETE_RELEASES +
(opt & (GETKEY_MOD_SHIFT + GETKEY_MOD_ALPHA));
keydev_set_transform(d, (keydev_transform_t){ o, getkey_repeater });
repeat_mode = NONE;
@ -118,5 +117,3 @@ void getkey_set_feature_function(getkey_feature_t function)
{
feature_function = function;
}

View file

@ -19,9 +19,9 @@ void keydev_init(keydev_t *d)
// Driver event generation
//---
/* queue_push(): Add an event in a device's buffer
/* keydev_queue_push(): Add an event in a device's buffer
Returns false if the event cannot be pushed. */
static bool queue_push(keydev_t *d, keydev_event_t e)
bool keydev_queue_push(keydev_t *d, key_event_t ev)
{
int next = (d->queue_end + 1) % KEYBOARD_QUEUE_SIZE;
if(next == d->queue_next)
@ -30,18 +30,18 @@ static bool queue_push(keydev_t *d, keydev_event_t e)
return false;
}
d->queue[d->queue_end] = e;
d->queue[d->queue_end] = ev;
d->queue_end = next;
return true;
}
/* queue_poll(): Generate key events from the buffer
Sets (*e) and returns true on success, otherwise false. */
static bool queue_poll(keydev_t *d, keydev_event_t *e)
static bool queue_poll(keydev_t *d, key_event_t *ev)
{
if(d->queue_next == d->queue_end) return false;
*e = d->queue[d->queue_next];
*ev = d->queue[d->queue_next];
d->queue_next = (d->queue_next + 1) % KEYBOARD_QUEUE_SIZE;
return true;
}
@ -49,51 +49,86 @@ static bool queue_poll(keydev_t *d, keydev_event_t *e)
/* keydev_process_state(): Process the new keyboard states for events */
void keydev_process_state(keydev_t *d, uint8_t scan[12])
{
key_event_t ev = { 0 };
ev.time = d->time;
/* Compare new data with the internal state. Push releases before
presses so that a key change occurring within a single analysis
frame can be performed. This happens all the time when going back to
the main MENU via gint_osmenu() on a keybind. */
for(int row = 0; row < 12; row++)
{
int diff = ~scan[row] & d->state_now[row];
if(!diff) continue;
/* Update internal status if the event can be pushed */
keydev_event_t e = { d->time, diff, row, KEYEV_UP };
if(queue_push(d, e)) d->state_now[row] &= scan[row];
}
for(int row = 0; row < 12; row++)
ev.type = KEYEV_UP;
for(int mode = 0; mode < 2; mode++)
{
int diff = scan[row] & ~d->state_now[row];
if(!diff) continue;
for(int row = 0; row < 12; row++)
{
int diff = mode
? ~d->state_now[row] & scan[row]
: d->state_now[row] & ~scan[row];
if(!diff) continue;
keydev_event_t e = { d->time, diff, row, KEYEV_DOWN };
if(queue_push(d, e)) d->state_now[row] |= scan[row];
ev.key = (row << 4);
for(int mask = 0x80; mask != 0; mask >>= 1)
{
/* Update state only if the push succeeds */
if((diff & mask) && keydev_queue_push(d, ev))
d->state_now[row] = mode
? d->state_now[row] | mask
: d->state_now[row] & ~mask;
ev.key++;
}
}
ev.type = KEYEV_DOWN;
}
}
/* keydev_process_key(): Process a new key state for events */
void keydev_process_key(keydev_t *d, int keycode, bool state)
static bool can_repeat(keydev_t *d, int key)
{
/* If the key has changed state, push an event */
int row = (keycode >> 4) ^ 1;
int col = 0x80 >> (keycode & 0x7);
int tr = d->tr.enabled;
int shift = tr & (KEYDEV_TR_DELAYED_SHIFT | KEYDEV_TR_INSTANT_SHIFT);
int alpha = tr & (KEYDEV_TR_DELAYED_ALPHA | KEYDEV_TR_INSTANT_ALPHA);
int prev = d->state_now[row] & col;
if(state && !prev)
{
keydev_event_t e = { d->time, col, row, KEYEV_DOWN };
if(queue_push(d, e)) d->state_now[row] |= col;
}
else if(!state && prev)
{
keydev_event_t e = { d->time, col, row, KEYEV_UP };
if(queue_push(d, e)) d->state_now[row] &= ~col;
}
return !(key == KEY_SHIFT && shift) && !(key == KEY_ALPHA && alpha);
}
/* keydev_repeat_event(): Generate a repeat event if applicable */
key_event_t keydev_repeat_event(keydev_t *d)
{
key_event_t ev = { 0 };
ev.time = d->time;
/* <Repeats> is disabled */
if(!(d->tr.enabled & KEYDEV_TR_REPEATS)) return ev;
/* No key is being repeated, or it's too early */
if(!d->rep_key || d->rep_delay != 0) return ev;
/* Key is blocked by transform options modified during the streak */
if(!can_repeat(d, d->rep_key)) return ev;
/* Plan the next repeat the currently-pressed key */
int elapsed = (int16_t)(d->time - d->rep_time);
d->rep_delay = -1;
d->rep_count++;
/* Returning < 0 will block further repeats */
if(d->tr.repeater)
d->rep_delay = d->tr.repeater(d->rep_key,elapsed,d->rep_count);
/* Don't return an event on the first call (it's a KEYEV_DOWN) */
if(!d->rep_count) return ev;
ev.type = KEYEV_HOLD;
ev.key = d->rep_key;
return ev;
}
void keydev_tick(keydev_t *d, uint us)
{
/* Generate the next repeat */
key_event_t repeat = keydev_repeat_event(d);
if(repeat.type != KEYEV_NONE)
keydev_queue_push(d, repeat);
d->time++;
if(d->rep_key != 0)
@ -108,65 +143,35 @@ void keydev_tick(keydev_t *d, uint us)
// Keyboard event generation
//---
static bool can_repeat(keydev_t *d, int key)
{
int tr = d->tr.enabled;
int shift = tr & (KEYDEV_TR_DELAYED_SHIFT | KEYDEV_TR_INSTANT_SHIFT);
int alpha = tr & (KEYDEV_TR_DELAYED_ALPHA | KEYDEV_TR_INSTANT_ALPHA);
return !(key == KEY_SHIFT && shift) && !(key == KEY_ALPHA && alpha);
}
/* keydev_unqueue_event(): Retrieve the next keyboard event in queue */
key_event_t keydev_unqueue_event(keydev_t *d)
{
/* Every device event is unfolded into up to 8 keyboard events, stored
temporarily in the driver's structure. */
keydev_event_t e;
key_event_t kev = { .type = KEYEV_NONE, .time = d->time };
/* If there are no events, generate some */
if(d->out_size == 0)
{
if(!queue_poll(d, &e)) return kev;
int changed = e.changed;
kev.type = e.kind;
for(int code = ((e.row ^ 1) << 4) | 0x7; code & 0x7; code--)
{
if(changed & 1)
{
kev.key = code;
d->out[d->out_size++] = kev;
}
changed >>= 1;
}
}
/* Return one of the available events */
kev = d->out[--(d->out_size)];
key_event_t ev = { 0 };
ev.time = d->time;
if(!queue_poll(d, &ev))
return ev;
/* Update the event state accordingly */
int row = (kev.key >> 4) ^ 1;
int col = 0x80 >> (kev.key & 0x7);
int row = (ev.key >> 4);
int col = 0x80 >> (ev.key & 0x7);
if(kev.type == KEYEV_DOWN)
if(ev.type == KEYEV_DOWN)
{
d->state_queue[row] |= col;
/* Mark this key as the currently repeating one */
if(d->rep_key == 0 && can_repeat(d, kev.key))
if(d->rep_key == 0 && can_repeat(d, ev.key))
{
d->rep_key = kev.key;
d->rep_key = ev.key;
d->rep_count = -1;
d->rep_time = 0;
d->rep_delay = 0;
}
}
if(kev.type == KEYEV_UP)
else if(ev.type == KEYEV_UP)
{
d->state_queue[row] &= ~col;
/* End the current repeating streak */
if(d->rep_key == kev.key)
if(d->rep_key == ev.key)
{
d->rep_key = 0;
d->rep_count = -1;
@ -177,66 +182,18 @@ key_event_t keydev_unqueue_event(keydev_t *d)
}
}
return kev;
}
/* keydev_repeat_event(): Generate a repeat event if applicable */
key_event_t keydev_repeat_event(keydev_t *d)
{
key_event_t e = { .type = KEYEV_NONE, .time = d->time };
/* <Repeats> is disabled */
if(!(d->tr.enabled & KEYDEV_TR_REPEATS)) return e;
/* No key is being repeated, or it's too early */
if(!d->rep_key || d->rep_delay != 0) return e;
/* Key is blocked by transform options modified during the streak */
if(!can_repeat(d, d->rep_key)) return e;
/* Plan the next repeat the currently-pressed key */
int elapsed = (int16_t)(d->time - d->rep_time);
d->rep_delay = -1;
d->rep_count++;
/* Returning < 0 will block further repeats */
if(d->tr.repeater)
d->rep_delay = d->tr.repeater(d->rep_key,elapsed,d->rep_count);
/* Don't return an event on the first call (it's a KEYEV_DOWN) */
if(!d->rep_count) return e;
e.key = d->rep_key;
e.type = KEYEV_HOLD;
return e;
return ev;
}
/* keydev_keydown(): Check if a key is down according to generated events */
bool keydev_keydown(keydev_t *d, int key)
{
int row = (key >> 4) ^ 1;
int row = (key >> 4);
int col = 0x80 >> (key & 0x7);
return (d->state_queue[row] & col) != 0;
}
/* keydev_idle(): Check if all keys are released */
bool keydev_idle(keydev_t *d, ...)
{
uint32_t *state = (void *)d->state_queue;
uint32_t check[3] = { state[0], state[1], state[2] };
int key;
va_list args;
va_start(args, d);
while((key = va_arg(args, int)))
{
int row = (key >> 4) ^ 1;
int col = 0x80 >> (key & 0x7);
((uint8_t *)check)[row] &= ~col;
}
va_end(args);
return (check[0] == 0) && (check[1] == 0) && (check[2] == 0);
}
//---
// Event transforms
//---
@ -274,22 +231,12 @@ key_event_t keydev_read(keydev_t *d)
while(1)
{
/* Repeat at the end of every tick, or if we're late */
bool empty = (d->queue_next == d->queue_end) && !d->out_size;
bool end_of_tick = (d->time_repeats == d->time - 1) && empty;
bool late_repeat = (d->time_repeats <= d->time - 2);
if(end_of_tick || late_repeat)
e = keydev_repeat_event(d);
if(e.type == KEYEV_NONE)
e = keydev_unqueue_event(d);
e = keydev_unqueue_event(d);
if(e.type == KEYEV_NONE)
return e;
int k = e.key;
if(opt(INSTANT_SHIFT) || opt(INSTANT_ALPHA)) e.mod = 1;
if(opt(DELAYED_SHIFT) || opt(DELAYED_ALPHA)) e.mod = 1;
e.mod = (opt(ALL_MODS) != 0);
// <Instant SHIFT> and <Instant ALPHA>
@ -299,7 +246,6 @@ key_event_t keydev_read(keydev_t *d)
e.shift |= keydev_keydown(d, KEY_SHIFT);
if(opt(INSTANT_ALPHA) && k != KEY_ALPHA)
e.alpha |= keydev_keydown(d, KEY_ALPHA);
}
// <Delayed SHIFT> and <Delayed ALPHA>
@ -308,10 +254,9 @@ key_event_t keydev_read(keydev_t *d)
{
if(e.type == KEYEV_DOWN && k == KEY_SHIFT)
{
if(d->delayed_shift)
d->delayed_shift = 0;
else if(keydev_idle(d,KEY_SHIFT,0))
if(!d->delayed_shift)
d->pressed_shift = 1;
d->delayed_shift = 0;
}
else if(e.type != KEYEV_UP && k == d->rep_key)
{
@ -329,10 +274,9 @@ key_event_t keydev_read(keydev_t *d)
{
if(e.type == KEYEV_DOWN && k == KEY_ALPHA)
{
if(d->delayed_alpha)
d->delayed_alpha = 0;
else if(keydev_idle(d,KEY_ALPHA,0))
if(!d->delayed_alpha)
d->pressed_alpha = 1;
d->delayed_alpha = 0;
}
else if(e.type != KEYEV_UP && k == d->rep_key)
{

23
src/keysc/keydev_idle.c Normal file
View file

@ -0,0 +1,23 @@
#include <gint/drivers/keydev.h>
#include <stdint.h>
#include <stdarg.h>
/* keydev_idle(): Check if all keys are released */
bool keydev_idle(keydev_t *d, ...)
{
uint32_t *state = (void *)d->state_queue;
uint32_t check[3] = { state[0], state[1], state[2] };
int key;
va_list args;
va_start(args, d);
while((key = va_arg(args, int)))
{
int row = (key >> 4);
int col = 0x80 >> (key & 0x7);
((uint8_t *)check)[row] &= ~col;
}
va_end(args);
return (check[0] == 0) && (check[1] == 0) && (check[2] == 0);
}

View file

@ -0,0 +1,30 @@
#include <gint/drivers/keydev.h>
#include <stdbool.h>
bool keydev_queue_push(keydev_t *d, key_event_t ev);
/* keydev_process_key(): Process a new key state for events */
void keydev_process_key(keydev_t *d, int keycode, bool state)
{
/* If the key has changed state, push an event */
int row = (keycode >> 4);
int col = 0x80 >> (keycode & 0x7);
int prev = d->state_now[row] & col;
if(state && !prev)
{
key_event_t ev = { 0 };
ev.time = d->time;
ev.type = KEYEV_DOWN;
ev.key = keycode;
if(keydev_queue_push(d, ev)) d->state_now[row] |= col;
}
else if(!state && prev)
{
key_event_t ev = { 0 };
ev.time = d->time;
ev.type = KEYEV_UP;
ev.key = keycode;
if(keydev_queue_push(d, ev)) d->state_now[row] &= ~col;
}
}

21
src/keysc/keydown_all.c Normal file
View file

@ -0,0 +1,21 @@
#include <gint/keyboard.h>
#include <stdarg.h>
/* keydown_all(): Check a set of keys for simultaneous input
Returns non-zero if all provided keys are down. The list should end with an
integer 0 as terminator. */
int keydown_all(int key, ...)
{
va_list args;
va_start(args, key);
int st = 1;
while(key && st)
{
st = keydown(key);
key = va_arg(args, int);
}
va_end(args);
return st;
}

21
src/keysc/keydown_any.c Normal file
View file

@ -0,0 +1,21 @@
#include <gint/keyboard.h>
#include <stdarg.h>
/* keydown_any(): Check a set of keys for any input
Returns nonzero if any one of the specified keys is currently pressed. THe
sequence should be terminated by a 0 integer. */
int keydown_any(int key, ...)
{
va_list args;
va_start(args, key);
int st = 0;
while(key && !st)
{
st = keydown(key);
key = va_arg(args, int);
}
va_end(args);
return st;
}

View file

@ -19,44 +19,19 @@
/* Keyboard scan frequency in Hertz. Start with 128 Hz, this frequency *must
be high* for the keyboard to work! Reading at low frequencies produces a lot
of artifacts. See https://www.casiopeia.net/forum/viewtopic.php?p=20592. */
static int scan_frequency = 128;
int keysc_scan_Hz = 128;
/* Approximation in microseconds, used by the timer and repeat delays */
static uint32_t scan_frequency_us = 7812; /* 1000000 / scan_frequency */
uint32_t keysc_scan_us = 7812; /* 1000000 / keysc_scan_Hz */
/* Keyboard scanner timer */
static int keysc_tid = -1;
int keysc_tid = -1;
/* Keyboard input device for this Key Scan Interface */
static keydev_t dev_keysc;
static keydev_t keysc_dev;
/* keydev_std(): Standard keyboard input device */
keydev_t *keydev_std(void)
{
return &dev_keysc;
}
/* keysc_scan_frequency(): Get the current keyboard scan frequency in Hertz */
int keysc_scan_frequency(void)
{
return scan_frequency;
}
/* keysc_scan_frequency_us(): Get keyboard scan delay in microseconds */
uint32_t keysc_scan_frequency_us(void)
{
return scan_frequency_us;
}
/* keysc_set_scan_frequency(): Set the keyboard scan frequency in Hertz */
void keysc_set_scan_frequency(int freq)
{
if(freq < 64) freq = 64;
if(freq > 32768) freq = 32768;
scan_frequency = freq;
scan_frequency_us = 1000000 / freq;
if(keysc_tid < 0) return;
uint32_t TCOR = timer_delay(keysc_tid, scan_frequency_us, 0);
timer_reload(keysc_tid, TCOR);
return &keysc_dev;
}
/* keysc_tick(): Update the keyboard to the next state */
@ -71,18 +46,21 @@ static int keysc_tick(void)
volatile uint16_t *KEYSC = (void *)0xa44b0000;
uint16_t *array = (void *)&scan;
for(int i = 0; i < 6; i++) array[i] = KEYSC[i];
for(int i = 0; i < 6; i++) {
array[i] = KEYSC[i];
array[i] = (array[i] << 8) | (array[i] >> 8);
}
}
keydev_process_state(&dev_keysc, scan);
keydev_tick(&dev_keysc, scan_frequency_us);
keydev_process_state(&keysc_dev, scan);
keydev_tick(&keysc_dev, keysc_scan_us);
return TIMER_CONTINUE;
}
/* pollevent() - poll the next keyboard event */
key_event_t pollevent(void)
{
return keydev_unqueue_event(&dev_keysc);
return keydev_unqueue_event(&keysc_dev);
}
/* waitevent() - wait for the next keyboard event */
@ -97,7 +75,7 @@ key_event_t waitevent(volatile int *timeout)
sleep();
}
key_event_t ev = { .type = KEYEV_NONE, .time = dev_keysc.time };
key_event_t ev = { .type = KEYEV_NONE, .time = keysc_dev.time };
return ev;
}
@ -107,67 +85,25 @@ void clearevents(void)
while(pollevent().type != KEYEV_NONE);
}
//---
// Immediate key access
//---
/* keydown(): Current key state */
int keydown(int key)
{
return keydev_keydown(&dev_keysc, key);
}
/* keydown_all(): Check a set of keys for simultaneous input
Returns non-zero if all provided keys are down. The list should end with an
integer 0 as terminator. */
int keydown_all(int key, ...)
{
va_list args;
va_start(args, key);
int st = 1;
while(key && st)
{
st = keydown(key);
key = va_arg(args, int);
}
va_end(args);
return st;
}
/* keydown_any(): Check a set of keys for any input
Returns nonzero if any one of the specified keys is currently pressed. THe
sequence should be terminated by a 0 integer. */
int keydown_any(int key, ...)
{
va_list args;
va_start(args, key);
int st = 0;
while(key && !st)
{
st = keydown(key);
key = va_arg(args, int);
}
va_end(args);
return st;
return keydev_keydown(&keysc_dev, key);
}
//---
// Driver initialization
// Driver initialization
//---
static void configure(void)
{
keydev_init(&dev_keysc);
keydev_init(&keysc_dev);
/* Set the default repeat times (milliseconds) */
getkey_repeat(400, 40);
/* The timer will be stopped when the timer driver is unloaded */
keysc_tid = timer_configure(TIMER_ANY, scan_frequency_us,
keysc_tid = timer_configure(TIMER_ANY, keysc_scan_us,
GINT_CALL(keysc_tick));
if(keysc_tid >= 0) timer_start(keysc_tid);

View file

@ -0,0 +1,31 @@
#include <gint/keyboard.h>
#include <gint/timer.h>
extern int keysc_scan_Hz;
extern uint32_t keysc_scan_us;
extern int keysc_tid;
/* keysc_scan_frequency(): Get the current keyboard scan frequency in Hertz */
int keysc_scan_frequency(void)
{
return keysc_scan_Hz;
}
/* keysc_scan_frequency_us(): Get keyboard scan delay in microseconds */
uint32_t keysc_scan_frequency_us(void)
{
return keysc_scan_us;
}
/* keysc_set_scan_frequency(): Set the keyboard scan frequency in Hertz */
void keysc_set_scan_frequency(int freq)
{
if(freq < 64) freq = 64;
if(freq > 32768) freq = 32768;
keysc_scan_Hz = freq;
keysc_scan_us = 1000000 / freq;
if(keysc_tid < 0) return;
uint32_t TCOR = timer_delay(keysc_tid, keysc_scan_us, 0);
timer_reload(keysc_tid, TCOR);
}