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