用X11显示获取UTF-8input

我一直在尝试,并在互联网上阅读大量的资源,试图find一种方法来从X显示获得UTF-8键盘(组合)input。 但我无法做到这一点。

我试过这个链接的示例代码(例如11-4),但没有成功。

我也写了一个简单的例子(下面),试图使其工作。 我简单的testing案例是打印一个“é”,这是通过input急性,然后是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); } }