TMkey.c revision 1477040f
1444c061aSmrg/* $Xorg: TMkey.c,v 1.4 2001/02/09 02:03:58 xorgcvs Exp $ */
2444c061aSmrg/*LINTLIBRARY*/
3444c061aSmrg
4444c061aSmrg/***********************************************************
51477040fSmrgCopyright 1993 Sun Microsystems, Inc.  All rights reserved.
61477040fSmrg
71477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
81477040fSmrgcopy of this software and associated documentation files (the "Software"),
91477040fSmrgto deal in the Software without restriction, including without limitation
101477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
111477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
121477040fSmrgSoftware is furnished to do so, subject to the following conditions:
131477040fSmrg
141477040fSmrgThe above copyright notice and this permission notice (including the next
151477040fSmrgparagraph) shall be included in all copies or substantial portions of the
161477040fSmrgSoftware.
171477040fSmrg
181477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
191477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
201477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
211477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
221477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
231477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
241477040fSmrgDEALINGS IN THE SOFTWARE.
251477040fSmrg
261477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
27444c061aSmrg
28444c061aSmrg                        All Rights Reserved
29444c061aSmrg
30444c061aSmrgPermission to use, copy, modify, and distribute this software and its
31444c061aSmrgdocumentation for any purpose and without fee is hereby granted,
32444c061aSmrgprovided that the above copyright notice appear in all copies and that
33444c061aSmrgboth that copyright notice and this permission notice appear in
341477040fSmrgsupporting documentation, and that the name of Digital not be
35444c061aSmrgused in advertising or publicity pertaining to distribution of the
36444c061aSmrgsoftware without specific, written prior permission.
37444c061aSmrg
38444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
39444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
40444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
41444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
42444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
43444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
44444c061aSmrgSOFTWARE.
45444c061aSmrg
46444c061aSmrg******************************************************************/
47444c061aSmrg
48444c061aSmrg/*
49444c061aSmrg
50444c061aSmrgCopyright 1987, 1988, 1994, 1998  The Open Group
51444c061aSmrg
52444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
53444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
54444c061aSmrgthe above copyright notice appear in all copies and that both that
55444c061aSmrgcopyright notice and this permission notice appear in supporting
56444c061aSmrgdocumentation.
57444c061aSmrg
58444c061aSmrgThe above copyright notice and this permission notice shall be included in
59444c061aSmrgall copies or substantial portions of the Software.
60444c061aSmrg
61444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
62444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
63444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
64444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
65444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
66444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
67444c061aSmrg
68444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
69444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
70444c061aSmrgin this Software without prior written authorization from The Open Group.
71444c061aSmrg
72444c061aSmrg*/
73444c061aSmrg/* $XFree86: xc/lib/Xt/TMkey.c,v 3.10 2001/12/14 19:56:30 dawes Exp $ */
74444c061aSmrg
75444c061aSmrg#define XK_MISCELLANY
76444c061aSmrg#define XK_LATIN1
77444c061aSmrg#define XK_LATIN2
78444c061aSmrg#define XK_LATIN3
79444c061aSmrg#define XK_LATIN4
80444c061aSmrg
81444c061aSmrg#ifdef HAVE_CONFIG_H
82444c061aSmrg#include <config.h>
83444c061aSmrg#endif
84444c061aSmrg#include "IntrinsicI.h"
85444c061aSmrg#include <X11/keysymdef.h>
86444c061aSmrg#ifdef XKB
87444c061aSmrg#include <X11/XKBlib.h>
88444c061aSmrg#endif
89444c061aSmrg
90444c061aSmrg#define FLUSHKEYCACHE(ctx) \
91444c061aSmrg	bzero((char *)&ctx->keycache, sizeof(TMKeyCache))
92444c061aSmrg
93444c061aSmrg/*
94444c061aSmrg * The following array reorders the modifier bits so that the most common ones
95444c061aSmrg * (used by a translator) are in the top-most bits with respect to the size of
96444c061aSmrg * the keycache.  The array currently just reverses the bits as a good guess.
97444c061aSmrg * This might be more trouble than it is worth, but it seems to help.
98444c061aSmrg */
99444c061aSmrg
100444c061aSmrg#define FM(i) i >> (8 - TMKEYCACHELOG2)
101444c061aSmrgstatic const unsigned char modmix[256] = {
102444c061aSmrgFM(0x0f), FM(0x8f), FM(0x4f), FM(0xcf), FM(0x2f), FM(0xaf), FM(0x6f), FM(0xef),
103444c061aSmrgFM(0x1f), FM(0x9f), FM(0x5f), FM(0xdf), FM(0x3f), FM(0xbf), FM(0x7f), FM(0xff),
104444c061aSmrgFM(0x07), FM(0x87), FM(0x47), FM(0xc7), FM(0x27), FM(0xa7), FM(0x67), FM(0xe7),
105444c061aSmrgFM(0x17), FM(0x97), FM(0x57), FM(0xd7), FM(0x37), FM(0xb7), FM(0x77), FM(0xf7),
106444c061aSmrgFM(0x0b), FM(0x8b), FM(0x4b), FM(0xcb), FM(0x2b), FM(0xab), FM(0x6b), FM(0xeb),
107444c061aSmrgFM(0x1b), FM(0x9b), FM(0x5b), FM(0xdb), FM(0x3b), FM(0xbb), FM(0x7b), FM(0xfb),
108444c061aSmrgFM(0x03), FM(0x83), FM(0x43), FM(0xc3), FM(0x23), FM(0xa3), FM(0x63), FM(0xe3),
109444c061aSmrgFM(0x13), FM(0x93), FM(0x53), FM(0xd3), FM(0x33), FM(0xb3), FM(0x73), FM(0xf3),
110444c061aSmrgFM(0x0d), FM(0x8d), FM(0x4d), FM(0xcd), FM(0x2d), FM(0xad), FM(0x6d), FM(0xed),
111444c061aSmrgFM(0x1d), FM(0x9d), FM(0x5d), FM(0xdd), FM(0x3d), FM(0xbd), FM(0x7d), FM(0xfd),
112444c061aSmrgFM(0x05), FM(0x85), FM(0x45), FM(0xc5), FM(0x25), FM(0xa5), FM(0x65), FM(0xe5),
113444c061aSmrgFM(0x15), FM(0x95), FM(0x55), FM(0xd5), FM(0x35), FM(0xb5), FM(0x75), FM(0xf5),
114444c061aSmrgFM(0x09), FM(0x89), FM(0x49), FM(0xc9), FM(0x29), FM(0xa9), FM(0x69), FM(0xe9),
115444c061aSmrgFM(0x19), FM(0x99), FM(0x59), FM(0xd9), FM(0x39), FM(0xb9), FM(0x79), FM(0xf9),
116444c061aSmrgFM(0x01), FM(0x81), FM(0x41), FM(0xc1), FM(0x21), FM(0xa1), FM(0x61), FM(0xe1),
117444c061aSmrgFM(0x11), FM(0x91), FM(0x51), FM(0xd1), FM(0x31), FM(0xb1), FM(0x71), FM(0xf1),
118444c061aSmrgFM(0x00), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee),
119444c061aSmrgFM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe),
120444c061aSmrgFM(0x08), FM(0x88), FM(0x48), FM(0xc8), FM(0x28), FM(0xa8), FM(0x68), FM(0xe8),
121444c061aSmrgFM(0x18), FM(0x98), FM(0x58), FM(0xd8), FM(0x38), FM(0xb8), FM(0x78), FM(0xf8),
122444c061aSmrgFM(0x04), FM(0x84), FM(0x44), FM(0xc4), FM(0x24), FM(0xa4), FM(0x64), FM(0xe4),
123444c061aSmrgFM(0x14), FM(0x94), FM(0x54), FM(0xd4), FM(0x34), FM(0xb4), FM(0x74), FM(0xf4),
124444c061aSmrgFM(0x0c), FM(0x8c), FM(0x4c), FM(0xcc), FM(0x2c), FM(0xac), FM(0x6c), FM(0xec),
125444c061aSmrgFM(0x1c), FM(0x9c), FM(0x5c), FM(0xdc), FM(0x3c), FM(0xbc), FM(0x7c), FM(0xfc),
126444c061aSmrgFM(0x02), FM(0x82), FM(0x42), FM(0xc2), FM(0x22), FM(0xa2), FM(0x62), FM(0xe2),
127444c061aSmrgFM(0x12), FM(0x92), FM(0x52), FM(0xd2), FM(0x32), FM(0xb2), FM(0x72), FM(0xf2),
128444c061aSmrgFM(0x0a), FM(0x8a), FM(0x4a), FM(0xca), FM(0x2a), FM(0xaa), FM(0x6a), FM(0xea),
129444c061aSmrgFM(0x1a), FM(0x9a), FM(0x5a), FM(0xda), FM(0x3a), FM(0xba), FM(0x7a), FM(0xfa),
130444c061aSmrgFM(0x06), FM(0x86), FM(0x46), FM(0xc6), FM(0x26), FM(0xa6), FM(0x66), FM(0xe6),
131444c061aSmrgFM(0x16), FM(0x96), FM(0x56), FM(0xd6), FM(0x36), FM(0xb6), FM(0x76), FM(0xf6),
132444c061aSmrgFM(0x0e), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee),
133444c061aSmrgFM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe)
134444c061aSmrg};
135444c061aSmrg#undef FM
136444c061aSmrg
137444c061aSmrg#define MOD_RETURN(ctx, key) (ctx)->keycache.modifiers_return[key]
138444c061aSmrg
139444c061aSmrg#define TRANSLATE(ctx,pd,dpy,key,mod,mod_ret,sym_ret) \
140444c061aSmrg{ \
141444c061aSmrg    int _i_ = (((key) - (pd)->min_keycode + modmix[(mod) & 0xff]) & \
142444c061aSmrg	       (TMKEYCACHESIZE-1)); \
1432265a131Smrg    if ((key) == 0) { /* Xlib XIM composed input */ \
1442265a131Smrg	mod_ret = 0; \
1452265a131Smrg	sym_ret = 0; \
1462265a131Smrg    } else if (   /* not Xlib XIM composed input */ \
147444c061aSmrg	(ctx)->keycache.keycode[_i_] == (key) && \
148444c061aSmrg	(ctx)->keycache.modifiers[_i_] == (mod)) { \
149444c061aSmrg	mod_ret = MOD_RETURN(ctx, key); \
150444c061aSmrg	sym_ret = (ctx)->keycache.keysym[_i_]; \
151444c061aSmrg    } else { \
152444c061aSmrg	XtTranslateKeycode(dpy, key, mod, &mod_ret, &sym_ret); \
153444c061aSmrg	(ctx)->keycache.keycode[_i_] = key; \
154444c061aSmrg	(ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
155444c061aSmrg	(ctx)->keycache.keysym[_i_] = sym_ret; \
156444c061aSmrg	MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \
157444c061aSmrg    } \
158444c061aSmrg}
159444c061aSmrg
160444c061aSmrg#define UPDATE_CACHE(ctx, pd, key, mod, mod_ret, sym_ret) \
161444c061aSmrg{ \
162444c061aSmrg    int _i_ = (((key) - (pd)->min_keycode + modmix[(mod) & 0xff]) & \
163444c061aSmrg	       (TMKEYCACHESIZE-1)); \
164444c061aSmrg    (ctx)->keycache.keycode[_i_] = key; \
165444c061aSmrg    (ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
166444c061aSmrg    (ctx)->keycache.keysym[_i_] = sym_ret; \
167444c061aSmrg    MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \
168444c061aSmrg}
169444c061aSmrg
170444c061aSmrg/* usual number of expected keycodes in XtKeysymToKeycodeList */
171444c061aSmrg#define KEYCODE_ARRAY_SIZE 10
172444c061aSmrg
173444c061aSmrgBoolean _XtComputeLateBindings(
174444c061aSmrg    Display *dpy,
175444c061aSmrg    LateBindingsPtr lateModifiers,
176444c061aSmrg    Modifiers *computed,
177444c061aSmrg    Modifiers *computedMask)
178444c061aSmrg{
179444c061aSmrg    int i,j,ref;
180444c061aSmrg    ModToKeysymTable* temp;
181444c061aSmrg    XtPerDisplay perDisplay;
182444c061aSmrg    Boolean found;
183444c061aSmrg    KeySym tempKeysym = NoSymbol;
184444c061aSmrg
185444c061aSmrg    perDisplay = _XtGetPerDisplay(dpy);
186444c061aSmrg    if (perDisplay == NULL) {
187444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
188444c061aSmrg		"displayError","invalidDisplay",XtCXtToolkitError,
189444c061aSmrg            "Can't find display structure",
190444c061aSmrg            (String *)NULL, (Cardinal *)NULL);
191444c061aSmrg         return FALSE;
192444c061aSmrg    }
193444c061aSmrg    _InitializeKeysymTables(dpy, perDisplay);
194444c061aSmrg    for (ref=0; lateModifiers[ref].keysym; ref++) {
195444c061aSmrg        found = FALSE;
196444c061aSmrg        for (i=0;i<8;i++) {
197444c061aSmrg            temp = &(perDisplay->modsToKeysyms[i]);
198444c061aSmrg            for (j=0;j<temp->count;j++){
199444c061aSmrg                if (perDisplay->modKeysyms[temp->idx+j] ==
200444c061aSmrg		    lateModifiers[ref].keysym) {
201444c061aSmrg                    *computedMask = *computedMask | temp->mask;
202444c061aSmrg                    if (!lateModifiers[ref].knot)
203444c061aSmrg		      *computed |= temp->mask;
204444c061aSmrg                    tempKeysym = lateModifiers[ref].keysym;
205444c061aSmrg                    found = TRUE; break;
206444c061aSmrg                }
207444c061aSmrg            }
208444c061aSmrg            if (found) break;
209444c061aSmrg        }
210444c061aSmrg        if (!found  && !lateModifiers[ref].knot)
211444c061aSmrg            if (!lateModifiers[ref].pair && (tempKeysym == NoSymbol))
212444c061aSmrg                return FALSE;
213444c061aSmrg        /* if you didn't find the modifier and the modifier must be
214444c061aSmrg           asserted then return FALSE. If you didn't find the modifier
215444c061aSmrg           and the modifier must be off, then it is OK . Don't
216444c061aSmrg           return FALSE if this is the first member of a pair or if
217444c061aSmrg           it is the second member of a pair when the first member
218444c061aSmrg           was bound to a modifier */
219444c061aSmrg    if (!lateModifiers[ref].pair) tempKeysym = NoSymbol;
220444c061aSmrg    }
221444c061aSmrg    return TRUE;
222444c061aSmrg}
223444c061aSmrg
224444c061aSmrgvoid _XtAllocTMContext(
225444c061aSmrg    XtPerDisplay pd)
226444c061aSmrg{
227444c061aSmrg    TMKeyContext ctx;
228444c061aSmrg    ctx = (TMKeyContext)_XtHeapAlloc(&pd->heap,
229444c061aSmrg				     sizeof(TMKeyContextRec));
230444c061aSmrg    ctx->event = NULL;
231444c061aSmrg    ctx->serial = 0;
232444c061aSmrg    ctx->keysym = NoSymbol;
233444c061aSmrg    ctx->modifiers = 0;
234444c061aSmrg    FLUSHKEYCACHE(ctx);
235444c061aSmrg    pd->tm_context = ctx;
236444c061aSmrg}
237444c061aSmrg
238444c061aSmrgstatic unsigned int num_bits(unsigned long mask)
239444c061aSmrg{
240444c061aSmrg    register unsigned long y;
241444c061aSmrg
242444c061aSmrg    y = (mask >> 1) &033333333333;
243444c061aSmrg    y = mask - y - ((y >>1) & 033333333333);
244444c061aSmrg    return ((unsigned int) (((y + (y >> 3)) & 030707070707) % 077));
245444c061aSmrg}
246444c061aSmrg
247444c061aSmrgBoolean _XtMatchUsingDontCareMods(
248444c061aSmrg    TMTypeMatch 	typeMatch,
249444c061aSmrg    TMModifierMatch 	modMatch,
250444c061aSmrg    TMEventPtr 		eventSeq)
251444c061aSmrg{
252444c061aSmrg    Modifiers modifiers_return;
253444c061aSmrg    KeySym keysym_return;
254444c061aSmrg    Modifiers useful_mods;
255444c061aSmrg    int i, num_modbits;
256444c061aSmrg    Modifiers computed = 0;
257444c061aSmrg    Modifiers computedMask = 0;
258444c061aSmrg    Boolean resolved = TRUE;
259444c061aSmrg    Display *dpy = eventSeq->xev->xany.display;
260444c061aSmrg    XtPerDisplay pd;
261444c061aSmrg    TMKeyContext tm_context;
262444c061aSmrg
263444c061aSmrg    if (modMatch->lateModifiers != NULL)
264444c061aSmrg	resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
265444c061aSmrg					  &computed, &computedMask);
266444c061aSmrg    if (!resolved) return FALSE;
267444c061aSmrg    computed |= modMatch->modifiers;
268444c061aSmrg    computedMask |= modMatch->modifierMask; /* gives do-care mask */
269444c061aSmrg
270444c061aSmrg    if ( (computed & computedMask) ==
271444c061aSmrg        (eventSeq->event.modifiers & computedMask) ) {
272444c061aSmrg
273444c061aSmrg	pd = _XtGetPerDisplay(dpy);
274444c061aSmrg	tm_context = pd->tm_context;
275444c061aSmrg	TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode,
276444c061aSmrg			    (unsigned)0, modifiers_return, keysym_return);
277444c061aSmrg
278444c061aSmrg        if ((keysym_return & typeMatch->eventCodeMask)  == typeMatch->eventCode ) {
279444c061aSmrg	    tm_context->event = eventSeq->xev;
280444c061aSmrg	    tm_context->serial = eventSeq->xev->xany.serial;
281444c061aSmrg	    tm_context->keysym = keysym_return;
282444c061aSmrg	    tm_context->modifiers = (Modifiers)0;
283444c061aSmrg	    return TRUE;
284444c061aSmrg	}
285444c061aSmrg        useful_mods = ~computedMask & modifiers_return;
286444c061aSmrg        if (useful_mods == 0) return FALSE;
287444c061aSmrg
288444c061aSmrg	switch (num_modbits = num_bits(useful_mods)) {
289444c061aSmrg	case 1:
290444c061aSmrg	case 8:
291444c061aSmrg	    /*
292444c061aSmrg	     * one modbit should never happen, in fact the implementation
293444c061aSmrg	     * of XtTranslateKey and XmTranslateKey guarantee that it
294444c061aSmrg	     * won't, so don't care if the loop is set up for the case
295444c061aSmrg	     * when one modbit is set.
296444c061aSmrg	     * The performance implications of all eight modbits being
297444c061aSmrg	     * set is horrendous. This isn't a problem with Xt/Xaw based
298444c061aSmrg	     * applications. We can only hope that Motif's virtual
299444c061aSmrg	     * modifiers won't result in all eight modbits being set.
300444c061aSmrg	     */
301444c061aSmrg	    for (i = useful_mods; i > 0; i--) {
302444c061aSmrg		TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
303444c061aSmrg			  (Modifiers)i, modifiers_return, keysym_return);
304444c061aSmrg		if (keysym_return ==
305444c061aSmrg		    (typeMatch->eventCode & typeMatch->eventCodeMask)) {
306444c061aSmrg		    tm_context->event = eventSeq->xev;
307444c061aSmrg		    tm_context->serial = eventSeq->xev->xany.serial;
308444c061aSmrg		    tm_context->keysym = keysym_return;
309444c061aSmrg		    tm_context->modifiers = (Modifiers)i;
310444c061aSmrg		    return TRUE;
311444c061aSmrg		}
312444c061aSmrg	    }
313444c061aSmrg	    break;
314444c061aSmrg	default: /* (2..7) */
315444c061aSmrg	    {
316444c061aSmrg	    /*
317444c061aSmrg	     * Only translate using combinations of the useful modifiers.
318444c061aSmrg	     * to minimize the chance of invalidating the cache.
319444c061aSmrg	     */
320444c061aSmrg		static char pows[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
321444c061aSmrg		Modifiers tmod, mod_masks[8];
322444c061aSmrg		int j;
323444c061aSmrg		for (tmod = 1, i = 0; tmod <= (Mod5Mask<<1); tmod <<= 1)
324444c061aSmrg		    if (tmod & useful_mods) mod_masks[i++] = tmod;
325444c061aSmrg		for (j = (int) pows[num_modbits]; j > 0; j--) {
326444c061aSmrg		    tmod = 0;
327444c061aSmrg		    for (i = 0; i < num_modbits; i++)
328444c061aSmrg			if (j & (1<<i)) tmod |= mod_masks[i];
329444c061aSmrg		    TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
330444c061aSmrg			      tmod, modifiers_return, keysym_return);
331444c061aSmrg		    if (keysym_return ==
332444c061aSmrg			(typeMatch->eventCode & typeMatch->eventCodeMask)) {
333444c061aSmrg			tm_context->event = eventSeq->xev;
334444c061aSmrg			tm_context->serial = eventSeq->xev->xany.serial;
335444c061aSmrg			tm_context->keysym = keysym_return;
336444c061aSmrg			tm_context->modifiers = (Modifiers)i;
337444c061aSmrg			return TRUE;
338444c061aSmrg		    }
339444c061aSmrg		}
340444c061aSmrg	    }
341444c061aSmrg	    break;
342444c061aSmrg	} /* switch (num_modbits) */
343444c061aSmrg    }
344444c061aSmrg    return FALSE;
345444c061aSmrg}
346444c061aSmrg
347444c061aSmrgvoid XtConvertCase(
348444c061aSmrg    Display *dpy,
349444c061aSmrg    KeySym keysym,
350444c061aSmrg    KeySym *lower_return,
351444c061aSmrg    KeySym *upper_return)
352444c061aSmrg{
353444c061aSmrg    XtPerDisplay pd;
354444c061aSmrg    CaseConverterPtr ptr;
355444c061aSmrg    DPY_TO_APPCON(dpy);
356444c061aSmrg
357444c061aSmrg    LOCK_APP(app);
358444c061aSmrg    pd = _XtGetPerDisplay(dpy);
359444c061aSmrg
360444c061aSmrg    *lower_return = *upper_return = keysym;
361444c061aSmrg    for (ptr=pd->case_cvt;  ptr; ptr = ptr->next)
362444c061aSmrg	if (ptr->start <= keysym && keysym <= ptr->stop) {
363444c061aSmrg	    (*ptr->proc)(dpy, keysym, lower_return, upper_return);
364444c061aSmrg	    return;
365444c061aSmrg	}
366444c061aSmrg    XConvertCase(keysym, lower_return, upper_return);
367444c061aSmrg    UNLOCK_APP(app);
368444c061aSmrg}
369444c061aSmrg
370444c061aSmrgBoolean _XtMatchUsingStandardMods (
371444c061aSmrg    TMTypeMatch typeMatch,
372444c061aSmrg    TMModifierMatch modMatch,
373444c061aSmrg    TMEventPtr eventSeq)
374444c061aSmrg{
375444c061aSmrg    Modifiers modifiers_return;
376444c061aSmrg    KeySym keysym_return;
377444c061aSmrg    Modifiers computed= 0;
378444c061aSmrg    Modifiers computedMask = 0;
379444c061aSmrg    Boolean resolved = TRUE;
380444c061aSmrg    Display *dpy = eventSeq->xev->xany.display;
381444c061aSmrg    XtPerDisplay pd = _XtGetPerDisplay(dpy);
382444c061aSmrg    TMKeyContext tm_context = pd->tm_context;
383444c061aSmrg    Modifiers translateModifiers;
384444c061aSmrg
385444c061aSmrg    /* To maximize cache utilization, we mask off nonstandard modifiers
386444c061aSmrg       before cache lookup.  For a given key translator, standard modifiers
387444c061aSmrg       are constant per KeyCode.  If a key translator uses no standard
388444c061aSmrg       modifiers this implementation will never reference the cache.
389444c061aSmrg     */
390444c061aSmrg
391444c061aSmrg    modifiers_return = MOD_RETURN(tm_context, eventSeq->event.eventCode);
392444c061aSmrg    if (!modifiers_return) {
393444c061aSmrg	XtTranslateKeycode(dpy, (KeyCode)eventSeq->event.eventCode,
394444c061aSmrg			   eventSeq->event.modifiers, &modifiers_return,
395444c061aSmrg			   &keysym_return);
396444c061aSmrg	translateModifiers = eventSeq->event.modifiers & modifiers_return;
397444c061aSmrg	UPDATE_CACHE(tm_context, pd, eventSeq->event.eventCode,
398444c061aSmrg		     translateModifiers, modifiers_return, keysym_return);
399444c061aSmrg    } else {
400444c061aSmrg	translateModifiers = eventSeq->event.modifiers & modifiers_return;
401444c061aSmrg	TRANSLATE(tm_context, pd, dpy, (KeyCode)eventSeq->event.eventCode,
402444c061aSmrg		  translateModifiers, modifiers_return, keysym_return);
403444c061aSmrg    }
404444c061aSmrg
405444c061aSmrg    if ((typeMatch->eventCode & typeMatch->eventCodeMask) ==
406444c061aSmrg             (keysym_return & typeMatch->eventCodeMask)) {
407444c061aSmrg        if (modMatch->lateModifiers != NULL)
408444c061aSmrg            resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
409444c061aSmrg					      &computed, &computedMask);
410444c061aSmrg        if (!resolved) return FALSE;
411444c061aSmrg        computed |= modMatch->modifiers;
412444c061aSmrg        computedMask |= modMatch->modifierMask;
413444c061aSmrg
414444c061aSmrg        if ((computed & computedMask) ==
415444c061aSmrg	    (eventSeq->event.modifiers & ~modifiers_return & computedMask)) {
416444c061aSmrg	    tm_context->event = eventSeq->xev;
417444c061aSmrg	    tm_context->serial = eventSeq->xev->xany.serial;
418444c061aSmrg	    tm_context->keysym = keysym_return;
419444c061aSmrg	    tm_context->modifiers = translateModifiers;
420444c061aSmrg	    return TRUE;
421444c061aSmrg	}
422444c061aSmrg    }
423444c061aSmrg    return FALSE;
424444c061aSmrg}
425444c061aSmrg
426444c061aSmrg
427444c061aSmrgvoid _XtBuildKeysymTables(
428444c061aSmrg    Display *dpy,
429444c061aSmrg    register XtPerDisplay pd)
430444c061aSmrg{
431444c061aSmrg    ModToKeysymTable *table;
432444c061aSmrg    int maxCount,i,j,k,tempCount,idx;
433444c061aSmrg    KeySym keysym,tempKeysym;
434444c061aSmrg    XModifierKeymap* modKeymap;
435444c061aSmrg    KeyCode keycode;
436444c061aSmrg#define KeysymTableSize 16
437444c061aSmrg
438444c061aSmrg    FLUSHKEYCACHE(pd->tm_context);
439444c061aSmrg    if (pd->keysyms)
440444c061aSmrg	XFree( (char *)pd->keysyms );
441444c061aSmrg    pd->keysyms_serial = NextRequest(dpy);
442444c061aSmrg    pd->keysyms = XGetKeyboardMapping(dpy, pd->min_keycode,
443444c061aSmrg				      pd->max_keycode-pd->min_keycode+1,
444444c061aSmrg				      &pd->keysyms_per_keycode);
445444c061aSmrg    if (pd->modKeysyms)
446444c061aSmrg	XtFree((char *)pd->modKeysyms);
447444c061aSmrg    if (pd->modsToKeysyms)
448444c061aSmrg	XtFree((char *)pd->modsToKeysyms);
449444c061aSmrg    pd->modKeysyms = (KeySym*)__XtMalloc((Cardinal)KeysymTableSize*sizeof(KeySym));
450444c061aSmrg    maxCount = KeysymTableSize;
451444c061aSmrg    tempCount = 0;
452444c061aSmrg
453444c061aSmrg    table = (ModToKeysymTable*)__XtMalloc((Cardinal)8*sizeof(ModToKeysymTable));
454444c061aSmrg    pd->modsToKeysyms = table;
455444c061aSmrg
456444c061aSmrg    table[0].mask = ShiftMask;
457444c061aSmrg    table[1].mask = LockMask;
458444c061aSmrg    table[2].mask = ControlMask;
459444c061aSmrg    table[3].mask = Mod1Mask;
460444c061aSmrg    table[4].mask = Mod2Mask;
461444c061aSmrg    table[5].mask = Mod3Mask;
462444c061aSmrg    table[6].mask = Mod4Mask;
463444c061aSmrg    table[7].mask = Mod5Mask;
464444c061aSmrg    tempKeysym = 0;
465444c061aSmrg
466444c061aSmrg    modKeymap = XGetModifierMapping(dpy);
467444c061aSmrg    for (i=0;i<32;i++)
468444c061aSmrg	pd->isModifier[i] = 0;
469444c061aSmrg    pd->mode_switch = 0;
470444c061aSmrg    pd->num_lock = 0;
471444c061aSmrg    for (i=0;i<8;i++) {
472444c061aSmrg        table[i].idx = tempCount;
473444c061aSmrg        table[i].count = 0;
474444c061aSmrg        for (j=0;j<modKeymap->max_keypermod;j++) {
475444c061aSmrg            keycode = modKeymap->modifiermap[i*modKeymap->max_keypermod+j];
476444c061aSmrg            if (keycode != 0) {
477444c061aSmrg		pd->isModifier[keycode>>3] |= 1 << (keycode & 7);
478444c061aSmrg                for (k=0; k<pd->keysyms_per_keycode;k++) {
479444c061aSmrg                    idx = ((keycode-pd->min_keycode)*
480444c061aSmrg                             pd->keysyms_per_keycode)+k;
481444c061aSmrg                    keysym = pd->keysyms[idx];
482444c061aSmrg		    if ((keysym == XK_Mode_switch) && (i > 2))
483444c061aSmrg			pd->mode_switch |= 1 << i;
484444c061aSmrg		    if ((keysym == XK_Num_Lock) && (i > 2))
485444c061aSmrg			pd->num_lock |= 1 << i;
486444c061aSmrg                    if (keysym != 0 && keysym != tempKeysym ){
487444c061aSmrg                        if (tempCount==maxCount) {
488444c061aSmrg                            maxCount += KeysymTableSize;
489444c061aSmrg                            pd->modKeysyms = (KeySym*)XtRealloc(
490444c061aSmrg                                (char*)pd->modKeysyms,
491444c061aSmrg                                (unsigned) (maxCount*sizeof(KeySym)) );
492444c061aSmrg                        }
493444c061aSmrg                        pd->modKeysyms[tempCount++] = keysym;
494444c061aSmrg                        table[i].count++;
495444c061aSmrg                        tempKeysym = keysym;
496444c061aSmrg                    }
497444c061aSmrg                }
498444c061aSmrg            }
499444c061aSmrg        }
500444c061aSmrg    }
501444c061aSmrg    pd->lock_meaning = NoSymbol;
502444c061aSmrg    for (i = 0; i < table[1].count; i++) {
503444c061aSmrg	keysym = pd->modKeysyms[table[1].idx + i];
504444c061aSmrg	if (keysym == XK_Caps_Lock) {
505444c061aSmrg	    pd->lock_meaning = XK_Caps_Lock;
506444c061aSmrg	    break;
507444c061aSmrg	} else if (keysym == XK_Shift_Lock) {
508444c061aSmrg	    pd->lock_meaning = XK_Shift_Lock;
509444c061aSmrg	}
510444c061aSmrg    }
511444c061aSmrg    XFreeModifiermap(modKeymap);
512444c061aSmrg}
513444c061aSmrg
514444c061aSmrgvoid XtTranslateKeycode (
515444c061aSmrg    Display *dpy,
516444c061aSmrg    _XtKeyCode keycode,
517444c061aSmrg    Modifiers modifiers,
518444c061aSmrg    Modifiers *modifiers_return,
519444c061aSmrg    KeySym *keysym_return)
520444c061aSmrg{
521444c061aSmrg    XtPerDisplay pd;
522444c061aSmrg    DPY_TO_APPCON(dpy);
523444c061aSmrg
524444c061aSmrg    LOCK_APP(app);
525444c061aSmrg    pd = _XtGetPerDisplay(dpy);
526444c061aSmrg    _InitializeKeysymTables(dpy, pd);
527444c061aSmrg    (*pd->defaultKeycodeTranslator)(
528444c061aSmrg            dpy,keycode,modifiers,modifiers_return,keysym_return);
529444c061aSmrg    UNLOCK_APP(app);
530444c061aSmrg}
531444c061aSmrg
532444c061aSmrg/* This code should match XTranslateKey (internal, sigh) in Xlib */
533444c061aSmrgvoid XtTranslateKey(
534444c061aSmrg    register Display *dpy,
535444c061aSmrg    _XtKeyCode keycode,
536444c061aSmrg    Modifiers modifiers,
537444c061aSmrg    Modifiers *modifiers_return,
538444c061aSmrg    KeySym *keysym_return)
539444c061aSmrg{
540444c061aSmrg#ifndef XKB
541444c061aSmrg    XtPerDisplay pd;
542444c061aSmrg    int per;
543444c061aSmrg    register KeySym *syms;
544444c061aSmrg    KeySym sym, lsym, usym;
545444c061aSmrg    DPY_TO_APPCON(dpy);
546444c061aSmrg
547444c061aSmrg    LOCK_APP(app);
548444c061aSmrg    pd = _XtGetPerDisplay(dpy);
549444c061aSmrg    *modifiers_return = (ShiftMask|LockMask) | pd->mode_switch | pd->num_lock;
550444c061aSmrg    if (((int)keycode < pd->min_keycode) || ((int)keycode > pd->max_keycode)) {
551444c061aSmrg	*keysym_return = NoSymbol;
552444c061aSmrg	UNLOCK_APP(app);
553444c061aSmrg	return;
554444c061aSmrg    }
555444c061aSmrg    per = pd->keysyms_per_keycode;
556444c061aSmrg    syms = &pd->keysyms[(keycode - pd->min_keycode) * per];
557444c061aSmrg    while ((per > 2) && (syms[per - 1] == NoSymbol))
558444c061aSmrg	per--;
559444c061aSmrg    if ((per > 2) && (modifiers & pd->mode_switch)) {
560444c061aSmrg	syms += 2;
561444c061aSmrg	per -= 2;
562444c061aSmrg    }
563444c061aSmrg    if ((modifiers & pd->num_lock) &&
564444c061aSmrg	(per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) {
565444c061aSmrg	if ((modifiers & ShiftMask) ||
566444c061aSmrg	    ((modifiers & LockMask) && (pd->lock_meaning == XK_Shift_Lock)))
567444c061aSmrg	    *keysym_return = syms[0];
568444c061aSmrg	else
569444c061aSmrg	    *keysym_return = syms[1];
570444c061aSmrg    } else if (!(modifiers & ShiftMask) &&
571444c061aSmrg	(!(modifiers & LockMask) || (pd->lock_meaning == NoSymbol))) {
572444c061aSmrg	if ((per == 1) || (syms[1] == NoSymbol))
573444c061aSmrg	    XtConvertCase(dpy, syms[0], keysym_return, &usym);
574444c061aSmrg	else
575444c061aSmrg	    *keysym_return = syms[0];
576444c061aSmrg    } else if (!(modifiers & LockMask) ||
577444c061aSmrg	       (pd->lock_meaning != XK_Caps_Lock)) {
578444c061aSmrg	if ((per == 1) || ((usym = syms[1]) == NoSymbol))
579444c061aSmrg	    XtConvertCase(dpy, syms[0], &lsym, &usym);
580444c061aSmrg	*keysym_return = usym;
581444c061aSmrg    } else {
582444c061aSmrg	if ((per == 1) || ((sym = syms[1]) == NoSymbol))
583444c061aSmrg	    sym = syms[0];
584444c061aSmrg	XtConvertCase(dpy, sym, &lsym, &usym);
585444c061aSmrg	if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
586444c061aSmrg	    ((sym != usym) || (lsym == usym)))
587444c061aSmrg	    XtConvertCase(dpy, syms[0], &lsym, &usym);
588444c061aSmrg	*keysym_return = usym;
589444c061aSmrg    }
590444c061aSmrg
591444c061aSmrg    if (*keysym_return == XK_VoidSymbol)
592444c061aSmrg	*keysym_return = NoSymbol;
593444c061aSmrg    UNLOCK_APP(app);
594444c061aSmrg#else
595444c061aSmrg    XkbLookupKeySym(dpy, keycode, modifiers, modifiers_return, keysym_return);
596444c061aSmrg#endif
597444c061aSmrg}
598444c061aSmrg
599444c061aSmrgvoid XtSetKeyTranslator(
600444c061aSmrg    Display *dpy,
601444c061aSmrg    XtKeyProc translator)
602444c061aSmrg{
603444c061aSmrg    XtPerDisplay pd;
604444c061aSmrg    DPY_TO_APPCON(dpy);
605444c061aSmrg
606444c061aSmrg    LOCK_APP(app);
607444c061aSmrg    pd = _XtGetPerDisplay(dpy);
608444c061aSmrg
609444c061aSmrg    pd->defaultKeycodeTranslator = translator;
610444c061aSmrg    FLUSHKEYCACHE(pd->tm_context);
611444c061aSmrg    /* XXX should now redo grabs */
612444c061aSmrg    UNLOCK_APP(app);
613444c061aSmrg}
614444c061aSmrg
615444c061aSmrgvoid XtRegisterCaseConverter(
616444c061aSmrg    Display *dpy,
617444c061aSmrg    XtCaseProc proc,
618444c061aSmrg    KeySym start,
619444c061aSmrg    KeySym stop)
620444c061aSmrg{
621444c061aSmrg    XtPerDisplay pd;
622444c061aSmrg    CaseConverterPtr ptr, prev;
623444c061aSmrg    DPY_TO_APPCON(dpy);
624444c061aSmrg
625444c061aSmrg    LOCK_APP(app);
626444c061aSmrg    pd = _XtGetPerDisplay(dpy);
627444c061aSmrg
628444c061aSmrg    ptr = (CaseConverterPtr) __XtMalloc(sizeof(CaseConverterRec));
629444c061aSmrg    ptr->start = start;
630444c061aSmrg    ptr->stop = stop;
631444c061aSmrg    ptr->proc = proc;
632444c061aSmrg    ptr->next = pd->case_cvt;
633444c061aSmrg    pd->case_cvt = ptr;
634444c061aSmrg
635444c061aSmrg    /* Remove obsolete case converters from the list */
636444c061aSmrg    prev = ptr;
637444c061aSmrg    for (ptr=ptr->next; ptr; ptr=prev->next) {
638444c061aSmrg	if (start <= ptr->start && stop >= ptr->stop) {
639444c061aSmrg	    prev->next = ptr->next;
640444c061aSmrg	    XtFree((char *)ptr);
641444c061aSmrg	}
642444c061aSmrg	else prev = ptr;
643444c061aSmrg    }
644444c061aSmrg    FLUSHKEYCACHE(pd->tm_context);
645444c061aSmrg    /* XXX should now redo grabs */
646444c061aSmrg    UNLOCK_APP(app);
647444c061aSmrg}
648444c061aSmrg
649444c061aSmrgKeySym *XtGetKeysymTable(
650444c061aSmrg    Display *dpy,
651444c061aSmrg    KeyCode *min_keycode_return,
652444c061aSmrg    int *keysyms_per_keycode_return)
653444c061aSmrg{
654444c061aSmrg    XtPerDisplay pd;
655444c061aSmrg    KeySym* retval;
656444c061aSmrg    DPY_TO_APPCON(dpy);
657444c061aSmrg
658444c061aSmrg    LOCK_APP(app);
659444c061aSmrg    pd = _XtGetPerDisplay(dpy);
660444c061aSmrg    _InitializeKeysymTables(dpy, pd);
661444c061aSmrg    *min_keycode_return = pd->min_keycode; /* %%% */
662444c061aSmrg    *keysyms_per_keycode_return = pd->keysyms_per_keycode;
663444c061aSmrg    retval = pd->keysyms;
664444c061aSmrg    UNLOCK_APP(app);
665444c061aSmrg    return retval;
666444c061aSmrg}
667444c061aSmrg
668444c061aSmrgvoid XtKeysymToKeycodeList(
669444c061aSmrg    Display *dpy,
670444c061aSmrg    KeySym keysym,
671444c061aSmrg    KeyCode **keycodes_return,
672444c061aSmrg    Cardinal *keycount_return)
673444c061aSmrg{
674444c061aSmrg    XtPerDisplay pd;
675444c061aSmrg    unsigned keycode;
676444c061aSmrg    int per, match;
677444c061aSmrg    register KeySym *syms;
678444c061aSmrg    register int i, j;
679444c061aSmrg    KeySym lsym, usym;
680444c061aSmrg    unsigned maxcodes = 0;
681444c061aSmrg    unsigned ncodes = 0;
682444c061aSmrg    KeyCode *keycodes, *codeP = NULL;
683444c061aSmrg    DPY_TO_APPCON(dpy);
684444c061aSmrg
685444c061aSmrg    LOCK_APP(app);
686444c061aSmrg    pd = _XtGetPerDisplay(dpy);
687444c061aSmrg    _InitializeKeysymTables(dpy, pd);
688444c061aSmrg    keycodes = NULL;
689444c061aSmrg    per = pd->keysyms_per_keycode;
690444c061aSmrg    for (syms = pd->keysyms, keycode = (unsigned) pd->min_keycode;
691444c061aSmrg	 (int)keycode <= pd->max_keycode;
692444c061aSmrg	 syms += per, keycode++) {
693444c061aSmrg	match = 0;
694444c061aSmrg	for (j = 0; j < per; j++) {
695444c061aSmrg	    if (syms[j] == keysym) {
696444c061aSmrg		match = 1;
697444c061aSmrg		break;
698444c061aSmrg	    }
699444c061aSmrg	}
700444c061aSmrg	if (!match)
701444c061aSmrg	    for (i = 1; i < 5; i += 2) {
702444c061aSmrg		if ((per == i) || ((per > i) && (syms[i] == NoSymbol))) {
703444c061aSmrg		    XtConvertCase(dpy, syms[i-1], &lsym, &usym);
704444c061aSmrg		    if ((lsym == keysym) || (usym == keysym)) {
705444c061aSmrg			match = 1;
706444c061aSmrg			break;
707444c061aSmrg		    }
708444c061aSmrg		}
709444c061aSmrg	    }
710444c061aSmrg	if (match) {
711444c061aSmrg	    if (ncodes == maxcodes) {
712444c061aSmrg		KeyCode *old = keycodes;
713444c061aSmrg		maxcodes += KEYCODE_ARRAY_SIZE;
714444c061aSmrg		keycodes = (KeyCode*)__XtMalloc(maxcodes*sizeof(KeyCode));
715444c061aSmrg		if (ncodes) {
716444c061aSmrg		    (void) memmove((char *)keycodes, (char *)old,
717444c061aSmrg				   ncodes*sizeof(KeyCode) );
718444c061aSmrg		    XtFree((char *)old);
719444c061aSmrg		}
720444c061aSmrg		codeP = &keycodes[ncodes];
721444c061aSmrg	    }
722444c061aSmrg	    *codeP++ = (KeyCode) keycode;
723444c061aSmrg	    ncodes++;
724444c061aSmrg	}
725444c061aSmrg    }
726444c061aSmrg    *keycodes_return = keycodes;
727444c061aSmrg    *keycount_return = ncodes;
728444c061aSmrg    UNLOCK_APP(app);
729444c061aSmrg}
730