No error on xcb_grab_key but event loop not catchi

2019-02-19 03:21发布

I am trying to set up a global hotkey on Linux.

I had initially used x11 (libX11.so) however I had to do this from a thread. I tried it but the XPendingEvent and XNextEvent would eventually crash the app.

So I switched to xcb (libxcb.so.1). There is no errors, I even check with xcb_request_check however the event loop is not picking anything up. As soon as I start the loop, I get only one event which looks like this:

{
    response_type: 0,
    pad0: 10,
    sequence: 2,
    pad: [620, 2162688, 0, 0, 0, 0, 0],
    full_sequence: 2
}

Here is my code, I actually do this in js-ctypes, but I cut down all the stuff to just show simple agnostic as possible code:

conn = xcb_connect(null, null);

keysyms = xcb_key_symbols_alloc(conn);

keycodesPtr = xcb_key_symbols_get_keycode(keysyms, XK_Space);

setup = xcb_get_setup(conn);

screens = xcb_setup_roots_iterator(setup);
screensCnt = screens.rem;

for (var i=0; i<screensCnt; i++) {
    rez_grab = xcb_grab_key(conn, 1, screens.data.root, XCB_MOD_MASK_ANY, keycodesPtr[0], XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);

    rez_err = xcb_request_check(conn, rez_grab);
    // rez_err is null

    xcb_screen_next(&screens);
}

xcb_flush(conn);

// start event loop
while (true) {
    ev = xcb_poll_for_event(conn);

    console.log(ev);

    if (ev != null) {
        free(ev);
    }

    Sleep(50);
}

console.log(ev) gives me what I posted above earlier, response_type of 0 and then forever after that ev is just null.

Does anyone know what's up? rez_grab as a raw string is xcb_void_cookie_t(2)

Thanks much

标签: linux x11 xcb
1条回答
聊天终结者
2楼-- · 2019-02-19 03:36

Figured it out at long last!! Ah figured this one out! I was using XCB_MOD_MASK_ANY and this constant works on Debian but not on Ubuntu, which is what I was using to test. I switched that up to use num lock, caps lock etc and now it works! :)

ostypes.API('xcb_grab_key')(conn, 1, screens.data.contents.root, ostypes.CONST.XCB_MOD_MASK_LOCK, keycodesArr[j], ostypes.CONST.XCB_GRAB_MODE_ASYNC, ostypes.CONST.XCB_GRAB_MODE_ASYNC); // caps lock
ostypes.API('xcb_grab_key')(conn, 1, screens.data.contents.root, ostypes.CONST.XCB_MOD_MASK_2, keycodesArr[j], ostypes.CONST.XCB_GRAB_MODE_ASYNC, ostypes.CONST.XCB_GRAB_MODE_ASYNC); // num lock
ostypes.API('xcb_grab_key')(conn, 1, screens.data.contents.root, ostypes.CONST.XCB_MOD_MASK_LOCK | ostypes.CONST.XCB_MOD_MASK_2, keycodesArr[j], ostypes.CONST.XCB_GRAB_MODE_ASYNC, ostypes.CONST.XCB_GRAB_MODE_ASYNC); // caps lock AND num lock

that was very very crazy i had no idea the XCB_MOD_MASK_ANY constant didnt work on Ubuntu -

var rez_grab = ostypes.API('xcb_grab_key')(conn, 1, screens.data.contents.root, ostypes.CONST.XCB_MOD_MASK_ANY, keycodesArr[j], ostypes.CONST.XCB_GRAB_MODE_ASYNC, ostypes.CONST.XCB_GRAB_MODE_ASYNC);

I also tried @n.m's code. On ubuntu it didnt work, but worked on debian -

#include <xcb/xcb.h>
#define XK_LATIN1
#include <xcb/xcb_keysyms.h>
#include <X11/keysymdef.h>
#include <stdio.h>
#include <stdlib.h>

int
main ()
{
  xcb_connection_t *conn;

  conn = xcb_connect (NULL, NULL);

  xcb_key_symbols_t * keysyms = xcb_key_symbols_alloc(conn);

  xcb_keycode_t * keycodesPtr = xcb_key_symbols_get_keycode(keysyms, XK_space);

  const xcb_setup_t* setup = xcb_get_setup(conn);

  xcb_screen_iterator_t screens = xcb_setup_roots_iterator(setup);
  int screensCnt = screens.rem;

  for (int i=0; i<screensCnt; i++) {

      xcb_void_cookie_t rez_grab = xcb_grab_key(conn, 1, screens.data->root, XCB_MOD_MASK_ANY, keycodesPtr[0], XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC);

      const static uint32_t values[] = { XCB_EVENT_MASK_EXPOSURE | XCB_EVENT_MASK_BUTTON_PRESS };

      xcb_change_window_attributes (conn, screens.data->root, XCB_CW_EVENT_MASK, values);

      xcb_screen_next(&screens);
  }

  xcb_flush(conn);

  // start event loop
  while (1) {
      xcb_generic_event_t *ev = xcb_wait_for_event(conn);

      if (ev && ((ev->response_type & ~0x80) == XCB_KEY_PRESS))
      {
          xcb_key_press_event_t *kp = (xcb_key_press_event_t *)ev;
          printf ("Got key press %d\n", (int)kp->event);
      }

      if (ev != NULL) {
          free(ev);
      }
  }

  return 0;
}
查看更多
登录 后发表回答