XKBBind.c revision 9c019ec5
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) {
116818534a1Smrg        int lastSym, tmp, nGrp;
117818534a1Smrg
118818534a1Smrg        lastSym = 3;
119818534a1Smrg        nGrp = XkbKeyNumGroups(xkb, kc);
120818534a1Smrg        if ((nGrp > 0) &&
121818534a1Smrg            ((tmp = XkbKeyGroupWidth(xkb, kc, XkbGroup1Index)) > 2)) {
122818534a1Smrg            if (col <= (lastSym + tmp - 2))
123818534a1Smrg                return XkbKeycodeToKeysym(dpy, kc, XkbGroup1Index,
124818534a1Smrg                                          col - lastSym + 2);
125818534a1Smrg            lastSym += tmp - 2;
126818534a1Smrg        }
127818534a1Smrg        if ((nGrp > 1) &&
128818534a1Smrg            ((tmp = XkbKeyGroupWidth(xkb, kc, XkbGroup2Index)) > 2)) {
129818534a1Smrg            if (col <= (lastSym + tmp - 2))
130818534a1Smrg                return XkbKeycodeToKeysym(dpy, kc, XkbGroup2Index,
131818534a1Smrg                                          col - lastSym + 2);
132818534a1Smrg            lastSym += tmp - 2;
133818534a1Smrg        }
134818534a1Smrg        if (nGrp > 2) {
135818534a1Smrg            tmp = XkbKeyGroupWidth(xkb, kc, XkbGroup3Index);
136818534a1Smrg            if (col <= lastSym + tmp)
137818534a1Smrg                return XkbKeycodeToKeysym(dpy, kc, XkbGroup3Index,
138818534a1Smrg                                          col - lastSym);
139818534a1Smrg            lastSym += tmp;
140818534a1Smrg        }
141818534a1Smrg        if (nGrp > 3) {
142818534a1Smrg            tmp = XkbKeyGroupWidth(xkb, kc, XkbGroup4Index);
143818534a1Smrg            if (col <= lastSym + tmp)
144818534a1Smrg                return XkbKeycodeToKeysym(dpy, kc, XkbGroup4Index,
145818534a1Smrg                                          col - lastSym);
146818534a1Smrg        }
147818534a1Smrg        return NoSymbol;
1481ab64890Smrg    }
149818534a1Smrg    return XkbKeycodeToKeysym(dpy, kc, (col >> 1), (col & 1));
1501ab64890Smrg}
1511ab64890Smrg
1521ab64890SmrgKeyCode
1531ab64890SmrgXKeysymToKeycode(Display *dpy, KeySym ks)
1541ab64890Smrg{
1551ab64890Smrg    register int i, j, gotOne;
1561ab64890Smrg
1571ab64890Smrg    if (_XkbUnavailable(dpy))
158818534a1Smrg        return _XKeysymToKeycode(dpy, ks);
159818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
1601ab64890Smrg
161818534a1Smrg    j = 0;
1621ab64890Smrg    do {
163818534a1Smrg        register XkbDescRec *xkb = dpy->xkb_info->desc;
164818534a1Smrg        gotOne = 0;
165818534a1Smrg        for (i = dpy->min_keycode; i <= dpy->max_keycode; i++) {
166818534a1Smrg            if (j < (int) XkbKeyNumSyms(xkb, i)) {
167818534a1Smrg                gotOne = 1;
168818534a1Smrg                if ((XkbKeySym(xkb, i, j) == ks))
169818534a1Smrg                    return i;
170818534a1Smrg            }
171818534a1Smrg        }
172818534a1Smrg        j++;
1731ab64890Smrg    } while (gotOne);
1741ab64890Smrg    return 0;
1751ab64890Smrg}
1761ab64890Smrg
1771ab64890Smrgstatic int
1781ab64890Smrg_XkbComputeModmap(Display *dpy)
1791ab64890Smrg{
180818534a1Smrg    register XkbDescPtr xkb;
1811ab64890Smrg
182818534a1Smrg    xkb = dpy->xkb_info->desc;
183818534a1Smrg    if (XkbGetUpdatedMap(dpy, XkbModifierMapMask, xkb) == Success)
184818534a1Smrg        return 1;
1851ab64890Smrg    return 0;
1861ab64890Smrg}
1871ab64890Smrg
1881ab64890Smrgunsigned
189818534a1SmrgXkbKeysymToModifiers(Display *dpy, KeySym ks)
1901ab64890Smrg{
1911ab64890Smrg    XkbDescRec *xkb;
192818534a1Smrg    register int i, j;
1931ab64890Smrg    register KeySym *pSyms;
1941ab64890Smrg    CARD8 mods;
1951ab64890Smrg
1961ab64890Smrg    if (_XkbUnavailable(dpy))
197818534a1Smrg        return _XKeysymToModifiers(dpy, ks);
198818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
199818534a1Smrg
200818534a1Smrg    if (_XkbNeedModmap(dpy->xkb_info) && (!_XkbComputeModmap(dpy)))
201818534a1Smrg        return _XKeysymToModifiers(dpy, ks);
202818534a1Smrg
203818534a1Smrg    xkb = dpy->xkb_info->desc;
204818534a1Smrg    mods = 0;
205818534a1Smrg    for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
206818534a1Smrg        pSyms = XkbKeySymsPtr(xkb, i);
207818534a1Smrg        for (j = XkbKeyNumSyms(xkb, i) - 1; j >= 0; j--) {
208818534a1Smrg            if (pSyms[j] == ks) {
209818534a1Smrg                mods |= xkb->map->modmap[i];
210818534a1Smrg                break;
211818534a1Smrg            }
212818534a1Smrg        }
2131ab64890Smrg    }
2141ab64890Smrg    return mods;
2151ab64890Smrg}
2161ab64890Smrg
2171ab64890SmrgKeySym
218818534a1SmrgXLookupKeysym(register XKeyEvent * event, int col)
2191ab64890Smrg{
2201ab64890Smrg    Display *dpy = event->display;
221818534a1Smrg
2221ab64890Smrg    if (_XkbUnavailable(dpy))
223818534a1Smrg        return _XLookupKeysym(event, col);
224818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
2251ab64890Smrg    return XKeycodeToKeysym(dpy, event->keycode, col);
2261ab64890Smrg}
2271ab64890Smrg
2281ab64890Smrg   /*
22961b2299dSmrg    * Not a public entry point -- XkbTranslateKey is an obsolete name
23061b2299dSmrg    * that is preserved here so that functions linked against the old
2311ab64890Smrg    * version will continue to work in a shared library environment.
2321ab64890Smrg    */
2331ab64890Smrgint
234818534a1SmrgXkbTranslateKey(register Display *dpy,
235818534a1Smrg                KeyCode key,
236818534a1Smrg                register unsigned int mods,
237818534a1Smrg                unsigned int *mods_rtrn,
238818534a1Smrg                KeySym *keysym_rtrn);
239818534a1Smrg
2401ab64890Smrgint
241818534a1SmrgXkbTranslateKey(register Display *dpy,
242818534a1Smrg                KeyCode key,
243818534a1Smrg                register unsigned int mods,
244818534a1Smrg                unsigned int *mods_rtrn,
245818534a1Smrg                KeySym *keysym_rtrn)
2461ab64890Smrg{
247818534a1Smrg    return XkbLookupKeySym(dpy, key, mods, mods_rtrn, keysym_rtrn);
2481ab64890Smrg}
2491ab64890Smrg
2501ab64890SmrgBool
251818534a1SmrgXkbLookupKeySym(register Display *dpy,
252818534a1Smrg                KeyCode key,
253818534a1Smrg                register unsigned int mods,
254818534a1Smrg                unsigned int *mods_rtrn,
255818534a1Smrg                KeySym *keysym_rtrn)
2561ab64890Smrg{
2571ab64890Smrg    if (_XkbUnavailable(dpy))
258818534a1Smrg        return _XTranslateKey(dpy, key, mods, mods_rtrn, keysym_rtrn);
259818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
260818534a1Smrg    return XkbTranslateKeyCode(dpy->xkb_info->desc, key, mods, mods_rtrn,
261818534a1Smrg                               keysym_rtrn);
2621ab64890Smrg}
2631ab64890Smrg
2641ab64890SmrgBool
265818534a1SmrgXkbTranslateKeyCode(register XkbDescPtr xkb,
266818534a1Smrg                    KeyCode key,
267818534a1Smrg                    register unsigned int mods,
268818534a1Smrg                    unsigned int *mods_rtrn,
269818534a1Smrg                    KeySym *keysym_rtrn)
2701ab64890Smrg{
2711ab64890Smrg    XkbKeyTypeRec *type;
272818534a1Smrg    int col, nKeyGroups;
273818534a1Smrg    unsigned preserve, effectiveGroup;
2741ab64890Smrg    KeySym *syms;
2751ab64890Smrg
276818534a1Smrg    if (mods_rtrn != NULL)
277818534a1Smrg        *mods_rtrn = 0;
2781ab64890Smrg
279818534a1Smrg    nKeyGroups = XkbKeyNumGroups(xkb, key);
280818534a1Smrg    if ((!XkbKeycodeInRange(xkb, key)) || (nKeyGroups == 0)) {
281818534a1Smrg        if (keysym_rtrn != NULL)
282818534a1Smrg            *keysym_rtrn = NoSymbol;
283818534a1Smrg        return False;
2841ab64890Smrg    }
2851ab64890Smrg
286818534a1Smrg    syms = XkbKeySymsPtr(xkb, key);
2871ab64890Smrg
2881ab64890Smrg    /* find the offset of the effective group */
2891ab64890Smrg    col = 0;
290818534a1Smrg    effectiveGroup = XkbGroupForCoreState(mods);
291818534a1Smrg    if (effectiveGroup >= nKeyGroups) {
292818534a1Smrg        unsigned groupInfo = XkbKeyGroupInfo(xkb, key);
293818534a1Smrg
294818534a1Smrg        switch (XkbOutOfRangeGroupAction(groupInfo)) {
295818534a1Smrg        default:
296818534a1Smrg            effectiveGroup %= nKeyGroups;
297818534a1Smrg            break;
298818534a1Smrg        case XkbClampIntoRange:
299818534a1Smrg            effectiveGroup = nKeyGroups - 1;
300818534a1Smrg            break;
301818534a1Smrg        case XkbRedirectIntoRange:
302818534a1Smrg            effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
303818534a1Smrg            if (effectiveGroup >= nKeyGroups)
304818534a1Smrg                effectiveGroup = 0;
305818534a1Smrg            break;
306818534a1Smrg        }
3071ab64890Smrg    }
308818534a1Smrg    col = effectiveGroup * XkbKeyGroupsWidth(xkb, key);
309818534a1Smrg    type = XkbKeyKeyType(xkb, key, effectiveGroup);
310818534a1Smrg
311818534a1Smrg    preserve = 0;
312818534a1Smrg    if (type->map) {  /* find the column (shift level) within the group */
313818534a1Smrg        register int i;
314818534a1Smrg        register XkbKTMapEntryPtr entry;
315818534a1Smrg
316818534a1Smrg        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
317818534a1Smrg            if ((entry->active) &&
318818534a1Smrg                ((mods & type->mods.mask) == entry->mods.mask)) {
319818534a1Smrg                col += entry->level;
320818534a1Smrg                if (type->preserve)
321818534a1Smrg                    preserve = type->preserve[i].mask;
322818534a1Smrg                break;
323818534a1Smrg            }
324818534a1Smrg        }
3251ab64890Smrg    }
3261ab64890Smrg
327818534a1Smrg    if (keysym_rtrn != NULL)
328818534a1Smrg        *keysym_rtrn = syms[col];
3291ab64890Smrg    if (mods_rtrn) {
330818534a1Smrg        *mods_rtrn = type->mods.mask & (~preserve);
331818534a1Smrg        /* The Motif VTS doesn't get the help callback called if help
332818534a1Smrg         * is bound to Shift+<whatever>, and it appears as though it
333818534a1Smrg         * is XkbTranslateKeyCode that is causing the problem.  The
334818534a1Smrg         * core X version of XTranslateKey always OR's in ShiftMask
335818534a1Smrg         * and LockMask for mods_rtrn, so this "fix" keeps this behavior
336818534a1Smrg         * and solves the VTS problem.
337818534a1Smrg         */
338818534a1Smrg        if ((xkb->dpy) && (xkb->dpy->xkb_info) &&
339818534a1Smrg            (xkb->dpy->xkb_info->
340818534a1Smrg             xlib_ctrls & XkbLC_AlwaysConsumeShiftAndLock)) {
341818534a1Smrg            *mods_rtrn |= (ShiftMask | LockMask);
342818534a1Smrg        }
3431ab64890Smrg    }
344818534a1Smrg    return (syms[col] != NoSymbol);
3451ab64890Smrg}
3461ab64890Smrg
3471ab64890SmrgStatus
348818534a1SmrgXkbRefreshKeyboardMapping(register XkbMapNotifyEvent * event)
3491ab64890Smrg{
3501ab64890Smrg    Display *dpy = event->display;
3511ab64890Smrg    XkbInfoPtr xkbi;
3521ab64890Smrg
3531ab64890Smrg    if (_XkbUnavailable(dpy)) {
354818534a1Smrg        _XRefreshKeyboardMapping((XMappingEvent *) event);
355818534a1Smrg        return Success;
3561ab64890Smrg    }
357818534a1Smrg    xkbi = dpy->xkb_info;
3581ab64890Smrg
359818534a1Smrg    if (((event->type & 0x7f) - xkbi->codes->first_event) != XkbEventCode)
360818534a1Smrg        return BadMatch;
361818534a1Smrg    if (event->xkb_type == XkbNewKeyboardNotify) {
362818534a1Smrg        _XkbReloadDpy(dpy);
363818534a1Smrg        return Success;
3641ab64890Smrg    }
365818534a1Smrg    if (event->xkb_type == XkbMapNotify) {
366818534a1Smrg        XkbMapChangesRec changes;
367818534a1Smrg        Status rtrn;
368818534a1Smrg
369818534a1Smrg        if (xkbi->flags & XkbMapPending)
370818534a1Smrg            changes = xkbi->changes;
371818534a1Smrg        else
372818534a1Smrg            bzero(&changes, sizeof(changes));
373818534a1Smrg        XkbNoteMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
374818534a1Smrg        if ((rtrn = XkbGetMapChanges(dpy, xkbi->desc, &changes)) != Success) {
3751ab64890Smrg#ifdef DEBUG
376818534a1Smrg            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
3771ab64890Smrg#endif
378818534a1Smrg            xkbi->changes = changes;
379818534a1Smrg        }
380818534a1Smrg        else if (xkbi->flags & XkbMapPending) {
381818534a1Smrg            xkbi->flags &= ~XkbMapPending;
382818534a1Smrg            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
383818534a1Smrg        }
384818534a1Smrg        return rtrn;
3851ab64890Smrg    }
3861ab64890Smrg    return BadMatch;
3871ab64890Smrg}
3881ab64890Smrg
3891ab64890Smrgint
390818534a1SmrgXRefreshKeyboardMapping(register XMappingEvent * event)
3911ab64890Smrg{
392818534a1Smrg    XkbEvent *xkbevent = (XkbEvent *) event;
3931ab64890Smrg    Display *dpy = event->display;
3941ab64890Smrg    XkbMapChangesRec changes;
3951ab64890Smrg    XkbInfoPtr xkbi;
3961ab64890Smrg
3971ab64890Smrg    /* always do this for input methods, which still use the old keymap */
3981ab64890Smrg    (void) _XRefreshKeyboardMapping(event);
3991ab64890Smrg
4001ab64890Smrg    if (_XkbUnavailable(dpy))
401818534a1Smrg        return 1;
4021ab64890Smrg
4031ab64890Smrg    xkbi = dpy->xkb_info;
4041ab64890Smrg
405818534a1Smrg    if (((event->type & 0x7f) - xkbi->codes->first_event) == XkbEventCode)
406818534a1Smrg        return XkbRefreshKeyboardMapping(&xkbevent->map);
4071ab64890Smrg
408818534a1Smrg    if (xkbi->flags & XkbXlibNewKeyboard) {
409818534a1Smrg        _XkbReloadDpy(dpy);
410818534a1Smrg        return 1;
4111ab64890Smrg    }
4121ab64890Smrg
413818534a1Smrg    if ((xkbi->flags & XkbMapPending) || (event->request == MappingKeyboard)) {
414818534a1Smrg        if (xkbi->flags & XkbMapPending) {
415818534a1Smrg            changes = xkbi->changes;
416818534a1Smrg            _XkbNoteCoreMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
417818534a1Smrg        }
418818534a1Smrg        else {
419818534a1Smrg            bzero(&changes, sizeof(changes));
420818534a1Smrg            changes.changed = XkbKeySymsMask;
421818534a1Smrg            if (xkbi->desc->min_key_code < xkbi->desc->max_key_code) {
422818534a1Smrg                changes.first_key_sym = xkbi->desc->min_key_code;
423818534a1Smrg                changes.num_key_syms = xkbi->desc->max_key_code -
424818534a1Smrg                    xkbi->desc->min_key_code + 1;
425818534a1Smrg            }
426818534a1Smrg            else {
427818534a1Smrg                changes.first_key_sym = event->first_keycode;
428818534a1Smrg                changes.num_key_syms = event->count;
429818534a1Smrg            }
430818534a1Smrg        }
431818534a1Smrg
432818534a1Smrg        if (XkbGetMapChanges(dpy, xkbi->desc, &changes) != Success) {
4331ab64890Smrg#ifdef DEBUG
434818534a1Smrg            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
435818534a1Smrg            if (changes.changed & XkbKeyTypesMask) {
436818534a1Smrg                int first = changes.first_type;
437818534a1Smrg                int last = changes.first_type + changes.num_types - 1;
438818534a1Smrg
439818534a1Smrg                fprintf(stderr, "       types:  %d..%d\n", first, last);
440818534a1Smrg            }
441818534a1Smrg            if (changes.changed & XkbKeySymsMask) {
442818534a1Smrg                int first = changes.first_key_sym;
443818534a1Smrg                int last = changes.first_key_sym + changes.num_key_syms - 1;
444818534a1Smrg
445818534a1Smrg                fprintf(stderr, "     symbols:  %d..%d\n", first, last);
446818534a1Smrg            }
447818534a1Smrg            if (changes.changed & XkbKeyActionsMask) {
448818534a1Smrg                int first = changes.first_key_act;
449818534a1Smrg                int last = changes.first_key_act + changes.num_key_acts - 1;
450818534a1Smrg
451818534a1Smrg                fprintf(stderr, "     acts:  %d..%d\n", first, last);
452818534a1Smrg            }
453818534a1Smrg            if (changes.changed & XkbKeyBehaviorsMask) {
454818534a1Smrg                int first = changes.first_key_behavior;
455818534a1Smrg                int last = first + changes.num_key_behaviors - 1;
456818534a1Smrg
457818534a1Smrg                fprintf(stderr, "   behaviors:  %d..%d\n", first, last);
458818534a1Smrg            }
459818534a1Smrg            if (changes.changed & XkbVirtualModsMask) {
460818534a1Smrg                fprintf(stderr, "virtual mods: 0x%04x\n", changes.vmods);
461818534a1Smrg            }
462818534a1Smrg            if (changes.changed & XkbExplicitComponentsMask) {
463818534a1Smrg                int first = changes.first_key_explicit;
464818534a1Smrg                int last = first + changes.num_key_explicit - 1;
465818534a1Smrg
466818534a1Smrg                fprintf(stderr, "    explicit:  %d..%d\n", first, last);
467818534a1Smrg            }
4681ab64890Smrg#endif
469818534a1Smrg        }
470818534a1Smrg        LockDisplay(dpy);
471818534a1Smrg        if (xkbi->flags & XkbMapPending) {
472818534a1Smrg            xkbi->flags &= ~XkbMapPending;
473818534a1Smrg            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
474818534a1Smrg        }
475818534a1Smrg        UnlockDisplay(dpy);
4761ab64890Smrg    }
477818534a1Smrg    if (event->request == MappingModifier) {
478818534a1Smrg        LockDisplay(dpy);
479818534a1Smrg        if (xkbi->desc->map->modmap) {
480818534a1Smrg            _XkbFree(xkbi->desc->map->modmap);
481818534a1Smrg            xkbi->desc->map->modmap = NULL;
482818534a1Smrg        }
483818534a1Smrg        if (dpy->key_bindings) {
484818534a1Smrg            register struct _XKeytrans *p;
485818534a1Smrg
486818534a1Smrg            for (p = dpy->key_bindings; p; p = p->next) {
487818534a1Smrg                register int i;
488818534a1Smrg
489818534a1Smrg                p->state = 0;
490818534a1Smrg                if (p->mlen > 0) {
491818534a1Smrg                    for (i = 0; i < p->mlen; i++) {
492818534a1Smrg                        p->state |= XkbKeysymToModifiers(dpy, p->modifiers[i]);
493818534a1Smrg                    }
494818534a1Smrg                    if (p->state)
495818534a1Smrg                        p->state &= AllMods;
496818534a1Smrg                    else
497818534a1Smrg                        p->state = AnyModifier;
498818534a1Smrg                }
499818534a1Smrg            }
500818534a1Smrg        }
501818534a1Smrg        UnlockDisplay(dpy);
5021ab64890Smrg    }
5031ab64890Smrg    return 1;
5041ab64890Smrg}
5051ab64890Smrg
5061ab64890Smrgstatic int
5071ab64890Smrg_XkbLoadDpy(Display *dpy)
5081ab64890Smrg{
5091ab64890Smrg    XkbInfoPtr xkbi;
510818534a1Smrg    unsigned query, oldEvents;
5111ab64890Smrg    XkbDescRec *desc;
5121ab64890Smrg
513818534a1Smrg    if (!XkbUseExtension(dpy, NULL, NULL))
514818534a1Smrg        return 0;
5151ab64890Smrg
5161ab64890Smrg    xkbi = dpy->xkb_info;
5171ab64890Smrg    query = XkbAllClientInfoMask;
518818534a1Smrg    desc = XkbGetMap(dpy, query, XkbUseCoreKbd);
5191ab64890Smrg    if (!desc) {
5201ab64890Smrg#ifdef DEBUG
521818534a1Smrg        fprintf(stderr, "Warning! XkbGetMap failed!\n");
5221ab64890Smrg#endif
523818534a1Smrg        return 0;
5241ab64890Smrg    }
5251ab64890Smrg    LockDisplay(dpy);
5261ab64890Smrg    xkbi->desc = desc;
5271ab64890Smrg
5281ab64890Smrg    UnlockDisplay(dpy);
529818534a1Smrg    oldEvents = xkbi->selected_events;
530818534a1Smrg    if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards)) {
531818534a1Smrg        XkbSelectEventDetails(dpy, xkbi->desc->device_spec,
532818534a1Smrg                              XkbNewKeyboardNotify,
533818534a1Smrg                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask,
534818534a1Smrg                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask);
5351ab64890Smrg    }
536818534a1Smrg    XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
537818534a1Smrg                          XkbAllClientInfoMask, XkbAllClientInfoMask);
5381ab64890Smrg    LockDisplay(dpy);
539818534a1Smrg    xkbi->selected_events = oldEvents;
5401ab64890Smrg    UnlockDisplay(dpy);
5411ab64890Smrg    return 1;
5421ab64890Smrg}
5431ab64890Smrg
5441ab64890Smrgvoid
5451ab64890Smrg_XkbReloadDpy(Display *dpy)
5461ab64890Smrg{
5471ab64890Smrg    XkbInfoPtr xkbi;
5481ab64890Smrg    XkbDescRec *desc;
549818534a1Smrg    unsigned oldDeviceID;
5501ab64890Smrg
5511ab64890Smrg    if (_XkbUnavailable(dpy))
552818534a1Smrg        return;
5531ab64890Smrg
5541ab64890Smrg    xkbi = dpy->xkb_info;
5551ab64890Smrg    LockDisplay(dpy);
5561ab64890Smrg    if (xkbi->desc) {
557818534a1Smrg        oldDeviceID = xkbi->desc->device_spec;
558818534a1Smrg        XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, True);
559818534a1Smrg        xkbi->desc = NULL;
560818534a1Smrg        xkbi->flags &= ~(XkbMapPending | XkbXlibNewKeyboard);
561818534a1Smrg        xkbi->changes.changed = 0;
5621ab64890Smrg    }
563818534a1Smrg    else
564818534a1Smrg        oldDeviceID = XkbUseCoreKbd;
5651ab64890Smrg    UnlockDisplay(dpy);
566818534a1Smrg    desc = XkbGetMap(dpy, XkbAllClientInfoMask, XkbUseCoreKbd);
5671ab64890Smrg    if (!desc)
568818534a1Smrg        return;
5691ab64890Smrg    LockDisplay(dpy);
5701ab64890Smrg    xkbi->desc = desc;
5711ab64890Smrg    UnlockDisplay(dpy);
5721ab64890Smrg
573818534a1Smrg    if (desc->device_spec != oldDeviceID) {
574818534a1Smrg        /* transfer(?) event masks here */
5751ab64890Smrg#ifdef NOTYET
576818534a1Smrg        unsigned oldEvents;
577818534a1Smrg
578818534a1Smrg        oldEvents = xkbi->selected_events;
579818534a1Smrg        XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
580818534a1Smrg                              XkbAllMapComponentsMask, XkbAllClientInfoMask);
581818534a1Smrg        LockDisplay(dpy);
582818534a1Smrg        xkbi->selected_events = oldEvents;
583818534a1Smrg        UnlockDisplay(dpy);
5841ab64890Smrg#endif
5851ab64890Smrg    }
5861ab64890Smrg    return;
5871ab64890Smrg}
5881ab64890Smrg
5891ab64890Smrgint
590818534a1SmrgXkbTranslateKeySym(register Display *dpy,
591818534a1Smrg                   register KeySym *sym_rtrn,
592818534a1Smrg                   unsigned int mods,
593818534a1Smrg                   char *buffer,
594818534a1Smrg                   int nbytes,
595818534a1Smrg                   int *extra_rtrn)
5961ab64890Smrg{
597818534a1Smrg    register XkbInfoPtr xkb;
5981ab64890Smrg    XkbKSToMBFunc cvtr;
5991ab64890Smrg    XPointer priv;
6001ab64890Smrg    char tmp[4];
6011ab64890Smrg    int n;
6021ab64890Smrg
603818534a1Smrg    xkb = dpy->xkb_info;
6041ab64890Smrg    if (!xkb->cvt.KSToMB) {
605818534a1Smrg        _XkbGetConverters(_XkbGetCharset(), &xkb->cvt);
606818534a1Smrg        _XkbGetConverters("ISO8859-1", &xkb->latin1cvt);
6071ab64890Smrg    }
6081ab64890Smrg
6091ab64890Smrg    if (extra_rtrn)
610818534a1Smrg        *extra_rtrn = 0;
6111ab64890Smrg
612818534a1Smrg    if ((buffer == NULL) || (nbytes == 0)) {
613818534a1Smrg        buffer = tmp;
614818534a1Smrg        nbytes = 4;
6151ab64890Smrg    }
6161ab64890Smrg
6171ab64890Smrg    /* see if symbol rebound, if so, return that string. */
618818534a1Smrg    n = XkbLookupKeyBinding(dpy, *sym_rtrn, mods, buffer, nbytes, extra_rtrn);
6191ab64890Smrg    if (n)
6201ab64890Smrg        return n;
6211ab64890Smrg
622818534a1Smrg    if (nbytes > 0)
623818534a1Smrg        buffer[0] = '\0';
6241ab64890Smrg
625818534a1Smrg    if (xkb->cvt.KSToUpper && (mods & LockMask)) {
626818534a1Smrg        *sym_rtrn = (*xkb->cvt.KSToUpper) (*sym_rtrn);
6271ab64890Smrg    }
6281ab64890Smrg    if (xkb->xlib_ctrls & XkbLC_ForceLatin1Lookup) {
629818534a1Smrg        cvtr = xkb->latin1cvt.KSToMB;
630818534a1Smrg        priv = xkb->latin1cvt.KSToMBPriv;
631818534a1Smrg    }
632818534a1Smrg    else {
633818534a1Smrg        cvtr = xkb->cvt.KSToMB;
634818534a1Smrg        priv = xkb->cvt.KSToMBPriv;
6351ab64890Smrg    }
6361ab64890Smrg
637818534a1Smrg    n = (*cvtr) (priv, *sym_rtrn, buffer, nbytes, extra_rtrn);
638818534a1Smrg
639818534a1Smrg    if ((!xkb->cvt.KSToUpper) && (mods & LockMask)) {
640818534a1Smrg        register int i;
641818534a1Smrg        int change;
642818534a1Smrg
643818534a1Smrg        for (i = change = 0; i < n; i++) {
644818534a1Smrg            char ch = toupper(buffer[i]);
645818534a1Smrg            change = (change || (buffer[i] != ch));
646818534a1Smrg            buffer[i] = ch;
647818534a1Smrg        }
648818534a1Smrg        if (change) {
649818534a1Smrg            if (n == 1)
650818534a1Smrg                *sym_rtrn =
651818534a1Smrg                    (*xkb->cvt.MBToKS) (xkb->cvt.MBToKSPriv, buffer, n, NULL);
652818534a1Smrg            else
653818534a1Smrg                *sym_rtrn = NoSymbol;
654818534a1Smrg        }
6551ab64890Smrg    }
6561ab64890Smrg
657818534a1Smrg    if (mods & ControlMask) {
658818534a1Smrg        if (n == 1) {
659818534a1Smrg            buffer[0] = XkbToControl(buffer[0]);
660818534a1Smrg            if (nbytes > 1)
661818534a1Smrg                buffer[1] = '\0';
662818534a1Smrg            return 1;
663818534a1Smrg        }
664818534a1Smrg        if (nbytes > 0)
665818534a1Smrg            buffer[0] = '\0';
666818534a1Smrg        return 0;
6671ab64890Smrg    }
6681ab64890Smrg    return n;
6691ab64890Smrg}
6701ab64890Smrg
6711ab64890Smrgint
672818534a1SmrgXLookupString(register XKeyEvent *event,
673818534a1Smrg              char *buffer,
674818534a1Smrg              int nbytes,
675818534a1Smrg              KeySym *keysym,
676818534a1Smrg              XComposeStatus *status)
6771ab64890Smrg{
678818534a1Smrg    KeySym dummy;
6791ab64890Smrg    int rtrnLen;
6801ab64890Smrg    unsigned int new_mods;
6811ab64890Smrg    Display *dpy = event->display;
6821ab64890Smrg
683818534a1Smrg    if (keysym == NULL)
684818534a1Smrg        keysym = &dummy;
685818534a1Smrg    if (!XkbLookupKeySym(dpy, event->keycode, event->state, &new_mods, keysym))
686818534a1Smrg        return 0;
687818534a1Smrg    new_mods = (event->state & (~new_mods));
6881ab64890Smrg
6891ab64890Smrg    /* find the group where a symbol can be converted to control one */
690818534a1Smrg    if (new_mods & ControlMask && *keysym > 0x7F &&
691818534a1Smrg        (dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
692818534a1Smrg        XKeyEvent tmp_ev = *event;
693818534a1Smrg        KeySym tmp_keysym;
694818534a1Smrg        unsigned int tmp_new_mods;
695818534a1Smrg
696818534a1Smrg        if (_XkbUnavailable(dpy)) {
697818534a1Smrg            tmp_ev.state = event->state ^ dpy->mode_switch;
6981ab64890Smrg            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
6991ab64890Smrg                                &tmp_new_mods, &tmp_keysym) &&
700818534a1Smrg                tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
7011ab64890Smrg                *keysym = tmp_keysym;
7021ab64890Smrg            }
703818534a1Smrg        }
704818534a1Smrg        else {
7051ab64890Smrg            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
7061ab64890Smrg            int i;
707818534a1Smrg
7081ab64890Smrg            for (i = 0; i < n; i++) {
7091ab64890Smrg                if (XkbGroupForCoreState(event->state) == i)
7101ab64890Smrg                    continue;
711818534a1Smrg                tmp_ev.state = XkbBuildCoreState(tmp_ev.state, i);
7121ab64890Smrg                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
713818534a1Smrg                                    &tmp_new_mods, &tmp_keysym) &&
714818534a1Smrg                    tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
7151ab64890Smrg                    *keysym = tmp_keysym;
716818534a1Smrg                    new_mods = (event->state & (~tmp_new_mods));
7171ab64890Smrg                    break;
7181ab64890Smrg                }
7191ab64890Smrg            }
7201ab64890Smrg        }
72161b2299dSmrg    }
7221ab64890Smrg
7231ab64890Smrg    /* We *should* use the new_mods (which does not contain any modifiers */
7241ab64890Smrg    /* that were used to compute the symbol here, but pre-XKB XLookupString */
7251ab64890Smrg    /* did not and we have to remain compatible.  Sigh. */
7261ab64890Smrg    if (_XkbUnavailable(dpy) ||
727818534a1Smrg        (dpy->xkb_info->xlib_ctrls & XkbLC_ConsumeLookupMods) == 0)
728818534a1Smrg        new_mods = event->state;
7291ab64890Smrg
730818534a1Smrg    rtrnLen = XkbLookupKeyBinding(dpy, *keysym, new_mods, buffer, nbytes, NULL);
731818534a1Smrg    if (rtrnLen > 0)
732818534a1Smrg        return rtrnLen;
7331ab64890Smrg
734818534a1Smrg    return XkbTranslateKeySym(dpy, keysym, new_mods, buffer, nbytes, NULL);
7351ab64890Smrg}
7361ab64890Smrg
7371ab64890Smrg
7381ab64890Smrgint
739818534a1SmrgXkbLookupKeyBinding(Display *dpy,
740818534a1Smrg                    register KeySym sym,
741818534a1Smrg                    unsigned int mods,
742818534a1Smrg                    char *buffer,
743818534a1Smrg                    int nbytes,
744818534a1Smrg                    int *extra_rtrn)
7451ab64890Smrg{
74661b2299dSmrg    register struct _XKeytrans *p;
7471ab64890Smrg
7481ab64890Smrg    if (extra_rtrn)
749818534a1Smrg        *extra_rtrn = 0;
7501ab64890Smrg    for (p = dpy->key_bindings; p; p = p->next) {
751818534a1Smrg        if (((mods & AllMods) == p->state) && (sym == p->key)) {
752818534a1Smrg            int tmp = p->len;
753818534a1Smrg
754818534a1Smrg            if (tmp > nbytes) {
755818534a1Smrg                if (extra_rtrn)
756818534a1Smrg                    *extra_rtrn = (tmp - nbytes);
757818534a1Smrg                tmp = nbytes;
758818534a1Smrg            }
7599c019ec5Smaya            memcpy(buffer, p->string, (size_t) tmp);
760818534a1Smrg            if (tmp < nbytes)
761818534a1Smrg                buffer[tmp] = '\0';
762818534a1Smrg            return tmp;
763818534a1Smrg        }
7641ab64890Smrg    }
7651ab64890Smrg    return 0;
7661ab64890Smrg}
7671ab64890Smrg
7681ab64890Smrgchar
769818534a1SmrgXkbToControl(char ch)
7701ab64890Smrg{
7711ab64890Smrg    register char c = ch;
77261b2299dSmrg
773818534a1Smrg    if ((c >= '@' && c < '\177') || c == ' ')
774818534a1Smrg        c &= 0x1F;
775818534a1Smrg    else if (c == '2')
776818534a1Smrg        c = '\000';
777818534a1Smrg    else if (c >= '3' && c <= '7')
778818534a1Smrg        c -= ('3' - '\033');
779818534a1Smrg    else if (c == '8')
780818534a1Smrg        c = '\177';
781818534a1Smrg    else if (c == '/')
782818534a1Smrg        c = '_' & 0x1F;
7831ab64890Smrg    return c;
7841ab64890Smrg}
785