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