Use X Input Methods for keyboard handling. - sam - An updated version of the sam text editor.
 (HTM) git clone git://vernunftzentrum.de/sam.git
 (DIR) Log
 (DIR) Files
 (DIR) Refs
 (DIR) LICENSE
       ---
 (DIR) commit 5d68a20e2050958499f4a6a706403d0e89a3e434
 (DIR) parent 64ca870b0f576d609030cee84808d195d57b5009
 (HTM) Author: Rob King <jking@deadpixi.com>
       Date:   Fri, 19 May 2017 22:21:30 -0500
       
       Use X Input Methods for keyboard handling.
       
       Diffstat:
         doc/sam.1                           |       6 ++++++
         libXg/gwin.c                        |      27 ++++++++++++++++++---------
         libXg/xtbinit.c                     |      44 ++++++++-----------------------
       
       3 files changed, 35 insertions(+), 42 deletions(-)
       ---
 (DIR) diff --git a/doc/sam.1 b/doc/sam.1
       @@ -1118,6 +1118,12 @@ Stores output of shell commands executed by
        .Xr samrc 5
        .Sh BUGS
        .Pp
       +The character composition as described in
       +.Xs "Composed Text Input"
       +may be overridden or limited by the user's specified input method.
       +This is not necessarily a bug,
       +but rather a concession to the user's implied preferences.
       +.Pp
        The only human language in which colors may be specified is English.
        .Pp
        The only human language in which output is generated is English.
 (DIR) diff --git a/libXg/gwin.c b/libXg/gwin.c
       @@ -106,6 +106,8 @@ WidgetClass gwinWidgetClass = (WidgetClass) &gwinClassRec;
        
        static XModifierKeymap *modmap;
        static int keypermod;
       +extern XIC xic;
       +extern XIM xim;
        
        static void
        Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs)
       @@ -119,6 +121,13 @@ Realize(Widget w, XtValueMask *valueMask, XSetWindowAttributes *attrs)
                keypermod = modmap->max_keypermod;
        
            Resize(w);
       +
       +    xic = XCreateIC(xim, XNInputStyle, XIMPreeditNothing | XIMStatusNothing,
       +                    XNClientWindow, XtWindow(w), XNFocusWindow, XtWindow(w), NULL);
       +    if (!xic){
       +        fprintf(stderr, "could not create input context\n");
       +        exit(EXIT_FAILURE);
       +    }
        }
        
        static void
       @@ -239,6 +248,7 @@ freebindings(void)
        static void
        Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
        {
       +    extern XIC xic;
            static unsigned char compose[5];
            static int composing = -2;
            int kind = Kraw;
       @@ -247,7 +257,8 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
            KeySym k, mk;
            Charfunc f;
            Modifiers md;
       -    char buf[100] = {0};
       +    Status s;
       +    wchar_t buf[32] = {0};
        
            c = 0;
            len = 0;
       @@ -255,8 +266,8 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
            /* Translate the keycode into a key symbol. */
            if(e->xany.type != KeyPress)
                return;
       -    XkbTranslateKeyCode(xkb, (KeyCode)e->xkey.keycode, e->xkey.state, &md, &k);
       -    XkbTranslateKeySym(e->xany.display, &k, e->xkey.state, buf, sizeof(buf) - 1, &len);
       +
       +    len = XwcLookupString(xic, &e->xkey, buf, 32, &k, &s);
        
            /* Check to see if it's a specially-handled key first. */
            for (Keymapping *m = keymappings; m; m = m->next){
       @@ -288,14 +299,12 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
                }
            }
        
       -    /*
       -     * The following song and dance is so we can have our chosen
       +    /* The following song and dance is so we can have our chosen
             * modifier key behave like a compose key, i.e, press and release
             * and then type the compose sequence, like Plan 9.  We have
             * to find out which key is the compose key first though.
             */
       -    if (IsModifierKey(k) && ((GwinWidget)w)->gwin.compose
       -            && composing == -2 && modmap) {
       +    if (IsModifierKey(k) && ((GwinWidget)w)->gwin.compose && composing == -2 && modmap) {
                minmod = (((GwinWidget)w)->gwin.compose+2)*keypermod;
                for (c = minmod; c < minmod+keypermod; c++) {
                    XtTranslateKeycode(e->xany.display,
       @@ -318,7 +327,7 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
            /* If we got a lone modifier key, no key, or a key outside of the
             * representable range, ignore it.
             */
       -    if (IsModifierKey(k) || k == NoSymbol || k > 0xff00)
       +    if (IsModifierKey(k) || k == NoSymbol || k > 0xff00 || len <= 0)
                return;
        
            /* Check to see if we are in a composition sequence */
       @@ -363,7 +372,7 @@ Keyaction(Widget w, XEvent *e, String *p, Cardinal *np)
        
            f = ((GwinWidget)w)->gwin.gotchar;
            if(f)
       -        (*f)(c, kind, Tcurrent, 0, 0, NULL);
       +        (*f)(c? c : buf[0], kind, Tcurrent, 0, 0, NULL);
        }
        
        typedef struct Chordmapping Chordmapping;
 (DIR) diff --git a/libXg/xtbinit.c b/libXg/xtbinit.c
       @@ -39,7 +39,8 @@
        #endif
        
        /* libg globals */
       -XkbDescPtr xkb;
       +XIM xim;
       +XIC xic;
        Bitmap  screen;
        XftFont *font;
        XftColor fontcolor;
       @@ -211,38 +212,15 @@ xtbinit(Errfunc f, char *class, int *pargc, char **argv, char **fallbacks)
            atexit(freebindings);
            atexit(freechords);
        
       -    int xkbmajor = XkbMajorVersion;
       -    int xkbminor = XkbMinorVersion;
       -    int xkbop    = 0;
       -    int xkbevent = 0;
       -    int xkberr   = 0;
       -    if (!XkbQueryExtension(_dpy, &xkbop, &xkbevent, &xkberr, &xkbmajor, &xkbminor)){
       -        fprintf(stderr, "could not initialize X Keyboard Extension\n");
       -        exit(EXIT_FAILURE);
       -    }
       -
       -    int ndevs = 0;
       -    XDeviceInfo *devs = XListInputDevices(_dpy, &ndevs);
       -    if (!devs){
       -        fprintf(stderr, "could not get input devices\n");
       -        exit(EXIT_FAILURE);
       -    }
       -
       -    int keyid = XkbUseCoreKbd;
       -    for (int i = 0; i < ndevs && keyid == XkbUseCoreKbd; i++){
       -        if (devs[i].use == IsXKeyboard)
       -            keyid = devs[i].id;
       -    }
       -
       -    xkb = XkbGetKeyboard(_dpy, XkbAllComponentsMask, keyid);
       -    if (xkb == NULL || xkb->geom == NULL || XkbGetControls(_dpy, XkbAllControlsMask, xkb)){
       -        fprintf(stderr, "could not initialize keyboard\n");
       -        exit(EXIT_FAILURE);
       -    }
       -
       -    if (XkbGetUpdatedMap(_dpy, XkbKeyTypesMask | XkbKeySymsMask | XkbModifierMapMask, xkb) != Success){
       -        fprintf(stderr, "could not get updated keymap\n");
       -        exit(EXIT_FAILURE);
       +    if ((xim = XOpenIM(_dpy, NULL, NULL, NULL)) == NULL) {
       +        XSetLocaleModifiers("@im=local");
       +        if ((xim =  XOpenIM(_dpy, NULL, NULL, NULL)) == NULL) {
       +            XSetLocaleModifiers("@im=");
       +            if ((xim = XOpenIM(_dpy, NULL, NULL, NULL)) == NULL) {
       +                fprintf(stderr, "could not open input method\n");
       +                exit(EXIT_FAILURE);
       +            }
       +        }
            }
        
            font = XftFontOpenName(_dpy, DefaultScreen(_dpy), fontspec[0] ? fontspec : getenv("FONT") ? getenv("FONT") : "monospace");