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