X11 FocusIn 不工作

X11 FocusIn is not working

据我了解,只要 window 获得焦点,就会触发 X11 FocusIn 事件。它是键盘输入发送到的 window。我无法触发此事件。我确保在创建 window 时给它 FocusChangeMask。我在我的事件处理程序中创建了一个断点,其中 FocusIn 事件应该发生并且它不会停止。

我有 2 个独立的 window,一个透明的,一个不透明的。目前我有它,所以透明 window 总是在非透明 window 之上。每当我切换焦点然后切换回透明 window 时,不透明 window 就在正下方。这导致其他windows卡在'between'透明和不透明window。

我注意到,每当我关注下方的非透明 window 时,就会触发 FocusIn 事件。我无法获得透明 window 来触发事件。这与 window 为 32 位颜色有关吗?

我错过了什么?

while(!renderer->stop)
    {
        XNextEvent(renderer->x_display, &event);
        switch(event.type)
        {
            case Expose:
            if (event.xexpose.window == gstreamer_window)
            {
                XRaiseWindow(renderer->x_display, renderer->opengl_window);
            }
            break;

            case FocusIn:
            if (event.xfocus.window == renderer->opengl_window)
            {
                XRaiseWindow(renderer->x_display, gstreamer_window);
            }
            break;

            case ConfigureNotify:
            if (event.xconfigure.window == renderer->opengl_window)
            {
                XMoveWindow(renderer->x_display, gstreamer_window,
                            event.xconfigure.x, event.xconfigure.y - top_border_offset);
            }
            break;
        }
    }

下面是我创建 window 的方法。

XSetWindowAttributes  swa;
    swa.event_mask = ExposureMask | PointerMotionMask | KeyPressMask | FocusChangeMask;
    swa.colormap = XCreateColormap(x_display, XDefaultRootWindow(x_display), visual, AllocNone);
    swa.background_pixel = 0;
    swa.border_pixel = 0;

    /* Create a window */
    opengl_window = XCreateWindow (
              x_display, parent,
              0, 0, m_plane_width, m_plane_height, 0,
              depth, InputOutput,
              visual, CWEventMask | CWBackPixel | CWColormap | CWBorderPixel,
              &swa );

从你的问题中不清楚你的问题中引用的 windows 是顶级应用程序 windows,还是次要的、辅助的 windows,它们是 windows 的子应用程序 windows您的顶级应用程序 windows.

但在所有情况下,正确的输入焦点处理都需要您告知 window 管理器您的应用程序期望如何处理输入焦点。

有关详细信息,请参阅 section 4.1.7 of the ICCCM specification。不幸的是,仅仅编写一个处理 FocusIn 消息的事件循环并期望它们从天而降是不够的。首先,您需要告诉 window 经理您将如何处理输入焦点切换,然后响应 window 经理的消息,如 ICCCM 规范中所述;也许通过为您自己的应用程序显式发送 SetInputFocus 请求 windows.

好像我在错误的地方设置了 FocusChangeMask。通过添加行 XSelectInput(x_display, opengl_window, FocusChangeMask) ,它现在触发 FocusIn 事件。它触发了另一个显示器,因为它有面具,但这个没有。

在 OP 自己接受的背景答案下查看我的 post

我遇到了同样的问题,如果您使用 XSelectInput,它似乎会覆盖 window 的事件掩码,而不是添加到它。您需要:

  • 跳过添加 XSelectInput 并在创建时在 window 上设置事件掩码

  • 或将 window 的掩码 所有 添加到 XSelectInput 命令

这是我添加 XSelectInput 行之前的类似设置:

swa.event_mask = StructureNotifyMask | SubstructureNotifyMask | FocusChangeMask | ExposureMask | KeyPressMask;
wnd = XCreateWindow(disp, wndRoot, left, top, width, height, 0, vi->depth, InputOutput, vi->visual, CWColormap | CWEventMask, &swa);
XMapWindow(disp, wnd);

当我添加这个用于捕获键输入时:

XSelectInput(disp, wnd, KeyPressMask | KeyReleaseMask);

其他一切都停止工作,直到现在我才意识到这一点,因为我只是在测试密钥。

我有一个 window 应用程序,在客户区没有控件,所以我不知道 XSelectInput 对已经有掩码的 window 还能做什么,但是没有它我确实会收到关键的上下消息。在 OP 的自我接受的答案中,他只是走了另一条路,而是将 'FocusChangeMask' 添加到 XSelectInput

在我看来,很多 X11 的文档很像标准的 Apple 文档,它有一个痛苦的地方,即从不说明该功能的实际作用或影响,而是告诉您所有其他内容。 (请参阅此处的底部片段)公平地说,Cocoa 文档的很大一部分相当不错,但可能有一半不是。这也适用于许多或大部分参数。

来自 Linux 手册页,我认为可能与这里的 Xlib 手册完全相同 https://tronche.com/gui/x/xlib/

The XSelectInput function requests that the X server report the events associated with the specified event mask.

Setting the event-mask attribute of a window overrides any previous call for the same window but not for other clients.


(以下是我自己对 XInputSelect 文档的可能不正确的改写)

这可以解释为:

XSelectInput sets the event-mask on a window for a display for events reported to the client. Each client can set its own independent mask for events it wants to receive with the following exceptions (skipping the exceptions).

现在是关键部分:

XInputSelect will override and replace for a client any previous event-mask settings for a window on a display, including any event-mask set when creating the window.

我希望它被写成确保它被理解,如果是真的,XInputSelect 没有做任何其他事情,比如启用字符解释键等等,因为我相信核心混淆是来自所有那里的各种例子给人的印象是除了设置面具之外还有其他一些魔法。我假设没有,而且文档中提到除了面具之外没有其他魔法。

XInputSelect sets the event-mask for a window and allows for setting an event mask after a window is created.

我的意见是那一行应该放在第一行。