TMkey.c revision fdf6a26f
1/***********************************************************
2Copyright (c) 1993, Oracle and/or its affiliates.
3
4Permission is hereby granted, free of charge, to any person obtaining a
5copy of this software and associated documentation files (the "Software"),
6to deal in the Software without restriction, including without limitation
7the rights to use, copy, modify, merge, publish, distribute, sublicense,
8and/or sell copies of the Software, and to permit persons to whom the
9Software is furnished to do so, subject to the following conditions:
10
11The above copyright notice and this permission notice (including the next
12paragraph) shall be included in all copies or substantial portions of the
13Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
21DEALINGS IN THE SOFTWARE.
22
23Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24
25                        All Rights Reserved
26
27Permission to use, copy, modify, and distribute this software and its
28documentation for any purpose and without fee is hereby granted,
29provided that the above copyright notice appear in all copies and that
30both that copyright notice and this permission notice appear in
31supporting documentation, and that the name of Digital not be
32used in advertising or publicity pertaining to distribution of the
33software without specific, written prior permission.
34
35DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41SOFTWARE.
42
43******************************************************************/
44
45/*
46
47Copyright 1987, 1988, 1994, 1998  The Open Group
48
49Permission to use, copy, modify, distribute, and sell this software and its
50documentation for any purpose is hereby granted without fee, provided that
51the above copyright notice appear in all copies and that both that
52copyright notice and this permission notice appear in supporting
53documentation.
54
55The above copyright notice and this permission notice shall be included in
56all copies or substantial portions of the Software.
57
58THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64
65Except as contained in this notice, the name of The Open Group shall not be
66used in advertising or otherwise to promote the sale, use or other dealings
67in this Software without prior written authorization from The Open Group.
68
69*/
70
71#define XK_MISCELLANY
72#define XK_LATIN1
73#define XK_LATIN2
74#define XK_LATIN3
75#define XK_LATIN4
76
77#ifdef HAVE_CONFIG_H
78#include <config.h>
79#endif
80#include "IntrinsicI.h"
81#include <X11/keysymdef.h>
82#ifdef XKB
83#include <X11/XKBlib.h>
84#endif
85
86#define FLUSHKEYCACHE(ctx) \
87        memset((void *)&ctx->keycache, 0, sizeof(TMKeyCache))
88
89/*
90 * The following array reorders the modifier bits so that the most common ones
91 * (used by a translator) are in the top-most bits with respect to the size of
92 * the keycache.  The array currently just reverses the bits as a good guess.
93 * This might be more trouble than it is worth, but it seems to help.
94 */
95
96#define FM(i) i >> (8 - TMKEYCACHELOG2)
97
98/* *INDENT-OFF* */
99static const unsigned char modmix[256] = {
100FM(0x0f), FM(0x8f), FM(0x4f), FM(0xcf), FM(0x2f), FM(0xaf), FM(0x6f), FM(0xef),
101FM(0x1f), FM(0x9f), FM(0x5f), FM(0xdf), FM(0x3f), FM(0xbf), FM(0x7f), FM(0xff),
102FM(0x07), FM(0x87), FM(0x47), FM(0xc7), FM(0x27), FM(0xa7), FM(0x67), FM(0xe7),
103FM(0x17), FM(0x97), FM(0x57), FM(0xd7), FM(0x37), FM(0xb7), FM(0x77), FM(0xf7),
104FM(0x0b), FM(0x8b), FM(0x4b), FM(0xcb), FM(0x2b), FM(0xab), FM(0x6b), FM(0xeb),
105FM(0x1b), FM(0x9b), FM(0x5b), FM(0xdb), FM(0x3b), FM(0xbb), FM(0x7b), FM(0xfb),
106FM(0x03), FM(0x83), FM(0x43), FM(0xc3), FM(0x23), FM(0xa3), FM(0x63), FM(0xe3),
107FM(0x13), FM(0x93), FM(0x53), FM(0xd3), FM(0x33), FM(0xb3), FM(0x73), FM(0xf3),
108FM(0x0d), FM(0x8d), FM(0x4d), FM(0xcd), FM(0x2d), FM(0xad), FM(0x6d), FM(0xed),
109FM(0x1d), FM(0x9d), FM(0x5d), FM(0xdd), FM(0x3d), FM(0xbd), FM(0x7d), FM(0xfd),
110FM(0x05), FM(0x85), FM(0x45), FM(0xc5), FM(0x25), FM(0xa5), FM(0x65), FM(0xe5),
111FM(0x15), FM(0x95), FM(0x55), FM(0xd5), FM(0x35), FM(0xb5), FM(0x75), FM(0xf5),
112FM(0x09), FM(0x89), FM(0x49), FM(0xc9), FM(0x29), FM(0xa9), FM(0x69), FM(0xe9),
113FM(0x19), FM(0x99), FM(0x59), FM(0xd9), FM(0x39), FM(0xb9), FM(0x79), FM(0xf9),
114FM(0x01), FM(0x81), FM(0x41), FM(0xc1), FM(0x21), FM(0xa1), FM(0x61), FM(0xe1),
115FM(0x11), FM(0x91), FM(0x51), FM(0xd1), FM(0x31), FM(0xb1), FM(0x71), FM(0xf1),
116FM(0x00), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee),
117FM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe),
118FM(0x08), FM(0x88), FM(0x48), FM(0xc8), FM(0x28), FM(0xa8), FM(0x68), FM(0xe8),
119FM(0x18), FM(0x98), FM(0x58), FM(0xd8), FM(0x38), FM(0xb8), FM(0x78), FM(0xf8),
120FM(0x04), FM(0x84), FM(0x44), FM(0xc4), FM(0x24), FM(0xa4), FM(0x64), FM(0xe4),
121FM(0x14), FM(0x94), FM(0x54), FM(0xd4), FM(0x34), FM(0xb4), FM(0x74), FM(0xf4),
122FM(0x0c), FM(0x8c), FM(0x4c), FM(0xcc), FM(0x2c), FM(0xac), FM(0x6c), FM(0xec),
123FM(0x1c), FM(0x9c), FM(0x5c), FM(0xdc), FM(0x3c), FM(0xbc), FM(0x7c), FM(0xfc),
124FM(0x02), FM(0x82), FM(0x42), FM(0xc2), FM(0x22), FM(0xa2), FM(0x62), FM(0xe2),
125FM(0x12), FM(0x92), FM(0x52), FM(0xd2), FM(0x32), FM(0xb2), FM(0x72), FM(0xf2),
126FM(0x0a), FM(0x8a), FM(0x4a), FM(0xca), FM(0x2a), FM(0xaa), FM(0x6a), FM(0xea),
127FM(0x1a), FM(0x9a), FM(0x5a), FM(0xda), FM(0x3a), FM(0xba), FM(0x7a), FM(0xfa),
128FM(0x06), FM(0x86), FM(0x46), FM(0xc6), FM(0x26), FM(0xa6), FM(0x66), FM(0xe6),
129FM(0x16), FM(0x96), FM(0x56), FM(0xd6), FM(0x36), FM(0xb6), FM(0x76), FM(0xf6),
130FM(0x0e), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee),
131FM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe)
132};
133/* *INDENT-ON* */
134#undef FM
135
136#define MOD_RETURN(ctx, key) (ctx)->keycache.modifiers_return[key]
137
138#define TRANSLATE(ctx,pd,dpy,key,mod,mod_ret,sym_ret) \
139{ \
140    int _i_ = (((key) - (TMLongCard) (pd)->min_keycode + modmix[(mod) & 0xff]) & \
141               (TMKEYCACHESIZE-1)); \
142    if ((key) == 0) { /* Xlib XIM composed input */ \
143        mod_ret = 0; \
144        sym_ret = 0; \
145    } else if (   /* not Xlib XIM composed input */ \
146        (ctx)->keycache.keycode[_i_] == (key) && \
147        (ctx)->keycache.modifiers[_i_] == (mod)) { \
148        mod_ret = MOD_RETURN(ctx, key); \
149        sym_ret = (ctx)->keycache.keysym[_i_]; \
150    } else { \
151        XtTranslateKeycode(dpy, (KeyCode) key, mod, &mod_ret, &sym_ret); \
152        (ctx)->keycache.keycode[_i_] = (KeyCode) (key); \
153        (ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
154        (ctx)->keycache.keysym[_i_] = sym_ret; \
155        MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \
156    } \
157}
158
159#define UPDATE_CACHE(ctx, pd, key, mod, mod_ret, sym_ret) \
160{ \
161    int _i_ = (((key) - (TMLongCard) (pd)->min_keycode + modmix[(mod) & 0xff]) & \
162               (TMKEYCACHESIZE-1)); \
163    (ctx)->keycache.keycode[_i_] = (KeyCode) (key); \
164    (ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
165    (ctx)->keycache.keysym[_i_] = sym_ret; \
166    MOD_RETURN(ctx, key) = (unsigned char)(mod_ret); \
167}
168
169/* usual number of expected keycodes in XtKeysymToKeycodeList */
170#define KEYCODE_ARRAY_SIZE 10
171
172Boolean
173_XtComputeLateBindings(Display *dpy,
174                       LateBindingsPtr lateModifiers,
175                       Modifiers *computed,
176                       Modifiers *computedMask)
177{
178    int i, j, ref;
179    ModToKeysymTable *temp;
180    XtPerDisplay perDisplay;
181    KeySym tempKeysym = NoSymbol;
182
183    perDisplay = _XtGetPerDisplay(dpy);
184    if (perDisplay == NULL) {
185        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
186                        "displayError", "invalidDisplay", XtCXtToolkitError,
187                        "Can't find display structure", NULL, NULL);
188        return FALSE;
189    }
190    _InitializeKeysymTables(dpy, perDisplay);
191    for (ref = 0; lateModifiers[ref].keysym; ref++) {
192        Boolean found = FALSE;
193
194        for (i = 0; i < 8; i++) {
195            temp = &(perDisplay->modsToKeysyms[i]);
196            for (j = 0; j < temp->count; j++) {
197                if (perDisplay->modKeysyms[temp->idx + j] ==
198                    lateModifiers[ref].keysym) {
199                    *computedMask = *computedMask | temp->mask;
200                    if (!lateModifiers[ref].knot)
201                        *computed |= temp->mask;
202                    tempKeysym = lateModifiers[ref].keysym;
203                    found = TRUE;
204                    break;
205                }
206            }
207            if (found)
208                break;
209        }
210        if (!found && !lateModifiers[ref].knot)
211            if (!lateModifiers[ref].pair && (tempKeysym == NoSymbol))
212                return FALSE;
213        /* if you didn't find the modifier and the modifier must be
214           asserted then return FALSE. If you didn't find the modifier
215           and the modifier must be off, then it is OK . Don't
216           return FALSE if this is the first member of a pair or if
217           it is the second member of a pair when the first member
218           was bound to a modifier */
219        if (!lateModifiers[ref].pair)
220            tempKeysym = NoSymbol;
221    }
222    return TRUE;
223}
224
225void
226_XtAllocTMContext(XtPerDisplay pd)
227{
228    TMKeyContext ctx;
229
230    ctx = (TMKeyContext) _XtHeapAlloc(&pd->heap, sizeof(TMKeyContextRec));
231    ctx->event = NULL;
232    ctx->serial = 0;
233    ctx->keysym = NoSymbol;
234    ctx->modifiers = 0;
235    FLUSHKEYCACHE(ctx);
236    pd->tm_context = ctx;
237}
238
239static unsigned int
240num_bits(unsigned long mask)
241{
242    register unsigned long y;
243
244    y = (mask >> 1) & 033333333333;
245    y = mask - y - ((y >> 1) & 033333333333);
246    return ((unsigned int) (((y + (y >> 3)) & 030707070707) % 077));
247}
248
249Boolean
250_XtMatchUsingDontCareMods(TMTypeMatch typeMatch,
251                          TMModifierMatch modMatch,
252                          TMEventPtr eventSeq)
253{
254    Modifiers modifiers_return;
255    KeySym keysym_return;
256    Modifiers useful_mods;
257    Modifiers computed = 0;
258    Modifiers computedMask = 0;
259    Boolean resolved = TRUE;
260    Display *dpy = eventSeq->xev->xany.display;
261    XtPerDisplay pd;
262
263    if (modMatch->lateModifiers != NULL)
264        resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
265                                          &computed, &computedMask);
266    if (!resolved)
267        return FALSE;
268    computed = (Modifiers) (computed | modMatch->modifiers);
269    computedMask = (Modifiers) (computedMask | modMatch->modifierMask); /* gives do-care mask */
270
271    if ((computed & computedMask) == (eventSeq->event.modifiers & computedMask)) {
272        TMKeyContext tm_context;
273        int num_modbits;
274        int i;
275
276        pd = _XtGetPerDisplay(dpy);
277        tm_context = pd->tm_context;
278        TRANSLATE(tm_context, pd, dpy, (KeyCode) eventSeq->event.eventCode,
279                  (unsigned) 0, modifiers_return, keysym_return);
280
281        if ((keysym_return & typeMatch->eventCodeMask) == typeMatch->eventCode) {
282            tm_context->event = eventSeq->xev;
283            tm_context->serial = eventSeq->xev->xany.serial;
284            tm_context->keysym = keysym_return;
285            tm_context->modifiers = (Modifiers) 0;
286            return TRUE;
287        }
288        useful_mods = ~computedMask & modifiers_return;
289        if (useful_mods == 0)
290            return FALSE;
291
292        switch (num_modbits = (int) num_bits(useful_mods)) {
293        case 1:
294        case 8:
295            /*
296             * one modbit should never happen, in fact the implementation
297             * of XtTranslateKey and XmTranslateKey guarantee that it
298             * won't, so don't care if the loop is set up for the case
299             * when one modbit is set.
300             * The performance implications of all eight modbits being
301             * set is horrendous. This isn't a problem with Xt/Xaw based
302             * applications. We can only hope that Motif's virtual
303             * modifiers won't result in all eight modbits being set.
304             */
305            for (i = (int) useful_mods; i > 0; i--) {
306                TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
307                          (Modifiers) i, modifiers_return, keysym_return);
308                if (keysym_return ==
309                    (typeMatch->eventCode & typeMatch->eventCodeMask)) {
310                    tm_context->event = eventSeq->xev;
311                    tm_context->serial = eventSeq->xev->xany.serial;
312                    tm_context->keysym = keysym_return;
313                    tm_context->modifiers = (Modifiers) i;
314                    return TRUE;
315                }
316            }
317            break;
318        default:               /* (2..7) */
319        {
320            /*
321             * Only translate using combinations of the useful modifiers.
322             * to minimize the chance of invalidating the cache.
323             */
324            static char pows[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
325            Modifiers tmod, mod_masks[8];
326            int j;
327
328            for (tmod = 1, i = 0; tmod <= (Mod5Mask << 1); tmod <<= 1)
329                if (tmod & useful_mods)
330                    mod_masks[i++] = tmod;
331            for (j = (int) pows[num_modbits]; j > 0; j--) {
332                tmod = 0;
333                for (i = 0; i < num_modbits; i++)
334                    if (j & (1 << i))
335                        tmod |= mod_masks[i];
336                TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
337                          tmod, modifiers_return, keysym_return);
338                if (keysym_return ==
339                    (typeMatch->eventCode & typeMatch->eventCodeMask)) {
340                    tm_context->event = eventSeq->xev;
341                    tm_context->serial = eventSeq->xev->xany.serial;
342                    tm_context->keysym = keysym_return;
343                    tm_context->modifiers = (Modifiers) i;
344                    return TRUE;
345                }
346            }
347        }
348            break;
349        }                       /* switch (num_modbits) */
350    }
351    return FALSE;
352}
353
354void
355XtConvertCase(Display *dpy,
356              KeySym keysym,
357              KeySym *lower_return,
358              KeySym *upper_return)
359{
360    XtPerDisplay pd;
361    CaseConverterPtr ptr;
362
363    DPY_TO_APPCON(dpy);
364
365    LOCK_APP(app);
366    pd = _XtGetPerDisplay(dpy);
367
368    *lower_return = *upper_return = keysym;
369    for (ptr = pd->case_cvt; ptr; ptr = ptr->next)
370        if (ptr->start <= keysym && keysym <= ptr->stop) {
371            (*ptr->proc) (dpy, keysym, lower_return, upper_return);
372            return;
373        }
374    XConvertCase(keysym, lower_return, upper_return);
375    UNLOCK_APP(app);
376}
377
378Boolean
379_XtMatchUsingStandardMods(TMTypeMatch typeMatch,
380                          TMModifierMatch modMatch,
381                          TMEventPtr eventSeq)
382{
383    Modifiers modifiers_return;
384    KeySym keysym_return;
385    Modifiers computed = 0;
386    Modifiers computedMask = 0;
387    Display *dpy = eventSeq->xev->xany.display;
388    XtPerDisplay pd = _XtGetPerDisplay(dpy);
389    TMKeyContext tm_context = pd->tm_context;
390    Modifiers translateModifiers;
391
392    /* To maximize cache utilization, we mask off nonstandard modifiers
393       before cache lookup.  For a given key translator, standard modifiers
394       are constant per KeyCode.  If a key translator uses no standard
395       modifiers this implementation will never reference the cache.
396     */
397
398    modifiers_return = MOD_RETURN(tm_context, eventSeq->event.eventCode);
399    if (!modifiers_return) {
400        XtTranslateKeycode(dpy, (KeyCode) eventSeq->event.eventCode,
401                           (Modifiers) eventSeq->event.modifiers,
402                           &modifiers_return, &keysym_return);
403        translateModifiers =
404            (Modifiers) (eventSeq->event.modifiers & modifiers_return);
405        UPDATE_CACHE(tm_context, pd, eventSeq->event.eventCode,
406                     translateModifiers, modifiers_return, keysym_return);
407    }
408    else {
409        translateModifiers =
410            (Modifiers) (eventSeq->event.modifiers & modifiers_return);
411        TRANSLATE(tm_context, pd, dpy, (KeyCode) eventSeq->event.eventCode,
412                  translateModifiers, modifiers_return, keysym_return);
413    }
414
415    if ((typeMatch->eventCode & typeMatch->eventCodeMask) ==
416        (keysym_return & typeMatch->eventCodeMask)) {
417        Boolean resolved = TRUE;
418
419        if (modMatch->lateModifiers != NULL)
420            resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
421                                              &computed, &computedMask);
422        if (!resolved)
423            return FALSE;
424        computed = (Modifiers) (computed | modMatch->modifiers);
425        computedMask = (Modifiers) (computedMask | modMatch->modifierMask);
426
427        if ((computed & computedMask) ==
428            (eventSeq->event.modifiers & ~modifiers_return & computedMask)) {
429            tm_context->event = eventSeq->xev;
430            tm_context->serial = eventSeq->xev->xany.serial;
431            tm_context->keysym = keysym_return;
432            tm_context->modifiers = translateModifiers;
433            return TRUE;
434        }
435    }
436    return FALSE;
437}
438
439void
440_XtBuildKeysymTables(Display *dpy, register XtPerDisplay pd)
441{
442    ModToKeysymTable *table;
443    int maxCount, i, j, k, tempCount, idx;
444    KeySym keysym, tempKeysym;
445    XModifierKeymap *modKeymap;
446    KeyCode keycode;
447
448#define KeysymTableSize 16
449
450    FLUSHKEYCACHE(pd->tm_context);
451
452    XFree((char *) pd->keysyms);
453    pd->keysyms_serial = NextRequest(dpy);
454    pd->keysyms = XGetKeyboardMapping(dpy, (KeyCode) pd->min_keycode,
455                                      pd->max_keycode - pd->min_keycode + 1,
456                                      &pd->keysyms_per_keycode);
457    XtFree((char *) pd->modKeysyms);
458
459    pd->modKeysyms = XtMallocArray(KeysymTableSize, (Cardinal) sizeof(KeySym));
460    maxCount = KeysymTableSize;
461    tempCount = 0;
462
463    XtFree((char *) pd->modsToKeysyms);
464    table = XtMallocArray(8, (Cardinal) sizeof(ModToKeysymTable));
465    pd->modsToKeysyms = table;
466
467    table[0].mask = ShiftMask;
468    table[1].mask = LockMask;
469    table[2].mask = ControlMask;
470    table[3].mask = Mod1Mask;
471    table[4].mask = Mod2Mask;
472    table[5].mask = Mod3Mask;
473    table[6].mask = Mod4Mask;
474    table[7].mask = Mod5Mask;
475    tempKeysym = 0;
476
477    modKeymap = XGetModifierMapping(dpy);
478    for (i = 0; i < 32; i++)
479        pd->isModifier[i] = 0;
480    pd->mode_switch = 0;
481    pd->num_lock = 0;
482    for (i = 0; i < 8; i++) {
483        table[i].idx = tempCount;
484        table[i].count = 0;
485        for (j = 0; j < modKeymap->max_keypermod; j++) {
486            keycode = modKeymap->modifiermap[i * modKeymap->max_keypermod + j];
487            if (keycode != 0) {
488                pd->isModifier[keycode >> 3] |=
489                    (unsigned char) (1 << (keycode & 7));
490                for (k = 0; k < pd->keysyms_per_keycode; k++) {
491                    idx = ((keycode - pd->min_keycode) *
492                           pd->keysyms_per_keycode) + k;
493                    keysym = pd->keysyms[idx];
494                    if ((keysym == XK_Mode_switch) && (i > 2))
495                        pd->mode_switch =
496                            (pd->mode_switch | (Modifiers) (1 << i));
497                    if ((keysym == XK_Num_Lock) && (i > 2))
498                        pd->num_lock = (pd->num_lock | (Modifiers) (1 << i));
499                    if (keysym != 0 && keysym != tempKeysym) {
500                        if (tempCount == maxCount) {
501                            maxCount += KeysymTableSize;
502                            pd->modKeysyms =
503                                XtReallocArray(pd->modKeysyms,
504                                               (Cardinal) maxCount,
505                                               (Cardinal) sizeof(KeySym));
506                        }
507                        pd->modKeysyms[tempCount++] = keysym;
508                        table[i].count++;
509                        tempKeysym = keysym;
510                    }
511                }
512            }
513        }
514    }
515    pd->lock_meaning = NoSymbol;
516    for (i = 0; i < table[1].count; i++) {
517        keysym = pd->modKeysyms[table[1].idx + i];
518        if (keysym == XK_Caps_Lock) {
519            pd->lock_meaning = XK_Caps_Lock;
520            break;
521        }
522        else if (keysym == XK_Shift_Lock) {
523            pd->lock_meaning = XK_Shift_Lock;
524        }
525    }
526    XFreeModifiermap(modKeymap);
527}
528
529void
530XtTranslateKeycode(Display *dpy,
531                   _XtKeyCode keycode,
532                   Modifiers modifiers,
533                   Modifiers *modifiers_return,
534                   KeySym *keysym_return)
535{
536    XtPerDisplay pd;
537
538    DPY_TO_APPCON(dpy);
539
540    LOCK_APP(app);
541    pd = _XtGetPerDisplay(dpy);
542    _InitializeKeysymTables(dpy, pd);
543    (*pd->defaultKeycodeTranslator) (dpy, keycode, modifiers, modifiers_return,
544                                     keysym_return);
545    UNLOCK_APP(app);
546}
547
548/* This code should match XTranslateKey (internal, sigh) in Xlib */
549void
550XtTranslateKey(register Display *dpy,
551               _XtKeyCode keycode,
552               Modifiers modifiers,
553               Modifiers *modifiers_return,
554               KeySym *keysym_return)
555{
556#ifndef XKB
557    XtPerDisplay pd;
558    int per;
559    register KeySym *syms;
560    KeySym sym, lsym, usym;
561
562    DPY_TO_APPCON(dpy);
563
564    LOCK_APP(app);
565    pd = _XtGetPerDisplay(dpy);
566    *modifiers_return = (ShiftMask | LockMask) | pd->mode_switch | pd->num_lock;
567    if (((int) keycode < pd->min_keycode) || ((int) keycode > pd->max_keycode)) {
568        *keysym_return = NoSymbol;
569        UNLOCK_APP(app);
570        return;
571    }
572    per = pd->keysyms_per_keycode;
573    syms = &pd->keysyms[(keycode - pd->min_keycode) * per];
574    while ((per > 2) && (syms[per - 1] == NoSymbol))
575        per--;
576    if ((per > 2) && (modifiers & pd->mode_switch)) {
577        syms += 2;
578        per -= 2;
579    }
580    if ((modifiers & pd->num_lock) &&
581        (per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) {
582        if ((modifiers & ShiftMask) ||
583            ((modifiers & LockMask) && (pd->lock_meaning == XK_Shift_Lock)))
584            *keysym_return = syms[0];
585        else
586            *keysym_return = syms[1];
587    }
588    else if (!(modifiers & ShiftMask) &&
589             (!(modifiers & LockMask) || (pd->lock_meaning == NoSymbol))) {
590        if ((per == 1) || (syms[1] == NoSymbol))
591            XtConvertCase(dpy, syms[0], keysym_return, &usym);
592        else
593            *keysym_return = syms[0];
594    }
595    else if (!(modifiers & LockMask) || (pd->lock_meaning != XK_Caps_Lock)) {
596        if ((per == 1) || ((usym = syms[1]) == NoSymbol))
597            XtConvertCase(dpy, syms[0], &lsym, &usym);
598        *keysym_return = usym;
599    }
600    else {
601        if ((per == 1) || ((sym = syms[1]) == NoSymbol))
602            sym = syms[0];
603        XtConvertCase(dpy, sym, &lsym, &usym);
604        if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
605            ((sym != usym) || (lsym == usym)))
606            XtConvertCase(dpy, syms[0], &lsym, &usym);
607        *keysym_return = usym;
608    }
609
610    if (*keysym_return == XK_VoidSymbol)
611        *keysym_return = NoSymbol;
612    UNLOCK_APP(app);
613#else
614    XkbLookupKeySym(dpy, (KeyCode) keycode, modifiers, modifiers_return,
615                    keysym_return);
616#endif
617}
618
619void
620XtSetKeyTranslator(Display *dpy, XtKeyProc translator)
621{
622    XtPerDisplay pd;
623
624    DPY_TO_APPCON(dpy);
625
626    LOCK_APP(app);
627    pd = _XtGetPerDisplay(dpy);
628
629    pd->defaultKeycodeTranslator = translator;
630    FLUSHKEYCACHE(pd->tm_context);
631    /* XXX should now redo grabs */
632    UNLOCK_APP(app);
633}
634
635void
636XtRegisterCaseConverter(Display *dpy,
637                        XtCaseProc proc,
638                        KeySym start,
639                        KeySym stop)
640{
641    XtPerDisplay pd;
642    CaseConverterPtr ptr, prev;
643
644    DPY_TO_APPCON(dpy);
645
646    LOCK_APP(app);
647    pd = _XtGetPerDisplay(dpy);
648
649    ptr = (CaseConverterPtr) __XtMalloc(sizeof(CaseConverterRec));
650    ptr->start = start;
651    ptr->stop = stop;
652    ptr->proc = proc;
653    ptr->next = pd->case_cvt;
654    pd->case_cvt = ptr;
655
656    /* Remove obsolete case converters from the list */
657    prev = ptr;
658    for (ptr = ptr->next; ptr; ptr = prev->next) {
659        if (start <= ptr->start && stop >= ptr->stop) {
660            prev->next = ptr->next;
661            XtFree((char *) ptr);
662        }
663        else
664            prev = ptr;
665    }
666    FLUSHKEYCACHE(pd->tm_context);
667    /* XXX should now redo grabs */
668    UNLOCK_APP(app);
669}
670
671KeySym *
672XtGetKeysymTable(Display *dpy,
673                 KeyCode *min_keycode_return,
674                 int *keysyms_per_keycode_return)
675{
676    XtPerDisplay pd;
677    KeySym *retval;
678
679    DPY_TO_APPCON(dpy);
680
681    LOCK_APP(app);
682    pd = _XtGetPerDisplay(dpy);
683    _InitializeKeysymTables(dpy, pd);
684    *min_keycode_return = (KeyCode) pd->min_keycode;    /* %%% */
685    *keysyms_per_keycode_return = pd->keysyms_per_keycode;
686    retval = pd->keysyms;
687    UNLOCK_APP(app);
688    return retval;
689}
690
691void
692XtKeysymToKeycodeList(Display *dpy,
693                      KeySym keysym,
694                      KeyCode **keycodes_return,
695                      Cardinal *keycount_return)
696{
697    XtPerDisplay pd;
698    unsigned keycode;
699    int per;
700    register KeySym *syms;
701    register int i, j;
702    KeySym lsym, usym;
703    unsigned maxcodes = 0;
704    unsigned ncodes = 0;
705    KeyCode *keycodes, *codeP = NULL;
706
707    DPY_TO_APPCON(dpy);
708
709    LOCK_APP(app);
710    pd = _XtGetPerDisplay(dpy);
711    _InitializeKeysymTables(dpy, pd);
712    keycodes = NULL;
713    per = pd->keysyms_per_keycode;
714    for (syms = pd->keysyms, keycode = (unsigned) pd->min_keycode;
715         (int) keycode <= pd->max_keycode; syms += per, keycode++) {
716        int match = 0;
717
718        for (j = 0; j < per; j++) {
719            if (syms[j] == keysym) {
720                match = 1;
721                break;
722            }
723        }
724        if (!match)
725            for (i = 1; i < 5; i += 2) {
726                if ((per == i) || ((per > i) && (syms[i] == NoSymbol))) {
727                    XtConvertCase(dpy, syms[i - 1], &lsym, &usym);
728                    if ((lsym == keysym) || (usym == keysym)) {
729                        match = 1;
730                        break;
731                    }
732                }
733            }
734        if (match) {
735            if (ncodes == maxcodes) {
736                KeyCode *old = keycodes;
737
738                maxcodes += KEYCODE_ARRAY_SIZE;
739                keycodes = XtMallocArray(maxcodes, (Cardinal) sizeof(KeyCode));
740                if (ncodes) {
741                    (void) memcpy(keycodes, old, ncodes * sizeof(KeyCode));
742                    XtFree((char *) old);
743                }
744                codeP = &keycodes[ncodes];
745            }
746            *codeP++ = (KeyCode) keycode;
747            ncodes++;
748        }
749    }
750    *keycodes_return = keycodes;
751    *keycount_return = ncodes;
752    UNLOCK_APP(app);
753}
754