跟踪 X11 进入/离开事件

huangapple go评论63阅读模式
英文:

Track X11 enter / leave events

问题

在给定的代码中,你想要在鼠标进入或离开窗口时收到通知,但有一些问题。代码的核心问题似乎是鼠标事件没有正确传递或者导致鼠标指针消失,以及其他窗口停止响应点击事件。你也尝试了一些不同的方法,但问题仍然存在。

如果你只需要监测鼠标进入或离开窗口,而不需要拦截鼠标事件,你可以尝试使用更简单的方法,如监听窗口的EnterNotify和LeaveNotify事件。这可以通过XCB来实现,而不涉及复杂的设备抓取。

以下是一个可能有用的示例代码片段:

#include <stdio.h>
#include <xcb/xcb.h>

int main() {
    xcb_connection_t *conn = xcb_connect(NULL, NULL);
    xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;
    xcb_window_t root = screen->root;

    xcb_generic_event_t *event;
    xcb_void_cookie_t cookie;

    uint32_t event_mask = XCB_CW_EVENT_MASK;
    uint32_t values[1] = { XCB_EVENT_MASK_ENTER_WINDOW | XCB_EVENT_MASK_LEAVE_WINDOW };

    cookie = xcb_change_window_attributes_checked(conn, root, event_mask, values);
    xcb_flush(conn);

    if (xcb_request_check(conn, cookie)) {
        fprintf(stderr, "Unable to set event mask on the root window\n");
        return 1;
    }

    while ((event = xcb_wait_for_event(conn))) {
        switch (event->response_type & ~0x80) {
            case XCB_ENTER_NOTIFY:
                printf("Mouse entered the window\n");
                break;
            case XCB_LEAVE_NOTIFY:
                printf("Mouse left the window\n");
                break;
        }
        free(event);
    }

    xcb_disconnect(conn);

    return 0;
}

这段代码会监听鼠标进入和离开根窗口的事件,而不会干扰其他窗口的事件响应。你可以根据你的需要修改此代码。希望这对你有所帮助。

英文:

I need to be notified when mouse enters or leaves a window (any window, that's why I'm grabbing on the root window). I have a solution using xcb_input_xi_grab_device() but it works only half way. When I run the app, I do get enter/leave events but the mouse pointer disappears and it consumes all mouse events and other windows stop (children of the root window) reacting to clicks.

Using XCB_INPUT_GRAB_OWNER_OWNER should allow passing-through the events but it doesn't work.

app.c:

#include &lt;stdio.h&gt;
#include &lt;xcb/xcb.h&gt;
#include &lt;xcb/xinput.h&gt;

xcb_input_device_id_t find_device(xcb_connection_t *conn)
{
    xcb_input_xi_query_device_reply_t *reply = xcb_input_xi_query_device_reply(
        conn, xcb_input_xi_query_device(conn, XCB_INPUT_DEVICE_ALL), NULL);
    xcb_input_xi_device_info_iterator_t iter =
        xcb_input_xi_query_device_infos_iterator(reply);

    xcb_input_device_id_t device_id;

    int found = 0;
    while (iter.rem) {
        xcb_input_xi_device_info_t *device = iter.data;
        switch (device-&gt;type) {
            case XCB_INPUT_DEVICE_TYPE_MASTER_POINTER:
            case XCB_INPUT_DEVICE_TYPE_SLAVE_POINTER:
            case XCB_INPUT_DEVICE_TYPE_FLOATING_SLAVE:
                device_id = device-&gt;deviceid;
                found = 1;
                break;
        }
        if (found) {
            break;
        }
        xcb_input_xi_device_info_next(&amp;iter);
    }
    free(reply);

    return device_id;
}

int main()
{
    xcb_connection_t *conn = xcb_connect(NULL, NULL);
    xcb_screen_t *screen = xcb_setup_roots_iterator(xcb_get_setup(conn)).data;

    uint32_t mask =
        XCB_INPUT_XI_EVENT_MASK_ENTER | XCB_INPUT_XI_EVENT_MASK_LEAVE;
    xcb_generic_error_t *error;
    xcb_input_xi_grab_device_reply_t *reply = xcb_input_xi_grab_device_reply(
        conn,
        xcb_input_xi_grab_device(conn, screen-&gt;root, XCB_CURRENT_TIME,
                                 XCB_CURSOR_NONE, find_device(conn),
                                 XCB_INPUT_GRAB_MODE_22_ASYNC,
                                 XCB_INPUT_GRAB_MODE_22_ASYNC,
                                 XCB_INPUT_GRAB_OWNER_OWNER, 1, &amp;mask),
        &amp;error);
    free(reply);
    if (error) {
        printf(&quot;failed to grab device\n&quot;);
        free(error);
        return -1;
    }

    xcb_flush(conn);

    xcb_generic_event_t *event;
    while ((event = xcb_wait_for_event(conn))) {
        xcb_ge_event_t *generic_event = event;
        switch (generic_event-&gt;event_type) {
            case XCB_INPUT_ENTER:
                printf(&quot;enter\n&quot;);
                break;
            case XCB_INPUT_LEAVE:
                printf(&quot;leave\n&quot;);
                break;
        }
        free(event);
    }

    return -1;  // never reached
}
cc -O2 app.c -o app `pkg-config --cflags --libs xcb xcb-xinput`

I also tried to achieve it with xcb_grab_button(), xcb_input_xi_select_events(), xcb_input_xi_passive_grab_device() or xcb_grab_pointer() but then the problem is the same. Either the mouse events are not passed-through or I don't receive enter/leave events at all.

答案1

得分: 1

需要在鼠标进入或离开窗口时通知我。我会通过选择所有窗口上的进入和离开事件来实现这一点(事件掩码为EnterWindow和LeaveWindow)。

当然,“所有窗口”部分需要是动态的:当新窗口被创建时,它们也需要被监视。因此,您还需要SubstructureNotify,以便在创建新窗口时获得CreateNotify事件。

英文:

> I need to be notified when mouse enters or leaves a window

I would implement that by selecting enter and leave events on all windows (event masks EnterWindow and LeaveWindow).

The "all windows" part would of course need to be dynamic: When new windows are created, they also need to be monitored. Thus, you also need SubstructureNotify so that you get CreateNotify events when new windows are created.

huangapple
  • 本文由 发表于 2023年2月9日 01:15:40
  • 转载请务必保留本文链接:https://go.coder-hub.com/75389393.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定