XForms: Cleaning up the key handling

From: Angus Leeming (angus.leeming@btopenworld.com)
Date: Thu Mar 27 2003 - 11:32:27 EST

  • Next message: Angus Leeming: "Re: XForms: Resurrecting xforms development pt 2"

    This is the third and final mail in my renewed contact Blitz. I hope that you
    still ahve the energy to peruse it ;-)

    The attached patch is pretty monstrous but is the necessary first step to
    enabling the display and input of Far Eastern characters by xforms. I
    actually regard it as a clean-up of some obfuscated code and it has worked
    perfectly for me for months.

    However, it does change the information passed by xforms to its widgets and
    may therefore break any home made widgets that relied on the old, obfuscated
    form of the data passed to them. I submit it therefore as a discussion
    document.

    If it turns out to be too much to consider in one go, then I can try and break
    it up into smaller parts...

    I have also provided some detailed explanations of what the patch does
    (below). Please bear with me ;-)

    What it does:
    1. xforms passes both FL_KEYPRESS and FL_KEYRELEASE events to do_keyboard and
    thence to fl_handle_object. However, the FL_KEYRELEASE event is then silently
    dropped. xforms has no right to do such a thing (who knows what widgets out
    there might want a KEYRELEASE event) and this patch therefore
    passes the FL_KEYRELEASE event to fl_keyboard and thence to the widgets.

    This, of itself, requires changes in a couple of places
            a. do_keyboard extracts information about the keyboard event using both
    XLookupString and XmbLookupString. However, XmbLookupString is undefined on a
    KeyRelease event so we store the keysym of the previous FL_KEYPRESS event
    and dispatch that on a FL_KEYRELEASE event.
            b. Given that XmbLookupString is undefined on a KeyRelease event, it is
    safest to bail out of fl_XLookupString in such a situation (although I
    emphasise that the routine should not be, and is not, called from do_keyboard
    on a KeyRelease event).

    2. Without beating about the bush, forms.c's do_keyboard is designed to
    confuse with no other real benefit ;-) This patch makes it 'do the right
    thing' at the expense of a changed behaviour that may break any home made
    widgets that relied on the old behaviour.

    Let me explain further.

    do_keyboard exists to extract the keysym from the XEvent and to dispatch this
    keysym to fl_handle_form. The important code is:
            KeySym keysym = 0;
            unsigned char keybuf[227];
            kbuflen = fl_XLookupString((XKeyEvent *) xev, (char *) keybuf,
                                       sizeof(keybuf), &keysym);

    It _should_ then pass this keysym to fl_handle_form, so:
            fl_handle_form(keyform, formevent, keysym, xev);

    but in a misguided attempt to be nice to mulitbyte languages, it actually does
    this:
            if (IsTab(keysym)) {
                    fl_handle_form(keyform, formevent, 9, xev);
            else if (IsCursorKey(keysym) || kbuflen == 0)
                    fl_handle_form(keyform, formevent, keysym, xev);
            else {
                    unsigned char *ch;
                    /* all regular keys, including mapped strings */
                    for (ch = keybuf; ch < (keybuf + kbuflen) && keyform; ch++)
                            fl_handle_form(keyform, formevent, *ch, xev);
            }

    Changing the code to just pass the keysym results in changes elsewhere in the
    source such as:
    -#define Control(c) ((c) - 'a' + 1)
    +#define Control(c) ((c) | FL_CONTROL_MASK)

    and
                 else if (str[i] == '[')
    - sc[j++] = 27 + offset;
    + sc[j++] = XK_Escape + offset;

    I contend that this immediately makes the source more understandable. However,
    as I have already stated, it will break any home made widgets that relied on
    this behaviour. Your call.

    I said above that the code is written as it is in a misguided attempt to be
    nice to mulitbyte languages. What was meant to happen was that the receiving
    widget could check the timestamp of the XEvent passed with each call of
                    for (ch = keybuf; ch < (keybuf + kbuflen) && keyform; ch++)
                            fl_handle_form(keyform, formevent, *ch, xev);
    XEvents with the same timestamps are the same and therefore the widget was
    meant to piece together the multibyte info needed to create a Chinese
    character (for example).

    Having spent a great deal of time with CG Han actually getting xforms to
    display and input Chinese, Korean and Japanese (CJK) characters, I can
    definitively say that this approach sucks ;-) (Incidentally this patch does
    _not_ enable CJK support but it is a necessary precursor to it.)

    Instead, the keybuf and kbuflen data that are initialised at the same time as
    keysym by fl_XLookupString should be made available to any widget that
    desires them. This we do by providing the following new accessor function:

    /* These vars are initialised in do_keyboard.
     * They are global vars so that we can make them accessible to the outside
     * world. CJK users will find them useful.
     */
    static int kbuflen;
    static char keybuf[256];

    void fl_get_composed_string(int * ptr_kbuflen, char const ** ptr_keybuf)
    {
        if (!ptr_kbuflen) return;
        *ptr_kbuflen = kbuflen;
        *ptr_keybuf = keybuf;
    }

    it is not used internally by xforms in this patch but is used by input.c in CG
    Han's CJK patch being used successfully as we speak in CJK-LyX 1.3.0 released
    on February 26. FWIW, you can read his announcement here:
    http://www.lyx.org/announce/1_3_0cjk.txt.

    3. As a result of getting xforms to work with CJK characters, the large
    ifthenelse block in input.c's handle_key routine was split out into a
    separate draw_char function. CJK input calls this routine multiple times per
    XEvent, once for each char of the keybuf (above). For the sake of overall
    simplicity this change is included in the present patch.

    I hope that this long explanation proves useful when you come to look at the
    patch and enables us to start a discussion about it.

    Best regards,
    Angus



    _________________________________________________
    To unsubscribe, send the message "unsubscribe" to
    xforms-request@bob.usuhs.mil or see
    http://bob.usuhs.mil/mailserv/xforms.html
    XForms Home Page: http://world.std.com/~xforms
    List Archive: http://bob.usuhs.mil/mailserv/list-archives/



    This archive was generated by hypermail 2b29 : Thu Mar 27 2003 - 13:06:37 EST