Global alt+space hotkey grabbing - weird keyboard

2019-06-26 08:50发布

问题:

I'm grabbing Alt+Space global hotkey using xcb_grab_key, as follows:

xcb_key_symbols_t *keysyms = xcb_key_symbols_alloc(c);
xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, XK_space), keycode;

// add bindings for all screens
xcb_screen_iterator_t iter;
iter = xcb_setup_roots_iterator (xcb_get_setup (c));
for (; iter.rem; xcb_screen_next (&iter)) {
    int i = 0;
    while(keycodes[i] != XCB_NO_SYMBOL) {
        keycode = keycodes[i];
        xcb_grab_key(c, true, iter.data->root, XCB_MOD_MASK_ANY, keycode, XCB_GRAB_MODE_SYNC, XCB_GRAB_MODE_SYNC);
        i += 1;
    }
}

Then in Qt's QAbstractNativeEventFilter subclass I process it and emit a Qt signal if key matches Alt+Space:

xcb_keycode_t *keycodes = xcb_key_symbols_get_keycode(keysyms, XK_space);
int i = 0;
bool found = false;
while(keycodes[i] != XCB_NO_SYMBOL) {
    if(event->detail == keycodes[i]) {
        if(event->state & GetModifier(c, keysyms, XK_Alt_L) || event->state & GetModifier(c, keysyms,  XK_Alt_R)) {
            xcb_allow_events(c, XCB_ALLOW_ASYNC_KEYBOARD, event->time);
            emit gotHotKey();
            found = true;
        } else {
            xcb_allow_events(c, XCB_ALLOW_REPLAY_KEYBOARD, event->time);
        }
        break;
    }
    i += 1;
}
if(found) return true;

(GetModifier is copied from VLC but I think this part doesn't matter since Alt-key is matched correctly)

The problem I'm having is that after show()ing main window when the hotkey is pressed, keyboard is most of the times1 not focused properly. I can type, but the cursor is not visible, input's border is not highlighted, and the shortcut Ctrl+Q for quitting desn't work. It can be worked around by moving the window, or pressing space - then focus is restored - cursor+border reappears and Ctrl+Q works. What might be causing this behaviour?

I'm using Qt 5.0.0 and xcb 1.8.1. Complete application can be downloaded for compiling from github.

1 it means sometimes the issue is not reproducible - focus is set correctly even for repeated window hide/shows, but then other times it happens multiple times in a row of hide/shows. It occurs more often than not overall.

(Edit: I've implemented a (very ugly...) workaround, so to reproduce the issue for the github project, the following code needs to be removed)

#ifndef WIN32
    // Very ugly workaround for the problem described at http://stackoverflow.com/questions/14553810/
    // (just show and hide a modal dialog box, which for some reason restores proper keyboard focus)
    hackDialog.setGeometry(0, 0, 0, 0);
    hackDialog.setModal(true);
    hackDialog.show();
    QTimer::singleShot(100, &hackDialog, SLOT(reject()));
#endif
标签: c++ c qt x11 xcb