XKBBind.c revision 818534a1
11ab64890Smrg/*
21ab64890Smrg
31ab64890SmrgCopyright 1985, 1987, 1994, 1998  The Open Group
41ab64890Smrg
51ab64890SmrgPermission to use, copy, modify, distribute, and sell this software and its
61ab64890Smrgdocumentation for any purpose is hereby granted without fee, provided that
71ab64890Smrgthe above copyright notice appear in all copies and that both that
81ab64890Smrgcopyright notice and this permission notice appear in supporting
91ab64890Smrgdocumentation.
101ab64890Smrg
111ab64890SmrgThe above copyright notice and this permission notice shall be included
121ab64890Smrgin all copies or substantial portions of the Software.
131ab64890Smrg
141ab64890SmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
151ab64890SmrgOR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
161ab64890SmrgMERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
171ab64890SmrgIN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
181ab64890SmrgOTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
191ab64890SmrgARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
201ab64890SmrgOTHER DEALINGS IN THE SOFTWARE.
211ab64890Smrg
221ab64890SmrgExcept as contained in this notice, the name of The Open Group shall
231ab64890Smrgnot be used in advertising or otherwise to promote the sale, use or
241ab64890Smrgother dealings in this Software without prior written authorization
251ab64890Smrgfrom The Open Group.
261ab64890Smrg
271ab64890Smrg*/
281ab64890Smrg
29818534a1Smrg        /* the new monsters ate the old ones */
301ab64890Smrg
311ab64890Smrg#ifdef HAVE_CONFIG_H
321ab64890Smrg#include <config.h>
331ab64890Smrg#endif
341ab64890Smrg#include "XKBlib.h"
351ab64890Smrg#include <X11/Xlibint.h>
361ab64890Smrg#include <X11/Xutil.h>
371ab64890Smrg#include <X11/keysym.h>
381ab64890Smrg#include <stdio.h>
391ab64890Smrg#include <ctype.h>
401ab64890Smrg
411ab64890Smrg#include <X11/extensions/XKBproto.h>
421ab64890Smrg#include "XKBlibint.h"
431ab64890Smrg
441ab64890Smrg#ifdef USE_OWN_COMPOSE
45818534a1Smrg#define COMPOSE_NO_CONST_MEMBERS
461ab64890Smrg#include "imComp.h"
471ab64890Smrg#endif
481ab64890Smrg
491ab64890Smrg#define AllMods (ShiftMask|LockMask|ControlMask| \
50818534a1Smrg                 Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
511ab64890Smrg
52818534a1Smrgstatic int _XkbLoadDpy(Display *dpy);
531ab64890Smrg
541ab64890Smrgstruct _XKeytrans {
55818534a1Smrg    struct _XKeytrans *next;    /* next on list */
56818534a1Smrg    char *string;               /* string to return when the time comes */
57818534a1Smrg    int len;                    /* length of string (since NULL is legit) */
58818534a1Smrg    KeySym key;                 /* keysym rebound */
59818534a1Smrg    unsigned int state;         /* modifier state */
60818534a1Smrg    KeySym *modifiers;          /* modifier keysyms you want */
61818534a1Smrg    int mlen;                   /* length of modifier list */
621ab64890Smrg};
631ab64890Smrg
641ab64890SmrgKeySym
651ab64890SmrgXkbKeycodeToKeysym(Display *dpy,
661ab64890Smrg#if NeedWidePrototypes
67818534a1Smrg                   unsigned int kc,
681ab64890Smrg#else
69818534a1Smrg                   KeyCode kc,
701ab64890Smrg#endif
71818534a1Smrg                   int group,
72818534a1Smrg                   int level)
731ab64890Smrg{
74818534a1Smrg    XkbDescRec *xkb;
7561b2299dSmrg
761ab64890Smrg    if (_XkbUnavailable(dpy))
77818534a1Smrg        return NoSymbol;
781ab64890Smrg
79818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
801ab64890Smrg
811ab64890Smrg    xkb = dpy->xkb_info->desc;
82818534a1Smrg    if ((kc < xkb->min_key_code) || (kc > xkb->max_key_code))
83818534a1Smrg        return NoSymbol;
84818534a1Smrg
85818534a1Smrg    if ((group < 0) || (level < 0) || (group >= XkbKeyNumGroups(xkb, kc)))
86818534a1Smrg        return NoSymbol;
87818534a1Smrg    if (level >= XkbKeyGroupWidth(xkb, kc, group)) {
88818534a1Smrg        /* for compatibility with the core protocol, _always_ allow  */
89818534a1Smrg        /* two symbols in the first two groups.   If either of the   */
90818534a1Smrg        /* two is of type ONE_LEVEL, just replicate the first symbol */
91818534a1Smrg        if ((group > XkbGroup2Index) || (XkbKeyGroupWidth(xkb, kc, group) != 1)
92818534a1Smrg            || (level != 1)) {
93818534a1Smrg            return NoSymbol;
94818534a1Smrg        }
95818534a1Smrg        level = 0;
961ab64890Smrg    }
97818534a1Smrg    return XkbKeySymEntry(xkb, kc, level, group);
981ab64890Smrg}
991ab64890Smrg
1001ab64890SmrgKeySym
1011ab64890SmrgXKeycodeToKeysym(Display *dpy,
1021ab64890Smrg#if NeedWidePrototypes
103818534a1Smrg                 unsigned int kc,
1041ab64890Smrg#else
105818534a1Smrg                 KeyCode kc,
1061ab64890Smrg#endif
107818534a1Smrg                 int col)
1081ab64890Smrg{
109818534a1Smrg    XkbDescRec *xkb;
11061b2299dSmrg
1111ab64890Smrg    if (_XkbUnavailable(dpy))
112818534a1Smrg        return _XKeycodeToKeysym(dpy, kc, col);
1131ab64890Smrg
114818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
1151ab64890Smrg
1161ab64890Smrg    xkb = dpy->xkb_info->desc;
117818534a1Smrg    if ((kc < xkb->min_key_code) || (kc > xkb->max_key_code))
118818534a1Smrg        return NoSymbol;
119818534a1Smrg
120818534a1Smrg    if (col > 3) {
121818534a1Smrg        int lastSym, tmp, nGrp;
122818534a1Smrg
123818534a1Smrg        lastSym = 3;
124818534a1Smrg        nGrp = XkbKeyNumGroups(xkb, kc);
125818534a1Smrg        if ((nGrp > 0) &&
126818534a1Smrg            ((tmp = XkbKeyGroupWidth(xkb, kc, XkbGroup1Index)) > 2)) {
127818534a1Smrg            if (col <= (lastSym + tmp - 2))
128818534a1Smrg                return XkbKeycodeToKeysym(dpy, kc, XkbGroup1Index,
129818534a1Smrg                                          col - lastSym + 2);
130818534a1Smrg            lastSym += tmp - 2;
131818534a1Smrg        }
132818534a1Smrg        if ((nGrp > 1) &&
133818534a1Smrg            ((tmp = XkbKeyGroupWidth(xkb, kc, XkbGroup2Index)) > 2)) {
134818534a1Smrg            if (col <= (lastSym + tmp - 2))
135818534a1Smrg                return XkbKeycodeToKeysym(dpy, kc, XkbGroup2Index,
136818534a1Smrg                                          col - lastSym + 2);
137818534a1Smrg            lastSym += tmp - 2;
138818534a1Smrg        }
139818534a1Smrg        if (nGrp > 2) {
140818534a1Smrg            tmp = XkbKeyGroupWidth(xkb, kc, XkbGroup3Index);
141818534a1Smrg            if (col <= lastSym + tmp)
142818534a1Smrg                return XkbKeycodeToKeysym(dpy, kc, XkbGroup3Index,
143818534a1Smrg                                          col - lastSym);
144818534a1Smrg            lastSym += tmp;
145818534a1Smrg        }
146818534a1Smrg        if (nGrp > 3) {
147818534a1Smrg            tmp = XkbKeyGroupWidth(xkb, kc, XkbGroup4Index);
148818534a1Smrg            if (col <= lastSym + tmp)
149818534a1Smrg                return XkbKeycodeToKeysym(dpy, kc, XkbGroup4Index,
150818534a1Smrg                                          col - lastSym);
151818534a1Smrg        }
152818534a1Smrg        return NoSymbol;
1531ab64890Smrg    }
154818534a1Smrg    return XkbKeycodeToKeysym(dpy, kc, (col >> 1), (col & 1));
1551ab64890Smrg}
1561ab64890Smrg
1571ab64890SmrgKeyCode
1581ab64890SmrgXKeysymToKeycode(Display *dpy, KeySym ks)
1591ab64890Smrg{
1601ab64890Smrg    register int i, j, gotOne;
1611ab64890Smrg
1621ab64890Smrg    if (_XkbUnavailable(dpy))
163818534a1Smrg        return _XKeysymToKeycode(dpy, ks);
164818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
1651ab64890Smrg
166818534a1Smrg    j = 0;
1671ab64890Smrg    do {
168818534a1Smrg        register XkbDescRec *xkb = dpy->xkb_info->desc;
169818534a1Smrg        gotOne = 0;
170818534a1Smrg        for (i = dpy->min_keycode; i <= dpy->max_keycode; i++) {
171818534a1Smrg            if (j < (int) XkbKeyNumSyms(xkb, i)) {
172818534a1Smrg                gotOne = 1;
173818534a1Smrg                if ((XkbKeySym(xkb, i, j) == ks))
174818534a1Smrg                    return i;
175818534a1Smrg            }
176818534a1Smrg        }
177818534a1Smrg        j++;
1781ab64890Smrg    } while (gotOne);
1791ab64890Smrg    return 0;
1801ab64890Smrg}
1811ab64890Smrg
1821ab64890Smrgstatic int
1831ab64890Smrg_XkbComputeModmap(Display *dpy)
1841ab64890Smrg{
185818534a1Smrg    register XkbDescPtr xkb;
1861ab64890Smrg
187818534a1Smrg    xkb = dpy->xkb_info->desc;
188818534a1Smrg    if (XkbGetUpdatedMap(dpy, XkbModifierMapMask, xkb) == Success)
189818534a1Smrg        return 1;
1901ab64890Smrg    return 0;
1911ab64890Smrg}
1921ab64890Smrg
1931ab64890Smrgunsigned
194818534a1SmrgXkbKeysymToModifiers(Display *dpy, KeySym ks)
1951ab64890Smrg{
1961ab64890Smrg    XkbDescRec *xkb;
197818534a1Smrg    register int i, j;
1981ab64890Smrg    register KeySym *pSyms;
1991ab64890Smrg    CARD8 mods;
2001ab64890Smrg
2011ab64890Smrg    if (_XkbUnavailable(dpy))
202818534a1Smrg        return _XKeysymToModifiers(dpy, ks);
203818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
204818534a1Smrg
205818534a1Smrg    if (_XkbNeedModmap(dpy->xkb_info) && (!_XkbComputeModmap(dpy)))
206818534a1Smrg        return _XKeysymToModifiers(dpy, ks);
207818534a1Smrg
208818534a1Smrg    xkb = dpy->xkb_info->desc;
209818534a1Smrg    mods = 0;
210818534a1Smrg    for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
211818534a1Smrg        pSyms = XkbKeySymsPtr(xkb, i);
212818534a1Smrg        for (j = XkbKeyNumSyms(xkb, i) - 1; j >= 0; j--) {
213818534a1Smrg            if (pSyms[j] == ks) {
214818534a1Smrg                mods |= xkb->map->modmap[i];
215818534a1Smrg                break;
216818534a1Smrg            }
217818534a1Smrg        }
2181ab64890Smrg    }
2191ab64890Smrg    return mods;
2201ab64890Smrg}
2211ab64890Smrg
2221ab64890SmrgKeySym
223818534a1SmrgXLookupKeysym(register XKeyEvent * event, int col)
2241ab64890Smrg{
2251ab64890Smrg    Display *dpy = event->display;
226818534a1Smrg
2271ab64890Smrg    if (_XkbUnavailable(dpy))
228818534a1Smrg        return _XLookupKeysym(event, col);
229818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
2301ab64890Smrg    return XKeycodeToKeysym(dpy, event->keycode, col);
2311ab64890Smrg}
2321ab64890Smrg
2331ab64890Smrg   /*
23461b2299dSmrg    * Not a public entry point -- XkbTranslateKey is an obsolete name
23561b2299dSmrg    * that is preserved here so that functions linked against the old
2361ab64890Smrg    * version will continue to work in a shared library environment.
2371ab64890Smrg    */
2381ab64890Smrgint
239818534a1SmrgXkbTranslateKey(register Display *dpy,
240818534a1Smrg                KeyCode key,
241818534a1Smrg                register unsigned int mods,
242818534a1Smrg                unsigned int *mods_rtrn,
243818534a1Smrg                KeySym *keysym_rtrn);
244818534a1Smrg
2451ab64890Smrgint
246818534a1SmrgXkbTranslateKey(register Display *dpy,
247818534a1Smrg                KeyCode key,
248818534a1Smrg                register unsigned int mods,
249818534a1Smrg                unsigned int *mods_rtrn,
250818534a1Smrg                KeySym *keysym_rtrn)
2511ab64890Smrg{
252818534a1Smrg    return XkbLookupKeySym(dpy, key, mods, mods_rtrn, keysym_rtrn);
2531ab64890Smrg}
2541ab64890Smrg
2551ab64890SmrgBool
256818534a1SmrgXkbLookupKeySym(register Display *dpy,
257818534a1Smrg                KeyCode key,
258818534a1Smrg                register unsigned int mods,
259818534a1Smrg                unsigned int *mods_rtrn,
260818534a1Smrg                KeySym *keysym_rtrn)
2611ab64890Smrg{
2621ab64890Smrg    if (_XkbUnavailable(dpy))
263818534a1Smrg        return _XTranslateKey(dpy, key, mods, mods_rtrn, keysym_rtrn);
264818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
265818534a1Smrg    return XkbTranslateKeyCode(dpy->xkb_info->desc, key, mods, mods_rtrn,
266818534a1Smrg                               keysym_rtrn);
2671ab64890Smrg}
2681ab64890Smrg
2691ab64890SmrgBool
270818534a1SmrgXkbTranslateKeyCode(register XkbDescPtr xkb,
271818534a1Smrg                    KeyCode key,
272818534a1Smrg                    register unsigned int mods,
273818534a1Smrg                    unsigned int *mods_rtrn,
274818534a1Smrg                    KeySym *keysym_rtrn)
2751ab64890Smrg{
2761ab64890Smrg    XkbKeyTypeRec *type;
277818534a1Smrg    int col, nKeyGroups;
278818534a1Smrg    unsigned preserve, effectiveGroup;
2791ab64890Smrg    KeySym *syms;
2801ab64890Smrg
281818534a1Smrg    if (mods_rtrn != NULL)
282818534a1Smrg        *mods_rtrn = 0;
2831ab64890Smrg
284818534a1Smrg    nKeyGroups = XkbKeyNumGroups(xkb, key);
285818534a1Smrg    if ((!XkbKeycodeInRange(xkb, key)) || (nKeyGroups == 0)) {
286818534a1Smrg        if (keysym_rtrn != NULL)
287818534a1Smrg            *keysym_rtrn = NoSymbol;
288818534a1Smrg        return False;
2891ab64890Smrg    }
2901ab64890Smrg
291818534a1Smrg    syms = XkbKeySymsPtr(xkb, key);
2921ab64890Smrg
2931ab64890Smrg    /* find the offset of the effective group */
2941ab64890Smrg    col = 0;
295818534a1Smrg    effectiveGroup = XkbGroupForCoreState(mods);
296818534a1Smrg    if (effectiveGroup >= nKeyGroups) {
297818534a1Smrg        unsigned groupInfo = XkbKeyGroupInfo(xkb, key);
298818534a1Smrg
299818534a1Smrg        switch (XkbOutOfRangeGroupAction(groupInfo)) {
300818534a1Smrg        default:
301818534a1Smrg            effectiveGroup %= nKeyGroups;
302818534a1Smrg            break;
303818534a1Smrg        case XkbClampIntoRange:
304818534a1Smrg            effectiveGroup = nKeyGroups - 1;
305818534a1Smrg            break;
306818534a1Smrg        case XkbRedirectIntoRange:
307818534a1Smrg            effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
308818534a1Smrg            if (effectiveGroup >= nKeyGroups)
309818534a1Smrg                effectiveGroup = 0;
310818534a1Smrg            break;
311818534a1Smrg        }
3121ab64890Smrg    }
313818534a1Smrg    col = effectiveGroup * XkbKeyGroupsWidth(xkb, key);
314818534a1Smrg    type = XkbKeyKeyType(xkb, key, effectiveGroup);
315818534a1Smrg
316818534a1Smrg    preserve = 0;
317818534a1Smrg    if (type->map) {  /* find the column (shift level) within the group */
318818534a1Smrg        register int i;
319818534a1Smrg        register XkbKTMapEntryPtr entry;
320818534a1Smrg
321818534a1Smrg        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
322818534a1Smrg            if ((entry->active) &&
323818534a1Smrg                ((mods & type->mods.mask) == entry->mods.mask)) {
324818534a1Smrg                col += entry->level;
325818534a1Smrg                if (type->preserve)
326818534a1Smrg                    preserve = type->preserve[i].mask;
327818534a1Smrg                break;
328818534a1Smrg            }
329818534a1Smrg        }
3301ab64890Smrg    }
3311ab64890Smrg
332818534a1Smrg    if (keysym_rtrn != NULL)
333818534a1Smrg        *keysym_rtrn = syms[col];
3341ab64890Smrg    if (mods_rtrn) {
335818534a1Smrg        *mods_rtrn = type->mods.mask & (~preserve);
336818534a1Smrg        /* The Motif VTS doesn't get the help callback called if help
337818534a1Smrg         * is bound to Shift+<whatever>, and it appears as though it
338818534a1Smrg         * is XkbTranslateKeyCode that is causing the problem.  The
339818534a1Smrg         * core X version of XTranslateKey always OR's in ShiftMask
340818534a1Smrg         * and LockMask for mods_rtrn, so this "fix" keeps this behavior
341818534a1Smrg         * and solves the VTS problem.
342818534a1Smrg         */
343818534a1Smrg        if ((xkb->dpy) && (xkb->dpy->xkb_info) &&
344818534a1Smrg            (xkb->dpy->xkb_info->
345818534a1Smrg             xlib_ctrls & XkbLC_AlwaysConsumeShiftAndLock)) {
346818534a1Smrg            *mods_rtrn |= (ShiftMask | LockMask);
347818534a1Smrg        }
3481ab64890Smrg    }
349818534a1Smrg    return (syms[col] != NoSymbol);
3501ab64890Smrg}
3511ab64890Smrg
3521ab64890SmrgStatus
353818534a1SmrgXkbRefreshKeyboardMapping(register XkbMapNotifyEvent * event)
3541ab64890Smrg{
3551ab64890Smrg    Display *dpy = event->display;
3561ab64890Smrg    XkbInfoPtr xkbi;
3571ab64890Smrg
3581ab64890Smrg    if (_XkbUnavailable(dpy)) {
359818534a1Smrg        _XRefreshKeyboardMapping((XMappingEvent *) event);
360818534a1Smrg        return Success;
3611ab64890Smrg    }
362818534a1Smrg    xkbi = dpy->xkb_info;
3631ab64890Smrg
364818534a1Smrg    if (((event->type & 0x7f) - xkbi->codes->first_event) != XkbEventCode)
365818534a1Smrg        return BadMatch;
366818534a1Smrg    if (event->xkb_type == XkbNewKeyboardNotify) {
367818534a1Smrg        _XkbReloadDpy(dpy);
368818534a1Smrg        return Success;
3691ab64890Smrg    }
370818534a1Smrg    if (event->xkb_type == XkbMapNotify) {
371818534a1Smrg        XkbMapChangesRec changes;
372818534a1Smrg        Status rtrn;
373818534a1Smrg
374818534a1Smrg        if (xkbi->flags & XkbMapPending)
375818534a1Smrg            changes = xkbi->changes;
376818534a1Smrg        else
377818534a1Smrg            bzero(&changes, sizeof(changes));
378818534a1Smrg        XkbNoteMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
379818534a1Smrg        if ((rtrn = XkbGetMapChanges(dpy, xkbi->desc, &changes)) != Success) {
3801ab64890Smrg#ifdef DEBUG
381818534a1Smrg            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
3821ab64890Smrg#endif
383818534a1Smrg            xkbi->changes = changes;
384818534a1Smrg        }
385818534a1Smrg        else if (xkbi->flags & XkbMapPending) {
386818534a1Smrg            xkbi->flags &= ~XkbMapPending;
387818534a1Smrg            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
388818534a1Smrg        }
389818534a1Smrg        return rtrn;
3901ab64890Smrg    }
3911ab64890Smrg    return BadMatch;
3921ab64890Smrg}
3931ab64890Smrg
3941ab64890Smrgint
395818534a1SmrgXRefreshKeyboardMapping(register XMappingEvent * event)
3961ab64890Smrg{
397818534a1Smrg    XkbEvent *xkbevent = (XkbEvent *) event;
3981ab64890Smrg    Display *dpy = event->display;
3991ab64890Smrg    XkbMapChangesRec changes;
4001ab64890Smrg    XkbInfoPtr xkbi;
4011ab64890Smrg
4021ab64890Smrg    /* always do this for input methods, which still use the old keymap */
4031ab64890Smrg    (void) _XRefreshKeyboardMapping(event);
4041ab64890Smrg
4051ab64890Smrg    if (_XkbUnavailable(dpy))
406818534a1Smrg        return 1;
4071ab64890Smrg
4081ab64890Smrg    xkbi = dpy->xkb_info;
4091ab64890Smrg
410818534a1Smrg    if (((event->type & 0x7f) - xkbi->codes->first_event) == XkbEventCode)
411818534a1Smrg        return XkbRefreshKeyboardMapping(&xkbevent->map);
4121ab64890Smrg
413818534a1Smrg    if (xkbi->flags & XkbXlibNewKeyboard) {
414818534a1Smrg        _XkbReloadDpy(dpy);
415818534a1Smrg        return 1;
4161ab64890Smrg    }
4171ab64890Smrg
418818534a1Smrg    if ((xkbi->flags & XkbMapPending) || (event->request == MappingKeyboard)) {
419818534a1Smrg        if (xkbi->flags & XkbMapPending) {
420818534a1Smrg            changes = xkbi->changes;
421818534a1Smrg            _XkbNoteCoreMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
422818534a1Smrg        }
423818534a1Smrg        else {
424818534a1Smrg            bzero(&changes, sizeof(changes));
425818534a1Smrg            changes.changed = XkbKeySymsMask;
426818534a1Smrg            if (xkbi->desc->min_key_code < xkbi->desc->max_key_code) {
427818534a1Smrg                changes.first_key_sym = xkbi->desc->min_key_code;
428818534a1Smrg                changes.num_key_syms = xkbi->desc->max_key_code -
429818534a1Smrg                    xkbi->desc->min_key_code + 1;
430818534a1Smrg            }
431818534a1Smrg            else {
432818534a1Smrg                changes.first_key_sym = event->first_keycode;
433818534a1Smrg                changes.num_key_syms = event->count;
434818534a1Smrg            }
435818534a1Smrg        }
436818534a1Smrg
437818534a1Smrg        if (XkbGetMapChanges(dpy, xkbi->desc, &changes) != Success) {
4381ab64890Smrg#ifdef DEBUG
439818534a1Smrg            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
440818534a1Smrg            if (changes.changed & XkbKeyTypesMask) {
441818534a1Smrg                int first = changes.first_type;
442818534a1Smrg                int last = changes.first_type + changes.num_types - 1;
443818534a1Smrg
444818534a1Smrg                fprintf(stderr, "       types:  %d..%d\n", first, last);
445818534a1Smrg            }
446818534a1Smrg            if (changes.changed & XkbKeySymsMask) {
447818534a1Smrg                int first = changes.first_key_sym;
448818534a1Smrg                int last = changes.first_key_sym + changes.num_key_syms - 1;
449818534a1Smrg
450818534a1Smrg                fprintf(stderr, "     symbols:  %d..%d\n", first, last);
451818534a1Smrg            }
452818534a1Smrg            if (changes.changed & XkbKeyActionsMask) {
453818534a1Smrg                int first = changes.first_key_act;
454818534a1Smrg                int last = changes.first_key_act + changes.num_key_acts - 1;
455818534a1Smrg
456818534a1Smrg                fprintf(stderr, "     acts:  %d..%d\n", first, last);
457818534a1Smrg            }
458818534a1Smrg            if (changes.changed & XkbKeyBehaviorsMask) {
459818534a1Smrg                int first = changes.first_key_behavior;
460818534a1Smrg                int last = first + changes.num_key_behaviors - 1;
461818534a1Smrg
462818534a1Smrg                fprintf(stderr, "   behaviors:  %d..%d\n", first, last);
463818534a1Smrg            }
464818534a1Smrg            if (changes.changed & XkbVirtualModsMask) {
465818534a1Smrg                fprintf(stderr, "virtual mods: 0x%04x\n", changes.vmods);
466818534a1Smrg            }
467818534a1Smrg            if (changes.changed & XkbExplicitComponentsMask) {
468818534a1Smrg                int first = changes.first_key_explicit;
469818534a1Smrg                int last = first + changes.num_key_explicit - 1;
470818534a1Smrg
471818534a1Smrg                fprintf(stderr, "    explicit:  %d..%d\n", first, last);
472818534a1Smrg            }
4731ab64890Smrg#endif
474818534a1Smrg        }
475818534a1Smrg        LockDisplay(dpy);
476818534a1Smrg        if (xkbi->flags & XkbMapPending) {
477818534a1Smrg            xkbi->flags &= ~XkbMapPending;
478818534a1Smrg            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
479818534a1Smrg        }
480818534a1Smrg        UnlockDisplay(dpy);
4811ab64890Smrg    }
482818534a1Smrg    if (event->request == MappingModifier) {
483818534a1Smrg        LockDisplay(dpy);
484818534a1Smrg        if (xkbi->desc->map->modmap) {
485818534a1Smrg            _XkbFree(xkbi->desc->map->modmap);
486818534a1Smrg            xkbi->desc->map->modmap = NULL;
487818534a1Smrg        }
488818534a1Smrg        if (dpy->key_bindings) {
489818534a1Smrg            register struct _XKeytrans *p;
490818534a1Smrg
491818534a1Smrg            for (p = dpy->key_bindings; p; p = p->next) {
492818534a1Smrg                register int i;
493818534a1Smrg
494818534a1Smrg                p->state = 0;
495818534a1Smrg                if (p->mlen > 0) {
496818534a1Smrg                    for (i = 0; i < p->mlen; i++) {
497818534a1Smrg                        p->state |= XkbKeysymToModifiers(dpy, p->modifiers[i]);
498818534a1Smrg                    }
499818534a1Smrg                    if (p->state)
500818534a1Smrg                        p->state &= AllMods;
501818534a1Smrg                    else
502818534a1Smrg                        p->state = AnyModifier;
503818534a1Smrg                }
504818534a1Smrg            }
505818534a1Smrg        }
506818534a1Smrg        UnlockDisplay(dpy);
5071ab64890Smrg    }
5081ab64890Smrg    return 1;
5091ab64890Smrg}
5101ab64890Smrg
5111ab64890Smrgstatic int
5121ab64890Smrg_XkbLoadDpy(Display *dpy)
5131ab64890Smrg{
5141ab64890Smrg    XkbInfoPtr xkbi;
515818534a1Smrg    unsigned query, oldEvents;
5161ab64890Smrg    XkbDescRec *desc;
5171ab64890Smrg
518818534a1Smrg    if (!XkbUseExtension(dpy, NULL, NULL))
519818534a1Smrg        return 0;
5201ab64890Smrg
5211ab64890Smrg    xkbi = dpy->xkb_info;
5221ab64890Smrg    query = XkbAllClientInfoMask;
523818534a1Smrg    desc = XkbGetMap(dpy, query, XkbUseCoreKbd);
5241ab64890Smrg    if (!desc) {
5251ab64890Smrg#ifdef DEBUG
526818534a1Smrg        fprintf(stderr, "Warning! XkbGetMap failed!\n");
5271ab64890Smrg#endif
528818534a1Smrg        return 0;
5291ab64890Smrg    }
5301ab64890Smrg    LockDisplay(dpy);
5311ab64890Smrg    xkbi->desc = desc;
5321ab64890Smrg
5331ab64890Smrg    UnlockDisplay(dpy);
534818534a1Smrg    oldEvents = xkbi->selected_events;
535818534a1Smrg    if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards)) {
536818534a1Smrg        XkbSelectEventDetails(dpy, xkbi->desc->device_spec,
537818534a1Smrg                              XkbNewKeyboardNotify,
538818534a1Smrg                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask,
539818534a1Smrg                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask);
5401ab64890Smrg    }
541818534a1Smrg    XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
542818534a1Smrg                          XkbAllClientInfoMask, XkbAllClientInfoMask);
5431ab64890Smrg    LockDisplay(dpy);
544818534a1Smrg    xkbi->selected_events = oldEvents;
5451ab64890Smrg    UnlockDisplay(dpy);
5461ab64890Smrg    return 1;
5471ab64890Smrg}
5481ab64890Smrg
5491ab64890Smrgvoid
5501ab64890Smrg_XkbReloadDpy(Display *dpy)
5511ab64890Smrg{
5521ab64890Smrg    XkbInfoPtr xkbi;
5531ab64890Smrg    XkbDescRec *desc;
554818534a1Smrg    unsigned oldDeviceID;
5551ab64890Smrg
5561ab64890Smrg    if (_XkbUnavailable(dpy))
557818534a1Smrg        return;
5581ab64890Smrg
5591ab64890Smrg    xkbi = dpy->xkb_info;
5601ab64890Smrg    LockDisplay(dpy);
5611ab64890Smrg    if (xkbi->desc) {
562818534a1Smrg        oldDeviceID = xkbi->desc->device_spec;
563818534a1Smrg        XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, True);
564818534a1Smrg        xkbi->desc = NULL;
565818534a1Smrg        xkbi->flags &= ~(XkbMapPending | XkbXlibNewKeyboard);
566818534a1Smrg        xkbi->changes.changed = 0;
5671ab64890Smrg    }
568818534a1Smrg    else
569818534a1Smrg        oldDeviceID = XkbUseCoreKbd;
5701ab64890Smrg    UnlockDisplay(dpy);
571818534a1Smrg    desc = XkbGetMap(dpy, XkbAllClientInfoMask, XkbUseCoreKbd);
5721ab64890Smrg    if (!desc)
573818534a1Smrg        return;
5741ab64890Smrg    LockDisplay(dpy);
5751ab64890Smrg    xkbi->desc = desc;
5761ab64890Smrg    UnlockDisplay(dpy);
5771ab64890Smrg
578818534a1Smrg    if (desc->device_spec != oldDeviceID) {
579818534a1Smrg        /* transfer(?) event masks here */
5801ab64890Smrg#ifdef NOTYET
581818534a1Smrg        unsigned oldEvents;
582818534a1Smrg
583818534a1Smrg        oldEvents = xkbi->selected_events;
584818534a1Smrg        XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
585818534a1Smrg                              XkbAllMapComponentsMask, XkbAllClientInfoMask);
586818534a1Smrg        LockDisplay(dpy);
587818534a1Smrg        xkbi->selected_events = oldEvents;
588818534a1Smrg        UnlockDisplay(dpy);
5891ab64890Smrg#endif
5901ab64890Smrg    }
5911ab64890Smrg    return;
5921ab64890Smrg}
5931ab64890Smrg
5941ab64890Smrgint
595818534a1SmrgXkbTranslateKeySym(register Display *dpy,
596818534a1Smrg                   register KeySym *sym_rtrn,
597818534a1Smrg                   unsigned int mods,
598818534a1Smrg                   char *buffer,
599818534a1Smrg                   int nbytes,
600818534a1Smrg                   int *extra_rtrn)
6011ab64890Smrg{
602818534a1Smrg    register XkbInfoPtr xkb;
6031ab64890Smrg    XkbKSToMBFunc cvtr;
6041ab64890Smrg    XPointer priv;
6051ab64890Smrg    char tmp[4];
6061ab64890Smrg    int n;
6071ab64890Smrg
608818534a1Smrg    xkb = dpy->xkb_info;
6091ab64890Smrg    if (!xkb->cvt.KSToMB) {
610818534a1Smrg        _XkbGetConverters(_XkbGetCharset(), &xkb->cvt);
611818534a1Smrg        _XkbGetConverters("ISO8859-1", &xkb->latin1cvt);
6121ab64890Smrg    }
6131ab64890Smrg
6141ab64890Smrg    if (extra_rtrn)
615818534a1Smrg        *extra_rtrn = 0;
6161ab64890Smrg
617818534a1Smrg    if ((buffer == NULL) || (nbytes == 0)) {
618818534a1Smrg        buffer = tmp;
619818534a1Smrg        nbytes = 4;
6201ab64890Smrg    }
6211ab64890Smrg
6221ab64890Smrg    /* see if symbol rebound, if so, return that string. */
623818534a1Smrg    n = XkbLookupKeyBinding(dpy, *sym_rtrn, mods, buffer, nbytes, extra_rtrn);
6241ab64890Smrg    if (n)
6251ab64890Smrg        return n;
6261ab64890Smrg
627818534a1Smrg    if (nbytes > 0)
628818534a1Smrg        buffer[0] = '\0';
6291ab64890Smrg
630818534a1Smrg    if (xkb->cvt.KSToUpper && (mods & LockMask)) {
631818534a1Smrg        *sym_rtrn = (*xkb->cvt.KSToUpper) (*sym_rtrn);
6321ab64890Smrg    }
6331ab64890Smrg    if (xkb->xlib_ctrls & XkbLC_ForceLatin1Lookup) {
634818534a1Smrg        cvtr = xkb->latin1cvt.KSToMB;
635818534a1Smrg        priv = xkb->latin1cvt.KSToMBPriv;
636818534a1Smrg    }
637818534a1Smrg    else {
638818534a1Smrg        cvtr = xkb->cvt.KSToMB;
639818534a1Smrg        priv = xkb->cvt.KSToMBPriv;
6401ab64890Smrg    }
6411ab64890Smrg
642818534a1Smrg    n = (*cvtr) (priv, *sym_rtrn, buffer, nbytes, extra_rtrn);
643818534a1Smrg
644818534a1Smrg    if ((!xkb->cvt.KSToUpper) && (mods & LockMask)) {
645818534a1Smrg        register int i;
646818534a1Smrg        int change;
647818534a1Smrg
648818534a1Smrg        for (i = change = 0; i < n; i++) {
649818534a1Smrg            char ch = toupper(buffer[i]);
650818534a1Smrg            change = (change || (buffer[i] != ch));
651818534a1Smrg            buffer[i] = ch;
652818534a1Smrg        }
653818534a1Smrg        if (change) {
654818534a1Smrg            if (n == 1)
655818534a1Smrg                *sym_rtrn =
656818534a1Smrg                    (*xkb->cvt.MBToKS) (xkb->cvt.MBToKSPriv, buffer, n, NULL);
657818534a1Smrg            else
658818534a1Smrg                *sym_rtrn = NoSymbol;
659818534a1Smrg        }
6601ab64890Smrg    }
6611ab64890Smrg
662818534a1Smrg    if (mods & ControlMask) {
663818534a1Smrg        if (n == 1) {
664818534a1Smrg            buffer[0] = XkbToControl(buffer[0]);
665818534a1Smrg            if (nbytes > 1)
666818534a1Smrg                buffer[1] = '\0';
667818534a1Smrg            return 1;
668818534a1Smrg        }
669818534a1Smrg        if (nbytes > 0)
670818534a1Smrg            buffer[0] = '\0';
671818534a1Smrg        return 0;
6721ab64890Smrg    }
6731ab64890Smrg    return n;
6741ab64890Smrg}
6751ab64890Smrg
6761ab64890Smrgint
677818534a1SmrgXLookupString(register XKeyEvent *event,
678818534a1Smrg              char *buffer,
679818534a1Smrg              int nbytes,
680818534a1Smrg              KeySym *keysym,
681818534a1Smrg              XComposeStatus *status)
6821ab64890Smrg{
683818534a1Smrg    KeySym dummy;
6841ab64890Smrg    int rtrnLen;
6851ab64890Smrg    unsigned int new_mods;
6861ab64890Smrg    Display *dpy = event->display;
6871ab64890Smrg
688818534a1Smrg    if (keysym == NULL)
689818534a1Smrg        keysym = &dummy;
690818534a1Smrg    if (!XkbLookupKeySym(dpy, event->keycode, event->state, &new_mods, keysym))
691818534a1Smrg        return 0;
692818534a1Smrg    new_mods = (event->state & (~new_mods));
6931ab64890Smrg
6941ab64890Smrg    /* find the group where a symbol can be converted to control one */
695818534a1Smrg    if (new_mods & ControlMask && *keysym > 0x7F &&
696818534a1Smrg        (dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
697818534a1Smrg        XKeyEvent tmp_ev = *event;
698818534a1Smrg        KeySym tmp_keysym;
699818534a1Smrg        unsigned int tmp_new_mods;
700818534a1Smrg
701818534a1Smrg        if (_XkbUnavailable(dpy)) {
702818534a1Smrg            tmp_ev.state = event->state ^ dpy->mode_switch;
7031ab64890Smrg            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
7041ab64890Smrg                                &tmp_new_mods, &tmp_keysym) &&
705818534a1Smrg                tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
7061ab64890Smrg                *keysym = tmp_keysym;
7071ab64890Smrg            }
708818534a1Smrg        }
709818534a1Smrg        else {
7101ab64890Smrg            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
7111ab64890Smrg            int i;
712818534a1Smrg
7131ab64890Smrg            for (i = 0; i < n; i++) {
7141ab64890Smrg                if (XkbGroupForCoreState(event->state) == i)
7151ab64890Smrg                    continue;
716818534a1Smrg                tmp_ev.state = XkbBuildCoreState(tmp_ev.state, i);
7171ab64890Smrg                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
718818534a1Smrg                                    &tmp_new_mods, &tmp_keysym) &&
719818534a1Smrg                    tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
7201ab64890Smrg                    *keysym = tmp_keysym;
721818534a1Smrg                    new_mods = (event->state & (~tmp_new_mods));
7221ab64890Smrg                    break;
7231ab64890Smrg                }
7241ab64890Smrg            }
7251ab64890Smrg        }
72661b2299dSmrg    }
7271ab64890Smrg
7281ab64890Smrg#ifdef USE_OWN_COMPOSE
729818534a1Smrg    if (status) {
730818534a1Smrg        static int been_here = 0;
731818534a1Smrg
732818534a1Smrg        if (!been_here) {
733818534a1Smrg            XimCompInitTables();
734818534a1Smrg            been_here = 1;
735818534a1Smrg        }
736818534a1Smrg        if (!XimCompLegalStatus(status)) {
737818534a1Smrg            status->compose_ptr = NULL;
738818534a1Smrg            status->chars_matched = 0;
739818534a1Smrg        }
740818534a1Smrg        if (((status->chars_matched > 0) && (status->compose_ptr != NULL)) ||
741818534a1Smrg            XimCompIsComposeKey(*keysym, event->keycode, status)) {
742818534a1Smrg            XimCompRtrn rtrn;
743818534a1Smrg
744818534a1Smrg            switch (XimCompProcessSym(status, *keysym, &rtrn)) {
745818534a1Smrg            case XIM_COMP_IGNORE:
746818534a1Smrg                break;
747818534a1Smrg            case XIM_COMP_IN_PROGRESS:
748818534a1Smrg                if (keysym != NULL)
749818534a1Smrg                    *keysym = NoSymbol;
7501ab64890Smrg#ifndef NO_COMPOSE_LED
751818534a1Smrg                if (dpy->xkb_info->xlib_ctrls & XkbLC_ComposeLED) {
752818534a1Smrg                    XkbSetNamedIndicator(dpy, dpy->xkb_info->composeLED,
753818534a1Smrg                                         True, True, False, NULL);
754818534a1Smrg                }
7551ab64890Smrg#endif
756818534a1Smrg                return 0;
757818534a1Smrg            case XIM_COMP_FAIL:
758818534a1Smrg            {
759818534a1Smrg                static Atom _ComposeFail = None;
760818534a1Smrg                int n = 0, len = 0;
761818534a1Smrg
7621ab64890Smrg#ifndef NO_COMPOSE_LED
763818534a1Smrg                if (dpy->xkb_info->xlib_ctrls & XkbLC_ComposeLED) {
764818534a1Smrg                    XkbSetNamedIndicator(dpy, dpy->xkb_info->composeLED,
765818534a1Smrg                                         True, False, False, NULL);
766818534a1Smrg                }
7671ab64890Smrg#endif
7681ab64890Smrg#ifndef NO_BELL_ON_COMPOSE_FAIL
769818534a1Smrg                if (dpy->xkb_info->xlib_ctrls & XkbLC_BeepOnComposeFail) {
770818534a1Smrg                    if (_ComposeFail == None)
771818534a1Smrg                        _ComposeFail = XInternAtom(dpy, "ComposeFail", 0);
772818534a1Smrg                    XkbBell(dpy, event->window, 0, _ComposeFail);
773818534a1Smrg                }
7741ab64890Smrg#endif
775818534a1Smrg                for (n = len = 0; rtrn.sym[n] != XK_VoidSymbol; n++) {
776818534a1Smrg                    if (nbytes - len > 0) {
777818534a1Smrg                        len += XkbTranslateKeySym(dpy, &rtrn.sym[n], new_mods,
778818534a1Smrg                                                  buffer + len, nbytes - len,
779818534a1Smrg                                                  NULL);
780818534a1Smrg                    }
781818534a1Smrg                }
782818534a1Smrg                if (keysym != NULL) {
783818534a1Smrg                    if (n == 1)
784818534a1Smrg                        *keysym = rtrn.sym[0];
785818534a1Smrg                    else
786818534a1Smrg                        *keysym = NoSymbol;
787818534a1Smrg                }
788818534a1Smrg                return len;
789818534a1Smrg            }
790818534a1Smrg            case XIM_COMP_SUCCEED:
791818534a1Smrg            {
792818534a1Smrg                int len, n = 0;
7931ab64890Smrg
7941ab64890Smrg#ifndef NO_COMPOSE_LED
795818534a1Smrg                if (dpy->xkb_info->xlib_ctrls & XkbLC_ComposeLED) {
796818534a1Smrg                    XkbSetNamedIndicator(dpy, dpy->xkb_info->composeLED,
797818534a1Smrg                                         True, False, False, NULL);
798818534a1Smrg                }
7991ab64890Smrg#endif
800818534a1Smrg                *keysym = rtrn.matchSym;
801818534a1Smrg                if (rtrn.str[0] != '\0') {
802818534a1Smrg                    strncpy(buffer, rtrn.str, nbytes - 1);
803818534a1Smrg                    buffer[nbytes - 1] = '\0';
804818534a1Smrg                    len = (int) strlen(buffer);
805818534a1Smrg                }
806818534a1Smrg                else {
807818534a1Smrg                    len = XkbTranslateKeySym(dpy, keysym, new_mods,
808818534a1Smrg                                             buffer, nbytes, NULL);
809818534a1Smrg                }
810818534a1Smrg                for (n = 0; rtrn.sym[n] != XK_VoidSymbol; n++) {
811818534a1Smrg                    if (nbytes - len > 0) {
812818534a1Smrg                        len += XkbTranslateKeySym(dpy, &rtrn.sym[n],
813818534a1Smrg                                                  event->state,
814818534a1Smrg                                                  buffer + len, nbytes - len,
815818534a1Smrg                                                  NULL);
816818534a1Smrg                    }
817818534a1Smrg                }
818818534a1Smrg                return len;
819818534a1Smrg            }
820818534a1Smrg            }
821818534a1Smrg        }
8221ab64890Smrg    }
8231ab64890Smrg#endif
8241ab64890Smrg
8251ab64890Smrg    /* We *should* use the new_mods (which does not contain any modifiers */
8261ab64890Smrg    /* that were used to compute the symbol here, but pre-XKB XLookupString */
8271ab64890Smrg    /* did not and we have to remain compatible.  Sigh. */
8281ab64890Smrg    if (_XkbUnavailable(dpy) ||
829818534a1Smrg        (dpy->xkb_info->xlib_ctrls & XkbLC_ConsumeLookupMods) == 0)
830818534a1Smrg        new_mods = event->state;
8311ab64890Smrg
832818534a1Smrg    rtrnLen = XkbLookupKeyBinding(dpy, *keysym, new_mods, buffer, nbytes, NULL);
833818534a1Smrg    if (rtrnLen > 0)
834818534a1Smrg        return rtrnLen;
8351ab64890Smrg
836818534a1Smrg    return XkbTranslateKeySym(dpy, keysym, new_mods, buffer, nbytes, NULL);
8371ab64890Smrg}
8381ab64890Smrg
8391ab64890Smrg
8401ab64890Smrgint
841818534a1SmrgXkbLookupKeyBinding(Display *dpy,
842818534a1Smrg                    register KeySym sym,
843818534a1Smrg                    unsigned int mods,
844818534a1Smrg                    char *buffer,
845818534a1Smrg                    int nbytes,
846818534a1Smrg                    int *extra_rtrn)
8471ab64890Smrg{
84861b2299dSmrg    register struct _XKeytrans *p;
8491ab64890Smrg
8501ab64890Smrg    if (extra_rtrn)
851818534a1Smrg        *extra_rtrn = 0;
8521ab64890Smrg    for (p = dpy->key_bindings; p; p = p->next) {
853818534a1Smrg        if (((mods & AllMods) == p->state) && (sym == p->key)) {
854818534a1Smrg            int tmp = p->len;
855818534a1Smrg
856818534a1Smrg            if (tmp > nbytes) {
857818534a1Smrg                if (extra_rtrn)
858818534a1Smrg                    *extra_rtrn = (tmp - nbytes);
859818534a1Smrg                tmp = nbytes;
860818534a1Smrg            }
861818534a1Smrg            memcpy(buffer, p->string, tmp);
862818534a1Smrg            if (tmp < nbytes)
863818534a1Smrg                buffer[tmp] = '\0';
864818534a1Smrg            return tmp;
865818534a1Smrg        }
8661ab64890Smrg    }
8671ab64890Smrg    return 0;
8681ab64890Smrg}
8691ab64890Smrg
8701ab64890Smrgchar
871818534a1SmrgXkbToControl(char ch)
8721ab64890Smrg{
8731ab64890Smrg    register char c = ch;
87461b2299dSmrg
875818534a1Smrg    if ((c >= '@' && c < '\177') || c == ' ')
876818534a1Smrg        c &= 0x1F;
877818534a1Smrg    else if (c == '2')
878818534a1Smrg        c = '\000';
879818534a1Smrg    else if (c >= '3' && c <= '7')
880818534a1Smrg        c -= ('3' - '\033');
881818534a1Smrg    else if (c == '8')
882818534a1Smrg        c = '\177';
883818534a1Smrg    else if (c == '/')
884818534a1Smrg        c = '_' & 0x1F;
8851ab64890Smrg    return c;
8861ab64890Smrg}
887