XKBBind.c revision 507fd43f
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
205#ifdef __clang__
206#pragma clang diagnostic push
207#pragma clang diagnostic ignored "-Wdeprecated-declarations"
208#elif defined(__GNUC__)
209#pragma GCC diagnostic push
210#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
211#endif
212
213KeySym
214XLookupKeysym(register XKeyEvent * event, int col)
215{
216    Display *dpy = event->display;
217
218    if (_XkbUnavailable(dpy))
219        return _XLookupKeysym(event, col);
220    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
221
222    return XKeycodeToKeysym(dpy, event->keycode, col);
223}
224
225#ifdef __clang__
226#pragma clang diagnostic pop
227#elif defined(__GNUC__)
228#pragma GCC diagnostic pop
229#endif
230
231   /*
232    * Not a public entry point -- XkbTranslateKey is an obsolete name
233    * that is preserved here so that functions linked against the old
234    * version will continue to work in a shared library environment.
235    */
236int
237XkbTranslateKey(register Display *dpy,
238                KeyCode key,
239                register unsigned int mods,
240                unsigned int *mods_rtrn,
241                KeySym *keysym_rtrn);
242
243int
244XkbTranslateKey(register Display *dpy,
245                KeyCode key,
246                register unsigned int mods,
247                unsigned int *mods_rtrn,
248                KeySym *keysym_rtrn)
249{
250    return XkbLookupKeySym(dpy, key, mods, mods_rtrn, keysym_rtrn);
251}
252
253Bool
254XkbLookupKeySym(register Display *dpy,
255                KeyCode key,
256                register unsigned int mods,
257                unsigned int *mods_rtrn,
258                KeySym *keysym_rtrn)
259{
260    if (_XkbUnavailable(dpy))
261        return _XTranslateKey(dpy, key, mods, mods_rtrn, keysym_rtrn);
262    _XkbCheckPendingRefresh(dpy, dpy->xkb_info);
263    return XkbTranslateKeyCode(dpy->xkb_info->desc, key, mods, mods_rtrn,
264                               keysym_rtrn);
265}
266
267Bool
268XkbTranslateKeyCode(register XkbDescPtr xkb,
269                    KeyCode key,
270                    register unsigned int mods,
271                    unsigned int *mods_rtrn,
272                    KeySym *keysym_rtrn)
273{
274    XkbKeyTypeRec *type;
275    int col, nKeyGroups;
276    unsigned preserve, effectiveGroup;
277    KeySym *syms;
278
279    if (mods_rtrn != NULL)
280        *mods_rtrn = 0;
281
282    nKeyGroups = XkbKeyNumGroups(xkb, key);
283    if ((!XkbKeycodeInRange(xkb, key)) || (nKeyGroups == 0)) {
284        if (keysym_rtrn != NULL)
285            *keysym_rtrn = NoSymbol;
286        return False;
287    }
288
289    syms = XkbKeySymsPtr(xkb, key);
290
291    /* find the offset of the effective group */
292    col = 0;
293    effectiveGroup = XkbGroupForCoreState(mods);
294    if (effectiveGroup >= nKeyGroups) {
295        unsigned groupInfo = XkbKeyGroupInfo(xkb, key);
296
297        switch (XkbOutOfRangeGroupAction(groupInfo)) {
298        default:
299            effectiveGroup %= nKeyGroups;
300            break;
301        case XkbClampIntoRange:
302            effectiveGroup = nKeyGroups - 1;
303            break;
304        case XkbRedirectIntoRange:
305            effectiveGroup = XkbOutOfRangeGroupNumber(groupInfo);
306            if (effectiveGroup >= nKeyGroups)
307                effectiveGroup = 0;
308            break;
309        }
310    }
311    col = effectiveGroup * XkbKeyGroupsWidth(xkb, key);
312    type = XkbKeyKeyType(xkb, key, effectiveGroup);
313
314    preserve = 0;
315    if (type->map) {  /* find the column (shift level) within the group */
316        register int i;
317        register XkbKTMapEntryPtr entry;
318
319        for (i = 0, entry = type->map; i < type->map_count; i++, entry++) {
320            if ((entry->active) &&
321                ((mods & type->mods.mask) == entry->mods.mask)) {
322                col += entry->level;
323                if (type->preserve)
324                    preserve = type->preserve[i].mask;
325                break;
326            }
327        }
328    }
329
330    if (keysym_rtrn != NULL)
331        *keysym_rtrn = syms[col];
332    if (mods_rtrn) {
333        *mods_rtrn = type->mods.mask & (~preserve);
334        /* The Motif VTS doesn't get the help callback called if help
335         * is bound to Shift+<whatever>, and it appears as though it
336         * is XkbTranslateKeyCode that is causing the problem.  The
337         * core X version of XTranslateKey always OR's in ShiftMask
338         * and LockMask for mods_rtrn, so this "fix" keeps this behavior
339         * and solves the VTS problem.
340         */
341        if ((xkb->dpy) && (xkb->dpy->xkb_info) &&
342            (xkb->dpy->xkb_info->
343             xlib_ctrls & XkbLC_AlwaysConsumeShiftAndLock)) {
344            *mods_rtrn |= (ShiftMask | LockMask);
345        }
346    }
347    return (syms[col] != NoSymbol);
348}
349
350Status
351XkbRefreshKeyboardMapping(register XkbMapNotifyEvent * event)
352{
353    Display *dpy = event->display;
354    XkbInfoPtr xkbi;
355
356    if (_XkbUnavailable(dpy)) {
357        _XRefreshKeyboardMapping((XMappingEvent *) event);
358        return Success;
359    }
360    xkbi = dpy->xkb_info;
361
362    if (((event->type & 0x7f) - xkbi->codes->first_event) != XkbEventCode)
363        return BadMatch;
364    if (event->xkb_type == XkbNewKeyboardNotify) {
365        _XkbReloadDpy(dpy);
366        return Success;
367    }
368    if (event->xkb_type == XkbMapNotify) {
369        XkbMapChangesRec changes;
370        Status rtrn;
371
372        if (xkbi->flags & XkbMapPending)
373            changes = xkbi->changes;
374        else
375            bzero(&changes, sizeof(changes));
376        XkbNoteMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
377        if ((rtrn = XkbGetMapChanges(dpy, xkbi->desc, &changes)) != Success) {
378#ifdef DEBUG
379            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
380#endif
381            xkbi->changes = changes;
382        }
383        else if (xkbi->flags & XkbMapPending) {
384            xkbi->flags &= ~XkbMapPending;
385            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
386        }
387        return rtrn;
388    }
389    return BadMatch;
390}
391
392int
393XRefreshKeyboardMapping(register XMappingEvent * event)
394{
395    XkbEvent *xkbevent = (XkbEvent *) event;
396    Display *dpy = event->display;
397    XkbMapChangesRec changes;
398    XkbInfoPtr xkbi;
399
400    /* always do this for input methods, which still use the old keymap */
401    (void) _XRefreshKeyboardMapping(event);
402
403    if (_XkbUnavailable(dpy))
404        return 1;
405
406    xkbi = dpy->xkb_info;
407
408    if (((event->type & 0x7f) - xkbi->codes->first_event) == XkbEventCode)
409        return XkbRefreshKeyboardMapping(&xkbevent->map);
410
411    if (xkbi->flags & XkbXlibNewKeyboard) {
412        _XkbReloadDpy(dpy);
413        return 1;
414    }
415
416    if ((xkbi->flags & XkbMapPending) || (event->request == MappingKeyboard)) {
417        if (xkbi->flags & XkbMapPending) {
418            changes = xkbi->changes;
419            _XkbNoteCoreMapChanges(&changes, event, XKB_XLIB_MAP_MASK);
420        }
421        else {
422            bzero(&changes, sizeof(changes));
423            changes.changed = XkbKeySymsMask;
424            if (xkbi->desc->min_key_code < xkbi->desc->max_key_code) {
425                changes.first_key_sym = xkbi->desc->min_key_code;
426                changes.num_key_syms = xkbi->desc->max_key_code -
427                    xkbi->desc->min_key_code + 1;
428            }
429            else {
430                changes.first_key_sym = event->first_keycode;
431                changes.num_key_syms = event->count;
432            }
433        }
434
435        if (XkbGetMapChanges(dpy, xkbi->desc, &changes) != Success) {
436#ifdef DEBUG
437            fprintf(stderr, "Internal Error! XkbGetMapChanges failed:\n");
438            if (changes.changed & XkbKeyTypesMask) {
439                int first = changes.first_type;
440                int last = changes.first_type + changes.num_types - 1;
441
442                fprintf(stderr, "       types:  %d..%d\n", first, last);
443            }
444            if (changes.changed & XkbKeySymsMask) {
445                int first = changes.first_key_sym;
446                int last = changes.first_key_sym + changes.num_key_syms - 1;
447
448                fprintf(stderr, "     symbols:  %d..%d\n", first, last);
449            }
450            if (changes.changed & XkbKeyActionsMask) {
451                int first = changes.first_key_act;
452                int last = changes.first_key_act + changes.num_key_acts - 1;
453
454                fprintf(stderr, "     acts:  %d..%d\n", first, last);
455            }
456            if (changes.changed & XkbKeyBehaviorsMask) {
457                int first = changes.first_key_behavior;
458                int last = first + changes.num_key_behaviors - 1;
459
460                fprintf(stderr, "   behaviors:  %d..%d\n", first, last);
461            }
462            if (changes.changed & XkbVirtualModsMask) {
463                fprintf(stderr, "virtual mods: 0x%04x\n", changes.vmods);
464            }
465            if (changes.changed & XkbExplicitComponentsMask) {
466                int first = changes.first_key_explicit;
467                int last = first + changes.num_key_explicit - 1;
468
469                fprintf(stderr, "    explicit:  %d..%d\n", first, last);
470            }
471#endif
472        }
473        LockDisplay(dpy);
474        if (xkbi->flags & XkbMapPending) {
475            xkbi->flags &= ~XkbMapPending;
476            bzero(&xkbi->changes, sizeof(XkbMapChangesRec));
477        }
478        UnlockDisplay(dpy);
479    }
480    if (event->request == MappingModifier) {
481        LockDisplay(dpy);
482        if (xkbi->desc->map->modmap) {
483            _XkbFree(xkbi->desc->map->modmap);
484            xkbi->desc->map->modmap = NULL;
485        }
486        if (dpy->key_bindings) {
487            register struct _XKeytrans *p;
488
489            for (p = dpy->key_bindings; p; p = p->next) {
490                register int i;
491
492                p->state = 0;
493                if (p->mlen > 0) {
494                    for (i = 0; i < p->mlen; i++) {
495                        p->state |= XkbKeysymToModifiers(dpy, p->modifiers[i]);
496                    }
497                    if (p->state)
498                        p->state &= AllMods;
499                    else
500                        p->state = AnyModifier;
501                }
502            }
503        }
504        UnlockDisplay(dpy);
505    }
506    return 1;
507}
508
509static int
510_XkbLoadDpy(Display *dpy)
511{
512    XkbInfoPtr xkbi;
513    unsigned query, oldEvents;
514    XkbDescRec *desc;
515
516    if (!XkbUseExtension(dpy, NULL, NULL))
517        return 0;
518
519    xkbi = dpy->xkb_info;
520    query = XkbAllClientInfoMask;
521    desc = XkbGetMap(dpy, query, XkbUseCoreKbd);
522    if (!desc) {
523#ifdef DEBUG
524        fprintf(stderr, "Warning! XkbGetMap failed!\n");
525#endif
526        return 0;
527    }
528    LockDisplay(dpy);
529    xkbi->desc = desc;
530
531    UnlockDisplay(dpy);
532    oldEvents = xkbi->selected_events;
533    if (!(xkbi->xlib_ctrls & XkbLC_IgnoreNewKeyboards)) {
534        XkbSelectEventDetails(dpy, xkbi->desc->device_spec,
535                              XkbNewKeyboardNotify,
536                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask,
537                              XkbNKN_KeycodesMask | XkbNKN_DeviceIDMask);
538    }
539    XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
540                          XkbAllClientInfoMask, XkbAllClientInfoMask);
541    LockDisplay(dpy);
542    xkbi->selected_events = oldEvents;
543    UnlockDisplay(dpy);
544    return 1;
545}
546
547void
548_XkbReloadDpy(Display *dpy)
549{
550    XkbInfoPtr xkbi;
551    XkbDescRec *desc;
552    unsigned oldDeviceID;
553
554    if (_XkbUnavailable(dpy))
555        return;
556
557    xkbi = dpy->xkb_info;
558    LockDisplay(dpy);
559    if (xkbi->desc) {
560        oldDeviceID = xkbi->desc->device_spec;
561        XkbFreeKeyboard(xkbi->desc, XkbAllComponentsMask, True);
562        xkbi->desc = NULL;
563        xkbi->flags &= ~(XkbMapPending | XkbXlibNewKeyboard);
564        xkbi->changes.changed = 0;
565    }
566    else
567        oldDeviceID = XkbUseCoreKbd;
568    UnlockDisplay(dpy);
569    desc = XkbGetMap(dpy, XkbAllClientInfoMask, XkbUseCoreKbd);
570    if (!desc)
571        return;
572    LockDisplay(dpy);
573    xkbi->desc = desc;
574    UnlockDisplay(dpy);
575
576    if (desc->device_spec != oldDeviceID) {
577        /* transfer(?) event masks here */
578#ifdef NOTYET
579        unsigned oldEvents;
580
581        oldEvents = xkbi->selected_events;
582        XkbSelectEventDetails(dpy, xkbi->desc->device_spec, XkbMapNotify,
583                              XkbAllMapComponentsMask, XkbAllClientInfoMask);
584        LockDisplay(dpy);
585        xkbi->selected_events = oldEvents;
586        UnlockDisplay(dpy);
587#endif
588    }
589    return;
590}
591
592int
593XkbTranslateKeySym(Display *dpy,
594                   KeySym *sym_rtrn,
595                   unsigned int mods,
596                   char *buffer,
597                   int nbytes,
598                   int *extra_rtrn)
599{
600    register XkbInfoPtr xkb;
601    XkbKSToMBFunc cvtr;
602    XPointer priv;
603    char tmp[4];
604    int n;
605
606    xkb = dpy->xkb_info;
607    if (!xkb->cvt.KSToMB) {
608        _XkbGetConverters(_XkbGetCharset(), &xkb->cvt);
609        _XkbGetConverters("ISO8859-1", &xkb->latin1cvt);
610    }
611
612    if (extra_rtrn)
613        *extra_rtrn = 0;
614
615    if ((buffer == NULL) || (nbytes == 0)) {
616        buffer = tmp;
617        nbytes = 4;
618    }
619
620    /* see if symbol rebound, if so, return that string. */
621    n = XkbLookupKeyBinding(dpy, *sym_rtrn, mods, buffer, nbytes, extra_rtrn);
622    if (n)
623        return n;
624
625    if (nbytes > 0)
626        buffer[0] = '\0';
627
628    if (xkb->cvt.KSToUpper && (mods & LockMask)) {
629        *sym_rtrn = (*xkb->cvt.KSToUpper) (*sym_rtrn);
630    }
631    if (xkb->xlib_ctrls & XkbLC_ForceLatin1Lookup) {
632        cvtr = xkb->latin1cvt.KSToMB;
633        priv = xkb->latin1cvt.KSToMBPriv;
634    }
635    else {
636        cvtr = xkb->cvt.KSToMB;
637        priv = xkb->cvt.KSToMBPriv;
638    }
639
640    n = (*cvtr) (priv, *sym_rtrn, buffer, nbytes, extra_rtrn);
641
642    if ((!xkb->cvt.KSToUpper) && (mods & LockMask)) {
643        register int i;
644        int change;
645
646        for (i = change = 0; i < n; i++) {
647            char ch = toupper(buffer[i]);
648            change = (change || (buffer[i] != ch));
649            buffer[i] = ch;
650        }
651        if (change) {
652            if (n == 1)
653                *sym_rtrn =
654                    (*xkb->cvt.MBToKS) (xkb->cvt.MBToKSPriv, buffer, n, NULL);
655            else
656                *sym_rtrn = NoSymbol;
657        }
658    }
659
660    if (mods & ControlMask) {
661        if (n == 1) {
662            buffer[0] = XkbToControl(buffer[0]);
663            if (nbytes > 1)
664                buffer[1] = '\0';
665            return 1;
666        }
667        if (nbytes > 0)
668            buffer[0] = '\0';
669        return 0;
670    }
671    return n;
672}
673
674int
675XLookupString(register XKeyEvent *event,
676              char *buffer,
677              int nbytes,
678              KeySym *keysym,
679              XComposeStatus *status)
680{
681    KeySym dummy;
682    int rtrnLen;
683    unsigned int new_mods;
684    Display *dpy = event->display;
685
686    if (keysym == NULL)
687        keysym = &dummy;
688    if (!XkbLookupKeySym(dpy, event->keycode, event->state, &new_mods, keysym))
689        return 0;
690    new_mods = (event->state & (~new_mods));
691
692    /* find the group where a symbol can be converted to control one */
693    if (new_mods & ControlMask && *keysym > 0x7F &&
694        (dpy->xkb_info->xlib_ctrls & XkbLC_ControlFallback)) {
695        XKeyEvent tmp_ev = *event;
696        KeySym tmp_keysym;
697        unsigned int tmp_new_mods;
698
699        if (_XkbUnavailable(dpy)) {
700            tmp_ev.state = event->state ^ dpy->mode_switch;
701            if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
702                                &tmp_new_mods, &tmp_keysym) &&
703                tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
704                *keysym = tmp_keysym;
705            }
706        }
707        else {
708            int n = XkbKeyNumGroups(dpy->xkb_info->desc, tmp_ev.keycode);
709            int i;
710
711            for (i = 0; i < n; i++) {
712                if (XkbGroupForCoreState(event->state) == i)
713                    continue;
714                tmp_ev.state = XkbBuildCoreState(tmp_ev.state, i);
715                if (XkbLookupKeySym(dpy, tmp_ev.keycode, tmp_ev.state,
716                                    &tmp_new_mods, &tmp_keysym) &&
717                    tmp_keysym != NoSymbol && tmp_keysym < 0x80) {
718                    *keysym = tmp_keysym;
719                    new_mods = (event->state & (~tmp_new_mods));
720                    break;
721                }
722            }
723        }
724    }
725
726    /* We *should* use the new_mods (which does not contain any modifiers */
727    /* that were used to compute the symbol here, but pre-XKB XLookupString */
728    /* did not and we have to remain compatible.  Sigh. */
729    if (_XkbUnavailable(dpy) ||
730        (dpy->xkb_info->xlib_ctrls & XkbLC_ConsumeLookupMods) == 0)
731        new_mods = event->state;
732
733    rtrnLen = XkbLookupKeyBinding(dpy, *keysym, new_mods, buffer, nbytes, NULL);
734    if (rtrnLen > 0)
735        return rtrnLen;
736
737    return XkbTranslateKeySym(dpy, keysym, new_mods, buffer, nbytes, NULL);
738}
739
740
741int
742XkbLookupKeyBinding(Display *dpy,
743                    register KeySym sym,
744                    unsigned int mods,
745                    char *buffer,
746                    int nbytes,
747                    int *extra_rtrn)
748{
749    register struct _XKeytrans *p;
750
751    if (extra_rtrn)
752        *extra_rtrn = 0;
753    for (p = dpy->key_bindings; p; p = p->next) {
754        if (((mods & AllMods) == p->state) && (sym == p->key)) {
755            int tmp = p->len;
756
757            if (tmp > nbytes) {
758                if (extra_rtrn)
759                    *extra_rtrn = (tmp - nbytes);
760                tmp = nbytes;
761            }
762            memcpy(buffer, p->string, (size_t) tmp);
763            if (tmp < nbytes)
764                buffer[tmp] = '\0';
765            return tmp;
766        }
767    }
768    return 0;
769}
770
771char
772XkbToControl(char ch)
773{
774    register char c = ch;
775
776    if ((c >= '@' && c < '\177') || c == ' ')
777        c &= 0x1F;
778    else if (c == '2')
779        c = '\000';
780    else if (c >= '3' && c <= '7')
781        c -= ('3' - '\033');
782    else if (c == '8')
783        c = '\177';
784    else if (c == '/')
785        c = '_' & 0x1F;
786    return c;
787}
788