[Superkb-devel] [PATCH 2/2] Fix autorepeat in command when non-super was pressed first (bug #432887
Status: Alpha
Brought to you by:
alvarezp
From: Eduardo A. B. L. <ebu...@du...> - 2010-12-05 05:39:01
|
This fixes the autorepeat bug detailed in: - https://bugs.launchpad.net/superkb/+bug/432887/ --- superkb.c | 137 +++++++++++++++++++++++++++++++++--------------------------- 1 files changed, 75 insertions(+), 62 deletions(-) diff --git a/superkb.c b/superkb.c index 6c71b7b..3ffe5a9 100755 --- a/superkb.c +++ b/superkb.c @@ -200,6 +200,13 @@ void one_superkey_used_friendly_warning(int number, const char *keyname) { ); } +int key_is_released (Display *dpy, int keycode) +{ + char key_buffer [32]; + XQueryKeymap(dpy, key_buffer); + return (! (key_buffer[keycode >> 3] >> (keycode & 0x07)) & 0x01 ); +} + void superkb_start(superkb_p this) { @@ -438,61 +445,63 @@ void superkb_start(superkb_p this) } } else if (ev.type == KeyRelease) { - debug(1, "[sk] Super key has been released, code: %d, name: %s.\n", ev.xkey.keycode, - XKeysymToString(XKeycodeToKeysym(this->dpy, ev.xkey.keycode, 0))); - - if (--super_was_active) { - debug(2, "[sa] super_was_active decreased to %d, ignoring release.\n", super_was_active); - continue; - } - - debug(2, "[sa] super_was_active decreased to %d, taking action.\n", super_was_active); - - timerclear(&to[TO_DRAWKB]); - timerclear(&to[TO_CONFIG]); - - if (super_replay) { - /* Since Xlib only supports Replaying a key before getting the next keyboard event, - * we can't really use XAllowEvents() to replay the Super key in case the user - * asked to. So we try XSendEvent() with the Press from the saved event on KeyPress, - * and the Release we are currently using. - */ - event_save_for_replay.xkey.window = event_saved_window; - ev.xkey.window = event_saved_window; - event_save_for_replay.xkey.subwindow = 0; - ev.xkey.subwindow = 0; - - XSendEvent(this->dpy, event_saved_window, 1, KeyPressMask, &event_save_for_replay); - XSendEvent(this->dpy, event_saved_window, 1, KeyReleaseMask, &ev); - XSync(this->dpy, True); - debug(1, "[sr] Super key has been replayed\n"); - } - - /* Restore saved_autorepeat_mode. */ - XKeyboardControl xkbc; - /*xkbc.auto_repeat_mode = saved_autorepeat_mode; */ - xkbc.auto_repeat_mode = AutoRepeatModeOn; - XChangeKeyboardControl(this->dpy, KBAutoRepeatMode, &xkbc); - - debug(1, "[ar] AutoRepeat has been restored to: %d\n", saved_autorepeat_mode); - - XUngrabKeyboard(this->dpy, CurrentTime); - this->kbwin.unmap(this->dpy); - - for (x = 0; x < pressed_keys_n; x++) { - __Action(pressed_keys[x].keycode, pressed_keys[x].state); - - debug(1, "[ac] Due to Super key release, executed action for key code = %d, name: %s\n", pressed_keys[x].keycode, - XKeysymToString(XKeycodeToKeysym - (this->dpy, pressed_keys[x].keycode, 0))); - - } - + if ( key_is_released (this->dpy, ev.xkey.keycode) ) + { + debug(1, "[sk] Super key has been released, code: %d, name: %s.\n", ev.xkey.keycode, + XKeysymToString(XKeycodeToKeysym(this->dpy, ev.xkey.keycode, 0))); + + if (--super_was_active) { + debug(2, "[sa] super_was_active decreased to %d, ignoring release.\n", super_was_active); + continue; + } + + debug(2, "[sa] super_was_active decreased to %d, taking action.\n", super_was_active); + + timerclear(&to[TO_DRAWKB]); + timerclear(&to[TO_CONFIG]); + + if (super_replay) { + /* Since Xlib only supports Replaying a key before getting the next keyboard event, + * we can't really use XAllowEvents() to replay the Super key in case the user + * asked to. So we try XSendEvent() with the Press from the saved event on KeyPress, + * and the Release we are currently using. + */ + event_save_for_replay.xkey.window = event_saved_window; + ev.xkey.window = event_saved_window; + event_save_for_replay.xkey.subwindow = 0; + ev.xkey.subwindow = 0; + + XSendEvent(this->dpy, event_saved_window, 1, KeyPressMask, &event_save_for_replay); + XSendEvent(this->dpy, event_saved_window, 1, KeyReleaseMask, &ev); + XSync(this->dpy, True); + debug(1, "[sr] Super key has been replayed\n"); + } + + /* Restore saved_autorepeat_mode. */ + XKeyboardControl xkbc; + /*xkbc.auto_repeat_mode = saved_autorepeat_mode; */ + xkbc.auto_repeat_mode = AutoRepeatModeOn; + XChangeKeyboardControl(this->dpy, KBAutoRepeatMode, &xkbc); + + debug(1, "[ar] AutoRepeat has been restored to: %d\n", saved_autorepeat_mode); + + XUngrabKeyboard(this->dpy, CurrentTime); + this->kbwin.unmap(this->dpy); + + for (x = 0; x < pressed_keys_n; x++) { + + __Action(pressed_keys[x].keycode, pressed_keys[x].state); + + debug(1, "[ac] Due to Super key release, executed action for key code = %d, name: %s\n", pressed_keys[x].keycode, + XKeysymToString(XKeycodeToKeysym + (this->dpy, pressed_keys[x].keycode, 0))); + } + } clear_pressed_key_stack(); - debug(1, "---------------------------------------------\n"); - } + +} } else if (ev.type == KeyPress) { debug(1, "[kp] A non-Super key was pressed.\n"); super_replay = 0; @@ -507,23 +516,27 @@ void superkb_start(superkb_p this) debug(2, "[kp] Pushed key and state to stack: %d, %d\n", ev.xkey.keycode, squashed_state); } else if ((ev.type == KeyRelease && !ignore_release && super_was_active > 0)) { + + /* User might have asked for binding configuration, so ignore key * release. That's what ignore_release is for. */ - timerclear(&to[TO_CONFIG]); - - int squashed_state = ev.xkey.state & this->state_mask; + timerclear(&to[TO_CONFIG]); - __Action(ev.xkey.keycode, squashed_state); + int squashed_state = ev.xkey.state & this->state_mask; - debug(1, "[ac] Due to bound key release, executed action for key code = %d, name: %s\n", ev.xkey.keycode, - XKeysymToString(XKeycodeToKeysym - (this->dpy, ev.xkey.keycode, 0))); - debug(2, " ... and because super_was_active value was > 0: %d\n", super_was_active); + if ( key_is_released (this->dpy, ev.xkey.keycode) ) + { + __Action(ev.xkey.keycode, squashed_state); - remove_from_pressed_key_stack(ev.xkey.keycode, squashed_state); - debug(2, "[kp] Removed key and state to stack: %d, %d\n", ev.xkey.keycode, squashed_state); + debug(1, "[ac] Due to bound key release, executed action for key code = %d, name: %s\n", ev.xkey.keycode, + XKeysymToString(XKeycodeToKeysym + (this->dpy, ev.xkey.keycode, 0))); + debug(2, " ... and because super_was_active value was > 0: %d\n", super_was_active); + } + remove_from_pressed_key_stack(ev.xkey.keycode, squashed_state); + debug(2, "[kp] Removed key and state to stack: %d, %d\n", ev.xkey.keycode, squashed_state); } else { /* According to manual, this should not be necessary. */ /* XAllowEvents(this->dpy, ReplayKeyboard, CurrentTime); */ -- 1.7.2.3 |