TMkey.c revision 0568f49b
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	memset((void *)&ctx->keycache, 0, 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) - (TMLongCard) (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, (KeyCode) key, mod, &mod_ret, &sym_ret); \
151	(ctx)->keycache.keycode[_i_] = (KeyCode) (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) - (TMLongCard) (pd)->min_keycode + modmix[(mod) & 0xff]) & \
161	       (TMKEYCACHESIZE-1)); \
162    (ctx)->keycache.keycode[_i_] = (KeyCode) (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    KeySym tempKeysym = NoSymbol;
181
182    perDisplay = _XtGetPerDisplay(dpy);
183    if (perDisplay == NULL) {
184        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
185		"displayError","invalidDisplay",XtCXtToolkitError,
186            "Can't find display structure",
187            NULL, NULL);
188         return FALSE;
189    }
190    _InitializeKeysymTables(dpy, perDisplay);
191    for (ref=0; lateModifiers[ref].keysym; ref++) {
192        Boolean found = FALSE;
193        for (i=0;i<8;i++) {
194            temp = &(perDisplay->modsToKeysyms[i]);
195            for (j=0;j<temp->count;j++){
196                if (perDisplay->modKeysyms[temp->idx+j] ==
197		    lateModifiers[ref].keysym) {
198                    *computedMask = *computedMask | temp->mask;
199                    if (!lateModifiers[ref].knot)
200		      *computed |= temp->mask;
201                    tempKeysym = lateModifiers[ref].keysym;
202                    found = TRUE; break;
203                }
204            }
205            if (found) break;
206        }
207        if (!found  && !lateModifiers[ref].knot)
208            if (!lateModifiers[ref].pair && (tempKeysym == NoSymbol))
209                return FALSE;
210        /* if you didn't find the modifier and the modifier must be
211           asserted then return FALSE. If you didn't find the modifier
212           and the modifier must be off, then it is OK . Don't
213           return FALSE if this is the first member of a pair or if
214           it is the second member of a pair when the first member
215           was bound to a modifier */
216    if (!lateModifiers[ref].pair) tempKeysym = NoSymbol;
217    }
218    return TRUE;
219}
220
221void _XtAllocTMContext(
222    XtPerDisplay pd)
223{
224    TMKeyContext ctx;
225    ctx = (TMKeyContext)_XtHeapAlloc(&pd->heap,
226				     sizeof(TMKeyContextRec));
227    ctx->event = NULL;
228    ctx->serial = 0;
229    ctx->keysym = NoSymbol;
230    ctx->modifiers = 0;
231    FLUSHKEYCACHE(ctx);
232    pd->tm_context = ctx;
233}
234
235static unsigned int num_bits(unsigned long mask)
236{
237    register unsigned long y;
238
239    y = (mask >> 1) &033333333333;
240    y = mask - y - ((y >>1) & 033333333333);
241    return ((unsigned int) (((y + (y >> 3)) & 030707070707) % 077));
242}
243
244Boolean _XtMatchUsingDontCareMods(
245    TMTypeMatch 	typeMatch,
246    TMModifierMatch 	modMatch,
247    TMEventPtr 		eventSeq)
248{
249    Modifiers modifiers_return;
250    KeySym keysym_return;
251    Modifiers useful_mods;
252    Modifiers computed = 0;
253    Modifiers computedMask = 0;
254    Boolean resolved = TRUE;
255    Display *dpy = eventSeq->xev->xany.display;
256    XtPerDisplay pd;
257
258    if (modMatch->lateModifiers != NULL)
259	resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
260					  &computed, &computedMask);
261    if (!resolved) return FALSE;
262    computed = (Modifiers) (computed | modMatch->modifiers);
263    computedMask = (Modifiers) (computedMask | modMatch->modifierMask); /* gives do-care mask */
264
265    if ( (computed & computedMask) ==
266        (eventSeq->event.modifiers & computedMask) ) {
267	TMKeyContext tm_context;
268	int num_modbits;
269	int i;
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 = (int) 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 = (int) 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    Display *dpy = eventSeq->xev->xany.display;
378    XtPerDisplay pd = _XtGetPerDisplay(dpy);
379    TMKeyContext tm_context = pd->tm_context;
380    Modifiers translateModifiers;
381
382    /* To maximize cache utilization, we mask off nonstandard modifiers
383       before cache lookup.  For a given key translator, standard modifiers
384       are constant per KeyCode.  If a key translator uses no standard
385       modifiers this implementation will never reference the cache.
386     */
387
388    modifiers_return = MOD_RETURN(tm_context, eventSeq->event.eventCode);
389    if (!modifiers_return) {
390	XtTranslateKeycode(dpy, (KeyCode)eventSeq->event.eventCode,
391			   (Modifiers)eventSeq->event.modifiers, &modifiers_return,
392			   &keysym_return);
393	translateModifiers = (Modifiers) (eventSeq->event.modifiers & modifiers_return);
394	UPDATE_CACHE(tm_context, pd, eventSeq->event.eventCode,
395		     translateModifiers, modifiers_return, keysym_return);
396    } else {
397	translateModifiers = (Modifiers) (eventSeq->event.modifiers & modifiers_return);
398	TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode,
399		  translateModifiers, modifiers_return, keysym_return);
400    }
401
402    if ((typeMatch->eventCode & typeMatch->eventCodeMask) ==
403             (keysym_return & typeMatch->eventCodeMask)) {
404	Boolean resolved = TRUE;
405
406        if (modMatch->lateModifiers != NULL)
407            resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
408					      &computed, &computedMask);
409        if (!resolved) return FALSE;
410        computed = (Modifiers) (computed | modMatch->modifiers);
411        computedMask = (Modifiers) (computedMask | modMatch->modifierMask);
412
413        if ((computed & computedMask) ==
414	    (eventSeq->event.modifiers & ~modifiers_return & computedMask)) {
415	    tm_context->event = eventSeq->xev;
416	    tm_context->serial = eventSeq->xev->xany.serial;
417	    tm_context->keysym = keysym_return;
418	    tm_context->modifiers = translateModifiers;
419	    return TRUE;
420	}
421    }
422    return FALSE;
423}
424
425
426void _XtBuildKeysymTables(
427    Display *dpy,
428    register XtPerDisplay pd)
429{
430    ModToKeysymTable *table;
431    int maxCount,i,j,k,tempCount,idx;
432    KeySym keysym,tempKeysym;
433    XModifierKeymap* modKeymap;
434    KeyCode keycode;
435#define KeysymTableSize 16
436
437    FLUSHKEYCACHE(pd->tm_context);
438
439    XFree( (char *)pd->keysyms );
440    pd->keysyms_serial = NextRequest(dpy);
441    pd->keysyms = XGetKeyboardMapping(dpy, (KeyCode) pd->min_keycode,
442				      pd->max_keycode-pd->min_keycode+1,
443				      &pd->keysyms_per_keycode);
444    XtFree((char *)pd->modKeysyms);
445
446    pd->modKeysyms = (KeySym*)__XtMalloc((Cardinal)KeysymTableSize*sizeof(KeySym));
447    maxCount = KeysymTableSize;
448    tempCount = 0;
449
450    XtFree((char *)pd->modsToKeysyms);
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] |= (unsigned char) (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 = (pd->mode_switch | (Modifiers) (1 << i));
482		    if ((keysym == XK_Num_Lock) && (i > 2))
483			pd->num_lock = (pd->num_lock | (Modifiers) (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) ((size_t)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) 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 = (KeyCode) 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;
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	int 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