7

ポインターの動きについて通知を受けようとしています。ウィンドウマネージャーとして実行したくないので、XCB_EVENT_MASK_SUBSTRUCTURE_NOTIFY | XCB_EVENT_MASK_POINTER_MOTION起動時と作成通知イベントの両方で行うすべてのウィンドウで設定する必要があります。

これは一般的にうまく機能しているようで、すべてのウィンドウでモーション通知イベントを受け取ります。ただし、どういうわけか、これは Google Chrome ウィンドウには当てはまりません。後で明示的にクエリを実行してイベント マスクを確認したところ、正しく設定されています。伝播マスクにも異常は見られません。

Google Chrome がモーション通知イベントを報告しない原因は何ですか? 私の知る限り、X プロトコルでは、Chrome にはないアクティブなポインター グラブを除いて、それが許可されていません。

これが、既存のすべてのウィンドウに自分自身を登録する方法です。ルート ウィンドウを呼び出しregister_events、create notify イベントも受け取るたびに、次のようにします。

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);
}
4

3 に答える 3

8

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++);
  }
}

(これは概念実証として意図されたものであり、あまり良いものではありません。)

于 2015-05-07T18:40:35.323 に答える
2

@Jay Kominek の回答は役に立ち、有効でしたが、Xinput 拡張機能を使用すると、アプリケーションにまったく干渉しないため、はるかに優れたアプローチが提供されることに気付きました。

ツリー全体を単に選択すると、あらゆる種類の問題が発生します。たとえば、Chrome ではホバーが機能しなくなりました。

于 2015-08-30T21:36:10.177 に答える