8000 Batch updating the keyboard state / regrabbing keys by psychon · Pull Request #4367 · i3/i3 · GitHub
[go: up one dir, main page]
More Web Proxy on the site http://driver.im/
Skip to content

Batch updating the keyboard state / regrabbing keys #4367

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 4 commits into
base: next
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 53 additions & 15 deletions src/handlers.c
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,53 @@ bool event_is_ignored(const int sequence, const int response_type) {
return false;
}

typedef enum {
RG_DEFAULT = 0,
RG_TRANSLATE = 1,
RG_LOAD_KEYMAP_AND_TRANSLATE = 2,
RG_UPDATE_KEY_SYMBOLS_AND_LOAD_KEYMAP_AND_TRANSLATE = 3,
} regrab_mode_t;

static regrab_mode_t pending_regrab = RG_DEFAULT;
static ev_idle regrab_watcher;
static bool regrab_watcher_initialised = false;
extern struct ev_loop *main_loop;

static void regrab_keys_cb(EV_P_ ev_idle *w, int revents) {
ev_idle_stop(main_loop, w);

ungrab_all_keys(conn);
switch (pending_regrab) {
case RG_DEFAULT:
break;
case RG_UPDATE_KEY_SYMBOLS_AND_LOAD_KEYMAP_AND_TRANSLATE:
xcb_key_symbols_free(keysyms);
keysyms = xcb_key_symbols_alloc(conn);
/* fall through */
case RG_LOAD_KEYMAP_AND_TRANSLATE:
(void)load_keymap();
/* fall through */
case RG_TRANSLATE:
translate_keysyms();
break;
}
grab_all_keys(conn);

pending_regrab = RG_DEFAULT;
}

/*
* Called when the keyboard state changed and we need to re-grab keys.
*/
static void regrab_keys(regrab_mode_t mode) {
pending_regrab = max(pending_regrab, mode);
if (!regrab_watcher_initialised) {
regrab_watcher_initialised = true;
ev_idle_init(&regrab_watcher, regrab_keys_cb);
}
ev_idle_start(main_loop, &regrab_watcher);
}

/*
* Called with coordinates of an enter_notify event or motion_notify event
* to check if the user crossed virtual screen boundaries and adjust the
Expand Down Expand Up @@ -246,9 +293,7 @@ static void handle_mapping_notify(xcb_mapping_notify_event_t *event) {

xcb_numlock_mask = aio_get_mod_mask_for(XCB_NUM_LOCK, keysyms);

ungrab_all_keys(conn);
translate_keysyms();
grab_all_keys(conn);
regrab_keys(RG_TRANSLATE);
}

/*
Expand Down Expand Up @@ -1297,30 +1342,23 @@ void handle_event(int type, xcb_generic_event_t *event) {
xcb_key_symbols_free(keysyms);
keysyms = xcb_key_symbols_alloc(conn);
if (((xcb_xkb_new_keyboard_notify_event_t *)event)->changed & XCB_XKB_NKN_DETAIL_KEYCODES)
(void)load_keymap();
ungrab_all_keys(conn);
translate_keysyms();
grab_all_keys(conn);
regrab_keys(RG_LOAD_KEYMAP_AND_TRANSLATE);
else
regrab_keys(RG_TRANSLATE);
} else if (state->xkbType == XCB_XKB_MAP_NOTIFY) {
if (event_is_ignored(event->sequence, type)) {
DLOG("Ignoring map notify event for sequence %d.\n", state->sequence);
} else {
DLOG("xkb map notify, sequence %d, time %d\n", state->sequence, state->time);
add_ignore_event(event->sequence, type);
xcb_key_symbols_free(keysyms);
keysyms = xcb_key_symbols_alloc(conn);
ungrab_all_keys(conn);
translate_keysyms();
grab_all_keys(conn);
(void)load_keymap();
regrab_keys(RG_UPDATE_KEY_SYMBOLS_AND_LOAD_KEYMAP_AND_TRANSLATE);
}
} else if (state->xkbType == XCB_XKB_STATE_NOTIFY) {
DLOG("xkb state group = %d\n", state->group);
if (xkb_current_group == state->group)
return;
xkb_current_group = state->group;
ungrab_all_keys(conn);
grab_all_keys(conn);
regrab_keys(RG_DEFAULT);
}

return;
Expand Down
32 changes: 32 additions & 0 deletions testcases/t/600-slow-keyboard-update.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#!perl
# vim:ts=4:sw=4:expandtab
#
# Please read the following documents before working on tests:
# • https://build.i3wm.org/docs/testsuite.html
# (or docs/testsuite)
#
# • https://build.i3wm.org/docs/lib-i3test.html
# (alternatively: perldoc ./testcases/lib/i3test.pm)
#
# • https://build.i3wm.org/docs/ipc.html
# (or docs/ipc)
#
# • http://onyxneon.com/books/modern_perl/modern_perl_a4.pdf
# (unless you are already familiar with Perl)
#
# Test that updating the keyboard state is fast.
# Ticket: #3924
# Bug still in: 4.19.2-70-g42c3dbe0
use i3test;

my $start = time();

# The following causes an X11 event per line. Before the fix, running this took
# about 13 seconds until i3 became responsive again.
system(q@for x in $(seq 1 5000); do echo "keycode 107 = parenleft" ; done | xmodmap -@);
sync_with_i3;

my $delay = time() - $start;
ok($delay <= 2, 'Test finishes quickly');

done_testing;
0