【问题标题】:how to catch keyboard layout change event and get current new keyboard layout on Linux?如何在 Linux 上捕获键盘布局更改事件并获取当前新的键盘布局?
【发布时间】:2016-02-23 05:29:49
【问题描述】:

现在,我正在开发 Linux 上的应用程序,并希望捕获键盘布局更改事件(通过 UI/widget/shell/编程等更改键盘布局)并获取/设置新的键盘布局信息以进一步处理.我认为这不是一个新问题,但我一次又一次地从 stackoverflow 搜索,但没有答案。希望我能在这里得到正确的答案!

这里描述了我想学习的主要解决方案。在 windows 中,WM_INPUTLANGCHANGE windows 消息可能会在包含键盘布局信息的 WinProc 中被捕获。我们可以使用 GetKeyboardLayout() API 来获取当前的键盘布局信息。最后,如果我想使用我喜欢的键盘布局,我可以使用 ActivateKeyboardLayout() 来激活键盘布局。

总之,我希望在Linux中找到通知消息以及如何在代码中捕获消息(最好给我一个例子),Linux中的Get keyboard layout API和Set keyboard layout API。开发语言也是 C/C++。

提前致谢。

【问题讨论】:

    标签: linux layout keyboard


    【解决方案1】:

    另一个答案对我不起作用。它编译并运行,但是当我切换布局时,MappingNotify 事件不会发生。这是对我有用的修改。

    #include <stdio.h>
    #include <X11/Xutil.h>
    #include <X11/XKBlib.h>
    
    int main(int argc, char **argv)
    {
            XEvent e;
            Display *d;
    
            if (!(d = XOpenDisplay(NULL))) {
                    fprintf(stderr, "cannot open display\n");
                    return 1;
            }
    
            XKeysymToKeycode(d, XK_F1);
    
        int xkbEventType;
        XkbQueryExtension(d, 0, &xkbEventType, 0, 0, 0);
        XkbSelectEvents(d, XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask);
    
        XSync(d, False);
    
        while (1) {
            XNextEvent(d, &e);
            if (e.type == xkbEventType) {
                XkbEvent* xkbEvent = (XkbEvent*) &e;
                if (xkbEvent->any.xkb_type == XkbStateNotify) {
                    int lang = xkbEvent->state.group;
                    if (lang == 1) {
                        fprintf(stdout, "1\n");
                        fflush(stdout);
                    } else {
                        fprintf(stdout, "0\n");
                        fflush(stdout);
                    }
                }
            }
        }
    
        return(0);
    }
    

    编译:

    gcc -Wall -O2 xmappingnotify.c -o xmappingnotify -lX11
    

    我是这样使用的:

    xmappingnotify | xargs -I {} my-custom-command {} &
    

    所以my-custom-command [number_of_the_layout] 在我更改布局时运行。我有 2 种布局,xmappingnotify 一种布局输出“1”,另一种布局输出“0”。

    【讨论】:

    • 这总是在我的设置上打印出 0(Ubuntu 16.04,两种不同的语言/布局)。
    • 看起来该事件可能会针对相同的布局更改触发多次。 The X Keyboard protocol specification 可能会来解释。
    • 启用 X 键盘扩展时,必须听此答案代码中演示的事件,而不是其他答案中的事件。
    【解决方案2】:

    X11 的答案:

    通过MappingNotify 事件检测更改

    通过setxkbmap更改或查询布局

    这是一个用于检测 MappingNotify 事件的基本 xlib 示例:

    #include <stdio.h>
    #include <X11/Xlib.h>
    #include <X11/Xutil.h>
    #include <X11/keysym.h>
    
    int main(int argc, char **argv)
    {
            XEvent event;
            Display *dpy;
    
            if (!(dpy = XOpenDisplay(NULL))) {
                    fprintf(stderr, "cannot open display\n");
                    return 1;
            }
    
            /**
             * Note: We might never get a MappingNotify event if the
             * modifier and keymap information was never cached in Xlib.
             * The next line makes sure that this happens initially.
             */
            XKeysymToKeycode(dpy, XK_F1);
    
            while (1)
            {
                    XNextEvent(dpy, &event);
                    if (event.type == MappingNotify) {
                            XMappingEvent *e = (XMappingEvent *) &event;
                            if (e->request == MappingKeyboard) {
                                    fprintf(stderr, "The keyboard mapping was changed!\n");
                            }
                            XRefreshKeyboardMapping(e);
                    }
            }
    
            return(0);
    }
    

    内置命令:

    gcc -Wall -O2 xmappingnotify.c -o xmappingnotify -lX11
    

    【讨论】:

    【解决方案3】:

    我在 Suckless dwm 栏中使用@gvlasov 答案作为键盘布局通知,并带有每个窗口的键盘布局补丁。它在结果方面工作正常,但它产生了太多事件(ctrl、mod、shift 键按下释放和鼠标滚轮移动输出布局;正确的,但这不是必需的,只有当布局改变时才应该返回布局)。可能是@matanster 的评论中提到的。所以我做了一个改变,停止了鼠标滚轮移动的输出,尽管仍然产生了 ctrl、mod、shift 键按下释放的输出。不理想,稍微好点:

    换行:

    XkbSelectEvents(d, XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask);
    

    用这个:

    XkbSelectEventDetails(d, XkbUseCoreKbd, XkbMapNotifyMask, XkbAllEventsMask, XkbAllEventsMask);
    

    如果有人知道如何仅在键盘布局更改而不是 ctrl、mod、shift 键按下释放时获得结果/输出,欢迎。


    更新,使用这个:

    XkbSelectEventDetails(d, XkbUseCoreKbd, XkbStateNotify, XkbAllStateComponentsMask, XkbGroupStateMask);
    

    我得到了预期的结果。唯一通知的事件是键盘布局更改,既不是按键也不是按键释放。与我的上一行相比,它唯一的缺点是 caps 更改不会被通知,这在以前是可能的。

    【讨论】:

      猜你喜欢
      • 2012-09-04
      • 2014-02-24
      • 1970-01-01
      • 1970-01-01
      • 2013-07-19
      • 1970-01-01
      • 2012-05-01
      • 1970-01-01
      • 2019-12-09
      相关资源
      最近更新 更多