diff options
Diffstat (limited to 'console-client/xkb/xkbtimer.c')
-rw-r--r-- | console-client/xkb/xkbtimer.c | 236 |
1 files changed, 236 insertions, 0 deletions
diff --git a/console-client/xkb/xkbtimer.c b/console-client/xkb/xkbtimer.c new file mode 100644 index 00000000..f50bb9ad --- /dev/null +++ b/console-client/xkb/xkbtimer.c @@ -0,0 +1,236 @@ +/* xkbtimer.c -- Manage XKB timers. + + Copyright (C) 2003, 2004 Marco Gerards + + Written by Marco Gerards <marco@student.han.nl> + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. */ + +/* XKB requires a timer for key repeat and accessibility. Carefully + stack all compatibility features. */ + +#include <mach.h> +#include <errno.h> +#include <assert.h> + +#include "xkb.h" +#include "timer.h" + +/* Lock the access to handle_key. */ +static struct mutex *lock_key; + +/* Timer used to time key controls. */ +//static struct timer_list key_timer; + +/* For key repeat. */ +static int key_delay = 0; +static int key_repeat = 0; + +/* SlowKeys. */ +static int slowkeys_delay = 50; +static int slowkeys_active = 0; + +/* BounceKeys. */ +static int bouncekeys_delay = 100; +static int bouncekeys_active = 0; + +/* The current status of the timer. */ +enum timer_status + { + timer_stopped, + timer_slowkeys, + timer_repeat_delay, + timer_repeating + }; + +static struct per_key_timer +{ + /* Used for slowkeys and repeat. */ + struct timer_list enable_timer; + + /* Status of the enable timer. */ + enum timer_status enable_status; + + /* Used for bouncekeys. */ + struct timer_list disable_timer; +} per_key_timers[255]; + +/* The last pressed key. Only this key may generate keyrepeat events. */ +static int lastkey = 0; + +error_t +xkb_handle_key (keycode_t kc) +{ + static keycode_t prevkc = 0; + keypress_t key; + + key.keycode = kc & 127; + key.prevkc = prevkc; + key.repeat = (prevkc == kc); + key.redir = 0; + key.rel = kc & 128; + keystate[key.keycode & 127].keypressed = key.rel ? 0 : 1; + debug_printf ("PRESSED: %d\n", !(key.rel)); + xkb_input (key); + prevkc = key.keycode; + return 0; +} + +error_t +xkb_init_repeat (int delay, int repeat) +{ + error_t err; + err = timer_init (); + if (err) + return err; + + key_delay = delay; + key_repeat = repeat; + + return 0; +} + +static int +key_enable (void *handle) +{ + int key = (int) handle; + + /* Enable the key. */ + keystate[key].disabled = 0; + + return 0; +} + +/* Called by key timer. The global variable timer_status determines + the current control. */ +static int +key_timing (void *handle) +{ + int current_key = (int) handle; + + xkb_handle_key (current_key); + + /* Another key was pressed after this key, stop repeating. */ + if (lastkey != current_key) + { + per_key_timers[current_key].enable_status = timer_stopped; + return 0; + } + + switch (per_key_timers[current_key].enable_status) + { + case timer_stopped: + assert ("Stopped timer triggered timer event\n"); + break; + case timer_slowkeys: + per_key_timers[current_key].enable_timer.expires + = fetch_jiffies () + key_delay; + lastkey = current_key; + + if (keys[current_key].flags & KEYNOREPEAT) + { + per_key_timers[current_key].enable_status = timer_stopped; + /* Stop the timer. */ + return 0; + } + else + { + per_key_timers[current_key].enable_status = timer_repeat_delay; + } + break; + case timer_repeat_delay: + per_key_timers[current_key].enable_status = timer_repeating; + /* Fall through. */ + case timer_repeating: + per_key_timers[current_key].enable_timer.expires + = fetch_jiffies () + key_repeat; + break; + } + return 1; +} + +error_t +xkb_input_key (int key) +{ + int pressed = !(key & 128); + int keyc = key & 127; + + debug_printf ("KEYIN: %d\n", key); + + /* Filter out any double or disabled keys. */ + if (key == lastkey || keystate[keyc].disabled) + return 0; + + /* Always handle keyrelease events. */ + if (!pressed) + { + /* Stop the timer for this released key. */ + if (per_key_timers[keyc].enable_status != timer_stopped) + { + timer_remove (&per_key_timers[keyc].enable_timer); + per_key_timers[keyc].enable_status = timer_stopped; + } + + /* No more last key; it was released. */ + if (keyc == lastkey) + lastkey = 0; + + /* Make sure the key was pressed before releasing it, it might + not have been accepted. */ + if (keystate[key & 127].keypressed) + xkb_handle_key (key); + + /* If bouncekeys is active, disable the key. */ + if (bouncekeys_active) + { + keystate[keyc].disabled = 1; + + /* Setup a timer to enable the key. */ + timer_clear (&per_key_timers[keyc].disable_timer); + per_key_timers[keyc].disable_timer.fnc = key_enable; + per_key_timers[keyc].disable_timer.fnc_data = (void *) keyc; + per_key_timers[keyc].disable_timer.expires + = fetch_jiffies () + bouncekeys_delay; + timer_add (&per_key_timers[keyc].disable_timer); + } + + return 0; + } + + /* Setup the timer for slowkeys. */ + timer_clear (&per_key_timers[keyc].enable_timer); + lastkey = keyc; + per_key_timers[keyc].enable_timer.fnc = key_timing; + per_key_timers[keyc].enable_timer.fnc_data = (void *) keyc; + + if (slowkeys_active) + { + per_key_timers[keyc].enable_status = timer_slowkeys; + per_key_timers[keyc].enable_timer.expires + = fetch_jiffies () + slowkeys_delay; + } + else + { + /* Immediatly report the keypress. */ + xkb_handle_key (keyc); + + /* Check if this repeat is allowed for this keycode. */ + if (keys[keyc].flags & KEYNOREPEAT) + return 0; /* Nope. */ + + per_key_timers[keyc].enable_status = timer_repeat_delay; + per_key_timers[keyc].enable_timer.expires + = fetch_jiffies () + key_delay; + } + timer_add (&per_key_timers[keyc].enable_timer); + + return 0; +} |