【问题标题】:XCB – Not receiving motion notify events on all windowsXCB – 未在所有窗口上接收运动通知事件
【发布时间】:2015-07-13 23:22:09
【问题描述】:

我正在尝试收到有关任何指针运动的通知。由于我不想作为窗口管理器运行,我需要在所有窗口上设置XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION,我在启动时和收到创建通知事件时都会这样做。

这似乎工作正常,我在所有窗口上都收到运动通知事件。但是,不知何故,这不适用于 Google Chrome 窗口。我之后通过显式查询来检查事件掩码,并且设置正确。我也没有在传播掩码中看到任何异常。

什么可能导致 Google Chrome 不报告动态通知事件? AFAIK,除了 Chrome 肯定没有的主动指针抓取之外,X 协议不允许这样做。

这是我在所有现有窗口上注册自己的方法。我在根窗口上调用register_events,并且每当我收到创建通知事件时:

static void register_events(xcb_window_t window) {
    xcb_void_cookie_t cookie = xcb_change_window_attributes_checked(connection,                                         
        window, XCB_CW_EVENT_MASK, (uint32_t[]) { XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION | XCB_EVENT_MASK_LEAVE_WINDOW });
    xcb_generic_error_t *error = xcb_request_check(connection, cookie);
    if (error != NULL) {
        xcb_disconnect(connection);
        errx(EXIT_FAILURE, "could not subscribe to events on a window, bailing out");
    }   
}

static void register_existing_windows(void) {
    xcb_query_tree_reply_t *reply;
    if ((reply = xcb_query_tree_reply(connection, xcb_query_tree(connection, root), 0)) == NULL) {
        return;
    }   

    int len = xcb_query_tree_children_length(reply);
    xcb_window_t *children = xcb_query_tree_children(reply);
    for (int i = 0; i < len; i++) {
        register_events(children[i]);
    }   

    xcb_flush(connection);
    free(reply);
}

【问题讨论】:

  • 如果将xev 附加到 Chome 窗口,您会得到什么?
  • @AndrewHenle 附加它并将我的鼠标移动到那里,移动它,让它休息并再次离开窗口只会给我 Enter/LeaveNotify、KeymapNotify 和 FocusIn/Out (pastebin.com/XQ3ZkVhW)
  • 我还应该指出,同样的观察可以在不同的机器上使用 Chromium 进行。
  • 那么您在 Chrome 窗口中看到 zero 个事件了吗?连鼠标点击都被吞了? xpropxwininfo -all 在这些窗口中显示什么?
  • @AndrewHenle 点击一下,我会收到 EnterNotify、KeymapNotify、PropertyNotify、ConfigureNotify 和 LeaveNotify(是的,所有这些都只需点击一个有焦点的 Chrome 窗口)。按键触发相应的事件。 xprop output, xwininfo on reparenting container, xwininfo on actual container

标签: c google-chrome x11 xcb


【解决方案1】:

Chrome 窗口似乎由嵌套的子窗口树组成。看来您需要遍历窗口树并监视它们。此代码在我的整个 Chrome 窗口中获取指针运动事件:

#include <stdio.h>
#include <stdlib.h>
#include <xcb/xcb.h>
#include <X11/Xlib.h>

static void register_events(xcb_connection_t *conn,
                            xcb_window_t window) {
  xcb_void_cookie_t cookie =
    xcb_change_window_attributes_checked(conn,
                                         window, XCB_CW_EVENT_MASK,
                                         (uint32_t[]) {
                                           XCB_EVENT_MASK_POINTER_MOTION });
  xcb_generic_error_t *error = xcb_request_check(conn, cookie);
  if (error != NULL) {
    xcb_disconnect(conn);
    exit(-1);
  }
}

static void register_existing_windows(xcb_connection_t *conn,
                                      xcb_window_t root) {
  int i, len;
  xcb_window_t *children;
  xcb_query_tree_reply_t *reply;
  if ((reply = xcb_query_tree_reply(conn,
                                    xcb_query_tree(conn, root), 0))
      == NULL)
    {
      return;
    }

  len = xcb_query_tree_children_length(reply);
  children = xcb_query_tree_children(reply);
  for (i = 0; i < len; i++) {
    register_events(conn, children[i]);
    register_existing_windows(conn, children[i]);
  }

  xcb_flush(conn);
}

void main(void) {
  int i=0;

  /* Open the connection to the X server */
  xcb_connection_t *conn = xcb_connect (NULL, NULL);

  /* Get the first screen */
  xcb_screen_t *screen = xcb_setup_roots_iterator (xcb_get_setup (conn)).data;

  register_existing_windows(conn, screen->root);

  while(1) {
    xcb_generic_event_t *evt;
    evt = xcb_wait_for_event(conn);
    printf("%i\n", i++);
  }
}

(这只是作为概念证明,不是很好。)

【讨论】:

  • 我有一种预感,它可能是一种嵌套类型的问题,但只是看起来“深一层”。没想到我必须全部递归。我会试一试,然后回复你。感谢您的回答!
  • 是的,这似乎是问题所在。我对传播掩码的想法太复杂了。我现在在修复它之前检查过,如果我打开一个 new Chrome 窗口,我会收到所有事件,因为即使对于所有子窗口,我也会收到创建通知事件。只是这个最初的部分是有缺陷的。谢谢,这让我发疯了!
  • 啊,我知道它已经解决了。欢迎来到疯狂的 XWindows 世界。
  • 我将接受的答案更改为我自己的,因为使用 XInput 的效果要好几个数量级,但当然这并不是我最初的问题。因此,我希望您的回答是有效且非常有帮助的,但我只是想引导访问者朝着更好的方向前进。
【解决方案2】:

虽然@Jay Kominek 的回答很有帮助且有效,但我现在意识到使用 Xinput 扩展提供了一种更好的方法,因为它不会干扰任何应用程序。

简单地选择整个树会导致各种问题,例如,悬停在 Chrome 中不再起作用。

【讨论】:

    【解决方案3】:

    xcb 提供 xcb_grab_pointer 来捕获指针事件,无需在特定窗口上注册。

    #include <stdlib.h>
    #include <stdio.h>
    
    #include <xcb/xcb.h>
    
    void
    print_modifiers (uint32_t mask)
    {
      const char **mod, *mods[] = {
        "Shift", "Lock", "Ctrl", "Alt",
        "Mod2", "Mod3", "Mod4", "Mod5",
        "Button1", "Button2", "Button3", "Button4", "Button5"
      };
      printf ("Modifier mask: ");
      for (mod = mods ; mask; mask >>= 1, mod++)
        if (mask & 1)
          printf(*mod);
      putchar ('\n');
    }
    
    int
    main ()
    {
      xcb_connection_t    *c;
      xcb_screen_t        *screen;
      xcb_window_t         win;
      xcb_generic_event_t *e;
      uint32_t             mask = 0;
    
      /* Open the connection to the X server */
      c = xcb_connect (NULL, NULL);
    
      /* Get the first screen */
      screen = xcb_setup_roots_iterator (xcb_get_setup (c)).data;
    
      mask = XCB_EVENT_MASK_BUTTON_PRESS   |
                  XCB_EVENT_MASK_BUTTON_RELEASE | XCB_EVENT_MASK_POINTER_MOTION;
    
      xcb_grab_pointer(c, false, screen->root, mask, XCB_GRAB_MODE_ASYNC, XCB_GRAB_MODE_ASYNC, XCB_NONE, XCB_NONE, XCB_CURRENT_TIME);
    
      xcb_flush (c);
    
      while ((e = xcb_wait_for_event (c))) {
        switch (e->response_type & ~0x80) {
        case XCB_BUTTON_PRESS: {
          xcb_button_press_event_t *ev = (xcb_button_press_event_t *)e;
          print_modifiers(ev->state);
    
          switch (ev->detail) {
          case 4:
            printf ("Wheel Button up in window %ld, at coordinates (%d,%d)\n",
                    ev->event, ev->event_x, ev->event_y);
            break;
          case 5:
            printf ("Wheel Button down in window %ld, at coordinates (%d,%d)\n",
                    ev->event, ev->event_x, ev->event_y);
            break;
          default:
            printf ("Button %d pressed in window %ld, at coordinates (%d,%d)\n",
                    ev->detail, ev->event, ev->event_x, ev->event_y);
          }
          break;
        }
        case XCB_BUTTON_RELEASE: {
          xcb_button_release_event_t *ev = (xcb_button_release_event_t *)e;
          print_modifiers(ev->state);
    
          printf ("Button %d released in window %ld, at coordinates (%d,%d)\n",
                  ev->detail, ev->event, ev->event_x, ev->event_y);
          break;
        }
        case XCB_MOTION_NOTIFY: {
          xcb_motion_notify_event_t *ev = (xcb_motion_notify_event_t *)e;
    
          printf ("Mouse moved in window %ld, at coordinates (%d,%d)\n",
                  ev->event, ev->event_x, ev->event_y);
          break;
        }
        default:
          /* Unknown event type, ignore it */
          printf("Unknown event: %d\n", e->response_type);
          break;
        }
        /* Free the Generic Event */
        free (e);
      }
    
      return 0;
    }
    

    【讨论】:

      猜你喜欢
      • 2015-04-04
      • 1970-01-01
      • 2015-03-23
      • 1970-01-01
      • 2010-10-06
      • 2023-03-30
      • 2022-07-29
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多