我一直在尝试和阅读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。这是第三个事件,其中包含重音字符。
XFilterEvent
XFilterEvent(&ev, win)
True
False
如果您既想要原始事件,又想要通过输入法合成的原始事件,则当然可以使用自己做原始事件处理continue。
continue
请注意buf[count] = 0;,为了buf正确打印(或显式使用长度),您将需要Xutf8LookupString不对输出进行null终止。
buf[count] = 0;
buf
Xutf8LookupString
最后,如评论中所述,对于X11的最新版本,您将需要指定对的修改,XSetLocaleModifiers例如XSetLocaleModifiers("@im=none"),否则将不会生成额外的事件。
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); } }