XKBBind.c revision d4a3aaf4
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);
225d4a3aaf4Smrg
226d4a3aaf4Smrg#ifdef __clang__
227d4a3aaf4Smrg#pragma clang diagnostic push
228d4a3aaf4Smrg#pragma clang diagnostic ignored "-Wdeprecated-declarations"
229d4a3aaf4Smrg#elif defined(__GNUC__)
230d4a3aaf4Smrg#pragma GCC diagnostic push
231d4a3aaf4Smrg#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
232d4a3aaf4Smrg#endif
2331ab64890Smrg    return XKeycodeToKeysym(dpy, event->keycode, col);
234d4a3aaf4Smrg#ifdef __clang__
235d4a3aaf4Smrg#pragma clang diagnostic pop
236d4a3aaf4Smrg#elif defined(__GNUC__)
237d4a3aaf4Smrg#pragma GCC diagnostic pop
238d4a3aaf4Smrg#endif
239d4a3aaf4Smrg
2401ab64890Smrg}
2411ab64890Smrg
2421ab64890Smrg   /*
24361b2299dSmrg    * Not a public entry point -- XkbTranslateKey is an obsolete name
24461b2299dSmrg    * that is preserved here so that functions linked against the old
2451ab64890Smrg    * version will continue to work in a shared library environment.
2461ab64890Smrg    */
2471ab64890Smrgint
248818534a1SmrgXkbTranslateKey(register Display *dpy,
249818534a1Smrg                KeyCode key,
250818534a1Smrg                register unsigned int mods,
251818534a1Smrg                unsigned int *mods_rtrn,
252818534a1Smrg                KeySym *keysym_rtrn);
253818534a1Smrg
2541ab64890Smrgint
255818534a1SmrgXkbTranslateKey(register Display *dpy,
256818534a1Smrg                KeyCode key,
257818534a1Smrg                register unsigned int mods,
258818534a1Smrg                unsigned int *mods_rtrn,
259818534a1Smrg                KeySym *keysym_rtrn)
2601ab64890Smrg{
261818534a1Smrg    return XkbLookupKeySym(dpy, key, mods, mods_rtrn, keysym_rtrn);
2621ab64890Smrg}
2631ab64890Smrg
2641ab64890SmrgBool
265818534a1SmrgXkbLookupKeySym(register Display *dpy,
266818534a1Smrg                KeyCode key,
267818534a1Smrg                register unsigned int mods,
268818534a1Smrg                unsigned int *mods_rtrn,
269818534a1Smrg                KeySym *keysym_rtrn)
2701ab64890Smrg{
2711ab64890Smrg    if (_XkbUnavailable(dpy))
272818534a1Smrg        return _XTranslateKey(dpy, key, mods, mods_rtrn, keysym_rtrn);
273818534a1Smrg    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
274818534a1Smrg    return XkbTranslateKeyCode(dpy->xkb_info->desc, key, mods, mods_rtrn,
275818534a1Smrg                               keysym_rtrn);
2761ab64890Smrg}
2771ab64890Smrg
2781ab64890SmrgBool
279818534a1SmrgXkbTranslateKeyCode(register XkbDescPtr xkb,
280818534a1Smrg                    KeyCode key,
281818534a1Smrg                    register unsigned int mods,
282818534a1Smrg                    unsigned int *mods_rtrn,
283818534a1Smrg                    KeySym *keysym_rtrn)
2841ab64890Smrg{
2851ab64890Smrg    XkbKeyTypeRec *type;
286818534a1Smrg    int col, nKeyGroups;
287818534a1Smrg    unsigned preserve, effectiveGroup;
2881ab64890Smrg    KeySym *syms;
2891ab64890Smrg
290818534a1Smrg    if (mods_rtrn != NULL)
291818534a1Smrg        *mods_rtrn = 0;
2921ab64890Smrg
293818534a1Smrg    nKeyGroups = XkbKeyNumGroups(xkb, key);
294818534a1Smrg    if ((!XkbKeycodeInRange(xkb, key)) || (nKeyGroups == 0)) {
295818534a1Smrg        if (keysym_rtrn != NULL)
296818534a1Smrg            *keysym_rtrn = NoSymbol;
297818534a1Smrg        return False;
2981ab64890Smrg    }
2991ab64890Smrg
300818534a1Smrg    syms = XkbKeySymsPtr(xkb, key);
3011ab64890Smrg
3021ab64890Smrg    /* find the offset of the effective group */
3031ab64890Smrg    col = 0;
304818534a1Smrg    effectiveGroup = XkbGroupForCoreState(mods);
305818534a1Smrg    if (effectiveGroup >= nKeyGroups) {
306818534a1Smrg        unsigned groupInfo = XkbKeyGroupInfo(xkb, key);
307818534a1Smrg
308818534a1Smrg        switch (XkbOutOfRangeGroupAction(groupInfo)) {
309818534a1Smrg        default:
310818534a1Smrg            effectiveGroup %= nKeyGroups;
311818534a1Smrg            break;
312818534a1Smrg        case XkbClampIntoRange:
313818534a1Smrg            effectiveGroup = nKeyGroups - 1;
314818534a1Smrg            break;
315818534a1Smrg        case XkbRedirectIntoRange:
316818534a1Smrg            effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
317818534a1Smrg            if (effectiveGroup >= nKeyGroups)
318818534a1Smrg                effectiveGroup = 0;
319818534a1Smrg            break;
320818534a1Smrg        }
3211ab64890Smrg    }
322818534a1Smrg    col = effectiveGroup * XkbKeyGroupsWidth(xkb, key);
323818534a1Smrg    type = XkbKeyKeyType(xkb, key, effectiveGroup);
324818534a1Smrg
325818534a1Smrg    preserve = 0;
326818534a1Smrg    if (type->map) {  /* find the column (shift level) within the group */
327818534a1Smrg        register int i;
328818534a1Smrg        register XkbKTMapEntryPtr entry;
329818534a1Smrg
330818534a1Smrg        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
331818534a1Smrg            if ((entry->active) &&
332818534a1Smrg                ((mods & type->mods.mask) == entry->mods.mask)) {
333818534a1Smrg                col += entry->level;
334818534a1Smrg                if (type->preserve)
335818534a1Smrg                    preserve = type->preserve[i].mask;
336818534a1Smrg                break;
337818534a1Smrg            }
338818534a1Smrg        }
3391ab64890Smrg    }
3401ab64890Smrg
341818534a1Smrg    if (keysym_rtrn != NULL)
342818534a1Smrg        *keysym_rtrn = syms[col];
3431ab64890Smrg    if (mods_rtrn) {
344818534a1Smrg        *mods_rtrn = type->mods.mask & (~preserve);
345818534a1Smrg        /* The Motif VTS doesn't get the help callback called if help
346818534a1Smrg         * is bound to Shift+<whatever>, and it appears as though it
347818534a1Smrg         * is XkbTranslateKeyCode that is causing the problem.  The
348818534a1Smrg         * core X version of XTranslateKey always OR's in ShiftMask
349818534a1Smrg         * and LockMask for mods_rtrn, so this "fix" keeps this behavior
350818534a1Smrg         * and solves the VTS problem.
351818534a1Smrg         */
352818534a1Smrg        if ((xkb->dpy) && (xkb->dpy->xkb_info) &&
353818534a1Smrg            (xkb->dpy->xkb_info->
354818534a1Smrg             xlib_ctrls & XkbLC_AlwaysConsumeShiftAndLock)) {
355818534a1Smrg            *mods_rtrn |= (ShiftMask | LockMask);
356818534a1Smrg        }
3571ab64890Smrg    }
358818534a1Smrg    return (syms[col] != NoSymbol);
3591ab64890Smrg}
3601ab64890Smrg
3611ab64890SmrgStatus
362818534a1SmrgXkbRefreshKeyboardMapping(register XkbMapNotifyEvent * event)
3631ab64890Smrg{
3641ab64890Smrg    Display *dpy = event->display;
3651ab64890Smrg    XkbInfoPtr xkbi;
3661ab64890Smrg
3671ab64890Smrg    if (_XkbUnavailable(dpy)) {
368818534a1Smrg        _XRefreshKeyboardMapping((XMappingEvent *) event);
369818534a1Smrg        return Success;
3701ab64890Smrg    }
371818534a1Smrg    xkbi = dpy->xkb_info;
3721ab64890Smrg
373818534a1Smrg    if (((event->type & 0x7f) - xkbi->codes->first_event) != XkbEventCode)
374818534a1Smrg        return BadMatch;
375818534a1Smrg    if (event->xkb_type == XkbNewKeyboardNotify) {
376818534a1Smrg        _XkbReloadDpy(dpy);
377818534a1Smrg        return Success;
3781ab64890Smrg    }
379818534a1Smrg    if (event->xkb_type == XkbMapNotify) {
380818534a1Smrg        XkbMapChangesRec changes;
381818534a1Smrg        Status rtrn;
382818534a1Smrg
383818534a1Smrg        if (xkbi->flags & XkbMapPending)
384818534a1Smrg            changes = xkbi->changes;
385818534a1Smrg        else
386818534a1Smrg            bzero(&changes, sizeof(changes));
387818534a1Smrg        XkbNoteMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
388818534a1Smrg        if ((rtrn = XkbGetMapChanges(dpy, xkbi->desc, &changes)) != Success) {
3891ab64890Smrg#ifdef DEBUG
390818534a1Smrg            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
3911ab64890Smrg#endif
392818534a1Smrg            xkbi->changes = changes;
393818534a1Smrg        }
394818534a1Smrg        else if (xkbi->flags & XkbMapPending) {
395818534a1Smrg            xkbi->flags &= ~XkbMapPending;
396818534a1Smrg            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
397818534a1Smrg        }
398818534a1Smrg        return rtrn;
3991ab64890Smrg    }
4001ab64890Smrg    return BadMatch;
4011ab64890Smrg}
4021ab64890Smrg
4031ab64890Smrgint
404818534a1SmrgXRefreshKeyboardMapping(register XMappingEvent * event)
4051ab64890Smrg{
406818534a1Smrg    XkbEvent *xkbevent = (XkbEvent *) event;
4071ab64890Smrg    Display *dpy = event->display;
4081ab64890Smrg    XkbMapChangesRec changes;
4091ab64890Smrg    XkbInfoPtr xkbi;
4101ab64890Smrg
4111ab64890Smrg    /* always do this for input methods, which still use the old keymap */
4121ab64890Smrg    (void) _XRefreshKeyboardMapping(event);
4131ab64890Smrg
4141ab64890Smrg    if (_XkbUnavailable(dpy))
415818534a1Smrg        return 1;
4161ab64890Smrg
4171ab64890Smrg    xkbi = dpy->xkb_info;
4181ab64890Smrg
419818534a1Smrg    if (((event->type & 0x7f) - xkbi->codes->first_event) == XkbEventCode)
420818534a1Smrg        return XkbRefreshKeyboardMapping(&xkbevent->map);
4211ab64890Smrg
422818534a1Smrg    if (xkbi->flags & XkbXlibNewKeyboard) {
423818534a1Smrg        _XkbReloadDpy(dpy);
424818534a1Smrg        return 1;
4251ab64890Smrg    }
4261ab64890Smrg
427818534a1Smrg    if ((xkbi->flags & XkbMapPending) || (event->request == MappingKeyboard)) {
428818534a1Smrg        if (xkbi->flags & XkbMapPending) {
429818534a1Smrg            changes = xkbi->changes;
430818534a1Smrg            _XkbNoteCoreMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
431818534a1Smrg        }
432818534a1Smrg        else {
433818534a1Smrg            bzero(&changes, sizeof(changes));
434818534a1Smrg            changes.changed = XkbKeySymsMask;
435818534a1Smrg            if (xkbi->desc->min_key_code < xkbi->desc->max_key_code) {
436818534a1Smrg                changes.first_key_sym = xkbi->desc->min_key_code;
437818534a1Smrg                changes.num_key_syms = xkbi->desc->max_key_code -
438818534a1Smrg                    xkbi->desc->min_key_code + 1;
439818534a1Smrg            }
440818534a1Smrg            else {
441818534a1Smrg                changes.first_key_sym = event->first_keycode;
442818534a1Smrg                changes.num_key_syms = event->count;
443818534a1Smrg            }
444818534a1Smrg        }
445818534a1Smrg
446818534a1Smrg        if (XkbGetMapChanges(dpy, xkbi->desc, &changes) != Success) {
4471ab64890Smrg#ifdef DEBUG
448818534a1Smrg            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
449818534a1Smrg            if (changes.changed & XkbKeyTypesMask) {
450818534a1Smrg                int first = changes.first_type;
451818534a1Smrg                int last = changes.first_type + changes.num_types - 1;
452818534a1Smrg
453818534a1Smrg                fprintf(stderr, "       types:  %d..%d\n", first, last);
454818534a1Smrg            }
455818534a1Smrg            if (changes.changed & XkbKeySymsMask) {
456818534a1Smrg                int first = changes.first_key_sym;
457818534a1Smrg                int last = changes.first_key_sym + changes.num_key_syms - 1;
458818534a1Smrg
459818534a1Smrg                fprintf(stderr, "     symbols:  %d..%d\n", first, last);
460818534a1Smrg            }
461818534a1Smrg            if (changes.changed & XkbKeyActionsMask) {
462818534a1Smrg                int first = changes.first_key_act;
463818534a1Smrg                int last = changes.first_key_act + changes.num_key_acts - 1;
464818534a1Smrg
465818534a1Smrg                fprintf(stderr, "     acts:  %d..%d\n", first, last);
466818534a1Smrg            }
467818534a1Smrg            if (changes.changed & XkbKeyBehaviorsMask) {
468818534a1Smrg                int first = changes.first_key_behavior;
469818534a1Smrg                int last = first + changes.num_key_behaviors - 1;
470818534a1Smrg
471818534a1Smrg                fprintf(stderr, "   behaviors:  %d..%d\n", first, last);
472818534a1Smrg            }
473818534a1Smrg            if (changes.changed & XkbVirtualModsMask) {
474818534a1Smrg                fprintf(stderr, "virtual mods: 0x%04x\n", changes.vmods);
475818534a1Smrg            }
476818534a1Smrg            if (changes.changed & XkbExplicitComponentsMask) {
477818534a1Smrg                int first = changes.first_key_explicit;
478818534a1Smrg                int last = first + changes.num_key_explicit - 1;
479818534a1Smrg
480818534a1Smrg                fprintf(stderr, "    explicit:  %d..%d\n", first, last);
481818534a1Smrg            }
4821ab64890Smrg#endif
483818534a1Smrg        }
484818534a1Smrg        LockDisplay(dpy);
485818534a1Smrg        if (xkbi->flags & XkbMapPending) {
486818534a1Smrg            xkbi->flags &= ~XkbMapPending;
487818534a1Smrg            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
488818534a1Smrg        }
489818534a1Smrg        UnlockDisplay(dpy);
4901ab64890Smrg    }
491818534a1Smrg    if (event->request == MappingModifier) {
492818534a1Smrg        LockDisplay(dpy);
493818534a1Smrg        if (xkbi->desc->map->modmap) {
494818534a1Smrg            _XkbFree(xkbi->desc->map->modmap);
495818534a1Smrg            xkbi->desc->map->modmap = NULL;
496818534a1Smrg        }
497818534a1Smrg        if (dpy->key_bindings) {
498818534a1Smrg            register struct _XKeytrans *p;
499818534a1Smrg
500818534a1Smrg            for (p = dpy->key_bindings; p; p = p->next) {
501818534a1Smrg                register int i;
502818534a1Smrg
503818534a1Smrg                p->state = 0;
504818534a1Smrg                if (p->mlen > 0) {
505818534a1Smrg                    for (i = 0; i < p->mlen; i++) {
506818534a1Smrg                        p->state |= XkbKeysymToModifiers(dpy, p->modifiers[i]);
507818534a1Smrg                    }
508818534a1Smrg                    if (p->state)
509818534a1Smrg                        p->state &= AllMods;
510818534a1Smrg                    else
511818534a1Smrg                        p->state = AnyModifier;
512818534a1Smrg                }
513818534a1Smrg            }
514818534a1Smrg        }
515818534a1Smrg        UnlockDisplay(dpy);
5161ab64890Smrg    }
5171ab64890Smrg    return 1;
5181ab64890Smrg}
5191ab64890Smrg
5201ab64890Smrgstatic int
5211ab64890Smrg_XkbLoadDpy(Display *dpy)
5221ab64890Smrg{
5231ab64890Smrg    XkbInfoPtr xkbi;
524818534a1Smrg    unsigned query, oldEvents;
5251ab64890Smrg    XkbDescRec *desc;
5261ab64890Smrg
527818534a1Smrg    if (!XkbUseExtension(dpy, NULL, NULL))
528818534a1Smrg        return 0;
5291ab64890Smrg
5301ab64890Smrg    xkbi = dpy->xkb_info;
5311ab64890Smrg    query = XkbAllClientInfoMask;
532818534a1Smrg    desc = XkbGetMap(dpy, query, XkbUseCoreKbd);
5331ab64890Smrg    if (!desc) {
5341ab64890Smrg#ifdef DEBUG
535818534a1Smrg        fprintf(stderr, "Warning! XkbGetMap failed!\n");
5361ab64890Smrg#endif
537818534a1Smrg        return 0;
5381ab64890Smrg    }
5391ab64890Smrg    LockDisplay(dpy);
5401ab64890Smrg    xkbi->desc = desc;
5411ab64890Smrg
5421ab64890Smrg    UnlockDisplay(dpy);
543818534a1Smrg    oldEvents = xkbi->selected_events;
544818534a1Smrg    if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards)) {
545818534a1Smrg        XkbSelectEventDetails(dpy, xkbi->desc->device_spec,
546818534a1Smrg                              XkbNewKeyboardNotify,
547818534a1Smrg                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask,
548818534a1Smrg                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask);
5491ab64890Smrg    }
550818534a1Smrg    XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
551818534a1Smrg                          XkbAllClientInfoMask, XkbAllClientInfoMask);
5521ab64890Smrg    LockDisplay(dpy);
553818534a1Smrg    xkbi->selected_events = oldEvents;
5541ab64890Smrg    UnlockDisplay(dpy);
5551ab64890Smrg    return 1;
5561ab64890Smrg}
5571ab64890Smrg
5581ab64890Smrgvoid
5591ab64890Smrg_XkbReloadDpy(Display *dpy)
5601ab64890Smrg{
5611ab64890Smrg    XkbInfoPtr xkbi;
5621ab64890Smrg    XkbDescRec *desc;
563818534a1Smrg    unsigned oldDeviceID;
5641ab64890Smrg
5651ab64890Smrg    if (_XkbUnavailable(dpy))
566818534a1Smrg        return;
5671ab64890Smrg
5681ab64890Smrg    xkbi = dpy->xkb_info;
5691ab64890Smrg    LockDisplay(dpy);
5701ab64890Smrg    if (xkbi->desc) {
571818534a1Smrg        oldDeviceID = xkbi->desc->device_spec;
572818534a1Smrg        XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, True);
573818534a1Smrg        xkbi->desc = NULL;
574818534a1Smrg        xkbi->flags &= ~(XkbMapPending | XkbXlibNewKeyboard);
575818534a1Smrg        xkbi->changes.changed = 0;
5761ab64890Smrg    }
577818534a1Smrg    else
578818534a1Smrg        oldDeviceID = XkbUseCoreKbd;
5791ab64890Smrg    UnlockDisplay(dpy);
580818534a1Smrg    desc = XkbGetMap(dpy, XkbAllClientInfoMask, XkbUseCoreKbd);
5811ab64890Smrg    if (!desc)
582818534a1Smrg        return;
5831ab64890Smrg    LockDisplay(dpy);
5841ab64890Smrg    xkbi->desc = desc;
5851ab64890Smrg    UnlockDisplay(dpy);
5861ab64890Smrg
587818534a1Smrg    if (desc->device_spec != oldDeviceID) {
588818534a1Smrg        /* transfer(?) event masks here */
5891ab64890Smrg#ifdef NOTYET
590818534a1Smrg        unsigned oldEvents;
591818534a1Smrg
592818534a1Smrg        oldEvents = xkbi->selected_events;
593818534a1Smrg        XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
594818534a1Smrg                              XkbAllMapComponentsMask, XkbAllClientInfoMask);
595818534a1Smrg        LockDisplay(dpy);
596818534a1Smrg        xkbi->selected_events = oldEvents;
597818534a1Smrg        UnlockDisplay(dpy);
5981ab64890Smrg#endif
5991ab64890Smrg    }
6001ab64890Smrg    return;
6011ab64890Smrg}
6021ab64890Smrg
6031ab64890Smrgint
604d7c63e31SmrgXkbTranslateKeySym(Display *dpy,
605d7c63e31Smrg                   KeySym *sym_rtrn,
606818534a1Smrg                   unsigned int mods,
607818534a1Smrg                   char *buffer,
608818534a1Smrg                   int nbytes,
609818534a1Smrg                   int *extra_rtrn)
6101ab64890Smrg{
611818534a1Smrg    register XkbInfoPtr xkb;
6121ab64890Smrg    XkbKSToMBFunc cvtr;
6131ab64890Smrg    XPointer priv;
6141ab64890Smrg    char tmp[4];
6151ab64890Smrg    int n;
6161ab64890Smrg
617818534a1Smrg    xkb = dpy->xkb_info;
6181ab64890Smrg    if (!xkb->cvt.KSToMB) {
619818534a1Smrg        _XkbGetConverters(_XkbGetCharset(), &xkb->cvt);
620818534a1Smrg        _XkbGetConverters("ISO8859-1", &xkb->latin1cvt);
6211ab64890Smrg    }
6221ab64890Smrg
6231ab64890Smrg    if (extra_rtrn)
624818534a1Smrg        *extra_rtrn = 0;
6251ab64890Smrg
626818534a1Smrg    if ((buffer == NULL) || (nbytes == 0)) {
627818534a1Smrg        buffer = tmp;
628818534a1Smrg        nbytes = 4;
6291ab64890Smrg    }
6301ab64890Smrg
6311ab64890Smrg    /* see if symbol rebound, if so, return that string. */
632818534a1Smrg    n = XkbLookupKeyBinding(dpy, *sym_rtrn, mods, buffer, nbytes, extra_rtrn);
6331ab64890Smrg    if (n)
6341ab64890Smrg        return n;
6351ab64890Smrg
636818534a1Smrg    if (nbytes > 0)
637818534a1Smrg        buffer[0] = '\0';
6381ab64890Smrg
639818534a1Smrg    if (xkb->cvt.KSToUpper && (mods & LockMask)) {
640818534a1Smrg        *sym_rtrn = (*xkb->cvt.KSToUpper) (*sym_rtrn);
6411ab64890Smrg    }
6421ab64890Smrg    if (xkb->xlib_ctrls & XkbLC_ForceLatin1Lookup) {
643818534a1Smrg        cvtr = xkb->latin1cvt.KSToMB;
644818534a1Smrg        priv = xkb->latin1cvt.KSToMBPriv;
645818534a1Smrg    }
646818534a1Smrg    else {
647818534a1Smrg        cvtr = xkb->cvt.KSToMB;
648818534a1Smrg        priv = xkb->cvt.KSToMBPriv;
6491ab64890Smrg    }
6501ab64890Smrg
651818534a1Smrg    n = (*cvtr) (priv, *sym_rtrn, buffer, nbytes, extra_rtrn);
652818534a1Smrg
653818534a1Smrg    if ((!xkb->cvt.KSToUpper) && (mods & LockMask)) {
654818534a1Smrg        register int i;
655818534a1Smrg        int change;
656818534a1Smrg
657818534a1Smrg        for (i = change = 0; i < n; i++) {
658818534a1Smrg            char ch = toupper(buffer[i]);
659818534a1Smrg            change = (change || (buffer[i] != ch));
660818534a1Smrg            buffer[i] = ch;
661818534a1Smrg        }
662818534a1Smrg        if (change) {
663818534a1Smrg            if (n == 1)
664818534a1Smrg                *sym_rtrn =
665818534a1Smrg                    (*xkb->cvt.MBToKS) (xkb->cvt.MBToKSPriv, buffer, n, NULL);
666818534a1Smrg            else
667818534a1Smrg                *sym_rtrn = NoSymbol;
668818534a1Smrg        }
6691ab64890Smrg    }
6701ab64890Smrg
671818534a1Smrg    if (mods & ControlMask) {
672818534a1Smrg        if (n == 1) {
673818534a1Smrg            buffer[0] = XkbToControl(buffer[0]);
674818534a1Smrg            if (nbytes > 1)
675818534a1Smrg                buffer[1] = '\0';
676818534a1Smrg            return 1;
677818534a1Smrg        }
678818534a1Smrg        if (nbytes > 0)
679818534a1Smrg            buffer[0] = '\0';
680818534a1Smrg        return 0;
6811ab64890Smrg    }
6821ab64890Smrg    return n;
6831ab64890Smrg}
6841ab64890Smrg
6851ab64890Smrgint
686818534a1SmrgXLookupString(register XKeyEvent *event,
687818534a1Smrg              char *buffer,
688818534a1Smrg              int nbytes,
689818534a1Smrg              KeySym *keysym,
690818534a1Smrg              XComposeStatus *status)
6911ab64890Smrg{
692818534a1Smrg    KeySym dummy;
6931ab64890Smrg    int rtrnLen;
6941ab64890Smrg    unsigned int new_mods;
6951ab64890Smrg    Display *dpy = event->display;
6961ab64890Smrg
697818534a1Smrg    if (keysym == NULL)
698818534a1Smrg        keysym = &dummy;
699818534a1Smrg    if (!XkbLookupKeySym(dpy, event->keycode, event->state, &new_mods, keysym))
700818534a1Smrg        return 0;
701818534a1Smrg    new_mods = (event->state & (~new_mods));
7021ab64890Smrg
7031ab64890Smrg    /* find the group where a symbol can be converted to control one */
704818534a1Smrg    if (new_mods & ControlMask && *keysym > 0x7F &&
705818534a1Smrg        (dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
706818534a1Smrg        XKeyEvent tmp_ev = *event;
707818534a1Smrg        KeySym tmp_keysym;
708818534a1Smrg        unsigned int tmp_new_mods;
709818534a1Smrg
710818534a1Smrg        if (_XkbUnavailable(dpy)) {
711818534a1Smrg            tmp_ev.state = event->state ^ dpy->mode_switch;
7121ab64890Smrg            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
7131ab64890Smrg                                &tmp_new_mods, &tmp_keysym) &&
714818534a1Smrg                tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
7151ab64890Smrg                *keysym = tmp_keysym;
7161ab64890Smrg            }
717818534a1Smrg        }
718818534a1Smrg        else {
7191ab64890Smrg            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
7201ab64890Smrg            int i;
721818534a1Smrg
7221ab64890Smrg            for (i = 0; i < n; i++) {
7231ab64890Smrg                if (XkbGroupForCoreState(event->state) == i)
7241ab64890Smrg                    continue;
725818534a1Smrg                tmp_ev.state = XkbBuildCoreState(tmp_ev.state, i);
7261ab64890Smrg                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
727818534a1Smrg                                    &tmp_new_mods, &tmp_keysym) &&
728818534a1Smrg                    tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
7291ab64890Smrg                    *keysym = tmp_keysym;
730818534a1Smrg                    new_mods = (event->state & (~tmp_new_mods));
7311ab64890Smrg                    break;
7321ab64890Smrg                }
7331ab64890Smrg            }
7341ab64890Smrg        }
73561b2299dSmrg    }
7361ab64890Smrg
7371ab64890Smrg    /* We *should* use the new_mods (which does not contain any modifiers */
7381ab64890Smrg    /* that were used to compute the symbol here, but pre-XKB XLookupString */
7391ab64890Smrg    /* did not and we have to remain compatible.  Sigh. */
7401ab64890Smrg    if (_XkbUnavailable(dpy) ||
741818534a1Smrg        (dpy->xkb_info->xlib_ctrls & XkbLC_ConsumeLookupMods) == 0)
742818534a1Smrg        new_mods = event->state;
7431ab64890Smrg
744818534a1Smrg    rtrnLen = XkbLookupKeyBinding(dpy, *keysym, new_mods, buffer, nbytes, NULL);
745818534a1Smrg    if (rtrnLen > 0)
746818534a1Smrg        return rtrnLen;
7471ab64890Smrg
748818534a1Smrg    return XkbTranslateKeySym(dpy, keysym, new_mods, buffer, nbytes, NULL);
7491ab64890Smrg}
7501ab64890Smrg
7511ab64890Smrg
7521ab64890Smrgint
753818534a1SmrgXkbLookupKeyBinding(Display *dpy,
754818534a1Smrg                    register KeySym sym,
755818534a1Smrg                    unsigned int mods,
756818534a1Smrg                    char *buffer,
757818534a1Smrg                    int nbytes,
758818534a1Smrg                    int *extra_rtrn)
7591ab64890Smrg{
76061b2299dSmrg    register struct _XKeytrans *p;
7611ab64890Smrg
7621ab64890Smrg    if (extra_rtrn)
763818534a1Smrg        *extra_rtrn = 0;
7641ab64890Smrg    for (p = dpy->key_bindings; p; p = p->next) {
765818534a1Smrg        if (((mods & AllMods) == p->state) && (sym == p->key)) {
766818534a1Smrg            int tmp = p->len;
767818534a1Smrg
768818534a1Smrg            if (tmp > nbytes) {
769818534a1Smrg                if (extra_rtrn)
770818534a1Smrg                    *extra_rtrn = (tmp - nbytes);
771818534a1Smrg                tmp = nbytes;
772818534a1Smrg            }
7739c019ec5Smaya            memcpy(buffer, p->string, (size_t) tmp);
774818534a1Smrg            if (tmp < nbytes)
775818534a1Smrg                buffer[tmp] = '\0';
776818534a1Smrg            return tmp;
777818534a1Smrg        }
7781ab64890Smrg    }
7791ab64890Smrg    return 0;
7801ab64890Smrg}
7811ab64890Smrg
7821ab64890Smrgchar
783818534a1SmrgXkbToControl(char ch)
7841ab64890Smrg{
7851ab64890Smrg    register char c = ch;
78661b2299dSmrg
787818534a1Smrg    if ((c >= '@' && c < '\177') || c == ' ')
788818534a1Smrg        c &= 0x1F;
789818534a1Smrg    else if (c == '2')
790818534a1Smrg        c = '\000';
791818534a1Smrg    else if (c >= '3' && c <= '7')
792818534a1Smrg        c -= ('3' - '\033');
793818534a1Smrg    else if (c == '8')
794818534a1Smrg        c = '\177';
795818534a1Smrg    else if (c == '/')
796818534a1Smrg        c = '_' & 0x1F;
7971ab64890Smrg    return c;
7981ab64890Smrg}
799