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