In order to hunt down a very odd problem with the XmbLookupString and Xutf8LookupString functions, I have extended the good old xev command to print the output of these two functions as well, in addition to that of XLookupString.
In order to use XmbLookupString or Xutf8LookupString, one needs to provide an X Input Context (XIC), which one can get after opening an X Input Method (XIM). Not being an XIM guru, I have copied and simplified the minimally necessary code to get it running from xterm-170's charproc.c:VTInitI18N. Could someone who is at least slightly more familiar than me in XIM matters have a brief look at the attached patch (especially the last hunk), before I send it to the CVS maintainers? http://devel:<passwd>@www.xfree86.org/devel/cgi-bin/cvsweb.cgi/~checkout~/xc/programs/xev/xev.c?content-type=text/plain Thanks! Markus -- Markus G. Kuhn, Computer Laboratory, University of Cambridge, UK Email: mkuhn at acm.org, WWW: <http://www.cl.cam.ac.uk/~mgk25/>
--- xev.c.orig Tue Nov 26 02:10:51 2002 +++ xev.c Wed Nov 27 16:15:26 2002 @@ -30,117 +30,152 @@ */ /* $XFree86: xc/programs/xev/xev.c,v 1.6 2002/11/26 02:10:51 dawes Exp $ */ /* * Author: Jim Fulton, MIT X Consortium */ #include <stdio.h> #include <stdlib.h> #include <ctype.h> #include <X11/Xlocale.h> #include <X11/Xos.h> #include <X11/Xlib.h> #include <X11/Xutil.h> #include <X11/Xproto.h> #define INNER_WINDOW_WIDTH 50 #define INNER_WINDOW_HEIGHT 50 #define INNER_WINDOW_BORDER 4 #define INNER_WINDOW_X 10 #define INNER_WINDOW_Y 10 #define OUTER_WINDOW_MIN_WIDTH (INNER_WINDOW_WIDTH + \ 2 * (INNER_WINDOW_BORDER + INNER_WINDOW_X)) #define OUTER_WINDOW_MIN_HEIGHT (INNER_WINDOW_HEIGHT + \ 2 * (INNER_WINDOW_BORDER + INNER_WINDOW_Y)) #define OUTER_WINDOW_DEF_WIDTH (OUTER_WINDOW_MIN_WIDTH + 100) #define OUTER_WINDOW_DEF_HEIGHT (OUTER_WINDOW_MIN_HEIGHT + 100) #define OUTER_WINDOW_DEF_X 100 #define OUTER_WINDOW_DEF_Y 100 typedef unsigned long Pixel; const char *Yes = "YES"; const char *No = "NO"; const char *Unknown = "unknown"; const char *ProgramName; Display *dpy; int screen; +XIM xim = (XIM) NULL; +XIC xic = (XIC) NULL; void prologue (eventp, event_name) XEvent *eventp; char *event_name; { XAnyEvent *e = (XAnyEvent *) eventp; printf ("\n%s event, serial %ld, synthetic %s, window 0x%lx,\n", event_name, e->serial, e->send_event ? Yes : No, e->window); } +void +hexdump (s, len) + char *s; +{ + for (; len > 0; len--, s++) + printf("%02x%s", (unsigned char) *s, len > 1 ? " " : ""); +} void do_KeyPress (eventp) XEvent *eventp; { XKeyEvent *e = (XKeyEvent *) eventp; KeySym ks; char *ksname; int nbytes; char str[256+1]; nbytes = XLookupString (e, str, 256, &ks, NULL); if (ks == NoSymbol) ksname = "NoSymbol"; else if (!(ksname = XKeysymToString (ks))) ksname = "(no name)"; printf (" root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),\n", e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root); printf (" state 0x%x, keycode %u (keysym 0x%lx, %s), same_screen %s,\n", e->state, e->keycode, (unsigned long) ks, ksname, e->same_screen ? Yes : No); if (nbytes < 0) nbytes = 0; if (nbytes > 256) nbytes = 256; str[nbytes] = '\0'; - printf (" XLookupString gives %d bytes: \"%s\"\n", nbytes, str); + printf (" XLookupString gives %d bytes: \"%s\" (", nbytes, str); + hexdump(str, nbytes); + printf (")\n"); + if (e->type == KeyPress) { + if (xic) { + nbytes = XmbLookupString(xic, e, str, 256, &ks, NULL); + if (nbytes < 0) nbytes = 0; + if (nbytes > 256) nbytes = 256; + str[nbytes] = '\0'; + printf (" XmbLookupString gives %d bytes: \"%s\" (", + nbytes, str); + hexdump(str, nbytes); + printf (")\n"); + } +#ifdef X_HAVE_UTF8_STRING + if (xic) { + nbytes = Xutf8LookupString(xic, e, str, 256, &ks, NULL); + if (nbytes < 0) nbytes = 0; + if (nbytes > 256) nbytes = 256; + str[nbytes] = '\0'; + printf (" Xutf8LookupString gives %d bytes: \"%s\" (", + nbytes, str); + hexdump(str, nbytes); + printf (")\n"); + } + } +#endif } void do_KeyRelease (eventp) XEvent *eventp; { do_KeyPress (eventp); /* since it has the same info */ } void do_ButtonPress (eventp) XEvent *eventp; { XButtonEvent *e = (XButtonEvent *) eventp; printf (" root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),\n", e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root); printf (" state 0x%x, button %u, same_screen %s\n", e->state, e->button, e->same_screen ? Yes : No); } void do_ButtonRelease (eventp) XEvent *eventp; { do_ButtonPress (eventp); /* since it has the same info */ } void do_MotionNotify (eventp) XEvent *eventp; { XMotionEvent *e = (XMotionEvent *) eventp; printf (" root 0x%lx, subw 0x%lx, time %lu, (%d,%d), root:(%d,%d),\n", e->root, e->subwindow, e->time, e->x, e->y, e->x_root, e->y_root); printf (" state 0x%x, is_hint %u, same_screen %s\n", e->state, e->is_hint, e->same_screen ? Yes : No); } @@ -665,80 +700,81 @@ exit (1); } static int parse_backing_store (s) char *s; { int len = strlen (s); char *cp; for (cp = s; *cp; cp++) { if (isascii (*cp) && isupper (*cp)) *cp = tolower (*cp); } if (strncmp (s, "notuseful", len) == 0) return (NotUseful); if (strncmp (s, "whenmapped", len) == 0) return (WhenMapped); if (strncmp (s, "always", len) == 0) return (Always); usage (); } int main (argc, argv) int argc; char **argv; { char *displayname = NULL; char *geom = NULL; int i; XSizeHints hints; int borderwidth = 2; Window w, subw; XSetWindowAttributes attr; XWindowAttributes wattr; unsigned long mask = 0L; int done; char *name = "Event Tester"; Bool reverse = False; unsigned long back, fore; + char *p; ProgramName = argv[0]; if (setlocale(LC_ALL,"") == NULL) { fprintf(stderr, "%s: warning: could not set default locale\n", ProgramName); } w = 0; for (i = 1; i < argc; i++) { char *arg = argv[i]; if (arg[0] == '-') { switch (arg[1]) { case 'd': /* -display host:dpy */ if (++i >= argc) usage (); displayname = argv[i]; continue; case 'g': /* -geometry geom */ if (++i >= argc) usage (); geom = argv[i]; continue; case 'b': switch (arg[2]) { case 'w': /* -bw pixels */ if (++i >= argc) usage (); borderwidth = atoi (argv[i]); continue; case 's': /* -bs type */ if (++i >= argc) usage (); attr.backing_store = parse_backing_store (argv[i]); mask |= CWBackingStore; continue; default: usage (); } case 'i': /* -id */ if (++i >= argc) usage (); sscanf(argv[i], "0x%lx", &w); if (!w) @@ -786,80 +822,97 @@ SubstructureNotifyMask | SubstructureRedirectMask | FocusChangeMask | PropertyChangeMask | ColormapChangeMask | OwnerGrabButtonMask; if (w) { XGetWindowAttributes(dpy, w, &wattr); if (wattr.all_event_masks & ButtonPressMask) attr.event_mask &= ~ButtonPressMask; attr.event_mask &= ~SubstructureRedirectMask; XSelectInput(dpy, w, attr.event_mask); } else { set_sizehints (&hints, OUTER_WINDOW_MIN_WIDTH, OUTER_WINDOW_MIN_HEIGHT, OUTER_WINDOW_DEF_WIDTH, OUTER_WINDOW_DEF_HEIGHT, OUTER_WINDOW_DEF_X, OUTER_WINDOW_DEF_Y, geom); if (reverse) { back = BlackPixel(dpy,screen); fore = WhitePixel(dpy,screen); } else { back = WhitePixel(dpy,screen); fore = BlackPixel(dpy,screen); } attr.background_pixel = back; attr.border_pixel = fore; mask |= (CWBackPixel | CWBorderPixel | CWEventMask); w = XCreateWindow (dpy, RootWindow (dpy, screen), hints.x, hints.y, hints.width, hints.height, borderwidth, 0, InputOutput, (Visual *)CopyFromParent, mask, &attr); XSetStandardProperties (dpy, w, name, NULL, (Pixmap) 0, argv, argc, &hints); subw = XCreateSimpleWindow (dpy, w, INNER_WINDOW_X, INNER_WINDOW_Y, INNER_WINDOW_WIDTH, INNER_WINDOW_HEIGHT, INNER_WINDOW_BORDER, attr.border_pixel, attr.background_pixel); + /* attempt to open an X Input Method (for testing XmbLookupString) */ + if ((p = XSetLocaleModifiers("")) != NULL && *p) + xim = XOpenIM(dpy, NULL, NULL, NULL); + if (!xim && (p = XSetLocaleModifiers("@im=none")) != NULL && *p) + xim = XOpenIM(dpy, NULL, NULL, NULL); + if (!xim) + fprintf(stderr, "Failed to open input method.\n"); + else { + xic = XCreateIC(xim, + XNInputStyle, XIMPreeditNothing | XIMStatusNothing, + XNClientWindow, w, + XNFocusWindow, w, + NULL); + if (!xic) + fprintf(stderr, "Failed to create input context.\n"); + } + XMapWindow (dpy, subw); /* map before w so that it appears */ XMapWindow (dpy, w); printf ("Outer window is 0x%lx, inner window is 0x%lx\n", w, subw); } for (done = 0; !done; ) { XEvent event; XNextEvent (dpy, &event); switch (event.type) { case KeyPress: prologue (&event, "KeyPress"); do_KeyPress (&event); break; case KeyRelease: prologue (&event, "KeyRelease"); do_KeyRelease (&event); break; case ButtonPress: prologue (&event, "ButtonPress"); do_ButtonPress (&event); break; case ButtonRelease: prologue (&event, "ButtonRelease"); do_ButtonRelease (&event); break; case MotionNotify: prologue (&event, "MotionNotify"); do_MotionNotify (&event); break; case EnterNotify: prologue (&event, "EnterNotify"); do_EnterNotify (&event); break; case LeaveNotify: prologue (&event, "LeaveNotify"); do_LeaveNotify (&event); break;