XKBBind.c revision 5efbdfc3
1/*
2
3Copyright 1985, 1987, 1994, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included
12in all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20OTHER DEALINGS IN THE SOFTWARE.
21
22Except as contained in this notice, the name of The Open Group shall
23not be used in advertising or otherwise to promote the sale, use or
24other dealings in this Software without prior written authorization
25from The Open Group.
26
27*/
28
29        /* the new monsters ate the old ones */
30
31#ifdef HAVE_CONFIG_H
32#include <config.h>
33#endif
34#include "XKBlib.h"
35#include <X11/Xlibint.h>
36#include <X11/Xutil.h>
37#include <X11/keysym.h>
38#include <stdio.h>
39#include <ctype.h>
40
41#include <X11/extensions/XKBproto.h>
42#include "XKBlibint.h"
43
44#define AllMods (ShiftMask|LockMask|ControlMask| \
45                 Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
46
47static int _XkbLoadDpy(Display *dpy);
48
49struct _XKeytrans {
50    struct _XKeytrans *next;    /* next on list */
51    char *string;               /* string to return when the time comes */
52    int len;                    /* length of string (since NULL is legit) */
53    KeySym key;                 /* keysym rebound */
54    unsigned int state;         /* modifier state */
55    KeySym *modifiers;          /* modifier keysyms you want */
56    int mlen;                   /* length of modifier list */
57};
58
59KeySym
60XkbKeycodeToKeysym(Display *dpy,
61#if NeedWidePrototypes
62                   unsigned int kc,
63#else
64                   KeyCode kc,
65#endif
66                   int group,
67                   int level)
68{
69    XkbDescRec *xkb;
70
71    if (_XkbUnavailable(dpy))
72        return NoSymbol;
73
74    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
75
76    xkb = dpy->xkb_info->desc;
77    if ((kc < xkb->min_key_code) || (kc > xkb->max_key_code))
78        return NoSymbol;
79
80    if ((group < 0) || (level < 0) || (group >= XkbKeyNumGroups(xkb, kc)))
81        return NoSymbol;
82    if (level >= XkbKeyGroupWidth(xkb, kc, group)) {
83        /* for compatibility with the core protocol, _always_ allow  */
84        /* two symbols in the first two groups.   If either of the   */
85        /* two is of type ONE_LEVEL, just replicate the first symbol */
86        if ((group > XkbGroup2Index) || (XkbKeyGroupWidth(xkb, kc, group) != 1)
87            || (level != 1)) {
88            return NoSymbol;
89        }
90        level = 0;
91    }
92    return XkbKeySymEntry(xkb, kc, level, group);
93}
94
95KeySym
96XKeycodeToKeysym(Display *dpy,
97#if NeedWidePrototypes
98                 unsigned int kc,
99#else
100                 KeyCode kc,
101#endif
102                 int col)
103{
104    XkbDescRec *xkb;
105
106    if (_XkbUnavailable(dpy))
107        return _XKeycodeToKeysym(dpy, kc, col);
108
109    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
110
111    xkb = dpy->xkb_info->desc;
112    if ((kc < xkb->min_key_code) || (kc > xkb->max_key_code))
113        return NoSymbol;
114
115    if (col > 3) {
116        int firstSym, nGrp, grp;
117
118        firstSym = 4;
119        nGrp = XkbKeyNumGroups(xkb, kc);
120        for (grp = 0; grp < nGrp; grp++) {
121            int width = XkbKeyGroupWidth(xkb, kc, grp);
122            int skip = 0;
123            if (grp < 2) {
124                /* Skip the first two symbols in the first two groups, since we
125                 * return them below for indexes 0-3. */
126                skip = 2;
127                width -= skip;
128                if (width < 0)
129                    width = 0;
130            }
131            if (col < firstSym + width)
132                return XkbKeycodeToKeysym(dpy, kc, grp, col - firstSym + skip);
133            firstSym += width;
134        }
135        return NoSymbol;
136    }
137    return XkbKeycodeToKeysym(dpy, kc, (col >> 1), (col & 1));
138}
139
140KeyCode
141XKeysymToKeycode(Display *dpy, KeySym ks)
142{
143    register int i, j, gotOne;
144
145    if (_XkbUnavailable(dpy))
146        return _XKeysymToKeycode(dpy, ks);
147    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
148
149    j = 0;
150    do {
151        register XkbDescRec *xkb = dpy->xkb_info->desc;
152        gotOne = 0;
153        for (i = dpy->min_keycode; i <= dpy->max_keycode; i++) {
154            if (j < (int) XkbKeyNumSyms(xkb, i)) {
155                gotOne = 1;
156                if ((XkbKeySym(xkb, i, j) == ks))
157                    return i;
158            }
159        }
160        j++;
161    } while (gotOne);
162    return 0;
163}
164
165static int
166_XkbComputeModmap(Display *dpy)
167{
168    register XkbDescPtr xkb;
169
170    xkb = dpy->xkb_info->desc;
171    if (XkbGetUpdatedMap(dpy, XkbModifierMapMask, xkb) == Success)
172        return 1;
173    return 0;
174}
175
176unsigned
177XkbKeysymToModifiers(Display *dpy, KeySym ks)
178{
179    XkbDescRec *xkb;
180    register int i, j;
181    register KeySym *pSyms;
182    CARD8 mods;
183
184    if (_XkbUnavailable(dpy))
185        return _XKeysymToModifiers(dpy, ks);
186    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
187
188    if (_XkbNeedModmap(dpy->xkb_info) && (!_XkbComputeModmap(dpy)))
189        return _XKeysymToModifiers(dpy, ks);
190
191    xkb = dpy->xkb_info->desc;
192    mods = 0;
193    for (i = xkb->min_key_code; i <= (int) xkb->max_key_code; i++) {
194        pSyms = XkbKeySymsPtr(xkb, i);
195        for (j = XkbKeyNumSyms(xkb, i) - 1; j >= 0; j--) {
196            if (pSyms[j] == ks) {
197                mods |= xkb->map->modmap[i];
198                break;
199            }
200        }
201    }
202    return mods;
203}
204
205KeySym
206XLookupKeysym(register XKeyEvent * event, int col)
207{
208    Display *dpy = event->display;
209
210    if (_XkbUnavailable(dpy))
211        return _XLookupKeysym(event, col);
212    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
213
214#ifdef __clang__
215#pragma clang diagnostic push
216#pragma clang diagnostic ignored "-Wdeprecated-declarations"
217#elif defined(__GNUC__)
218#pragma GCC diagnostic push
219#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
220#endif
221    return XKeycodeToKeysym(dpy, event->keycode, col);
222#ifdef __clang__
223#pragma clang diagnostic pop
224#elif defined(__GNUC__)
225#pragma GCC diagnostic pop
226#endif
227
228}
229
230   /*
231    * Not a public entry point -- XkbTranslateKey is an obsolete name
232    * that is preserved here so that functions linked against the old
233    * version will continue to work in a shared library environment.
234    */
235int
236XkbTranslateKey(register Display *dpy,
237                KeyCode key,
238                register unsigned int mods,
239                unsigned int *mods_rtrn,
240                KeySym *keysym_rtrn);
241
242int
243XkbTranslateKey(register Display *dpy,
244                KeyCode key,
245                register unsigned int mods,
246                unsigned int *mods_rtrn,
247                KeySym *keysym_rtrn)
248{
249    return XkbLookupKeySym(dpy, key, mods, mods_rtrn, keysym_rtrn);
250}
251
252Bool
253XkbLookupKeySym(register Display *dpy,
254                KeyCode key,
255                register unsigned int mods,
256                unsigned int *mods_rtrn,
257                KeySym *keysym_rtrn)
258{
259    if (_XkbUnavailable(dpy))
260        return _XTranslateKey(dpy, key, mods, mods_rtrn, keysym_rtrn);
261    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
262    return XkbTranslateKeyCode(dpy->xkb_info->desc, key, mods, mods_rtrn,
263                               keysym_rtrn);
264}
265
266Bool
267XkbTranslateKeyCode(register XkbDescPtr xkb,
268                    KeyCode key,
269                    register unsigned int mods,
270                    unsigned int *mods_rtrn,
271                    KeySym *keysym_rtrn)
272{
273    XkbKeyTypeRec *type;
274    int col, nKeyGroups;
275    unsigned preserve, effectiveGroup;
276    KeySym *syms;
277
278    if (mods_rtrn != NULL)
279        *mods_rtrn = 0;
280
281    nKeyGroups = XkbKeyNumGroups(xkb, key);
282    if ((!XkbKeycodeInRange(xkb, key)) || (nKeyGroups == 0)) {
283        if (keysym_rtrn != NULL)
284            *keysym_rtrn = NoSymbol;
285        return False;
286    }
287
288    syms = XkbKeySymsPtr(xkb, key);
289
290    /* find the offset of the effective group */
291    col = 0;
292    effectiveGroup = XkbGroupForCoreState(mods);
293    if (effectiveGroup >= nKeyGroups) {
294        unsigned groupInfo = XkbKeyGroupInfo(xkb, key);
295
296        switch (XkbOutOfRangeGroupAction(groupInfo)) {
297        default:
298            effectiveGroup %= nKeyGroups;
299            break;
300        case XkbClampIntoRange:
301            effectiveGroup = nKeyGroups - 1;
302            break;
303        case XkbRedirectIntoRange:
304            effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
305            if (effectiveGroup >= nKeyGroups)
306                effectiveGroup = 0;
307            break;
308        }
309    }
310    col = effectiveGroup * XkbKeyGroupsWidth(xkb, key);
311    type = XkbKeyKeyType(xkb, key, effectiveGroup);
312
313    preserve = 0;
314    if (type->map) {  /* find the column (shift level) within the group */
315        register int i;
316        register XkbKTMapEntryPtr entry;
317
318        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
319            if ((entry->active) &&
320                ((mods & type->mods.mask) == entry->mods.mask)) {
321                col += entry->level;
322                if (type->preserve)
323                    preserve = type->preserve[i].mask;
324                break;
325            }
326        }
327    }
328
329    if (keysym_rtrn != NULL)
330        *keysym_rtrn = syms[col];
331    if (mods_rtrn) {
332        *mods_rtrn = type->mods.mask & (~preserve);
333        /* The Motif VTS doesn't get the help callback called if help
334         * is bound to Shift+<whatever>, and it appears as though it
335         * is XkbTranslateKeyCode that is causing the problem.  The
336         * core X version of XTranslateKey always OR's in ShiftMask
337         * and LockMask for mods_rtrn, so this "fix" keeps this behavior
338         * and solves the VTS problem.
339         */
340        if ((xkb->dpy) && (xkb->dpy->xkb_info) &&
341            (xkb->dpy->xkb_info->
342             xlib_ctrls & XkbLC_AlwaysConsumeShiftAndLock)) {
343            *mods_rtrn |= (ShiftMask | LockMask);
344        }
345    }
346    return (syms[col] != NoSymbol);
347}
348
349Status
350XkbRefreshKeyboardMapping(register XkbMapNotifyEvent * event)
351{
352    Display *dpy = event->display;
353    XkbInfoPtr xkbi;
354
355    if (_XkbUnavailable(dpy)) {
356        _XRefreshKeyboardMapping((XMappingEvent *) event);
357        return Success;
358    }
359    xkbi = dpy->xkb_info;
360
361    if (((event->type & 0x7f) - xkbi->codes->first_event) != XkbEventCode)
362        return BadMatch;
363    if (event->xkb_type == XkbNewKeyboardNotify) {
364        _XkbReloadDpy(dpy);
365        return Success;
366    }
367    if (event->xkb_type == XkbMapNotify) {
368        XkbMapChangesRec changes;
369        Status rtrn;
370
371        if (xkbi->flags & XkbMapPending)
372            changes = xkbi->changes;
373        else
374            bzero(&changes, sizeof(changes));
375        XkbNoteMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
376        if ((rtrn = XkbGetMapChanges(dpy, xkbi->desc, &changes)) != Success) {
377#ifdef DEBUG
378            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
379#endif
380            xkbi->changes = changes;
381        }
382        else if (xkbi->flags & XkbMapPending) {
383            xkbi->flags &= ~XkbMapPending;
384            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
385        }
386        return rtrn;
387    }
388    return BadMatch;
389}
390
391int
392XRefreshKeyboardMapping(register XMappingEvent * event)
393{
394    XkbEvent *xkbevent = (XkbEvent *) event;
395    Display *dpy = event->display;
396    XkbMapChangesRec changes;
397    XkbInfoPtr xkbi;
398
399    /* always do this for input methods, which still use the old keymap */
400    (void) _XRefreshKeyboardMapping(event);
401
402    if (_XkbUnavailable(dpy))
403        return 1;
404
405    xkbi = dpy->xkb_info;
406
407    if (((event->type & 0x7f) - xkbi->codes->first_event) == XkbEventCode)
408        return XkbRefreshKeyboardMapping(&xkbevent->map);
409
410    if (xkbi->flags & XkbXlibNewKeyboard) {
411        _XkbReloadDpy(dpy);
412        return 1;
413    }
414
415    if ((xkbi->flags & XkbMapPending) || (event->request == MappingKeyboard)) {
416        if (xkbi->flags & XkbMapPending) {
417            changes = xkbi->changes;
418            _XkbNoteCoreMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
419        }
420        else {
421            bzero(&changes, sizeof(changes));
422            changes.changed = XkbKeySymsMask;
423            if (xkbi->desc->min_key_code < xkbi->desc->max_key_code) {
424                changes.first_key_sym = xkbi->desc->min_key_code;
425                changes.num_key_syms = xkbi->desc->max_key_code -
426                    xkbi->desc->min_key_code + 1;
427            }
428            else {
429                changes.first_key_sym = event->first_keycode;
430                changes.num_key_syms = event->count;
431            }
432        }
433
434        if (XkbGetMapChanges(dpy, xkbi->desc, &changes) != Success) {
435#ifdef DEBUG
436            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
437            if (changes.changed & XkbKeyTypesMask) {
438                int first = changes.first_type;
439                int last = changes.first_type + changes.num_types - 1;
440
441                fprintf(stderr, "       types:  %d..%d\n", first, last);
442            }
443            if (changes.changed & XkbKeySymsMask) {
444                int first = changes.first_key_sym;
445                int last = changes.first_key_sym + changes.num_key_syms - 1;
446
447                fprintf(stderr, "     symbols:  %d..%d\n", first, last);
448            }
449            if (changes.changed & XkbKeyActionsMask) {
450                int first = changes.first_key_act;
451                int last = changes.first_key_act + changes.num_key_acts - 1;
452
453                fprintf(stderr, "     acts:  %d..%d\n", first, last);
454            }
455            if (changes.changed & XkbKeyBehaviorsMask) {
456                int first = changes.first_key_behavior;
457                int last = first + changes.num_key_behaviors - 1;
458
459                fprintf(stderr, "   behaviors:  %d..%d\n", first, last);
460            }
461            if (changes.changed & XkbVirtualModsMask) {
462                fprintf(stderr, "virtual mods: 0x%04x\n", changes.vmods);
463            }
464            if (changes.changed & XkbExplicitComponentsMask) {
465                int first = changes.first_key_explicit;
466                int last = first + changes.num_key_explicit - 1;
467
468                fprintf(stderr, "    explicit:  %d..%d\n", first, last);
469            }
470#endif
471        }
472        LockDisplay(dpy);
473        if (xkbi->flags & XkbMapPending) {
474            xkbi->flags &= ~XkbMapPending;
475            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
476        }
477        UnlockDisplay(dpy);
478    }
479    if (event->request == MappingModifier) {
480        LockDisplay(dpy);
481        if (xkbi->desc->map->modmap) {
482            _XkbFree(xkbi->desc->map->modmap);
483            xkbi->desc->map->modmap = NULL;
484        }
485        if (dpy->key_bindings) {
486            register struct _XKeytrans *p;
487
488            for (p = dpy->key_bindings; p; p = p->next) {
489                register int i;
490
491                p->state = 0;
492                if (p->mlen > 0) {
493                    for (i = 0; i < p->mlen; i++) {
494                        p->state |= XkbKeysymToModifiers(dpy, p->modifiers[i]);
495                    }
496                    if (p->state)
497                        p->state &= AllMods;
498                    else
499                        p->state = AnyModifier;
500                }
501            }
502        }
503        UnlockDisplay(dpy);
504    }
505    return 1;
506}
507
508static int
509_XkbLoadDpy(Display *dpy)
510{
511    XkbInfoPtr xkbi;
512    unsigned query, oldEvents;
513    XkbDescRec *desc;
514
515    if (!XkbUseExtension(dpy, NULL, NULL))
516        return 0;
517
518    xkbi = dpy->xkb_info;
519    query = XkbAllClientInfoMask;
520    desc = XkbGetMap(dpy, query, XkbUseCoreKbd);
521    if (!desc) {
522#ifdef DEBUG
523        fprintf(stderr, "Warning! XkbGetMap failed!\n");
524#endif
525        return 0;
526    }
527    LockDisplay(dpy);
528    xkbi->desc = desc;
529
530    UnlockDisplay(dpy);
531    oldEvents = xkbi->selected_events;
532    if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards)) {
533        XkbSelectEventDetails(dpy, xkbi->desc->device_spec,
534                              XkbNewKeyboardNotify,
535                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask,
536                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask);
537    }
538    XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
539                          XkbAllClientInfoMask, XkbAllClientInfoMask);
540    LockDisplay(dpy);
541    xkbi->selected_events = oldEvents;
542    UnlockDisplay(dpy);
543    return 1;
544}
545
546void
547_XkbReloadDpy(Display *dpy)
548{
549    XkbInfoPtr xkbi;
550    XkbDescRec *desc;
551    unsigned oldDeviceID;
552
553    if (_XkbUnavailable(dpy))
554        return;
555
556    xkbi = dpy->xkb_info;
557    LockDisplay(dpy);
558    if (xkbi->desc) {
559        oldDeviceID = xkbi->desc->device_spec;
560        XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, True);
561        xkbi->desc = NULL;
562        xkbi->flags &= ~(XkbMapPending | XkbXlibNewKeyboard);
563        xkbi->changes.changed = 0;
564    }
565    else
566        oldDeviceID = XkbUseCoreKbd;
567    UnlockDisplay(dpy);
568    desc = XkbGetMap(dpy, XkbAllClientInfoMask, XkbUseCoreKbd);
569    if (!desc)
570        return;
571    LockDisplay(dpy);
572    xkbi->desc = desc;
573    UnlockDisplay(dpy);
574
575    if (desc->device_spec != oldDeviceID) {
576        /* transfer(?) event masks here */
577#ifdef NOTYET
578        unsigned oldEvents;
579
580        oldEvents = xkbi->selected_events;
581        XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
582                              XkbAllMapComponentsMask, XkbAllClientInfoMask);
583        LockDisplay(dpy);
584        xkbi->selected_events = oldEvents;
585        UnlockDisplay(dpy);
586#endif
587    }
588    return;
589}
590
591int
592XkbTranslateKeySym(Display *dpy,
593                   KeySym *sym_rtrn,
594                   unsigned int mods,
595                   char *buffer,
596                   int nbytes,
597                   int *extra_rtrn)
598{
599    register XkbInfoPtr xkb;
600    XkbKSToMBFunc cvtr;
601    XPointer priv;
602    char tmp[4];
603    int n;
604
605    xkb = dpy->xkb_info;
606    if (!xkb->cvt.KSToMB) {
607        _XkbGetConverters(_XkbGetCharset(), &xkb->cvt);
608        _XkbGetConverters("ISO8859-1", &xkb->latin1cvt);
609    }
610
611    if (extra_rtrn)
612        *extra_rtrn = 0;
613
614    if ((buffer == NULL) || (nbytes == 0)) {
615        buffer = tmp;
616        nbytes = 4;
617    }
618
619    /* see if symbol rebound, if so, return that string. */
620    n = XkbLookupKeyBinding(dpy, *sym_rtrn, mods, buffer, nbytes, extra_rtrn);
621    if (n)
622        return n;
623
624    if (nbytes > 0)
625        buffer[0] = '\0';
626
627    if (xkb->cvt.KSToUpper && (mods & LockMask)) {
628        *sym_rtrn = (*xkb->cvt.KSToUpper) (*sym_rtrn);
629    }
630    if (xkb->xlib_ctrls & XkbLC_ForceLatin1Lookup) {
631        cvtr = xkb->latin1cvt.KSToMB;
632        priv = xkb->latin1cvt.KSToMBPriv;
633    }
634    else {
635        cvtr = xkb->cvt.KSToMB;
636        priv = xkb->cvt.KSToMBPriv;
637    }
638
639    n = (*cvtr) (priv, *sym_rtrn, buffer, nbytes, extra_rtrn);
640
641    if ((!xkb->cvt.KSToUpper) && (mods & LockMask)) {
642        register int i;
643        int change;
644
645        for (i = change = 0; i < n; i++) {
646            char ch = toupper(buffer[i]);
647            change = (change || (buffer[i] != ch));
648            buffer[i] = ch;
649        }
650        if (change) {
651            if (n == 1)
652                *sym_rtrn =
653                    (*xkb->cvt.MBToKS) (xkb->cvt.MBToKSPriv, buffer, n, NULL);
654            else
655                *sym_rtrn = NoSymbol;
656        }
657    }
658
659    if (mods & ControlMask) {
660        if (n == 1) {
661            buffer[0] = XkbToControl(buffer[0]);
662            if (nbytes > 1)
663                buffer[1] = '\0';
664            return 1;
665        }
666        if (nbytes > 0)
667            buffer[0] = '\0';
668        return 0;
669    }
670    return n;
671}
672
673int
674XLookupString(register XKeyEvent *event,
675              char *buffer,
676              int nbytes,
677              KeySym *keysym,
678              XComposeStatus *status)
679{
680    KeySym dummy;
681    int rtrnLen;
682    unsigned int new_mods;
683    Display *dpy = event->display;
684
685    if (keysym == NULL)
686        keysym = &dummy;
687    if (!XkbLookupKeySym(dpy, event->keycode, event->state, &new_mods, keysym))
688        return 0;
689    new_mods = (event->state & (~new_mods));
690
691    /* find the group where a symbol can be converted to control one */
692    if (new_mods & ControlMask && *keysym > 0x7F &&
693        (dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
694        XKeyEvent tmp_ev = *event;
695        KeySym tmp_keysym;
696        unsigned int tmp_new_mods;
697
698        if (_XkbUnavailable(dpy)) {
699            tmp_ev.state = event->state ^ dpy->mode_switch;
700            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
701                                &tmp_new_mods, &tmp_keysym) &&
702                tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
703                *keysym = tmp_keysym;
704            }
705        }
706        else {
707            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
708            int i;
709
710            for (i = 0; i < n; i++) {
711                if (XkbGroupForCoreState(event->state) == i)
712                    continue;
713                tmp_ev.state = XkbBuildCoreState(tmp_ev.state, i);
714                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
715                                    &tmp_new_mods, &tmp_keysym) &&
716                    tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
717                    *keysym = tmp_keysym;
718                    new_mods = (event->state & (~tmp_new_mods));
719                    break;
720                }
721            }
722        }
723    }
724
725    /* We *should* use the new_mods (which does not contain any modifiers */
726    /* that were used to compute the symbol here, but pre-XKB XLookupString */
727    /* did not and we have to remain compatible.  Sigh. */
728    if (_XkbUnavailable(dpy) ||
729        (dpy->xkb_info->xlib_ctrls & XkbLC_ConsumeLookupMods) == 0)
730        new_mods = event->state;
731
732    rtrnLen = XkbLookupKeyBinding(dpy, *keysym, new_mods, buffer, nbytes, NULL);
733    if (rtrnLen > 0)
734        return rtrnLen;
735
736    return XkbTranslateKeySym(dpy, keysym, new_mods, buffer, nbytes, NULL);
737}
738
739
740int
741XkbLookupKeyBinding(Display *dpy,
742                    register KeySym sym,
743                    unsigned int mods,
744                    char *buffer,
745                    int nbytes,
746                    int *extra_rtrn)
747{
748    register struct _XKeytrans *p;
749
750    if (extra_rtrn)
751        *extra_rtrn = 0;
752    for (p = dpy->key_bindings; p; p = p->next) {
753        if (((mods & AllMods) == p->state) && (sym == p->key)) {
754            int tmp = p->len;
755
756            if (tmp > nbytes) {
757                if (extra_rtrn)
758                    *extra_rtrn = (tmp - nbytes);
759                tmp = nbytes;
760            }
761            memcpy(buffer, p->string, (size_t) tmp);
762            if (tmp < nbytes)
763                buffer[tmp] = '\0';
764            return tmp;
765        }
766    }
767    return 0;
768}
769
770char
771XkbToControl(char ch)
772{
773    register char c = ch;
774
775    if ((c >= '@' && c < '\177') || c == ' ')
776        c &= 0x1F;
777    else if (c == '2')
778        c = '\000';
779    else if (c >= '3' && c <= '7')
780        c -= ('3' - '\033');
781    else if (c == '8')
782        c = '\177';
783    else if (c == '/')
784        c = '_' & 0x1F;
785    return c;
786}
787