Get UTF-8 input with X11 display

I tried and read many resources on the Internet, trying to find a way to get the input file with a UTF-8 keyboard with X Display. But I could not get it to work.

I tried the example code from this (exaple 11-4) but failed.

I also wrote a simple example (below) to try to get it to work. My simple test case is to type “é”, which happens by typing sharp and then e.

What's wrong?

Thanks,

Here is my example:

#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 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); } } 
+4
source share
1 answer

You must do this:

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

in your event loop. This starts the input mechanism, without it you will get raw X events. For example, when you click the dead accent button followed by a letter and do not call XFilterEvent , you will get two KeyPress events, as usual. But if you make a call, you get three events. There are two raw events for which XFilterEvent(&ev, win) returns True . And then there is one event synthesized by the input method for which XFilterEvent(&ev, win) returns False . It is this third event that contains an accented character.

If you want both raw events and those that were synthesized by the input method, you can, of course, do your own processing of raw events instead of continue .

Note that you will need buf[count] = 0; to correctly print buf (or explicitly use length), Xutf8LookupString does not terminate output zero.

Finally, as mentioned in the comments, with the latest versions of X11 you will need to point the change to XSetLocaleModifiers , for example XSetLocaleModifiers("@im=none") , otherwise additional events will not be generated.

Here is the corrected version of the code:

 #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 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); } } 
+8
source

Source: https://habr.com/ru/post/1497171/


All Articles