当前位置: 首页 > 面试题库 >

通过X11显示器获取UTF-8输入

李洋
2023-03-14
问题内容

我一直在尝试和阅读Internet上的大量资源,试图找到一种从X显示器获取UTF-8键盘(组合)输入的方法。但是我无法使其工作。

我已经尝试过此链接中的示例代码(例如11-4),但没有成功。

我还写了一个简单的示例(如下),试图使其工作。我的简单测试用例是打印一个“é”,这是通过先键入“ a”然后再键入e来实现的。

怎么了?

谢谢,

这是我的示例:

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Xlocale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char ** argv)
{
    int screen_num, width, height;
    unsigned long background, border;
    Window win;
    XEvent ev;
    Display *dpy;
    XIM im;
    XIC ic;
    char *failed_arg;
    XIMStyles *styles;
    XIMStyle xim_requested_style;

    /* First connect to the display server, as specified in the DISPLAY 
    environment variable. */
    if (setlocale(LC_ALL, "") == NULL) {
        return 9;
    }

    if (!XSupportsLocale()) {
        return 10;
    }
    if (XSetLocaleModifiers("") == NULL) {
        return 11;
    }

    dpy = XOpenDisplay(NULL);
    if (!dpy) {
        fprintf(stderr, "unable to connect to display");
        return 7;
    }
    /* these are macros that pull useful data out of the display object */
    /* we use these bits of info enough to want them in their own variables */
    screen_num = DefaultScreen(dpy);
    background = BlackPixel(dpy, screen_num);
    border = WhitePixel(dpy, screen_num);

    width = 400; /* start with a small window */
    height = 200;

    win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), /* display, parent */
        0,0, /* x, y: the window manager will place the window elsewhere */
        width, height, /* width, height */
        2, border, /* border width & colour, unless you have a window manager */
        background); /* background colour */

    /* tell the display server what kind of events we would like to see */
    XSelectInput(dpy, win, ButtonPressMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask|KeymapStateMask);

    /* okay, put the window on the screen, please */
    XMapWindow(dpy, win);

    im = XOpenIM(dpy, NULL, NULL, NULL);
    if (im == NULL) {
        fputs("Could not open input method\n", stdout);
        return 2;
    }

    failed_arg = XGetIMValues(im, XNQueryInputStyle, &styles, NULL);

    if (failed_arg != NULL) {
      fputs("XIM Can't get styles\n", stdout);
      return 3;
    }

    int i;
    for (i = 0; i < styles->count_styles; i++) {
        printf("style %d\n", styles->supported_styles[i]);
    }
    ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, NULL);
    if (ic == NULL) {
        printf("Could not open IC\n");
        return 4;
    }

    XSetICFocus(ic);

    /* as each event that we asked about occurs, we respond.  In this
     * case we note if the window's shape changed, and exit if a button
     * is pressed inside the window */
    while(1) {
        XNextEvent(dpy, &ev);
        switch(ev.type){
        case KeymapNotify:
            XRefreshKeyboardMapping(&ev.xmapping);
            break;
        case KeyPress:
            {
                int count = 0;
                KeySym keysym = 0;
                char buf[20];
                Status status = 0;
                count = Xutf8LookupString(ic, (XKeyPressedEvent*)&ev, buf, 20, &keysym, &status);

                printf("count: %d\n", count);
                if (status==XBufferOverflow)
                    printf("BufferOverflow\n");

                if (count)
                    printf("buffer: %s\n", buf);

                if (status == XLookupKeySym || status == XLookupBoth) {
                    printf("status: %d\n", status);
                }
                printf("pressed KEY: %d\n", keysym);
            }
            break;
        case KeyRelease:
            {
                int count = 0;
                KeySym keysym = 0;
                char buf[20];
                Status status = 0;
                count = XLookupString((XKeyEvent*)&ev, buf, 20, &keysym, NULL);

                if (count)
                    printf("in release buffer: %s\n", buf);

                printf("released KEY: %d\n", keysym);
            }
            break;
        case ConfigureNotify:
            if (width != ev.xconfigure.width
                    || height != ev.xconfigure.height) {
                width = ev.xconfigure.width;
                height = ev.xconfigure.height;
                printf("Size changed to: %d by %d", width, height);
            }
            break;
        case ButtonPress:
            XCloseDisplay(dpy);
            return 0;
        }
        fflush(stdout);
    }
}

问题答案:

您必须这样做:

            if (XFilterEvent(&ev, win))
                continue;

在您的事件循环中。这将运行输入法机制,没有它,您将获得原始X事件。例如,当您按一个重音符号后跟一个字母键,并且不进行调用XFilterEvent,您将像往常一样获得两个KeyPress事件。但是,如果您拨打电话,您将获得
三个 事件。有两个原始事件,需要为其XFilterEvent(&ev, win)返回True。然后,通过输入法合成了一个事件,针对该事件XFilterEvent(&ev, win)返回False。这是第三个事件,其中包含重音字符。

如果您既想要原始事件,又想要通过输入法合成的原始事件,则当然可以使用自己做原始事件处理continue

请注意buf[count] = 0;,为了buf正确打印(或显式使用长度),您将需要Xutf8LookupString不对输出进行null终止。

最后,如评论中所述,对于X11的最新版本,您将需要指定对的修改,XSetLocaleModifiers例如XSetLocaleModifiers("@im=none"),否则将不会生成额外的事件。

这是代码的更正版本:

#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xresource.h>
#include <X11/Xlocale.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(int argc, char ** argv)
{
    int screen_num, width, height;
    unsigned long background, border;
    Window win;
    XEvent ev;
    Display *dpy;
    XIM im;
    XIC ic;
    char *failed_arg;
    XIMStyles *styles;
    XIMStyle xim_requested_style;

    /* First connect to the display server, as specified in the DISPLAY 
    environment variable. */
    if (setlocale(LC_ALL, "") == NULL) {
        return 9;
    }

    if (!XSupportsLocale()) {
        return 10;
    }
    if (XSetLocaleModifiers("@im=none") == NULL) {
        return 11;
    }

    dpy = XOpenDisplay(NULL);
    if (!dpy) {
        fprintf(stderr, "unable to connect to display");
        return 7;
    }
    /* these are macros that pull useful data out of the display object */
    /* we use these bits of info enough to want them in their own variables */
    screen_num = DefaultScreen(dpy);
    background = BlackPixel(dpy, screen_num);
    border = WhitePixel(dpy, screen_num);

    width = 400; /* start with a small window */
    height = 200;

    win = XCreateSimpleWindow(dpy, DefaultRootWindow(dpy), /* display, parent */
        0,0, /* x, y: the window manager will place the window elsewhere */
        width, height, /* width, height */
        2, border, /* border width & colour, unless you have a window manager */
        background); /* background colour */

    /* tell the display server what kind of events we would like to see */
    XSelectInput(dpy, win, ButtonPressMask|StructureNotifyMask|KeyPressMask|KeyReleaseMask);

    /* okay, put the window on the screen, please */
    XMapWindow(dpy, win);

    im = XOpenIM(dpy, NULL, NULL, NULL);
    if (im == NULL) {
        fputs("Could not open input method\n", stdout);
        return 2;
    }

    failed_arg = XGetIMValues(im, XNQueryInputStyle, &styles, NULL);

    if (failed_arg != NULL) {
      fputs("XIM Can't get styles\n", stdout);
      return 3;
    }

    int i;
    for (i = 0; i < styles->count_styles; i++) {
        printf("style %d\n", (int)styles->supported_styles[i]);
    }
    ic = XCreateIC(im, XNInputStyle, XIMPreeditNothing | XIMStatusNothing, XNClientWindow, win, NULL);
    if (ic == NULL) {
        printf("Could not open IC\n");
        return 4;
    }

    XSetICFocus(ic);

    /* as each event that we asked about occurs, we respond.  In this
     * case we note if the window's shape changed, and exit if a button
     * is pressed inside the window */
    while(1) {
        XNextEvent(dpy, &ev);
        if (XFilterEvent(&ev, win))
            continue;
        switch(ev.type){
        case MappingNotify:
            XRefreshKeyboardMapping(&ev.xmapping);
            break;
        case KeyPress:
            {
                int count = 0;
                KeySym keysym = 0;
                char buf[20];
                Status status = 0;
                count = Xutf8LookupString(ic, (XKeyPressedEvent*)&ev, buf, 20, &keysym, &status);

                printf("count: %d\n", count);
                if (status==XBufferOverflow)
                    printf("BufferOverflow\n");

                if (count)
                    printf("buffer: %.*s\n", count, buf);

                if (status == XLookupKeySym || status == XLookupBoth) {
                    printf("status: %d\n", status);
                }
                printf("pressed KEY: %d\n", (int)keysym);
            }
            break;
        case KeyRelease:
            {
                int count = 0;
                KeySym keysym = 0;
                char buf[20];
                Status status = 0;
                count = XLookupString((XKeyEvent*)&ev, buf, 20, &keysym, NULL);

                if (count)
                    printf("in release buffer: %.*s\n", count, buf);

                printf("released KEY: %d\n", (int)keysym);
            }
            break;
        case ConfigureNotify:
            if (width != ev.xconfigure.width
                    || height != ev.xconfigure.height) {
                width = ev.xconfigure.width;
                height = ev.xconfigure.height;
                printf("Size changed to: %d by %d", width, height);
            }
            break;
        case ButtonPress:
            XCloseDisplay(dpy);
            return 0;
        }
        fflush(stdout);
    }
}


 类似资料:
  • 问题内容: 我已经阅读了一段时间的Unicode和UTF-8编码,并且我想我理解了,所以希望这不会是一个愚蠢的问题: 我有一个文件,其中包含一些CJK字符,并且已另存为UTF-8。我安装了各种亚洲语言包,并且其他应用程序可以正确显示这些字符,因此我知道可以做很多工作。 在我的Java应用程序中,我读取文件的方式如下: 输出将CJK字符显示为’???’。进行呼叫以确认它肯定是在使用UTF-8。我缺少

  • 问题内容: 如何在我的API上获得UTF-8支持?此刻,一个字符串输出如下: 代替: 在以下结帐app.js: 问题答案: 连接到响应生成器或创建执行以下操作的中间件: 否则,浏览器将以他喜欢的编码显示内容。 如果这不能帮助您,则DB可能编码错误。 编辑: 由于答案将近5年,API已更改。对于当前的node.js版本,请使用:

  • 问题内容: 因此,我已经处理这个问题已有一个多月了,并且我还在google以及Google上检查了几乎所有可能的相关解决方案,但找不到任何能够真正解决我问题的方法。我的问题是我正在尝试从网站下载html源,但是在大多数情况下,我得到的是某些文本显示一些“?” 其中的字符,很可能是因为该站点位于希伯来语中。这是我的代码, 谢谢。 问题答案: 要使用给定的编码从字节流中读取字符,请使用。在您的情况下,

  • 问题内容: 我的数据库已正确设置为UTF-8,并且正在处理包含日语字符的数据库。如果我从mysql命令行执行SELECT * …,我会正确看到日语字符。当将数据从数据库中拉出并显示在网页上时,我可以正确地看到它。 但是,在phpMyAdmin中查看表数据时,我只会看到垃圾文本。即。 ç§ã日本料ç†ãŒå¥½ããããã㥥œœ¬æ–™ç†ã… 如何获取phpMyAdmin以日语显示字

  • 我有一个任务: 当我使用命令时: 文本显示不正确。如何修复?谢谢

  • 问题内容: 是否可以在JavaScript中使用textarea元素的值,还是应该使用? 谢谢。 问题答案: 您应该使用.value