【问题标题】:How to get the character for an XLib key wrt the keyboard layout?如何在键盘布局中获取 XLib 键的字符?
【发布时间】:2016-05-24 12:24:47
【问题描述】:

使用XKeycodeToKeysym(在 C++ 中)我可以获得按键事件的 KeySym。据我了解,这已经应该尊重键盘布局。但是,当我切换键盘布局(在英语和希伯来语之间)时,我得到了相同的 KeySym。我怀疑 Xlib Keysym 只支持 X11 级别中定义的键盘布局?在我的系统中,键盘布局仅在桌面环境级别(Mate)中定义。如果是这样,有没有办法在不使用 Qt / GTK 之类的工具包的情况下获得正确的字符?我必须分别处理每个桌面环境吗?

[编辑]

我尝试了以下方法(根据 Andrey 的建议),但不起作用:

#include <X11/XKBlib.h>

#include <cstring>
#include <cassert>
#include <iostream>

int main() {
    Display *display = XOpenDisplay(nullptr);
    Window root, window;
    XSetWindowAttributes swa;
    root = DefaultRootWindow( display );
    XSelectInput( display, root, MappingNotify );
    std::memset(&swa, 0, sizeof swa );
    swa.event_mask = MappingNotify | KeyPressMask;
    window = XCreateWindow( display, root, 50, 200, 1024, 768, 0, CopyFromParent, InputOutput, CopyFromParent,
                             CWEventMask, &swa );
    XMapRaised( display, window );
    int xkbEventCode=0, n0=0, n1=0, n2=0, n3=0;
    bool isOk = XkbQueryExtension(  display, &n0, &xkbEventCode, &n1, &n2, &n3 ) ==True;
    assert( isOk );
    isOk = XkbSelectEvents( display, XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask ) ==True;
    assert( isOk );
    while (true) {
        XEvent event;
        std::memset( &event, 0, sizeof event );
        XNextEvent( display, &event );
        if (event.type == xkbEventCode)
            switch (reinterpret_cast<XkbEvent*>(&event)->any.xkb_type) {
              case XkbNewKeyboardNotify:
              case XkbMapNotify: {
                std::cout << "Keyboard mapping has changed." << std::endl;
                break;
                }
            default:  break;
            }
        else
            switch (event.type) {
              case KeyPress: {
                KeyCode keyCode = event.xkey.keycode;
                int keySymsPerkeyCode=0;
                KeySym *keySyms( XGetKeyboardMapping(display, keyCode, 1, &keySymsPerkeyCode)),
                       *keySym = keySyms;
                while (keySymsPerkeyCode--  &&  *keySym != NoSymbol) {
                    std::cout << *keySym << std::endl;
                    ++keySym;
                    }
                XFree( keySyms );
                break;
                }
              case MappingNotify: {
                std::cout << "Keyboard mapping has changed." << std::endl;
                break;
                }
              default:  break;
              }
        }
    return 0;
    }

【问题讨论】:

标签: c++ linux internationalization x11 xlib


【解决方案1】:

只能低级回答,不知道XKeycodeToKeysym是干什么的。

您需要收听MappingNotify 事件,并且每次收到它时重新读取XGetKeyboardMapping 的新映射(通常这意味着键盘布局/语言已更改)

这是核心 X 协议的一部分,桌面环境/独立于 WM

更新:

看起来 xlib 默认启用 XKeyboard 扩展。启用后,您需要明确表达对映射更改事件的兴趣(与始终将 MappingNotify 发送给所有客户端的核心协议不同) - 请参阅http://www.x.org/archive/X11R7.5/doc/man/man3/XkbSelectEvents.3.html

 XkbSelectEvents (display, XkbUseCoreKbd, XkbAllEventsMask, XkbAllEventsMask);

之后您回复XkbMapNotify 事件并执行XkbGetMap() 以获取新布局

【讨论】:

  • 恐怕这个函数给了我完全相同的 KeySym,这并没有考虑到我在 Mate 中的键盘布局。
  • 哪一个? XGetKeyboardMapping 在键盘布局改变后返回一个新的映射。另外,当您使用 Mate 切换器更改布局时,您会收到 MappingNotify 事件吗?
  • 不,我没有得到MappingNotifyXGetKeyboardMapping 返回相同的映射。
  • 您能发布您正在使用的代码的简单示例吗?
  • 有趣,如果使用 XKEYBOARD 扩展(并且 xlib 自动启用它),看起来您不会得到 MappingNotify。我没有在我的(非 xlib)代码中使用 xkeyboard - x.org/releases/X11R7.7/doc/kbproto/…
猜你喜欢
  • 1970-01-01
  • 2013-09-12
  • 2013-07-19
  • 2019-05-28
  • 2019-12-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多