keysc: make repeat settings global instead of just for getkey()

Having repeat settings only for getkey() meant that repeats that occur
while getkey() is not running (i.e., all of them) would be lost. This is
due to e57efb5e3 which replaced on-demand repeats with normal event
generation.

Now the settings are applied globally, which allows repeats to be
enabled even when getkey() is not active. This also reduces the feature
gap between getkey() and raw events, which reduces the risk of running
into edges cases by using both.

The previous API is retained for source compatibility until gint 3.0 but
the changes are now applied globally so the semantics are slightly
different.
master
Lephe 2 months ago
parent 4e1136d0ac
commit 6ea2f991a3
Signed by: Lephenixnoir
GPG Key ID: 1BBA026E13FC0495
  1. 36
      include/gint/drivers/keydev.h
  2. 79
      include/gint/keyboard.h
  3. 86
      src/keysc/getkey.c
  4. 15
      src/keysc/keydev.c
  5. 6
      src/keysc/keysc.c

@ -100,6 +100,9 @@ enum {
KEYDEV_TR_DELETE_RELEASES = 0x40,
};
/* keydev_repeat_profile_t: Function deciding when and how to repeat keys. */
typedef int (*keydev_repeat_profile_t)(int key, int duration, int count);
/* keydev_transform_t: Full specification for transforms on the event stream */
typedef struct {
/* List of enabled transforms. The order is cannot be changed because
@ -121,7 +124,7 @@ typedef struct {
that the precision of the delay is limited by the speed at which the
keyboard is scanned, which is nowhere near microsecond-level. By
default (128 Hz) the precision is about 7.8 ms. */
int (*repeater)(int key, int duration, int count);
keydev_repeat_profile_t repeater;
} GPACKEDENUM keydev_transform_t;
@ -190,6 +193,9 @@ typedef struct {
/* Event queue (circular buffer) */
key_event_t queue[KEYBOARD_QUEUE_SIZE];
/* Parameters for the standard repeat function */
int rep_standard_first, rep_standard_next;
} keydev_t;
/* keydev_std(): Standard keyboard input device
@ -234,10 +240,9 @@ void keydev_tick(keydev_t *d, uint us);
/* keydev_unqueue_event(): Retrieve the next keyboard event in queue
This source provides the queued KEYEV_UP and KEYEV_DOWN events generated
from the regular scans in chronological order. It does not generate the
KEYEV_HOLD events though, keyev_repeat_event() must be used to obtain these
at the end of every tick. */
This source provides the queued KEYEV_UP, KEYEV_DOWN and KEYEV_HOLD events
generated from the regular scans in chronological order. It does not apply
transforms; to do this, use keydev_read(). */
key_event_t keydev_unqueue_event(keydev_t *d);
/* keydev_idle(): Check if all keys are released
@ -258,6 +263,27 @@ keydev_transform_t keydev_transform(keydev_t *d);
/* keydev_set_transform(): Set transform parameters */
void keydev_set_transform(keydev_t *d, keydev_transform_t tr);
/* keydev_set_standard_repeats(): Enable a simple repeater
This function changes the [repeater] member of the devices's transform. It
loads the default repeat profile which applies one delay (in us) before the
first repeat, and then a second, usually shorter delay, between subsequent
repeats.
The unit of the argument is in microseconds, but the granularity of the
delay is dependent on the keyboard scan frequency. In the default setting
(128 Hz scans), the possible repeat delays are approximately 8 ms, 16 ms,
23 ms, 31 ms. The system default is (500 ms, 125 ms). With the 128 Hz
setting, this default is reached exactly without approximation. gint's
default is (400 ms, 40 ms) for more reactivity.
Note: Due to a current API limitation, every input device uses the delays
for the physical keyboard.
@first_us Delay between key press and first repeat (microseconds)
@next_us Delay between subsequent repeats (microseconds) */
void keydev_set_standard_repeats(keydev_t *d, int first_us, int next_us);
/* keydev_read(): Retrieve the next transformed event */
key_event_t keydev_read(keydev_t *d);

@ -225,10 +225,6 @@ enum {
GETKEY_DEFAULT = 0xdf,
};
/* 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_feature_t: Custom feature function
See getkey_set_feature_function() for details. */
typedef bool (*getkey_feature_t)(key_event_t event);
@ -260,53 +256,6 @@ typedef bool (*getkey_feature_t)(key_event_t event);
Returns a key event of type KEYEV_DOWN or KEYEV_HOLD with [mod=1]. */
key_event_t getkey_opt(int options, volatile int *timeout);
/* getkey_repeat(): Set repeat delays for getkey()
This function updates the repeat delays of getkey() and getkey_opt(). The
unit of the argument is in milliseconds, but the granularity of the delay is
dependent on the keyboard scan frequency.
In the default setting (128 Hz scans), the possible repeat delays are
approximately 8 ms, 16 ms, 23 ms, 31 ms... the provided arguments will be
rounded to the closest feasible delays to ensure that repetitions are
perfectly regular, rather than approximating the requested frequency.
The system default is (500 ms, 125 ms). With the 128 Hz setting, this
default is reached exactly without approximation. gint's default is (400 ms,
40 ms) for more reactivity.
@first Delay between key press and first repeat (no more than one hour)
@next Delay between subsequent repeats (no more than one hour) */
void getkey_repeat(int first, int next);
/* getkey_repeat_profile(): Get the current repeat profile function */
getkey_profile_t getkey_repeat_profile(void);
/* getkey_set_repeat_profile(): Set the repeat profile function
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 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 profile function must either return a positive number of microseconds to
wait until the next repeat, or -1 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.
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);
/* getkey_feature_function(): Get the current feature function */
getkey_feature_t getkey_feature_function(void);
@ -346,4 +295,32 @@ int keycode_digit(int keycode);
}
#endif
//---
// Deprecated functions for repeat control
//
// The following types and functions have been deprecated. The handling of
// repeats is done inside the keyboard device (see <gint/drivers/keydev.h>).
// Until gint 2.9, the device had repeats disabled by default and getkey()
// enabled them. The problem is that repeats usually occur while getkey() is
// not running, so repeats wouldn't work as expected.
//
// Thus, getkey()-specific APIs related to repeat settings are now deprecated
// in favor of the ones provided by <gint/drivers/keydev.h>, which apply
// globally instead of just when getkey() is being run.
//---
typedef void *getkey_profile_t;
__attribute__((deprecated(
"Use keydev_set_standard_repeats(), which is permanent, instead")))
void getkey_repeat(int first, int next);
__attribute__((deprecated(
"Use keydev_transform(keydev_std()).repeater instead")))
getkey_profile_t getkey_repeat_profile(void);
__attribute__((deprecated(
"Set the [repeater] attribute with keydev_set_transform() instead")))
void getkey_set_repeat_profile(getkey_profile_t profile);
#endif /* GINT_KEYBOARD */

@ -11,25 +11,8 @@
#include <gint/drivers/t6k11.h>
#endif
/* 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;
/* Feature function */
static getkey_feature_t feature_function = NULL;
/* Repeater specification */
static enum { NONE, ALL, ARROWS, FILTER } repeat_mode;
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)
@ -41,79 +24,92 @@ key_event_t getkey(void)
key_event_t getkey_opt(int opt, volatile int *timeout)
{
keydev_t *d = keydev_std();
keydev_transform_t tr0 = keydev_transform(d);
keydev_transform_t tr = keydev_transform(d);
key_event_t e;
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;
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;
keydev_set_transform(d, (keydev_transform_t){ o, tr.repeater });
while(1)
{
e = keydev_read(d);
if(e.type == KEYEV_NONE && timeout && *timeout) break;
/* Skip repeat events that are not enabled by options */
if(e.type == KEYEV_HOLD && !(opt & GETKEY_REP_ALL))
{
if(!(opt & GETKEY_REP_ARROWS))
continue;
if(e.key != KEY_LEFT && e.key != KEY_RIGHT &&
e.key != KEY_UP && e.key != KEY_DOWN)
continue;
}
#ifdef FX9860G
/* Backlight toggle */
else if((opt & GETKEY_BACKLIGHT) && e.type == KEYEV_DOWN &&
if((opt & GETKEY_BACKLIGHT) && e.type == KEYEV_DOWN &&
e.key == KEY_OPTN && e.shift && !e.alpha)
{
t6k11_backlight(-1);
continue;
}
#endif
/* Return-to-menu */
else if((opt & GETKEY_MENU) && e.type == KEYEV_DOWN &&
if((opt & GETKEY_MENU) && e.type == KEYEV_DOWN &&
e.key == KEY_MENU && !e.shift && !e.alpha)
{
gint_osmenu();
continue;
}
else if(e.type == KEYEV_DOWN || e.type == KEYEV_HOLD)
if(e.type == KEYEV_DOWN || e.type == KEYEV_HOLD)
{
/* Custom global features */
bool accepted = false;
if((opt & GETKEY_FEATURES) && feature_function)
accepted = feature_function(e);
/* Return if the even has not been accepted yet */
/* Return if the event has not been accepted yet */
if(!accepted) break;
}
}
keydev_set_transform(d, tr0);
/* Restore previous transform settings */
keydev_set_transform(d, tr);
return e;
}
/* getkey_repeat(): Set repeat delays for getkey() */
void getkey_repeat(int first, int next)
/* getkey_feature_function(): Get the current feature function */
getkey_feature_t getkey_feature_function(void)
{
rep_first = first;
rep_next = next;
return feature_function;
}
/* getkey_repeat_profile(): Get the current repeat profile function */
getkey_profile_t getkey_repeat_profile(void)
/* getkey_set_feature_function(): Set the global feature function */
void getkey_set_feature_function(getkey_feature_t function)
{
return repeat_profile;
feature_function = function;
}
/* getkey_set_repeat_profile(): Set the repeat profile function */
void getkey_set_repeat_profile(getkey_profile_t profile)
/* Deprecated repeat functions */
void getkey_repeat(int first, int next)
{
repeat_profile = profile;
keydev_set_standard_repeats(keydev_std(), first * 1000, next * 1000);
}
/* getkey_feature_function(): Get the current feature function */
getkey_feature_t getkey_feature_function(void)
getkey_profile_t getkey_repeat_profile(void)
{
return feature_function;
return keydev_transform(keydev_std()).repeater;
}
/* getkey_set_feature_function(): Set the global feature function */
void getkey_set_feature_function(getkey_feature_t function)
/* getkey_set_repeat_profile(): Set the repeat profile function */
void getkey_set_repeat_profile(getkey_profile_t profile)
{
feature_function = function;
keydev_transform_t tr = keydev_transform(keydev_std());
tr.repeater = profile;
keydev_set_transform(keydev_std(), tr);
}

@ -15,6 +15,13 @@ void keydev_init(keydev_t *d)
memset(d, 0, sizeof *d);
}
static int standard_repeater(GUNUSED int key, GUNUSED int duration, int count)
{
/* FIXME: Do not use the delays from keydev_std() on every device */
keydev_t *d = keydev_std();
return count ? d->rep_standard_next : d->rep_standard_first;
}
//---
// Driver event generation
//---
@ -223,6 +230,14 @@ void keydev_set_transform(keydev_t *d, keydev_transform_t tr)
d->tr = tr;
}
/* keydev_set_standard_repeats(): Enable a simple repeater */
void keydev_set_standard_repeats(keydev_t *d, int first, int next)
{
d->rep_standard_first = first;
d->rep_standard_next = next;
d->tr.repeater = standard_repeater;
}
/* keydev_read(): Retrieve the next transformed event */
key_event_t keydev_read(keydev_t *d)
{

@ -99,8 +99,10 @@ static void configure(void)
{
keydev_init(&keysc_dev);
/* Set the default repeat times (milliseconds) */
getkey_repeat(400, 40);
/* Set the default repeat to 400/40 ms */
keydev_t *d = keydev_std();
keydev_set_transform(d, (keydev_transform_t){ KEYDEV_TR_REPEATS, NULL });
keydev_set_standard_repeats(d, 400 * 1000, 40 * 1000);
/* The timer will be stopped when the timer driver is unloaded */
keysc_tid = timer_configure(TIMER_ANY, keysc_scan_us,

Loading…
Cancel
Save