在不创建 window 的情况下,是否可以检测当前的 XCB 修改器状态?

Without creating a window, is it possible to detect the current XCB modifier state?

我使用 Xkb sticky 选项,我想编写一个程序,当修改键状态发生变化时,它会向标准输出发送一些文本,例如当 Ctrl 处于“活动”状态时,无论是否按下物理 Ctrl 键。我希望这个程序能够在不创建可见 X window 并保持打开状态的情况下工作,因为这会妨碍我使用其他应用程序。

是否可以使用 Xkb、XkbCommon、Xlib and/or XCB 库?我尝试按照 in the Xkb spec 的建议使用 XNextEvent,但是这个函数会永远阻塞。

我对实现的完整尝试是 here,但这是相关部分:

#include <X11/X.h>
#include <X11/Xlib.h>
#include <X11/XKBlib.h>

/* Various X and Xkb data that are often needed together */
typedef struct ExtensionInfo {
    Display* display;         /* An X display */
    int base_event_code;      /* Integer code offset for Xkb events */
    int base_err_code;        /* Integer code offset for Xkb errors */
    int xkb_version_major;    /* Dual-purpose version indicator; see XkbOpenDisplay(3) */
    int xkb_version_minor;    /* Dual-purpose version indicator; see XkbOpenDisplay(3) */
    int xkb_reason;           /* Error reason if XkbOpenDisplay fails, or success reason */
} ExtensionInfo;

int main(int argc, char *argv[]) {
    ExtensionInfo *extension_info;
    XkbEvent xkb_event;

    extension_info->display = XkbOpenDisplay(
        /* NULL here is allowed by XkbOpenDisplay but not mentioned explicitly
         * in the XkbOpenDisplay man page - it defaults to $DISPLAY */
        NULL,
        &(extension_info->base_event_code),
        &(extension_info->base_err_code),
        &(extension_info->xkb_version_major),
        &(extension_info->xkb_version_minor),
        &(extension_info->xkb_reason)
    );

    const unsigned long int xkb_details_mask = (
        XkbModifierBaseMask |
        XkbModifierStateMask |
        XkbModifierLatchMask |
        XkbModifierLockMask
    );

    bool xkb_initialized = XkbSelectEventDetails(
        extension_info->display,
        XkbUseCoreKbd,
        XkbStateNotifyMask,
        xkb_details_mask,
        xkb_details_mask
    );

    printf("Waiting...\n");
    XNextEvent(extension_info->display, &xkb_event.core);
    printf("Done.\n");
}

一般来说,是的,完全有可能调用任何类型的需要 Window 句柄的 X11 请求(例如,用于获取或设置选择)而不会弹出 屏幕上的 window -- 通过创建 InputOnly window.

但是对于 Xkb* 你甚至不需要它。在发布的代码段中,您的问题是您根本没有调用 XkbSelectEvents,因此不会向您的 X11 客户端传送任何 Xkb 事件。

下面的小例子确实在状态改变时得到一个事件:

#include <X11/Xlib.h>
#include <X11/XKBlib.h>
#include <err.h>

int main(void){
        Display *dpy; int xkb_event;
        if(!(dpy = XkbOpenDisplay(0, &xkb_event, 0, 0, 0, 0)))
                errx(1, "cannot open display '%s'", XDisplayName(0));
        XkbSelectEvents(dpy, XkbUseCoreKbd, XkbStateNotifyMask,
                XkbStateNotifyMask);
        for(;;){
                XkbEvent e; XNextEvent(dpy, &e.core);
                if(e.type == xkb_event && e.any.xkb_type == XkbStateNotify)
                        warnx("xkb state changed!");
        }
}