mirror of
https://git.planet-casio.com/Lephenixnoir/gint.git
synced 2024-12-29 13:03:36 +01:00
getkey: use the new keydev interface
The repeat filter was also changed in favor of a forward-acting function, which determines repeat delays *before* the repeat actually occurs.
This commit is contained in:
parent
dd564f094a
commit
910677f7ff
5 changed files with 88 additions and 182 deletions
|
@ -210,8 +210,8 @@ enum {
|
|||
/* Repeat arrow keys, or even all keys */
|
||||
GETKEY_REP_ARROWS = 0x10,
|
||||
GETKEY_REP_ALL = 0x20,
|
||||
/* Enable repeat event filtering; see getkey_repeat_filter() */
|
||||
GETKEY_REP_FILTER = 0x40,
|
||||
/* Enable custom repeat profiles; see getkey_set_repeat_profile() */
|
||||
GETKEY_REP_PROFILE = 0x40,
|
||||
|
||||
/* No modifiers */
|
||||
GETKEY_NONE = 0x00,
|
||||
|
@ -219,6 +219,10 @@ enum {
|
|||
GETKEY_DEFAULT = 0x5f,
|
||||
};
|
||||
|
||||
/* getkey_profile_t: Custom repeat profile function
|
||||
See getkey_set_repeat_profile() for details. */
|
||||
typedef int (*getkey_profile_t)(int key, int duration, int count);
|
||||
|
||||
/* getkey_opt(): Enhanced getkey()
|
||||
|
||||
This function enhances getkey() with more general features. An
|
||||
|
@ -256,32 +260,33 @@ key_event_t getkey_opt(int options, volatile int *timeout);
|
|||
@next Delay between subsequent repeats (no more than one hour) */
|
||||
void getkey_repeat(int first, int next);
|
||||
|
||||
/* getkey_repeat_filter(): Set the repeat filter function
|
||||
/* getkey_repeat_profile(): Get the current repeat profile function */
|
||||
getkey_profile_t getkey_repeat_profile(void);
|
||||
|
||||
The repeat filter is called by getkey() and getkey_opt() every time a repeat
|
||||
event occurs when GETKEY_REP_FILTER is set. The filter can decide whether to
|
||||
keep, delay or drop the event. It can also change the repeat delays with
|
||||
getkey_repeat() for fully custom repeat delay curves.
|
||||
/* getkey_set_repeat_profile(): Set the repeat profile function
|
||||
|
||||
The time elapsed since the last accepted repeat is passed to the filter
|
||||
function; this time must be larger than the repeat time set with
|
||||
getkey_repeat() for getkey() and getkey_opt() to consider a repeat, but it
|
||||
can be much longer if some repeat events were previously filtered out.
|
||||
The repeat profile is called by getkey() and getkey_opt() when a key is
|
||||
pressed or held, and getkey() is planning to repeat it. The profile decides
|
||||
whether such repetition is allowed, and if so, how long it shoud take. The
|
||||
profile has access to the following information:
|
||||
|
||||
@key Key that is about to be repeated
|
||||
@duration Duration since last accepted repeat
|
||||
@count Number of previous repeats
|
||||
@key Key for which a repetition is being considered
|
||||
@duration Duration since the key was first pressed (us)
|
||||
@count Number of previous repeats (0 on the first call)
|
||||
|
||||
The repeat function must either return:
|
||||
* 0, in which case the even is accepted
|
||||
* A positive number of milliseconds, in which case the event is tentatively
|
||||
re-emitted after that time (the filter function will be called again)
|
||||
* A negative number, in which case the event is dropped and further repeats
|
||||
are denied.
|
||||
The profile function must either return a positive number of microseconds to
|
||||
wait until the next repeat, or 0 to block the repeat indefinitely. Note that
|
||||
the keyboard device typically updates every 7-8 ms, timings are tracked in
|
||||
microseconds only to limit deviations.
|
||||
|
||||
By default the filter function is NULL, which accepts all repeat events.
|
||||
This behavior can be restored explicitly by calling with function=NULL. */
|
||||
void getkey_repeat_filter(int (*filter)(int key, int duration, int count));
|
||||
Setting a repeat profile overrides GETKEY_REP_ARROWS, GETKEY_REP_ALL, and
|
||||
the repeat delays. Calling with profile=NULL restores this behavior.
|
||||
|
||||
This mechanism replaces a "repeat filter" that existed until gint 2.4. The
|
||||
main difference is that the repeat filter was called when the repeat event
|
||||
arrived, whereas the repeat profile is called one repeat earlier to schedule
|
||||
the repeat exactly when needed. */
|
||||
void getkey_set_repeat_profile(getkey_profile_t profile);
|
||||
|
||||
//---
|
||||
// Key code functions
|
||||
|
|
|
@ -3,23 +3,31 @@
|
|||
//---
|
||||
|
||||
#include <gint/keyboard.h>
|
||||
#include <gint/drivers/keydev.h>
|
||||
#include <gint/gint.h>
|
||||
#include <gint/defs/types.h>
|
||||
#include "getkey.h"
|
||||
|
||||
#ifdef FX9860G
|
||||
#include <gint/drivers/t6k11.h>
|
||||
#endif
|
||||
|
||||
/* Delay between a key press and the first repeat, in scan intervals */
|
||||
static int rep_first = 51;
|
||||
/* Delay between subsequent repeats, in scan intervals */
|
||||
static int rep_next = 5;
|
||||
/* Same in milliseconds (values supplied by the user */
|
||||
static int rep_first_ms = 400, rep_next_ms = 40;
|
||||
/* Delay before first repeat and subsequent repeats, in milliseconds */
|
||||
static int rep_first = 400, rep_next = 40;
|
||||
/* Repeat profile function */
|
||||
static getkey_profile_t repeat_profile = NULL;
|
||||
/* Repeater specification */
|
||||
static enum { NONE, ALL, ARROWS, FILTER } repeat_mode;
|
||||
|
||||
/* Repeat filter function */
|
||||
static int (*filter_function)(int key, int duration, int count) = NULL;
|
||||
static int getkey_repeater(int key, int duration, int count)
|
||||
{
|
||||
if(repeat_mode == NONE) return -1;
|
||||
if(repeat_mode == FILTER) return repeat_profile(key, duration, count);
|
||||
|
||||
if(repeat_mode == ARROWS && key != KEY_LEFT && key != KEY_RIGHT
|
||||
&& key != KEY_UP && key != KEY_DOWN) return -1;
|
||||
|
||||
return (count ? rep_next : rep_first) * 1000;
|
||||
}
|
||||
|
||||
/* getkey(): Wait for a key press */
|
||||
key_event_t getkey(void)
|
||||
|
@ -30,159 +38,61 @@ key_event_t getkey(void)
|
|||
/* getkey_opt(): Enhanced getkey() */
|
||||
key_event_t getkey_opt(int opt, volatile int *timeout)
|
||||
{
|
||||
key_event_t ev;
|
||||
int shift = 0, alpha = 0, key = 0;
|
||||
keydev_t *d = keydev_std();
|
||||
keydev_transform_t tr0 = keydev_transform(d);
|
||||
key_event_t e;
|
||||
|
||||
/* Last pressed key (only this key may be repeated) */
|
||||
static int rep_key = 0;
|
||||
/* Number of repeats already emitted */
|
||||
static int rep_count = 0;
|
||||
/* Keyboard time when the key was pressed */
|
||||
static int rep_time = 0;
|
||||
/* Additional repeat delay set by the filtering function */
|
||||
static int rep_delay = 0;
|
||||
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);
|
||||
keydev_set_transform(d, (keydev_transform_t){ o, getkey_repeater });
|
||||
|
||||
/* Reset the state if the repeated key went up while getkey() was not
|
||||
aware (this happens when different keyboard primitives are used) */
|
||||
if(rep_key && !keydown(rep_key))
|
||||
repeat_mode = NONE;
|
||||
if(opt & GETKEY_REP_ARROWS) repeat_mode = ARROWS;
|
||||
if(opt & GETKEY_REP_ALL) repeat_mode = ALL;
|
||||
if(opt & GETKEY_REP_PROFILE && repeat_profile) repeat_mode = FILTER;
|
||||
|
||||
while(1)
|
||||
{
|
||||
rep_key = 0;
|
||||
rep_count = 0;
|
||||
rep_time = 0;
|
||||
rep_delay = 0;
|
||||
}
|
||||
e = keydev_read(d);
|
||||
if(e.type == KEYEV_NONE && timeout && *timeout) break;
|
||||
|
||||
while(1) switch((ev = pollevent()).type)
|
||||
{
|
||||
/* Key press: handle modifiers or return an event */
|
||||
case KEYEV_DOWN:
|
||||
key = ev.key;
|
||||
if(rep_key && key != rep_key) break;
|
||||
|
||||
/* Handle backlight on fx9860g */
|
||||
#ifdef FX9860G
|
||||
if(opt & GETKEY_BACKLIGHT && key == KEY_OPTN && shift)
|
||||
{
|
||||
/* Backlight toggle */
|
||||
else if((opt & GETKEY_BACKLIGHT) && e.type == KEYEV_DOWN &&
|
||||
e.key == KEY_OPTN && e.shift && !e.alpha)
|
||||
t6k11_backlight(-1);
|
||||
shift = 0;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
/* Return to menu */
|
||||
if(opt & GETKEY_MENU && key == KEY_MENU && !(alpha || shift))
|
||||
{
|
||||
/* Return-to-menu */
|
||||
else if((opt & GETKEY_MENU) && e.type == KEYEV_DOWN &&
|
||||
e.key == KEY_MENU && !e.shift && !e.alpha)
|
||||
gint_osmenu();
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Update modifiers */
|
||||
if(opt & GETKEY_MOD_SHIFT && key == KEY_SHIFT)
|
||||
{
|
||||
shift ^= 1;
|
||||
rep_key = 0;
|
||||
continue;
|
||||
}
|
||||
if(opt & GETKEY_MOD_ALPHA && key == KEY_ALPHA)
|
||||
{
|
||||
alpha ^= 1;
|
||||
rep_key = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Return current event */
|
||||
rep_key = key;
|
||||
rep_count = 0;
|
||||
rep_time = ev.time;
|
||||
rep_delay = 0;
|
||||
|
||||
ev.mod = 1;
|
||||
ev.shift = shift;
|
||||
ev.alpha = alpha;
|
||||
return ev;
|
||||
|
||||
/* If nothing happens, stop or wait for a repeat to occur */
|
||||
case KEYEV_NONE:
|
||||
/* Timeout has expired, return KEYEV_NONE */
|
||||
if(timeout && *timeout) return ev;
|
||||
|
||||
/* Check that the last pressed key can be repeated */
|
||||
int arrow = (rep_key == KEY_LEFT || rep_key == KEY_RIGHT ||
|
||||
rep_key == KEY_UP || rep_key == KEY_DOWN);
|
||||
|
||||
if(!rep_key || !(
|
||||
(opt & GETKEY_REP_ALL) ||
|
||||
(opt & GETKEY_REP_ARROWS && arrow)
|
||||
)) break;
|
||||
|
||||
/* If the key is key pressed long enough, create a new event */
|
||||
int duration = (int16_t)(ev.time - rep_time);
|
||||
|
||||
if(rep_delay < 0) break;
|
||||
int target = (rep_count ? rep_next : rep_first) + rep_delay;
|
||||
if(duration < target) break;
|
||||
|
||||
/* Filter out the event if repeat filtering is on */
|
||||
if(filter_function && (opt & GETKEY_REP_FILTER))
|
||||
{
|
||||
int s = filter_function(rep_key, duration, rep_count);
|
||||
/* Drop repeats forever */
|
||||
if(s < 0)
|
||||
{
|
||||
rep_delay = -1;
|
||||
break;
|
||||
}
|
||||
/* Delay repeat by set amount */
|
||||
if(s > 0)
|
||||
{
|
||||
s = (s * keysc_scan_frequency()) / 1000;
|
||||
rep_delay += s;
|
||||
break;
|
||||
}
|
||||
/* Accepts repeat (fallthrough) */
|
||||
}
|
||||
|
||||
rep_time += target;
|
||||
rep_count++;
|
||||
rep_delay = 0;
|
||||
|
||||
ev.mod = 1;
|
||||
ev.shift = shift;
|
||||
ev.alpha = alpha;
|
||||
ev.type = KEYEV_HOLD;
|
||||
ev.key = rep_key;
|
||||
return ev;
|
||||
|
||||
/* Reset repeating information if the repeated key is released */
|
||||
case KEYEV_UP:
|
||||
if(ev.key != rep_key) break;
|
||||
|
||||
rep_key = 0;
|
||||
rep_count = 0;
|
||||
rep_time = 0;
|
||||
rep_delay = 0;
|
||||
break;
|
||||
else if(e.type == KEYEV_DOWN || e.type == KEYEV_HOLD) break;
|
||||
}
|
||||
|
||||
keydev_set_transform(d, tr0);
|
||||
return e;
|
||||
}
|
||||
|
||||
/* getkey_repeat(): Set repeat delays for getkey() */
|
||||
void getkey_repeat(int first, int next)
|
||||
{
|
||||
rep_first_ms = first;
|
||||
rep_next_ms = next;
|
||||
|
||||
rep_first = (first * keysc_scan_frequency()) / 1000;
|
||||
rep_next = (next * keysc_scan_frequency()) / 1000;
|
||||
rep_first = first;
|
||||
rep_next = next;
|
||||
}
|
||||
|
||||
/* getkey_repeat_filter(): Set the repeat filter function */
|
||||
void getkey_repeat_filter(int (*filter)(int key, int duration, int count))
|
||||
/* getkey_repeat_profile(): Get the current repeat profile function */
|
||||
getkey_profile_t getkey_repeat_profile(void)
|
||||
{
|
||||
filter_function = filter;
|
||||
return repeat_profile;
|
||||
}
|
||||
|
||||
/* Refresh repeat delays after a change in keyboard scan frequency */
|
||||
void getkey_refresh_delays(void)
|
||||
/* getkey_set_repeat_profile(): Set the repeat profile function */
|
||||
void getkey_set_repeat_profile(getkey_profile_t profile)
|
||||
{
|
||||
getkey_repeat(rep_first_ms, rep_next_ms);
|
||||
repeat_profile = profile;
|
||||
}
|
||||
|
|
|
@ -1,11 +0,0 @@
|
|||
//---
|
||||
// gint:keysc:getkey - Internal interface to getkey()
|
||||
//---
|
||||
|
||||
#ifndef GINT_KEYSC_GETKEY
|
||||
#define GINT_KEYSC_GETKEY
|
||||
|
||||
/* Refresh repeat delays after a change in keyboard scan frequency */
|
||||
void getkey_refresh_delays(void);
|
||||
|
||||
#endif /* GINT_KEYSC_GETKEY */
|
|
@ -304,7 +304,10 @@ key_event_t keydev_read(keydev_t *d)
|
|||
{
|
||||
if(e.type == KEYEV_DOWN && k == KEY_SHIFT)
|
||||
{
|
||||
d->pressed_shift |= keydev_idle(d,KEY_SHIFT,0);
|
||||
if(d->delayed_shift)
|
||||
d->delayed_shift = 0;
|
||||
else if(keydev_idle(d,KEY_SHIFT,0))
|
||||
d->pressed_shift = 1;
|
||||
}
|
||||
else if(e.type != KEYEV_UP && k == d->rep_key)
|
||||
{
|
||||
|
@ -322,7 +325,10 @@ key_event_t keydev_read(keydev_t *d)
|
|||
{
|
||||
if(e.type == KEYEV_DOWN && k == KEY_ALPHA)
|
||||
{
|
||||
d->pressed_alpha |= keydev_idle(d,KEY_ALPHA,0);
|
||||
if(d->delayed_alpha)
|
||||
d->delayed_alpha = 0;
|
||||
else if(keydev_idle(d,KEY_ALPHA,0))
|
||||
d->pressed_alpha = 1;
|
||||
}
|
||||
else if(e.type != KEYEV_UP && k == d->rep_key)
|
||||
{
|
||||
|
|
|
@ -14,8 +14,6 @@
|
|||
#include <gint/drivers/iokbd.h>
|
||||
#include <gint/hardware.h>
|
||||
|
||||
#include "getkey.h"
|
||||
|
||||
#include <stdarg.h>
|
||||
|
||||
/* Keyboard scan frequency in Hertz. Start with 128 Hz, this frequency *must
|
||||
|
@ -56,8 +54,6 @@ void keysc_set_scan_frequency(int freq)
|
|||
scan_frequency = freq;
|
||||
scan_frequency_us = 1000000 / freq;
|
||||
|
||||
getkey_refresh_delays();
|
||||
|
||||
if(keysc_tid < 0) return;
|
||||
uint32_t TCOR = timer_delay(keysc_tid, scan_frequency_us, 0);
|
||||
timer_reload(keysc_tid, TCOR);
|
||||
|
|
Loading…
Reference in a new issue