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;

Reply via email to