From e57efb5e375d719f80bddb7761836b5d9b24f76a Mon Sep 17 00:00:00 2001 From: Lephe Date: Sat, 23 Apr 2022 13:34:41 +0100 Subject: [PATCH] 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. --- CMakeLists.txt | 5 + include/gint/drivers/keydev.h | 70 +++++----- src/keysc/getkey.c | 11 +- src/keysc/keydev.c | 232 +++++++++++++-------------------- src/keysc/keydev_idle.c | 23 ++++ src/keysc/keydev_process_key.c | 30 +++++ src/keysc/keydown_all.c | 21 +++ src/keysc/keydown_any.c | 21 +++ src/keysc/keysc.c | 98 +++----------- src/keysc/scan_frequency.c | 31 +++++ 10 files changed, 273 insertions(+), 269 deletions(-) create mode 100644 src/keysc/keydev_idle.c create mode 100644 src/keysc/keydev_process_key.c create mode 100644 src/keysc/keydown_all.c create mode 100644 src/keysc/keydown_any.c create mode 100644 src/keysc/scan_frequency.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 39a8fbd..780b82b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -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 diff --git a/include/gint/drivers/keydev.h b/include/gint/drivers/keydev.h index 604a154..be56273 100644 --- a/include/gint/drivers/keydev.h +++ b/include/gint/drivers/keydev.h @@ -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. */ diff --git a/src/keysc/getkey.c b/src/keysc/getkey.c index 6747965..c3d2774 100644 --- a/src/keysc/getkey.c +++ b/src/keysc/getkey.c @@ -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; } - - diff --git a/src/keysc/keydev.c b/src/keysc/keydev.c index 54bff15..413d143 100644 --- a/src/keysc/keydev.c +++ b/src/keysc/keydev.c @@ -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; + /* 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 }; - /* 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); // and @@ -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); - } // and @@ -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) { diff --git a/src/keysc/keydev_idle.c b/src/keysc/keydev_idle.c new file mode 100644 index 0000000..bd7ad2d --- /dev/null +++ b/src/keysc/keydev_idle.c @@ -0,0 +1,23 @@ +#include +#include +#include + +/* 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); +} diff --git a/src/keysc/keydev_process_key.c b/src/keysc/keydev_process_key.c new file mode 100644 index 0000000..d32ec32 --- /dev/null +++ b/src/keysc/keydev_process_key.c @@ -0,0 +1,30 @@ +#include +#include + +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; + } +} diff --git a/src/keysc/keydown_all.c b/src/keysc/keydown_all.c new file mode 100644 index 0000000..7d8f2e4 --- /dev/null +++ b/src/keysc/keydown_all.c @@ -0,0 +1,21 @@ +#include +#include + +/* 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; +} diff --git a/src/keysc/keydown_any.c b/src/keysc/keydown_any.c new file mode 100644 index 0000000..94feced --- /dev/null +++ b/src/keysc/keydown_any.c @@ -0,0 +1,21 @@ +#include +#include + +/* 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; +} diff --git a/src/keysc/keysc.c b/src/keysc/keysc.c index 03822ac..d5ef2f6 100644 --- a/src/keysc/keysc.c +++ b/src/keysc/keysc.c @@ -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); diff --git a/src/keysc/scan_frequency.c b/src/keysc/scan_frequency.c new file mode 100644 index 0000000..af217cc --- /dev/null +++ b/src/keysc/scan_frequency.c @@ -0,0 +1,31 @@ +#include +#include + +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); +}