XKBBind.c revision 5efbdfc3
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#define AllMods (ShiftMask|LockMask|ControlMask| \
45818534a1Smrg                 Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
461ab64890Smrg
47818534a1Smrgstatic int _XkbLoadDpy(Display *dpy);
481ab64890Smrg
491ab64890Smrgstruct _XKeytrans {
50818534a1Smrg    struct _XKeytrans *next;    /* next on list */
51818534a1Smrg    char *string;               /* string to return when the time comes */
52818534a1Smrg    int len;                    /* length of string (since NULL is legit) */
53818534a1Smrg    KeySym key;                 /* keysym rebound */
54818534a1Smrg    unsigned int state;         /* modifier state */
55818534a1Smrg    KeySym *modifiers;          /* modifier keysyms you want */
56818534a1Smrg    int mlen;                   /* length of modifier list */
571ab64890Smrg};
581ab64890Smrg
591ab64890SmrgKeySym
601ab64890SmrgXkbKeycodeToKeysym(Display *dpy,
611ab64890Smrg#if NeedWidePrototypes
62818534a1Smrg                   unsigned int kc,
631ab64890Smrg#else
64818534a1Smrg                   KeyCode kc,
651ab64890Smrg#endif
66818534a1Smrg                   int group,
67818534a1Smrg                   int level)
681ab64890Smrg{
69818534a1Smrg    XkbDescRec *xkb;
7061b2299dSmrg
711ab64890Smrg    if (_XkbUnavailable(dpy))
72818534a1Smrg        return NoSymbol;
731ab64890Smrg
74818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
751ab64890Smrg
761ab64890Smrg    xkb = dpy->xkb_info->desc;
77818534a1Smrg    if ((kc < xkb->min_key_code) || (kc > xkb->max_key_code))
78818534a1Smrg        return NoSymbol;
79818534a1Smrg
80818534a1Smrg    if ((group < 0) || (level < 0) || (group >= XkbKeyNumGroups(xkb, kc)))
81818534a1Smrg        return NoSymbol;
82818534a1Smrg    if (level >= XkbKeyGroupWidth(xkb, kc, group)) {
83818534a1Smrg        /* for compatibility with the core protocol, _always_ allow  */
84818534a1Smrg        /* two symbols in the first two groups.   If either of the   */
85818534a1Smrg        /* two is of type ONE_LEVEL, just replicate the first symbol */
86818534a1Smrg        if ((group > XkbGroup2Index) || (XkbKeyGroupWidth(xkb, kc, group) != 1)
87818534a1Smrg            || (level != 1)) {
88818534a1Smrg            return NoSymbol;
89818534a1Smrg        }
90818534a1Smrg        level = 0;
911ab64890Smrg    }
92818534a1Smrg    return XkbKeySymEntry(xkb, kc, level, group);
931ab64890Smrg}
941ab64890Smrg
951ab64890SmrgKeySym
961ab64890SmrgXKeycodeToKeysym(Display *dpy,
971ab64890Smrg#if NeedWidePrototypes
98818534a1Smrg                 unsigned int kc,
991ab64890Smrg#else
100818534a1Smrg                 KeyCode kc,
1011ab64890Smrg#endif
102818534a1Smrg                 int col)
1031ab64890Smrg{
104818534a1Smrg    XkbDescRec *xkb;
10561b2299dSmrg
1061ab64890Smrg    if (_XkbUnavailable(dpy))
107818534a1Smrg        return _XKeycodeToKeysym(dpy, kc, col);
1081ab64890Smrg
109818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
1101ab64890Smrg
1111ab64890Smrg    xkb = dpy->xkb_info->desc;
112818534a1Smrg    if ((kc < xkb->min_key_code) || (kc > xkb->max_key_code))
113818534a1Smrg        return NoSymbol;
114818534a1Smrg
115818534a1Smrg    if (col > 3) {
1165efbdfc3Smrg        int firstSym, nGrp, grp;
117818534a1Smrg
1185efbdfc3Smrg        firstSym = 4;
119818534a1Smrg        nGrp = XkbKeyNumGroups(xkb, kc);
1205efbdfc3Smrg        for (grp = 0; grp < nGrp; grp++) {
1215efbdfc3Smrg            int width = XkbKeyGroupWidth(xkb, kc, grp);
1225efbdfc3Smrg            int skip = 0;
1235efbdfc3Smrg            if (grp < 2) {
1245efbdfc3Smrg                /* Skip the first two symbols in the first two groups, since we
1255efbdfc3Smrg                 * return them below for indexes 0-3. */
1265efbdfc3Smrg                skip = 2;
1275efbdfc3Smrg                width -= skip;
1285efbdfc3Smrg                if (width < 0)
1295efbdfc3Smrg                    width = 0;
1305efbdfc3Smrg            }
1315efbdfc3Smrg            if (col < firstSym + width)
1325efbdfc3Smrg                return XkbKeycodeToKeysym(dpy, kc, grp, col - firstSym + skip);
1335efbdfc3Smrg            firstSym += width;
134818534a1Smrg        }
135818534a1Smrg        return NoSymbol;
1361ab64890Smrg    }
137818534a1Smrg    return XkbKeycodeToKeysym(dpy, kc, (col >> 1), (col & 1));
1381ab64890Smrg}
1391ab64890Smrg
1401ab64890SmrgKeyCode
1411ab64890SmrgXKeysymToKeycode(Display *dpy, KeySym ks)
1421ab64890Smrg{
1431ab64890Smrg    register int i, j, gotOne;
1441ab64890Smrg
1451ab64890Smrg    if (_XkbUnavailable(dpy))
146818534a1Smrg        return _XKeysymToKeycode(dpy, ks);
147818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
1481ab64890Smrg
149818534a1Smrg    j = 0;
1501ab64890Smrg    do {
151818534a1Smrg        register XkbDescRec *xkb = dpy->xkb_info->desc;
152818534a1Smrg        gotOne = 0;
153818534a1Smrg        for (i = dpy->min_keycode; i <= dpy->max_keycode; i++) {
154818534a1Smrg            if (j < (int) XkbKeyNumSyms(xkb, i)) {
155818534a1Smrg                gotOne = 1;
156818534a1Smrg                if ((XkbKeySym(xkb, i, j) == ks))
157818534a1Smrg                    return i;
158818534a1Smrg            }
159818534a1Smrg        }
160818534a1Smrg        j++;
1611ab64890Smrg    } while (gotOne);
1621ab64890Smrg    return 0;
1631ab64890Smrg}
1641ab64890Smrg
1651ab64890Smrgstatic int
1661ab64890Smrg_XkbComputeModmap(Display *dpy)
1671ab64890Smrg{
168818534a1Smrg    register XkbDescPtr xkb;
1691ab64890Smrg
170818534a1Smrg    xkb = dpy->xkb_info->desc;
171818534a1Smrg    if (XkbGetUpdatedMap(dpy, XkbModifierMapMask, xkb) == Success)
172818534a1Smrg        return 1;
1731ab64890Smrg    return 0;
1741ab64890Smrg}
1751ab64890Smrg
1761ab64890Smrgunsigned
177818534a1SmrgXkbKeysymToModifiers(Display *dpy, KeySym ks)
1781ab64890Smrg{
1791ab64890Smrg    XkbDescRec *xkb;
180818534a1Smrg    register int i, j;
1811ab64890Smrg    register KeySym *pSyms;
1821ab64890Smrg    CARD8 mods;
1831ab64890Smrg
1841ab64890Smrg    if (_XkbUnavailable(dpy))
185818534a1Smrg        return _XKeysymToModifiers(dpy, ks);
186818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
187818534a1Smrg
188818534a1Smrg    if (_XkbNeedModmap(dpy->xkb_info) && (!_XkbComputeModmap(dpy)))
189818534a1Smrg        return _XKeysymToModifiers(dpy, ks);
190818534a1Smrg
191818534a1Smrg    xkb = dpy->xkb_info->desc;
192818534a1Smrg    mods = 0;
193818534a1Smrg    for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
194818534a1Smrg        pSyms = XkbKeySymsPtr(xkb, i);
195818534a1Smrg        for (j = XkbKeyNumSyms(xkb, i) - 1; j >= 0; j--) {
196818534a1Smrg            if (pSyms[j] == ks) {
197818534a1Smrg                mods |= xkb->map->modmap[i];
198818534a1Smrg                break;
199818534a1Smrg            }
200818534a1Smrg        }
2011ab64890Smrg    }
2021ab64890Smrg    return mods;
2031ab64890Smrg}
2041ab64890Smrg
2051ab64890SmrgKeySym
206818534a1SmrgXLookupKeysym(register XKeyEvent * event, int col)
2071ab64890Smrg{
2081ab64890Smrg    Display *dpy = event->display;
209818534a1Smrg
2101ab64890Smrg    if (_XkbUnavailable(dpy))
211818534a1Smrg        return _XLookupKeysym(event, col);
212818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
213d4a3aaf4Smrg
214d4a3aaf4Smrg#ifdef __clang__
215d4a3aaf4Smrg#pragma clang diagnostic push
216d4a3aaf4Smrg#pragma clang diagnostic ignored "-Wdeprecated-declarations"
217d4a3aaf4Smrg#elif defined(__GNUC__)
218d4a3aaf4Smrg#pragma GCC diagnostic push
219d4a3aaf4Smrg#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
220d4a3aaf4Smrg#endif
2211ab64890Smrg    return XKeycodeToKeysym(dpy, event->keycode, col);
222d4a3aaf4Smrg#ifdef __clang__
223d4a3aaf4Smrg#pragma clang diagnostic pop
224d4a3aaf4Smrg#elif defined(__GNUC__)
225d4a3aaf4Smrg#pragma GCC diagnostic pop
226d4a3aaf4Smrg#endif
227d4a3aaf4Smrg
2281ab64890Smrg}
2291ab64890Smrg
2301ab64890Smrg   /*
23161b2299dSmrg    * Not a public entry point -- XkbTranslateKey is an obsolete name
23261b2299dSmrg    * that is preserved here so that functions linked against the old
2331ab64890Smrg    * version will continue to work in a shared library environment.
2341ab64890Smrg    */
2351ab64890Smrgint
236818534a1SmrgXkbTranslateKey(register Display *dpy,
237818534a1Smrg                KeyCode key,
238818534a1Smrg                register unsigned int mods,
239818534a1Smrg                unsigned int *mods_rtrn,
240818534a1Smrg                KeySym *keysym_rtrn);
241818534a1Smrg
2421ab64890Smrgint
243818534a1SmrgXkbTranslateKey(register Display *dpy,
244818534a1Smrg                KeyCode key,
245818534a1Smrg                register unsigned int mods,
246818534a1Smrg                unsigned int *mods_rtrn,
247818534a1Smrg                KeySym *keysym_rtrn)
2481ab64890Smrg{
249818534a1Smrg    return XkbLookupKeySym(dpy, key, mods, mods_rtrn, keysym_rtrn);
2501ab64890Smrg}
2511ab64890Smrg
2521ab64890SmrgBool
253818534a1SmrgXkbLookupKeySym(register Display *dpy,
254818534a1Smrg                KeyCode key,
255818534a1Smrg                register unsigned int mods,
256818534a1Smrg                unsigned int *mods_rtrn,
257818534a1Smrg                KeySym *keysym_rtrn)
2581ab64890Smrg{
2591ab64890Smrg    if (_XkbUnavailable(dpy))
260818534a1Smrg        return _XTranslateKey(dpy, key, mods, mods_rtrn, keysym_rtrn);
261818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
262818534a1Smrg    return XkbTranslateKeyCode(dpy->xkb_info->desc, key, mods, mods_rtrn,
263818534a1Smrg                               keysym_rtrn);
2641ab64890Smrg}
2651ab64890Smrg
2661ab64890SmrgBool
267818534a1SmrgXkbTranslateKeyCode(register XkbDescPtr xkb,
268818534a1Smrg                    KeyCode key,
269818534a1Smrg                    register unsigned int mods,
270818534a1Smrg                    unsigned int *mods_rtrn,
271818534a1Smrg                    KeySym *keysym_rtrn)
2721ab64890Smrg{
2731ab64890Smrg    XkbKeyTypeRec *type;
274818534a1Smrg    int col, nKeyGroups;
275818534a1Smrg    unsigned preserve, effectiveGroup;
2761ab64890Smrg    KeySym *syms;
2771ab64890Smrg
278818534a1Smrg    if (mods_rtrn != NULL)
279818534a1Smrg        *mods_rtrn = 0;
2801ab64890Smrg
281818534a1Smrg    nKeyGroups = XkbKeyNumGroups(xkb, key);
282818534a1Smrg    if ((!XkbKeycodeInRange(xkb, key)) || (nKeyGroups == 0)) {
283818534a1Smrg        if (keysym_rtrn != NULL)
284818534a1Smrg            *keysym_rtrn = NoSymbol;
285818534a1Smrg        return False;
2861ab64890Smrg    }
2871ab64890Smrg
288818534a1Smrg    syms = XkbKeySymsPtr(xkb, key);
2891ab64890Smrg
2901ab64890Smrg    /* find the offset of the effective group */
2911ab64890Smrg    col = 0;
292818534a1Smrg    effectiveGroup = XkbGroupForCoreState(mods);
293818534a1Smrg    if (effectiveGroup >= nKeyGroups) {
294818534a1Smrg        unsigned groupInfo = XkbKeyGroupInfo(xkb, key);
295818534a1Smrg
296818534a1Smrg        switch (XkbOutOfRangeGroupAction(groupInfo)) {
297818534a1Smrg        default:
298818534a1Smrg            effectiveGroup %= nKeyGroups;
299818534a1Smrg            break;
300818534a1Smrg        case XkbClampIntoRange:
301818534a1Smrg            effectiveGroup = nKeyGroups - 1;
302818534a1Smrg            break;
303818534a1Smrg        case XkbRedirectIntoRange:
304818534a1Smrg            effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
305818534a1Smrg            if (effectiveGroup >= nKeyGroups)
306818534a1Smrg                effectiveGroup = 0;
307818534a1Smrg            break;
308818534a1Smrg        }
3091ab64890Smrg    }
310818534a1Smrg    col = effectiveGroup * XkbKeyGroupsWidth(xkb, key);
311818534a1Smrg    type = XkbKeyKeyType(xkb, key, effectiveGroup);
312818534a1Smrg
313818534a1Smrg    preserve = 0;
314818534a1Smrg    if (type->map) {  /* find the column (shift level) within the group */
315818534a1Smrg        register int i;
316818534a1Smrg        register XkbKTMapEntryPtr entry;
317818534a1Smrg
318818534a1Smrg        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
319818534a1Smrg            if ((entry->active) &&
320818534a1Smrg                ((mods & type->mods.mask) == entry->mods.mask)) {
321818534a1Smrg                col += entry->level;
322818534a1Smrg                if (type->preserve)
323818534a1Smrg                    preserve = type->preserve[i].mask;
324818534a1Smrg                break;
325818534a1Smrg            }
326818534a1Smrg        }
3271ab64890Smrg    }
3281ab64890Smrg
329818534a1Smrg    if (keysym_rtrn != NULL)
330818534a1Smrg        *keysym_rtrn = syms[col];
3311ab64890Smrg    if (mods_rtrn) {
332818534a1Smrg        *mods_rtrn = type->mods.mask & (~preserve);
333818534a1Smrg        /* The Motif VTS doesn't get the help callback called if help
334818534a1Smrg         * is bound to Shift+<whatever>, and it appears as though it
335818534a1Smrg         * is XkbTranslateKeyCode that is causing the problem.  The
336818534a1Smrg         * core X version of XTranslateKey always OR's in ShiftMask
337818534a1Smrg         * and LockMask for mods_rtrn, so this "fix" keeps this behavior
338818534a1Smrg         * and solves the VTS problem.
339818534a1Smrg         */
340818534a1Smrg        if ((xkb->dpy) && (xkb->dpy->xkb_info) &&
341818534a1Smrg            (xkb->dpy->xkb_info->
342818534a1Smrg             xlib_ctrls & XkbLC_AlwaysConsumeShiftAndLock)) {
343818534a1Smrg            *mods_rtrn |= (ShiftMask | LockMask);
344818534a1Smrg        }
3451ab64890Smrg    }
346818534a1Smrg    return (syms[col] != NoSymbol);
3471ab64890Smrg}
3481ab64890Smrg
3491ab64890SmrgStatus
350818534a1SmrgXkbRefreshKeyboardMapping(register XkbMapNotifyEvent * event)
3511ab64890Smrg{
3521ab64890Smrg    Display *dpy = event->display;
3531ab64890Smrg    XkbInfoPtr xkbi;
3541ab64890Smrg
3551ab64890Smrg    if (_XkbUnavailable(dpy)) {
356818534a1Smrg        _XRefreshKeyboardMapping((XMappingEvent *) event);
357818534a1Smrg        return Success;
3581ab64890Smrg    }
359818534a1Smrg    xkbi = dpy->xkb_info;
3601ab64890Smrg
361818534a1Smrg    if (((event->type & 0x7f) - xkbi->codes->first_event) != XkbEventCode)
362818534a1Smrg        return BadMatch;
363818534a1Smrg    if (event->xkb_type == XkbNewKeyboardNotify) {
364818534a1Smrg        _XkbReloadDpy(dpy);
365818534a1Smrg        return Success;
3661ab64890Smrg    }
367818534a1Smrg    if (event->xkb_type == XkbMapNotify) {
368818534a1Smrg        XkbMapChangesRec changes;
369818534a1Smrg        Status rtrn;
370818534a1Smrg
371818534a1Smrg        if (xkbi->flags & XkbMapPending)
372818534a1Smrg            changes = xkbi->changes;
373818534a1Smrg        else
374818534a1Smrg            bzero(&changes, sizeof(changes));
375818534a1Smrg        XkbNoteMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
376818534a1Smrg        if ((rtrn = XkbGetMapChanges(dpy, xkbi->desc, &changes)) != Success) {
3771ab64890Smrg#ifdef DEBUG
378818534a1Smrg            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
3791ab64890Smrg#endif
380818534a1Smrg            xkbi->changes = changes;
381818534a1Smrg        }
382818534a1Smrg        else if (xkbi->flags & XkbMapPending) {
383818534a1Smrg            xkbi->flags &= ~XkbMapPending;
384818534a1Smrg            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
385818534a1Smrg        }
386818534a1Smrg        return rtrn;
3871ab64890Smrg    }
3881ab64890Smrg    return BadMatch;
3891ab64890Smrg}
3901ab64890Smrg
3911ab64890Smrgint
392818534a1SmrgXRefreshKeyboardMapping(register XMappingEvent * event)
3931ab64890Smrg{
394818534a1Smrg    XkbEvent *xkbevent = (XkbEvent *) event;
3951ab64890Smrg    Display *dpy = event->display;
3961ab64890Smrg    XkbMapChangesRec changes;
3971ab64890Smrg    XkbInfoPtr xkbi;
3981ab64890Smrg
3991ab64890Smrg    /* always do this for input methods, which still use the old keymap */
4001ab64890Smrg    (void) _XRefreshKeyboardMapping(event);
4011ab64890Smrg
4021ab64890Smrg    if (_XkbUnavailable(dpy))
403818534a1Smrg        return 1;
4041ab64890Smrg
4051ab64890Smrg    xkbi = dpy->xkb_info;
4061ab64890Smrg
407818534a1Smrg    if (((event->type & 0x7f) - xkbi->codes->first_event) == XkbEventCode)
408818534a1Smrg        return XkbRefreshKeyboardMapping(&xkbevent->map);
4091ab64890Smrg
410818534a1Smrg    if (xkbi->flags & XkbXlibNewKeyboard) {
411818534a1Smrg        _XkbReloadDpy(dpy);
412818534a1Smrg        return 1;
4131ab64890Smrg    }
4141ab64890Smrg
415818534a1Smrg    if ((xkbi->flags & XkbMapPending) || (event->request == MappingKeyboard)) {
416818534a1Smrg        if (xkbi->flags & XkbMapPending) {
417818534a1Smrg            changes = xkbi->changes;
418818534a1Smrg            _XkbNoteCoreMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
419818534a1Smrg        }
420818534a1Smrg        else {
421818534a1Smrg            bzero(&changes, sizeof(changes));
422818534a1Smrg            changes.changed = XkbKeySymsMask;
423818534a1Smrg            if (xkbi->desc->min_key_code < xkbi->desc->max_key_code) {
424818534a1Smrg                changes.first_key_sym = xkbi->desc->min_key_code;
425818534a1Smrg                changes.num_key_syms = xkbi->desc->max_key_code -
426818534a1Smrg                    xkbi->desc->min_key_code + 1;
427818534a1Smrg            }
428818534a1Smrg            else {
429818534a1Smrg                changes.first_key_sym = event->first_keycode;
430818534a1Smrg                changes.num_key_syms = event->count;
431818534a1Smrg            }
432818534a1Smrg        }
433818534a1Smrg
434818534a1Smrg        if (XkbGetMapChanges(dpy, xkbi->desc, &changes) != Success) {
4351ab64890Smrg#ifdef DEBUG
436818534a1Smrg            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
437818534a1Smrg            if (changes.changed & XkbKeyTypesMask) {
438818534a1Smrg                int first = changes.first_type;
439818534a1Smrg                int last = changes.first_type + changes.num_types - 1;
440818534a1Smrg
441818534a1Smrg                fprintf(stderr, "       types:  %d..%d\n", first, last);
442818534a1Smrg            }
443818534a1Smrg            if (changes.changed & XkbKeySymsMask) {
444818534a1Smrg                int first = changes.first_key_sym;
445818534a1Smrg                int last = changes.first_key_sym + changes.num_key_syms - 1;
446818534a1Smrg
447818534a1Smrg                fprintf(stderr, "     symbols:  %d..%d\n", first, last);
448818534a1Smrg            }
449818534a1Smrg            if (changes.changed & XkbKeyActionsMask) {
450818534a1Smrg                int first = changes.first_key_act;
451818534a1Smrg                int last = changes.first_key_act + changes.num_key_acts - 1;
452818534a1Smrg
453818534a1Smrg                fprintf(stderr, "     acts:  %d..%d\n", first, last);
454818534a1Smrg            }
455818534a1Smrg            if (changes.changed & XkbKeyBehaviorsMask) {
456818534a1Smrg                int first = changes.first_key_behavior;
457818534a1Smrg                int last = first + changes.num_key_behaviors - 1;
458818534a1Smrg
459818534a1Smrg                fprintf(stderr, "   behaviors:  %d..%d\n", first, last);
460818534a1Smrg            }
461818534a1Smrg            if (changes.changed & XkbVirtualModsMask) {
462818534a1Smrg                fprintf(stderr, "virtual mods: 0x%04x\n", changes.vmods);
463818534a1Smrg            }
464818534a1Smrg            if (changes.changed & XkbExplicitComponentsMask) {
465818534a1Smrg                int first = changes.first_key_explicit;
466818534a1Smrg                int last = first + changes.num_key_explicit - 1;
467818534a1Smrg
468818534a1Smrg                fprintf(stderr, "    explicit:  %d..%d\n", first, last);
469818534a1Smrg            }
4701ab64890Smrg#endif
471818534a1Smrg        }
472818534a1Smrg        LockDisplay(dpy);
473818534a1Smrg        if (xkbi->flags & XkbMapPending) {
474818534a1Smrg            xkbi->flags &= ~XkbMapPending;
475818534a1Smrg            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
476818534a1Smrg        }
477818534a1Smrg        UnlockDisplay(dpy);
4781ab64890Smrg    }
479818534a1Smrg    if (event->request == MappingModifier) {
480818534a1Smrg        LockDisplay(dpy);
481818534a1Smrg        if (xkbi->desc->map->modmap) {
482818534a1Smrg            _XkbFree(xkbi->desc->map->modmap);
483818534a1Smrg            xkbi->desc->map->modmap = NULL;
484818534a1Smrg        }
485818534a1Smrg        if (dpy->key_bindings) {
486818534a1Smrg            register struct _XKeytrans *p;
487818534a1Smrg
488818534a1Smrg            for (p = dpy->key_bindings; p; p = p->next) {
489818534a1Smrg                register int i;
490818534a1Smrg
491818534a1Smrg                p->state = 0;
492818534a1Smrg                if (p->mlen > 0) {
493818534a1Smrg                    for (i = 0; i < p->mlen; i++) {
494818534a1Smrg                        p->state |= XkbKeysymToModifiers(dpy, p->modifiers[i]);
495818534a1Smrg                    }
496818534a1Smrg                    if (p->state)
497818534a1Smrg                        p->state &= AllMods;
498818534a1Smrg                    else
499818534a1Smrg                        p->state = AnyModifier;
500818534a1Smrg                }
501818534a1Smrg            }
502818534a1Smrg        }
503818534a1Smrg        UnlockDisplay(dpy);
5041ab64890Smrg    }
5051ab64890Smrg    return 1;
5061ab64890Smrg}
5071ab64890Smrg
5081ab64890Smrgstatic int
5091ab64890Smrg_XkbLoadDpy(Display *dpy)
5101ab64890Smrg{
5111ab64890Smrg    XkbInfoPtr xkbi;
512818534a1Smrg    unsigned query, oldEvents;
5131ab64890Smrg    XkbDescRec *desc;
5141ab64890Smrg
515818534a1Smrg    if (!XkbUseExtension(dpy, NULL, NULL))
516818534a1Smrg        return 0;
5171ab64890Smrg
5181ab64890Smrg    xkbi = dpy->xkb_info;
5191ab64890Smrg    query = XkbAllClientInfoMask;
520818534a1Smrg    desc = XkbGetMap(dpy, query, XkbUseCoreKbd);
5211ab64890Smrg    if (!desc) {
5221ab64890Smrg#ifdef DEBUG
523818534a1Smrg        fprintf(stderr, "Warning! XkbGetMap failed!\n");
5241ab64890Smrg#endif
525818534a1Smrg        return 0;
5261ab64890Smrg    }
5271ab64890Smrg    LockDisplay(dpy);
5281ab64890Smrg    xkbi->desc = desc;
5291ab64890Smrg
5301ab64890Smrg    UnlockDisplay(dpy);
531818534a1Smrg    oldEvents = xkbi->selected_events;
532818534a1Smrg    if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards)) {
533818534a1Smrg        XkbSelectEventDetails(dpy, xkbi->desc->device_spec,
534818534a1Smrg                              XkbNewKeyboardNotify,
535818534a1Smrg                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask,
536818534a1Smrg                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask);
5371ab64890Smrg    }
538818534a1Smrg    XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
539818534a1Smrg                          XkbAllClientInfoMask, XkbAllClientInfoMask);
5401ab64890Smrg    LockDisplay(dpy);
541818534a1Smrg    xkbi->selected_events = oldEvents;
5421ab64890Smrg    UnlockDisplay(dpy);
5431ab64890Smrg    return 1;
5441ab64890Smrg}
5451ab64890Smrg
5461ab64890Smrgvoid
5471ab64890Smrg_XkbReloadDpy(Display *dpy)
5481ab64890Smrg{
5491ab64890Smrg    XkbInfoPtr xkbi;
5501ab64890Smrg    XkbDescRec *desc;
551818534a1Smrg    unsigned oldDeviceID;
5521ab64890Smrg
5531ab64890Smrg    if (_XkbUnavailable(dpy))
554818534a1Smrg        return;
5551ab64890Smrg
5561ab64890Smrg    xkbi = dpy->xkb_info;
5571ab64890Smrg    LockDisplay(dpy);
5581ab64890Smrg    if (xkbi->desc) {
559818534a1Smrg        oldDeviceID = xkbi->desc->device_spec;
560818534a1Smrg        XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, True);
561818534a1Smrg        xkbi->desc = NULL;
562818534a1Smrg        xkbi->flags &= ~(XkbMapPending | XkbXlibNewKeyboard);
563818534a1Smrg        xkbi->changes.changed = 0;
5641ab64890Smrg    }
565818534a1Smrg    else
566818534a1Smrg        oldDeviceID = XkbUseCoreKbd;
5671ab64890Smrg    UnlockDisplay(dpy);
568818534a1Smrg    desc = XkbGetMap(dpy, XkbAllClientInfoMask, XkbUseCoreKbd);
5691ab64890Smrg    if (!desc)
570818534a1Smrg        return;
5711ab64890Smrg    LockDisplay(dpy);
5721ab64890Smrg    xkbi->desc = desc;
5731ab64890Smrg    UnlockDisplay(dpy);
5741ab64890Smrg
575818534a1Smrg    if (desc->device_spec != oldDeviceID) {
576818534a1Smrg        /* transfer(?) event masks here */
5771ab64890Smrg#ifdef NOTYET
578818534a1Smrg        unsigned oldEvents;
579818534a1Smrg
580818534a1Smrg        oldEvents = xkbi->selected_events;
581818534a1Smrg        XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
582818534a1Smrg                              XkbAllMapComponentsMask, XkbAllClientInfoMask);
583818534a1Smrg        LockDisplay(dpy);
584818534a1Smrg        xkbi->selected_events = oldEvents;
585818534a1Smrg        UnlockDisplay(dpy);
5861ab64890Smrg#endif
5871ab64890Smrg    }
5881ab64890Smrg    return;
5891ab64890Smrg}
5901ab64890Smrg
5911ab64890Smrgint
592d7c63e31SmrgXkbTranslateKeySym(Display *dpy,
593d7c63e31Smrg                   KeySym *sym_rtrn,
594818534a1Smrg                   unsigned int mods,
595818534a1Smrg                   char *buffer,
596818534a1Smrg                   int nbytes,
597818534a1Smrg                   int *extra_rtrn)
5981ab64890Smrg{
599818534a1Smrg    register XkbInfoPtr xkb;
6001ab64890Smrg    XkbKSToMBFunc cvtr;
6011ab64890Smrg    XPointer priv;
6021ab64890Smrg    char tmp[4];
6031ab64890Smrg    int n;
6041ab64890Smrg
605818534a1Smrg    xkb = dpy->xkb_info;
6061ab64890Smrg    if (!xkb->cvt.KSToMB) {
607818534a1Smrg        _XkbGetConverters(_XkbGetCharset(), &xkb->cvt);
608818534a1Smrg        _XkbGetConverters("ISO8859-1", &xkb->latin1cvt);
6091ab64890Smrg    }
6101ab64890Smrg
6111ab64890Smrg    if (extra_rtrn)
612818534a1Smrg        *extra_rtrn = 0;
6131ab64890Smrg
614818534a1Smrg    if ((buffer == NULL) || (nbytes == 0)) {
615818534a1Smrg        buffer = tmp;
616818534a1Smrg        nbytes = 4;
6171ab64890Smrg    }
6181ab64890Smrg
6191ab64890Smrg    /* see if symbol rebound, if so, return that string. */
620818534a1Smrg    n = XkbLookupKeyBinding(dpy, *sym_rtrn, mods, buffer, nbytes, extra_rtrn);
6211ab64890Smrg    if (n)
6221ab64890Smrg        return n;
6231ab64890Smrg
624818534a1Smrg    if (nbytes > 0)
625818534a1Smrg        buffer[0] = '\0';
6261ab64890Smrg
627818534a1Smrg    if (xkb->cvt.KSToUpper && (mods & LockMask)) {
628818534a1Smrg        *sym_rtrn = (*xkb->cvt.KSToUpper) (*sym_rtrn);
6291ab64890Smrg    }
6301ab64890Smrg    if (xkb->xlib_ctrls & XkbLC_ForceLatin1Lookup) {
631818534a1Smrg        cvtr = xkb->latin1cvt.KSToMB;
632818534a1Smrg        priv = xkb->latin1cvt.KSToMBPriv;
633818534a1Smrg    }
634818534a1Smrg    else {
635818534a1Smrg        cvtr = xkb->cvt.KSToMB;
636818534a1Smrg        priv = xkb->cvt.KSToMBPriv;
6371ab64890Smrg    }
6381ab64890Smrg
639818534a1Smrg    n = (*cvtr) (priv, *sym_rtrn, buffer, nbytes, extra_rtrn);
640818534a1Smrg
641818534a1Smrg    if ((!xkb->cvt.KSToUpper) && (mods & LockMask)) {
642818534a1Smrg        register int i;
643818534a1Smrg        int change;
644818534a1Smrg
645818534a1Smrg        for (i = change = 0; i < n; i++) {
646818534a1Smrg            char ch = toupper(buffer[i]);
647818534a1Smrg            change = (change || (buffer[i] != ch));
648818534a1Smrg            buffer[i] = ch;
649818534a1Smrg        }
650818534a1Smrg        if (change) {
651818534a1Smrg            if (n == 1)
652818534a1Smrg                *sym_rtrn =
653818534a1Smrg                    (*xkb->cvt.MBToKS) (xkb->cvt.MBToKSPriv, buffer, n, NULL);
654818534a1Smrg            else
655818534a1Smrg                *sym_rtrn = NoSymbol;
656818534a1Smrg        }
6571ab64890Smrg    }
6581ab64890Smrg
659818534a1Smrg    if (mods & ControlMask) {
660818534a1Smrg        if (n == 1) {
661818534a1Smrg            buffer[0] = XkbToControl(buffer[0]);
662818534a1Smrg            if (nbytes > 1)
663818534a1Smrg                buffer[1] = '\0';
664818534a1Smrg            return 1;
665818534a1Smrg        }
666818534a1Smrg        if (nbytes > 0)
667818534a1Smrg            buffer[0] = '\0';
668818534a1Smrg        return 0;
6691ab64890Smrg    }
6701ab64890Smrg    return n;
6711ab64890Smrg}
6721ab64890Smrg
6731ab64890Smrgint
674818534a1SmrgXLookupString(register XKeyEvent *event,
675818534a1Smrg              char *buffer,
676818534a1Smrg              int nbytes,
677818534a1Smrg              KeySym *keysym,
678818534a1Smrg              XComposeStatus *status)
6791ab64890Smrg{
680818534a1Smrg    KeySym dummy;
6811ab64890Smrg    int rtrnLen;
6821ab64890Smrg    unsigned int new_mods;
6831ab64890Smrg    Display *dpy = event->display;
6841ab64890Smrg
685818534a1Smrg    if (keysym == NULL)
686818534a1Smrg        keysym = &dummy;
687818534a1Smrg    if (!XkbLookupKeySym(dpy, event->keycode, event->state, &new_mods, keysym))
688818534a1Smrg        return 0;
689818534a1Smrg    new_mods = (event->state & (~new_mods));
6901ab64890Smrg
6911ab64890Smrg    /* find the group where a symbol can be converted to control one */
692818534a1Smrg    if (new_mods & ControlMask && *keysym > 0x7F &&
693818534a1Smrg        (dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
694818534a1Smrg        XKeyEvent tmp_ev = *event;
695818534a1Smrg        KeySym tmp_keysym;
696818534a1Smrg        unsigned int tmp_new_mods;
697818534a1Smrg
698818534a1Smrg        if (_XkbUnavailable(dpy)) {
699818534a1Smrg            tmp_ev.state = event->state ^ dpy->mode_switch;
7001ab64890Smrg            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
7011ab64890Smrg                                &tmp_new_mods, &tmp_keysym) &&
702818534a1Smrg                tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
7031ab64890Smrg                *keysym = tmp_keysym;
7041ab64890Smrg            }
705818534a1Smrg        }
706818534a1Smrg        else {
7071ab64890Smrg            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
7081ab64890Smrg            int i;
709818534a1Smrg
7101ab64890Smrg            for (i = 0; i < n; i++) {
7111ab64890Smrg                if (XkbGroupForCoreState(event->state) == i)
7121ab64890Smrg                    continue;
713818534a1Smrg                tmp_ev.state = XkbBuildCoreState(tmp_ev.state, i);
7141ab64890Smrg                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
715818534a1Smrg                                    &tmp_new_mods, &tmp_keysym) &&
716818534a1Smrg                    tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
7171ab64890Smrg                    *keysym = tmp_keysym;
718818534a1Smrg                    new_mods = (event->state & (~tmp_new_mods));
7191ab64890Smrg                    break;
7201ab64890Smrg                }
7211ab64890Smrg            }
7221ab64890Smrg        }
72361b2299dSmrg    }
7241ab64890Smrg
7251ab64890Smrg    /* We *should* use the new_mods (which does not contain any modifiers */
7261ab64890Smrg    /* that were used to compute the symbol here, but pre-XKB XLookupString */
7271ab64890Smrg    /* did not and we have to remain compatible.  Sigh. */
7281ab64890Smrg    if (_XkbUnavailable(dpy) ||
729818534a1Smrg        (dpy->xkb_info->xlib_ctrls & XkbLC_ConsumeLookupMods) == 0)
730818534a1Smrg        new_mods = event->state;
7311ab64890Smrg
732818534a1Smrg    rtrnLen = XkbLookupKeyBinding(dpy, *keysym, new_mods, buffer, nbytes, NULL);
733818534a1Smrg    if (rtrnLen > 0)
734818534a1Smrg        return rtrnLen;
7351ab64890Smrg
736818534a1Smrg    return XkbTranslateKeySym(dpy, keysym, new_mods, buffer, nbytes, NULL);
7371ab64890Smrg}
7381ab64890Smrg
7391ab64890Smrg
7401ab64890Smrgint
741818534a1SmrgXkbLookupKeyBinding(Display *dpy,
742818534a1Smrg                    register KeySym sym,
743818534a1Smrg                    unsigned int mods,
744818534a1Smrg                    char *buffer,
745818534a1Smrg                    int nbytes,
746818534a1Smrg                    int *extra_rtrn)
7471ab64890Smrg{
74861b2299dSmrg    register struct _XKeytrans *p;
7491ab64890Smrg
7501ab64890Smrg    if (extra_rtrn)
751818534a1Smrg        *extra_rtrn = 0;
7521ab64890Smrg    for (p = dpy->key_bindings; p; p = p->next) {
753818534a1Smrg        if (((mods & AllMods) == p->state) && (sym == p->key)) {
754818534a1Smrg            int tmp = p->len;
755818534a1Smrg
756818534a1Smrg            if (tmp > nbytes) {
757818534a1Smrg                if (extra_rtrn)
758818534a1Smrg                    *extra_rtrn = (tmp - nbytes);
759818534a1Smrg                tmp = nbytes;
760818534a1Smrg            }
7619c019ec5Smaya            memcpy(buffer, p->string, (size_t) tmp);
762818534a1Smrg            if (tmp < nbytes)
763818534a1Smrg                buffer[tmp] = '\0';
764818534a1Smrg            return tmp;
765818534a1Smrg        }
7661ab64890Smrg    }
7671ab64890Smrg    return 0;
7681ab64890Smrg}
7691ab64890Smrg
7701ab64890Smrgchar
771818534a1SmrgXkbToControl(char ch)
7721ab64890Smrg{
7731ab64890Smrg    register char c = ch;
77461b2299dSmrg
775818534a1Smrg    if ((c >= '@' && c < '\177') || c == ' ')
776818534a1Smrg        c &= 0x1F;
777818534a1Smrg    else if (c == '2')
778818534a1Smrg        c = '\000';
779818534a1Smrg    else if (c >= '3' && c <= '7')
780818534a1Smrg        c -= ('3' - '\033');
781818534a1Smrg    else if (c == '8')
782818534a1Smrg        c = '\177';
783818534a1Smrg    else if (c == '/')
784818534a1Smrg        c = '_' & 0x1F;
7851ab64890Smrg    return c;
7861ab64890Smrg}
787