Search code examples
c++x11c++14xcb

xcb ignoring repeated keys


I am trying to work out how to ignore repeated keys when using xcb for input.

I need something like this acheives:

uint32_t mask = XCB_KB_AUTO_REPEAT_MODE;
uint32_t values[] = {XCB_AUTO_REPEAT_MODE_OFF, None};

xcb_change_keyboard_control(xcb_connection, mask, values);

but without affecting the whole system.

I have read Ignore auto repeat in X11 applications, but I can't translate it to xcb. Namely, I can't find an xcb equivalent to XEventsQueued.

How do I go about doing this?


Solution

  • After getting a notification about this post just recently I thought I would add what my solution finally was when I came across the problem again.

    I created my own event queue and polled that for events:

    class event_queue{
        public:
            ~event_queue(){
                free(curr);
                free(prev);
                free(next);
            }
    
            xcb_generic_event_t *curr = nullptr, *prev = nullptr, *next = nullptr;
    };
    
    namespace {
        event_queue internal_eventq;
    }
    
    xcb_generic_event_t *poll_event(xcb_connection_t *conn){
        if(internal_eventq.curr){
            free(internal_eventq.prev);
            internal_eventq.prev = internal_eventq.curr;
        }
        internal_eventq.curr = internal_eventq.next;
        internal_eventq.next = xcb_poll_event(conn);
        return internal_eventq.curr;
    }
    

    So I can could check the previous and next events.

    Next I changed my input function to use the new polling function and changed how I handle key presses:

    // in same scope as 'poll_event'
    void handle_events(xcb_connection_t *conn){
        while(auto ev = poll_event(conn)){
            switch(ev->response_type){
                case /* xcb key press */:{
                    if(
                        (internal_eventq.next == /* xcb key release */) &&
                        (internal_eventq.next->keysym == ev->keysym) &&
                        (internal_eventq.next->time == ev->time)
                    ){
                        free(internal_eventq.next);
                        internal_eventq.next = nullptr; // ignore release part of key repeat
                        return; // ignore key repeat
                    }
    
                    break;
                }
    
                default:
                    break;
            }
        }
    }
    

    Which was a bit of a hassle, but I imagine it is similar to how Xlib handles it's event queue behind the scenes.