TMkey.c revision 249c3046
1/*LINTLIBRARY*/
2
3/***********************************************************
4Copyright (c) 1993, Oracle and/or its affiliates. All rights reserved.
5
6Permission is hereby granted, free of charge, to any person obtaining a
7copy of this software and associated documentation files (the "Software"),
8to deal in the Software without restriction, including without limitation
9the rights to use, copy, modify, merge, publish, distribute, sublicense,
10and/or sell copies of the Software, and to permit persons to whom the
11Software is furnished to do so, subject to the following conditions:
12
13The above copyright notice and this permission notice (including the next
14paragraph) shall be included in all copies or substantial portions of the
15Software.
16
17THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
20THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
22FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
23DEALINGS IN THE SOFTWARE.
24
25Copyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
26
27                        All Rights Reserved
28
29Permission to use, copy, modify, and distribute this software and its
30documentation for any purpose and without fee is hereby granted,
31provided that the above copyright notice appear in all copies and that
32both that copyright notice and this permission notice appear in
33supporting documentation, and that the name of Digital not be
34used in advertising or publicity pertaining to distribution of the
35software without specific, written prior permission.
36
37DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
38ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
39DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
40ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
41WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
42ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
43SOFTWARE.
44
45******************************************************************/
46
47/*
48
49Copyright 1987, 1988, 1994, 1998  The Open Group
50
51Permission to use, copy, modify, distribute, and sell this software and its
52documentation for any purpose is hereby granted without fee, provided that
53the above copyright notice appear in all copies and that both that
54copyright notice and this permission notice appear in supporting
55documentation.
56
57The above copyright notice and this permission notice shall be included in
58all copies or substantial portions of the Software.
59
60THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
61IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
62FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
63OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
64AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
65CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
66
67Except as contained in this notice, the name of The Open Group shall not be
68used in advertising or otherwise to promote the sale, use or other dealings
69in this Software without prior written authorization from The Open Group.
70
71*/
72
73#define XK_MISCELLANY
74#define XK_LATIN1
75#define XK_LATIN2
76#define XK_LATIN3
77#define XK_LATIN4
78
79#ifdef HAVE_CONFIG_H
80#include <config.h>
81#endif
82#include "IntrinsicI.h"
83#include <X11/keysymdef.h>
84#ifdef XKB
85#include <X11/XKBlib.h>
86#endif
87
88#define FLUSHKEYCACHE(ctx) \
89	bzero((char *)&ctx->keycache, sizeof(TMKeyCache))
90
91/*
92 * The following array reorders the modifier bits so that the most common ones
93 * (used by a translator) are in the top-most bits with respect to the size of
94 * the keycache.  The array currently just reverses the bits as a good guess.
95 * This might be more trouble than it is worth, but it seems to help.
96 */
97
98#define FM(i) i >> (8 - TMKEYCACHELOG2)
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#undef FM
134
135#define MOD_RETURN(ctx, key) (ctx)->keycache.modifiers_return[key]
136
137#define TRANSLATE(ctx,pd,dpy,key,mod,mod_ret,sym_ret) \
138{ \
139    int _i_ = (((key) - (pd)->min_keycode + modmix[(mod) & 0xff]) & \
140	       (TMKEYCACHESIZE-1)); \
141    if ((key) == 0) { /* Xlib XIM composed input */ \
142	mod_ret = 0; \
143	sym_ret = 0; \
144    } else if (   /* not Xlib XIM composed input */ \
145	(ctx)->keycache.keycode[_i_] == (key) && \
146	(ctx)->keycache.modifiers[_i_] == (mod)) { \
147	mod_ret = MOD_RETURN(ctx, key); \
148	sym_ret = (ctx)->keycache.keysym[_i_]; \
149    } else { \
150	XtTranslateKeycode(dpy, key, mod, &mod_ret, &sym_ret); \
151	(ctx)->keycache.keycode[_i_] = key; \
152	(ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
153	(ctx)->keycache.keysym[_i_] = sym_ret; \
154	MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \
155    } \
156}
157
158#define UPDATE_CACHE(ctx, pd, key, mod, mod_ret, sym_ret) \
159{ \
160    int _i_ = (((key) - (pd)->min_keycode + modmix[(mod) & 0xff]) & \
161	       (TMKEYCACHESIZE-1)); \
162    (ctx)->keycache.keycode[_i_] = key; \
163    (ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
164    (ctx)->keycache.keysym[_i_] = sym_ret; \
165    MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \
166}
167
168/* usual number of expected keycodes in XtKeysymToKeycodeList */
169#define KEYCODE_ARRAY_SIZE 10
170
171Boolean _XtComputeLateBindings(
172    Display *dpy,
173    LateBindingsPtr lateModifiers,
174    Modifiers *computed,
175    Modifiers *computedMask)
176{
177    int i,j,ref;
178    ModToKeysymTable* temp;
179    XtPerDisplay perDisplay;
180    Boolean found;
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",
188            (String *)NULL, (Cardinal *)NULL);
189         return FALSE;
190    }
191    _InitializeKeysymTables(dpy, perDisplay);
192    for (ref=0; lateModifiers[ref].keysym; ref++) {
193        found = FALSE;
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; break;
204                }
205            }
206            if (found) break;
207        }
208        if (!found  && !lateModifiers[ref].knot)
209            if (!lateModifiers[ref].pair && (tempKeysym == NoSymbol))
210                return FALSE;
211        /* if you didn't find the modifier and the modifier must be
212           asserted then return FALSE. If you didn't find the modifier
213           and the modifier must be off, then it is OK . Don't
214           return FALSE if this is the first member of a pair or if
215           it is the second member of a pair when the first member
216           was bound to a modifier */
217    if (!lateModifiers[ref].pair) tempKeysym = NoSymbol;
218    }
219    return TRUE;
220}
221
222void _XtAllocTMContext(
223    XtPerDisplay pd)
224{
225    TMKeyContext ctx;
226    ctx = (TMKeyContext)_XtHeapAlloc(&pd->heap,
227				     sizeof(TMKeyContextRec));
228    ctx->event = NULL;
229    ctx->serial = 0;
230    ctx->keysym = NoSymbol;
231    ctx->modifiers = 0;
232    FLUSHKEYCACHE(ctx);
233    pd->tm_context = ctx;
234}
235
236static unsigned int num_bits(unsigned long mask)
237{
238    register unsigned long y;
239
240    y = (mask >> 1) &033333333333;
241    y = mask - y - ((y >>1) & 033333333333);
242    return ((unsigned int) (((y + (y >> 3)) & 030707070707) % 077));
243}
244
245Boolean _XtMatchUsingDontCareMods(
246    TMTypeMatch 	typeMatch,
247    TMModifierMatch 	modMatch,
248    TMEventPtr 		eventSeq)
249{
250    Modifiers modifiers_return;
251    KeySym keysym_return;
252    Modifiers useful_mods;
253    int i, num_modbits;
254    Modifiers computed = 0;
255    Modifiers computedMask = 0;
256    Boolean resolved = TRUE;
257    Display *dpy = eventSeq->xev->xany.display;
258    XtPerDisplay pd;
259    TMKeyContext tm_context;
260
261    if (modMatch->lateModifiers != NULL)
262	resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
263					  &computed, &computedMask);
264    if (!resolved) return FALSE;
265    computed |= modMatch->modifiers;
266    computedMask |= modMatch->modifierMask; /* gives do-care mask */
267
268    if ( (computed & computedMask) ==
269        (eventSeq->event.modifiers & computedMask) ) {
270
271	pd = _XtGetPerDisplay(dpy);
272	tm_context = pd->tm_context;
273	TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode,
274			    (unsigned)0, modifiers_return, keysym_return);
275
276        if ((keysym_return & typeMatch->eventCodeMask)  == typeMatch->eventCode ) {
277	    tm_context->event = eventSeq->xev;
278	    tm_context->serial = eventSeq->xev->xany.serial;
279	    tm_context->keysym = keysym_return;
280	    tm_context->modifiers = (Modifiers)0;
281	    return TRUE;
282	}
283        useful_mods = ~computedMask & modifiers_return;
284        if (useful_mods == 0) return FALSE;
285
286	switch (num_modbits = num_bits(useful_mods)) {
287	case 1:
288	case 8:
289	    /*
290	     * one modbit should never happen, in fact the implementation
291	     * of XtTranslateKey and XmTranslateKey guarantee that it
292	     * won't, so don't care if the loop is set up for the case
293	     * when one modbit is set.
294	     * The performance implications of all eight modbits being
295	     * set is horrendous. This isn't a problem with Xt/Xaw based
296	     * applications. We can only hope that Motif's virtual
297	     * modifiers won't result in all eight modbits being set.
298	     */
299	    for (i = useful_mods; i > 0; i--) {
300		TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
301			  (Modifiers)i, modifiers_return, keysym_return);
302		if (keysym_return ==
303		    (typeMatch->eventCode & typeMatch->eventCodeMask)) {
304		    tm_context->event = eventSeq->xev;
305		    tm_context->serial = eventSeq->xev->xany.serial;
306		    tm_context->keysym = keysym_return;
307		    tm_context->modifiers = (Modifiers)i;
308		    return TRUE;
309		}
310	    }
311	    break;
312	default: /* (2..7) */
313	    {
314	    /*
315	     * Only translate using combinations of the useful modifiers.
316	     * to minimize the chance of invalidating the cache.
317	     */
318		static char pows[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
319		Modifiers tmod, mod_masks[8];
320		int j;
321		for (tmod = 1, i = 0; tmod <= (Mod5Mask<<1); tmod <<= 1)
322		    if (tmod & useful_mods) mod_masks[i++] = tmod;
323		for (j = (int) pows[num_modbits]; j > 0; j--) {
324		    tmod = 0;
325		    for (i = 0; i < num_modbits; i++)
326			if (j & (1<<i)) tmod |= mod_masks[i];
327		    TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
328			      tmod, modifiers_return, keysym_return);
329		    if (keysym_return ==
330			(typeMatch->eventCode & typeMatch->eventCodeMask)) {
331			tm_context->event = eventSeq->xev;
332			tm_context->serial = eventSeq->xev->xany.serial;
333			tm_context->keysym = keysym_return;
334			tm_context->modifiers = (Modifiers)i;
335			return TRUE;
336		    }
337		}
338	    }
339	    break;
340	} /* switch (num_modbits) */
341    }
342    return FALSE;
343}
344
345void XtConvertCase(
346    Display *dpy,
347    KeySym keysym,
348    KeySym *lower_return,
349    KeySym *upper_return)
350{
351    XtPerDisplay pd;
352    CaseConverterPtr ptr;
353    DPY_TO_APPCON(dpy);
354
355    LOCK_APP(app);
356    pd = _XtGetPerDisplay(dpy);
357
358    *lower_return = *upper_return = keysym;
359    for (ptr=pd->case_cvt;  ptr; ptr = ptr->next)
360	if (ptr->start <= keysym && keysym <= ptr->stop) {
361	    (*ptr->proc)(dpy, keysym, lower_return, upper_return);
362	    return;
363	}
364    XConvertCase(keysym, lower_return, upper_return);
365    UNLOCK_APP(app);
366}
367
368Boolean _XtMatchUsingStandardMods (
369    TMTypeMatch typeMatch,
370    TMModifierMatch modMatch,
371    TMEventPtr eventSeq)
372{
373    Modifiers modifiers_return;
374    KeySym keysym_return;
375    Modifiers computed= 0;
376    Modifiers computedMask = 0;
377    Boolean resolved = TRUE;
378    Display *dpy = eventSeq->xev->xany.display;
379    XtPerDisplay pd = _XtGetPerDisplay(dpy);
380    TMKeyContext tm_context = pd->tm_context;
381    Modifiers translateModifiers;
382
383    /* To maximize cache utilization, we mask off nonstandard modifiers
384       before cache lookup.  For a given key translator, standard modifiers
385       are constant per KeyCode.  If a key translator uses no standard
386       modifiers this implementation will never reference the cache.
387     */
388
389    modifiers_return = MOD_RETURN(tm_context, eventSeq->event.eventCode);
390    if (!modifiers_return) {
391	XtTranslateKeycode(dpy, (KeyCode)eventSeq->event.eventCode,
392			   eventSeq->event.modifiers, &modifiers_return,
393			   &keysym_return);
394	translateModifiers = eventSeq->event.modifiers & modifiers_return;
395	UPDATE_CACHE(tm_context, pd, eventSeq->event.eventCode,
396		     translateModifiers, modifiers_return, keysym_return);
397    } else {
398	translateModifiers = eventSeq->event.modifiers & modifiers_return;
399	TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode,
400		  translateModifiers, modifiers_return, keysym_return);
401    }
402
403    if ((typeMatch->eventCode & typeMatch->eventCodeMask) ==
404             (keysym_return & typeMatch->eventCodeMask)) {
405        if (modMatch->lateModifiers != NULL)
406            resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
407					      &computed, &computedMask);
408        if (!resolved) return FALSE;
409        computed |= modMatch->modifiers;
410        computedMask |= modMatch->modifierMask;
411
412        if ((computed & computedMask) ==
413	    (eventSeq->event.modifiers & ~modifiers_return & computedMask)) {
414	    tm_context->event = eventSeq->xev;
415	    tm_context->serial = eventSeq->xev->xany.serial;
416	    tm_context->keysym = keysym_return;
417	    tm_context->modifiers = translateModifiers;
418	    return TRUE;
419	}
420    }
421    return FALSE;
422}
423
424
425void _XtBuildKeysymTables(
426    Display *dpy,
427    register XtPerDisplay pd)
428{
429    ModToKeysymTable *table;
430    int maxCount,i,j,k,tempCount,idx;
431    KeySym keysym,tempKeysym;
432    XModifierKeymap* modKeymap;
433    KeyCode keycode;
434#define KeysymTableSize 16
435
436    FLUSHKEYCACHE(pd->tm_context);
437    if (pd->keysyms)
438	XFree( (char *)pd->keysyms );
439    pd->keysyms_serial = NextRequest(dpy);
440    pd->keysyms = XGetKeyboardMapping(dpy, pd->min_keycode,
441				      pd->max_keycode-pd->min_keycode+1,
442				      &pd->keysyms_per_keycode);
443    if (pd->modKeysyms)
444	XtFree((char *)pd->modKeysyms);
445    if (pd->modsToKeysyms)
446	XtFree((char *)pd->modsToKeysyms);
447    pd->modKeysyms = (KeySym*)__XtMalloc((Cardinal)KeysymTableSize*sizeof(KeySym));
448    maxCount = KeysymTableSize;
449    tempCount = 0;
450
451    table = (ModToKeysymTable*)__XtMalloc((Cardinal)8*sizeof(ModToKeysymTable));
452    pd->modsToKeysyms = table;
453
454    table[0].mask = ShiftMask;
455    table[1].mask = LockMask;
456    table[2].mask = ControlMask;
457    table[3].mask = Mod1Mask;
458    table[4].mask = Mod2Mask;
459    table[5].mask = Mod3Mask;
460    table[6].mask = Mod4Mask;
461    table[7].mask = Mod5Mask;
462    tempKeysym = 0;
463
464    modKeymap = XGetModifierMapping(dpy);
465    for (i=0;i<32;i++)
466	pd->isModifier[i] = 0;
467    pd->mode_switch = 0;
468    pd->num_lock = 0;
469    for (i=0;i<8;i++) {
470        table[i].idx = tempCount;
471        table[i].count = 0;
472        for (j=0;j<modKeymap->max_keypermod;j++) {
473            keycode = modKeymap->modifiermap[i*modKeymap->max_keypermod+j];
474            if (keycode != 0) {
475		pd->isModifier[keycode>>3] |= 1 << (keycode & 7);
476                for (k=0; k<pd->keysyms_per_keycode;k++) {
477                    idx = ((keycode-pd->min_keycode)*
478                             pd->keysyms_per_keycode)+k;
479                    keysym = pd->keysyms[idx];
480		    if ((keysym == XK_Mode_switch) && (i > 2))
481			pd->mode_switch |= 1 << i;
482		    if ((keysym == XK_Num_Lock) && (i > 2))
483			pd->num_lock |= 1 << i;
484                    if (keysym != 0 && keysym != tempKeysym ){
485                        if (tempCount==maxCount) {
486                            maxCount += KeysymTableSize;
487                            pd->modKeysyms = (KeySym*)XtRealloc(
488                                (char*)pd->modKeysyms,
489                                (unsigned) (maxCount*sizeof(KeySym)) );
490                        }
491                        pd->modKeysyms[tempCount++] = keysym;
492                        table[i].count++;
493                        tempKeysym = keysym;
494                    }
495                }
496            }
497        }
498    }
499    pd->lock_meaning = NoSymbol;
500    for (i = 0; i < table[1].count; i++) {
501	keysym = pd->modKeysyms[table[1].idx + i];
502	if (keysym == XK_Caps_Lock) {
503	    pd->lock_meaning = XK_Caps_Lock;
504	    break;
505	} else if (keysym == XK_Shift_Lock) {
506	    pd->lock_meaning = XK_Shift_Lock;
507	}
508    }
509    XFreeModifiermap(modKeymap);
510}
511
512void XtTranslateKeycode (
513    Display *dpy,
514    _XtKeyCode keycode,
515    Modifiers modifiers,
516    Modifiers *modifiers_return,
517    KeySym *keysym_return)
518{
519    XtPerDisplay pd;
520    DPY_TO_APPCON(dpy);
521
522    LOCK_APP(app);
523    pd = _XtGetPerDisplay(dpy);
524    _InitializeKeysymTables(dpy, pd);
525    (*pd->defaultKeycodeTranslator)(
526            dpy,keycode,modifiers,modifiers_return,keysym_return);
527    UNLOCK_APP(app);
528}
529
530/* This code should match XTranslateKey (internal, sigh) in Xlib */
531void XtTranslateKey(
532    register Display *dpy,
533    _XtKeyCode keycode,
534    Modifiers modifiers,
535    Modifiers *modifiers_return,
536    KeySym *keysym_return)
537{
538#ifndef XKB
539    XtPerDisplay pd;
540    int per;
541    register KeySym *syms;
542    KeySym sym, lsym, usym;
543    DPY_TO_APPCON(dpy);
544
545    LOCK_APP(app);
546    pd = _XtGetPerDisplay(dpy);
547    *modifiers_return = (ShiftMask|LockMask) | pd->mode_switch | pd->num_lock;
548    if (((int)keycode < pd->min_keycode) || ((int)keycode > pd->max_keycode)) {
549	*keysym_return = NoSymbol;
550	UNLOCK_APP(app);
551	return;
552    }
553    per = pd->keysyms_per_keycode;
554    syms = &pd->keysyms[(keycode - pd->min_keycode) * per];
555    while ((per > 2) && (syms[per - 1] == NoSymbol))
556	per--;
557    if ((per > 2) && (modifiers & pd->mode_switch)) {
558	syms += 2;
559	per -= 2;
560    }
561    if ((modifiers & pd->num_lock) &&
562	(per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) {
563	if ((modifiers & ShiftMask) ||
564	    ((modifiers & LockMask) && (pd->lock_meaning == XK_Shift_Lock)))
565	    *keysym_return = syms[0];
566	else
567	    *keysym_return = syms[1];
568    } else if (!(modifiers & ShiftMask) &&
569	(!(modifiers & LockMask) || (pd->lock_meaning == NoSymbol))) {
570	if ((per == 1) || (syms[1] == NoSymbol))
571	    XtConvertCase(dpy, syms[0], keysym_return, &usym);
572	else
573	    *keysym_return = syms[0];
574    } else if (!(modifiers & LockMask) ||
575	       (pd->lock_meaning != XK_Caps_Lock)) {
576	if ((per == 1) || ((usym = syms[1]) == NoSymbol))
577	    XtConvertCase(dpy, syms[0], &lsym, &usym);
578	*keysym_return = usym;
579    } else {
580	if ((per == 1) || ((sym = syms[1]) == NoSymbol))
581	    sym = syms[0];
582	XtConvertCase(dpy, sym, &lsym, &usym);
583	if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
584	    ((sym != usym) || (lsym == usym)))
585	    XtConvertCase(dpy, syms[0], &lsym, &usym);
586	*keysym_return = usym;
587    }
588
589    if (*keysym_return == XK_VoidSymbol)
590	*keysym_return = NoSymbol;
591    UNLOCK_APP(app);
592#else
593    XkbLookupKeySym(dpy, keycode, modifiers, modifiers_return, keysym_return);
594#endif
595}
596
597void XtSetKeyTranslator(
598    Display *dpy,
599    XtKeyProc translator)
600{
601    XtPerDisplay pd;
602    DPY_TO_APPCON(dpy);
603
604    LOCK_APP(app);
605    pd = _XtGetPerDisplay(dpy);
606
607    pd->defaultKeycodeTranslator = translator;
608    FLUSHKEYCACHE(pd->tm_context);
609    /* XXX should now redo grabs */
610    UNLOCK_APP(app);
611}
612
613void XtRegisterCaseConverter(
614    Display *dpy,
615    XtCaseProc proc,
616    KeySym start,
617    KeySym stop)
618{
619    XtPerDisplay pd;
620    CaseConverterPtr ptr, prev;
621    DPY_TO_APPCON(dpy);
622
623    LOCK_APP(app);
624    pd = _XtGetPerDisplay(dpy);
625
626    ptr = (CaseConverterPtr) __XtMalloc(sizeof(CaseConverterRec));
627    ptr->start = start;
628    ptr->stop = stop;
629    ptr->proc = proc;
630    ptr->next = pd->case_cvt;
631    pd->case_cvt = ptr;
632
633    /* Remove obsolete case converters from the list */
634    prev = ptr;
635    for (ptr=ptr->next; ptr; ptr=prev->next) {
636	if (start <= ptr->start && stop >= ptr->stop) {
637	    prev->next = ptr->next;
638	    XtFree((char *)ptr);
639	}
640	else prev = ptr;
641    }
642    FLUSHKEYCACHE(pd->tm_context);
643    /* XXX should now redo grabs */
644    UNLOCK_APP(app);
645}
646
647KeySym *XtGetKeysymTable(
648    Display *dpy,
649    KeyCode *min_keycode_return,
650    int *keysyms_per_keycode_return)
651{
652    XtPerDisplay pd;
653    KeySym* retval;
654    DPY_TO_APPCON(dpy);
655
656    LOCK_APP(app);
657    pd = _XtGetPerDisplay(dpy);
658    _InitializeKeysymTables(dpy, pd);
659    *min_keycode_return = pd->min_keycode; /* %%% */
660    *keysyms_per_keycode_return = pd->keysyms_per_keycode;
661    retval = pd->keysyms;
662    UNLOCK_APP(app);
663    return retval;
664}
665
666void XtKeysymToKeycodeList(
667    Display *dpy,
668    KeySym keysym,
669    KeyCode **keycodes_return,
670    Cardinal *keycount_return)
671{
672    XtPerDisplay pd;
673    unsigned keycode;
674    int per, match;
675    register KeySym *syms;
676    register int i, j;
677    KeySym lsym, usym;
678    unsigned maxcodes = 0;
679    unsigned ncodes = 0;
680    KeyCode *keycodes, *codeP = NULL;
681    DPY_TO_APPCON(dpy);
682
683    LOCK_APP(app);
684    pd = _XtGetPerDisplay(dpy);
685    _InitializeKeysymTables(dpy, pd);
686    keycodes = NULL;
687    per = pd->keysyms_per_keycode;
688    for (syms = pd->keysyms, keycode = (unsigned) pd->min_keycode;
689	 (int)keycode <= pd->max_keycode;
690	 syms += per, keycode++) {
691	match = 0;
692	for (j = 0; j < per; j++) {
693	    if (syms[j] == keysym) {
694		match = 1;
695		break;
696	    }
697	}
698	if (!match)
699	    for (i = 1; i < 5; i += 2) {
700		if ((per == i) || ((per > i) && (syms[i] == NoSymbol))) {
701		    XtConvertCase(dpy, syms[i-1], &lsym, &usym);
702		    if ((lsym == keysym) || (usym == keysym)) {
703			match = 1;
704			break;
705		    }
706		}
707	    }
708	if (match) {
709	    if (ncodes == maxcodes) {
710		KeyCode *old = keycodes;
711		maxcodes += KEYCODE_ARRAY_SIZE;
712		keycodes = (KeyCode*)__XtMalloc(maxcodes*sizeof(KeyCode));
713		if (ncodes) {
714		    (void) memmove((char *)keycodes, (char *)old,
715				   ncodes*sizeof(KeyCode) );
716		    XtFree((char *)old);
717		}
718		codeP = &keycodes[ncodes];
719	    }
720	    *codeP++ = (KeyCode) keycode;
721	    ncodes++;
722	}
723    }
724    *keycodes_return = keycodes;
725    *keycount_return = ncodes;
726    UNLOCK_APP(app);
727}
728