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