1444c061aSmrg/***********************************************************
2fdf6a26fSmrgCopyright (c) 1993, Oracle and/or its affiliates.
31477040fSmrg
41477040fSmrgPermission is hereby granted, free of charge, to any person obtaining a
51477040fSmrgcopy of this software and associated documentation files (the "Software"),
61477040fSmrgto deal in the Software without restriction, including without limitation
71477040fSmrgthe rights to use, copy, modify, merge, publish, distribute, sublicense,
81477040fSmrgand/or sell copies of the Software, and to permit persons to whom the
91477040fSmrgSoftware is furnished to do so, subject to the following conditions:
101477040fSmrg
111477040fSmrgThe above copyright notice and this permission notice (including the next
121477040fSmrgparagraph) shall be included in all copies or substantial portions of the
131477040fSmrgSoftware.
141477040fSmrg
151477040fSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
161477040fSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
171477040fSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
181477040fSmrgTHE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
191477040fSmrgLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
201477040fSmrgFROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
211477040fSmrgDEALINGS IN THE SOFTWARE.
221477040fSmrg
231477040fSmrgCopyright 1987, 1988 by Digital Equipment Corporation, Maynard, Massachusetts.
24444c061aSmrg
25444c061aSmrg                        All Rights Reserved
26444c061aSmrg
27444c061aSmrgPermission to use, copy, modify, and distribute this software and its
28444c061aSmrgdocumentation for any purpose and without fee is hereby granted,
29444c061aSmrgprovided that the above copyright notice appear in all copies and that
30444c061aSmrgboth that copyright notice and this permission notice appear in
311477040fSmrgsupporting documentation, and that the name of Digital not be
32444c061aSmrgused in advertising or publicity pertaining to distribution of the
33444c061aSmrgsoftware without specific, written prior permission.
34444c061aSmrg
35444c061aSmrgDIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
36444c061aSmrgALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
37444c061aSmrgDIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
38444c061aSmrgANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
39444c061aSmrgWHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
40444c061aSmrgARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
41444c061aSmrgSOFTWARE.
42444c061aSmrg
43444c061aSmrg******************************************************************/
44444c061aSmrg
45444c061aSmrg/*
46444c061aSmrg
47444c061aSmrgCopyright 1987, 1988, 1994, 1998  The Open Group
48444c061aSmrg
49444c061aSmrgPermission to use, copy, modify, distribute, and sell this software and its
50444c061aSmrgdocumentation for any purpose is hereby granted without fee, provided that
51444c061aSmrgthe above copyright notice appear in all copies and that both that
52444c061aSmrgcopyright notice and this permission notice appear in supporting
53444c061aSmrgdocumentation.
54444c061aSmrg
55444c061aSmrgThe above copyright notice and this permission notice shall be included in
56444c061aSmrgall copies or substantial portions of the Software.
57444c061aSmrg
58444c061aSmrgTHE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
59444c061aSmrgIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
60444c061aSmrgFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
61444c061aSmrgOPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
62444c061aSmrgAN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
63444c061aSmrgCONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
64444c061aSmrg
65444c061aSmrgExcept as contained in this notice, the name of The Open Group shall not be
66444c061aSmrgused in advertising or otherwise to promote the sale, use or other dealings
67444c061aSmrgin this Software without prior written authorization from The Open Group.
68444c061aSmrg
69444c061aSmrg*/
70444c061aSmrg
71444c061aSmrg#define XK_MISCELLANY
72444c061aSmrg#define XK_LATIN1
73444c061aSmrg#define XK_LATIN2
74444c061aSmrg#define XK_LATIN3
75444c061aSmrg#define XK_LATIN4
76444c061aSmrg
77444c061aSmrg#ifdef HAVE_CONFIG_H
78444c061aSmrg#include <config.h>
79444c061aSmrg#endif
80444c061aSmrg#include "IntrinsicI.h"
81444c061aSmrg#include <X11/keysymdef.h>
82444c061aSmrg#ifdef XKB
83444c061aSmrg#include <X11/XKBlib.h>
84444c061aSmrg#endif
85444c061aSmrg
86444c061aSmrg#define FLUSHKEYCACHE(ctx) \
87a3bd7f05Smrg        memset((void *)&ctx->keycache, 0, sizeof(TMKeyCache))
88444c061aSmrg
89444c061aSmrg/*
90444c061aSmrg * The following array reorders the modifier bits so that the most common ones
91444c061aSmrg * (used by a translator) are in the top-most bits with respect to the size of
92444c061aSmrg * the keycache.  The array currently just reverses the bits as a good guess.
93444c061aSmrg * This might be more trouble than it is worth, but it seems to help.
94444c061aSmrg */
95444c061aSmrg
96444c061aSmrg#define FM(i) i >> (8 - TMKEYCACHELOG2)
97a3bd7f05Smrg
98a3bd7f05Smrg/* *INDENT-OFF* */
99444c061aSmrgstatic const unsigned char modmix[256] = {
100444c061aSmrgFM(0x0f), FM(0x8f), FM(0x4f), FM(0xcf), FM(0x2f), FM(0xaf), FM(0x6f), FM(0xef),
101444c061aSmrgFM(0x1f), FM(0x9f), FM(0x5f), FM(0xdf), FM(0x3f), FM(0xbf), FM(0x7f), FM(0xff),
102444c061aSmrgFM(0x07), FM(0x87), FM(0x47), FM(0xc7), FM(0x27), FM(0xa7), FM(0x67), FM(0xe7),
103444c061aSmrgFM(0x17), FM(0x97), FM(0x57), FM(0xd7), FM(0x37), FM(0xb7), FM(0x77), FM(0xf7),
104444c061aSmrgFM(0x0b), FM(0x8b), FM(0x4b), FM(0xcb), FM(0x2b), FM(0xab), FM(0x6b), FM(0xeb),
105444c061aSmrgFM(0x1b), FM(0x9b), FM(0x5b), FM(0xdb), FM(0x3b), FM(0xbb), FM(0x7b), FM(0xfb),
106444c061aSmrgFM(0x03), FM(0x83), FM(0x43), FM(0xc3), FM(0x23), FM(0xa3), FM(0x63), FM(0xe3),
107444c061aSmrgFM(0x13), FM(0x93), FM(0x53), FM(0xd3), FM(0x33), FM(0xb3), FM(0x73), FM(0xf3),
108444c061aSmrgFM(0x0d), FM(0x8d), FM(0x4d), FM(0xcd), FM(0x2d), FM(0xad), FM(0x6d), FM(0xed),
109444c061aSmrgFM(0x1d), FM(0x9d), FM(0x5d), FM(0xdd), FM(0x3d), FM(0xbd), FM(0x7d), FM(0xfd),
110444c061aSmrgFM(0x05), FM(0x85), FM(0x45), FM(0xc5), FM(0x25), FM(0xa5), FM(0x65), FM(0xe5),
111444c061aSmrgFM(0x15), FM(0x95), FM(0x55), FM(0xd5), FM(0x35), FM(0xb5), FM(0x75), FM(0xf5),
112444c061aSmrgFM(0x09), FM(0x89), FM(0x49), FM(0xc9), FM(0x29), FM(0xa9), FM(0x69), FM(0xe9),
113444c061aSmrgFM(0x19), FM(0x99), FM(0x59), FM(0xd9), FM(0x39), FM(0xb9), FM(0x79), FM(0xf9),
114444c061aSmrgFM(0x01), FM(0x81), FM(0x41), FM(0xc1), FM(0x21), FM(0xa1), FM(0x61), FM(0xe1),
115444c061aSmrgFM(0x11), FM(0x91), FM(0x51), FM(0xd1), FM(0x31), FM(0xb1), FM(0x71), FM(0xf1),
116444c061aSmrgFM(0x00), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee),
117444c061aSmrgFM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe),
118444c061aSmrgFM(0x08), FM(0x88), FM(0x48), FM(0xc8), FM(0x28), FM(0xa8), FM(0x68), FM(0xe8),
119444c061aSmrgFM(0x18), FM(0x98), FM(0x58), FM(0xd8), FM(0x38), FM(0xb8), FM(0x78), FM(0xf8),
120444c061aSmrgFM(0x04), FM(0x84), FM(0x44), FM(0xc4), FM(0x24), FM(0xa4), FM(0x64), FM(0xe4),
121444c061aSmrgFM(0x14), FM(0x94), FM(0x54), FM(0xd4), FM(0x34), FM(0xb4), FM(0x74), FM(0xf4),
122444c061aSmrgFM(0x0c), FM(0x8c), FM(0x4c), FM(0xcc), FM(0x2c), FM(0xac), FM(0x6c), FM(0xec),
123444c061aSmrgFM(0x1c), FM(0x9c), FM(0x5c), FM(0xdc), FM(0x3c), FM(0xbc), FM(0x7c), FM(0xfc),
124444c061aSmrgFM(0x02), FM(0x82), FM(0x42), FM(0xc2), FM(0x22), FM(0xa2), FM(0x62), FM(0xe2),
125444c061aSmrgFM(0x12), FM(0x92), FM(0x52), FM(0xd2), FM(0x32), FM(0xb2), FM(0x72), FM(0xf2),
126444c061aSmrgFM(0x0a), FM(0x8a), FM(0x4a), FM(0xca), FM(0x2a), FM(0xaa), FM(0x6a), FM(0xea),
127444c061aSmrgFM(0x1a), FM(0x9a), FM(0x5a), FM(0xda), FM(0x3a), FM(0xba), FM(0x7a), FM(0xfa),
128444c061aSmrgFM(0x06), FM(0x86), FM(0x46), FM(0xc6), FM(0x26), FM(0xa6), FM(0x66), FM(0xe6),
129444c061aSmrgFM(0x16), FM(0x96), FM(0x56), FM(0xd6), FM(0x36), FM(0xb6), FM(0x76), FM(0xf6),
130444c061aSmrgFM(0x0e), FM(0x8e), FM(0x4e), FM(0xce), FM(0x2e), FM(0xae), FM(0x6e), FM(0xee),
131444c061aSmrgFM(0x1e), FM(0x9e), FM(0x5e), FM(0xde), FM(0x3e), FM(0xbe), FM(0x7e), FM(0xfe)
132444c061aSmrg};
133a3bd7f05Smrg/* *INDENT-ON* */
134444c061aSmrg#undef FM
135444c061aSmrg
136444c061aSmrg#define MOD_RETURN(ctx, key) (ctx)->keycache.modifiers_return[key]
137444c061aSmrg
138444c061aSmrg#define TRANSLATE(ctx,pd,dpy,key,mod,mod_ret,sym_ret) \
139444c061aSmrg{ \
1400568f49bSmrg    int _i_ = (((key) - (TMLongCard) (pd)->min_keycode + modmix[(mod) & 0xff]) & \
141a3bd7f05Smrg               (TMKEYCACHESIZE-1)); \
1422265a131Smrg    if ((key) == 0) { /* Xlib XIM composed input */ \
143a3bd7f05Smrg        mod_ret = 0; \
144a3bd7f05Smrg        sym_ret = 0; \
1452265a131Smrg    } else if (   /* not Xlib XIM composed input */ \
146a3bd7f05Smrg        (ctx)->keycache.keycode[_i_] == (key) && \
147a3bd7f05Smrg        (ctx)->keycache.modifiers[_i_] == (mod)) { \
148a3bd7f05Smrg        mod_ret = MOD_RETURN(ctx, key); \
149a3bd7f05Smrg        sym_ret = (ctx)->keycache.keysym[_i_]; \
150444c061aSmrg    } else { \
151a3bd7f05Smrg        XtTranslateKeycode(dpy, (KeyCode) key, mod, &mod_ret, &sym_ret); \
152a3bd7f05Smrg        (ctx)->keycache.keycode[_i_] = (KeyCode) (key); \
153a3bd7f05Smrg        (ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
154a3bd7f05Smrg        (ctx)->keycache.keysym[_i_] = sym_ret; \
155a3bd7f05Smrg        MOD_RETURN(ctx, key) = (unsigned char)mod_ret; \
156444c061aSmrg    } \
157444c061aSmrg}
158444c061aSmrg
159444c061aSmrg#define UPDATE_CACHE(ctx, pd, key, mod, mod_ret, sym_ret) \
160444c061aSmrg{ \
1610568f49bSmrg    int _i_ = (((key) - (TMLongCard) (pd)->min_keycode + modmix[(mod) & 0xff]) & \
162a3bd7f05Smrg               (TMKEYCACHESIZE-1)); \
1630568f49bSmrg    (ctx)->keycache.keycode[_i_] = (KeyCode) (key); \
164444c061aSmrg    (ctx)->keycache.modifiers[_i_] = (unsigned char)(mod); \
165444c061aSmrg    (ctx)->keycache.keysym[_i_] = sym_ret; \
1660568f49bSmrg    MOD_RETURN(ctx, key) = (unsigned char)(mod_ret); \
167444c061aSmrg}
168444c061aSmrg
169444c061aSmrg/* usual number of expected keycodes in XtKeysymToKeycodeList */
170444c061aSmrg#define KEYCODE_ARRAY_SIZE 10
171444c061aSmrg
172a3bd7f05SmrgBoolean
173a3bd7f05Smrg_XtComputeLateBindings(Display *dpy,
174a3bd7f05Smrg                       LateBindingsPtr lateModifiers,
175a3bd7f05Smrg                       Modifiers *computed,
176a3bd7f05Smrg                       Modifiers *computedMask)
177444c061aSmrg{
178a3bd7f05Smrg    int i, j, ref;
179a3bd7f05Smrg    ModToKeysymTable *temp;
180444c061aSmrg    XtPerDisplay perDisplay;
181444c061aSmrg    KeySym tempKeysym = NoSymbol;
182444c061aSmrg
183444c061aSmrg    perDisplay = _XtGetPerDisplay(dpy);
184444c061aSmrg    if (perDisplay == NULL) {
185444c061aSmrg        XtAppWarningMsg(XtDisplayToApplicationContext(dpy),
186a3bd7f05Smrg                        "displayError", "invalidDisplay", XtCXtToolkitError,
187a3bd7f05Smrg                        "Can't find display structure", NULL, NULL);
188a3bd7f05Smrg        return FALSE;
189444c061aSmrg    }
190444c061aSmrg    _InitializeKeysymTables(dpy, perDisplay);
191a3bd7f05Smrg    for (ref = 0; lateModifiers[ref].keysym; ref++) {
1920568f49bSmrg        Boolean found = FALSE;
193a3bd7f05Smrg
194a3bd7f05Smrg        for (i = 0; i < 8; i++) {
195444c061aSmrg            temp = &(perDisplay->modsToKeysyms[i]);
196a3bd7f05Smrg            for (j = 0; j < temp->count; j++) {
197a3bd7f05Smrg                if (perDisplay->modKeysyms[temp->idx + j] ==
198a3bd7f05Smrg                    lateModifiers[ref].keysym) {
199444c061aSmrg                    *computedMask = *computedMask | temp->mask;
200444c061aSmrg                    if (!lateModifiers[ref].knot)
201a3bd7f05Smrg                        *computed |= temp->mask;
202444c061aSmrg                    tempKeysym = lateModifiers[ref].keysym;
203a3bd7f05Smrg                    found = TRUE;
204a3bd7f05Smrg                    break;
205444c061aSmrg                }
206444c061aSmrg            }
207a3bd7f05Smrg            if (found)
208a3bd7f05Smrg                break;
209444c061aSmrg        }
210a3bd7f05Smrg        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 */
219a3bd7f05Smrg        if (!lateModifiers[ref].pair)
220a3bd7f05Smrg            tempKeysym = NoSymbol;
221444c061aSmrg    }
222444c061aSmrg    return TRUE;
223444c061aSmrg}
224444c061aSmrg
225a3bd7f05Smrgvoid
226a3bd7f05Smrg_XtAllocTMContext(XtPerDisplay pd)
227444c061aSmrg{
228444c061aSmrg    TMKeyContext ctx;
229a3bd7f05Smrg
230a3bd7f05Smrg    ctx = (TMKeyContext) _XtHeapAlloc(&pd->heap, sizeof(TMKeyContextRec));
231444c061aSmrg    ctx->event = NULL;
232444c061aSmrg    ctx->serial = 0;
233444c061aSmrg    ctx->keysym = NoSymbol;
234444c061aSmrg    ctx->modifiers = 0;
235444c061aSmrg    FLUSHKEYCACHE(ctx);
236444c061aSmrg    pd->tm_context = ctx;
237444c061aSmrg}
238444c061aSmrg
239a3bd7f05Smrgstatic unsigned int
240a3bd7f05Smrgnum_bits(unsigned long mask)
241444c061aSmrg{
242444c061aSmrg    register unsigned long y;
243444c061aSmrg
244a3bd7f05Smrg    y = (mask >> 1) & 033333333333;
245a3bd7f05Smrg    y = mask - y - ((y >> 1) & 033333333333);
246444c061aSmrg    return ((unsigned int) (((y + (y >> 3)) & 030707070707) % 077));
247444c061aSmrg}
248444c061aSmrg
249a3bd7f05SmrgBoolean
250a3bd7f05Smrg_XtMatchUsingDontCareMods(TMTypeMatch typeMatch,
251a3bd7f05Smrg                          TMModifierMatch modMatch,
252a3bd7f05Smrg                          TMEventPtr eventSeq)
253444c061aSmrg{
254444c061aSmrg    Modifiers modifiers_return;
255444c061aSmrg    KeySym keysym_return;
256444c061aSmrg    Modifiers useful_mods;
257444c061aSmrg    Modifiers computed = 0;
258444c061aSmrg    Modifiers computedMask = 0;
259444c061aSmrg    Boolean resolved = TRUE;
260444c061aSmrg    Display *dpy = eventSeq->xev->xany.display;
261444c061aSmrg    XtPerDisplay pd;
262444c061aSmrg
263444c061aSmrg    if (modMatch->lateModifiers != NULL)
264a3bd7f05Smrg        resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
265a3bd7f05Smrg                                          &computed, &computedMask);
266a3bd7f05Smrg    if (!resolved)
267a3bd7f05Smrg        return FALSE;
2680568f49bSmrg    computed = (Modifiers) (computed | modMatch->modifiers);
2690568f49bSmrg    computedMask = (Modifiers) (computedMask | modMatch->modifierMask); /* gives do-care mask */
270444c061aSmrg
271a3bd7f05Smrg    if ((computed & computedMask) == (eventSeq->event.modifiers & computedMask)) {
272a3bd7f05Smrg        TMKeyContext tm_context;
273a3bd7f05Smrg        int num_modbits;
274a3bd7f05Smrg        int i;
275a3bd7f05Smrg
276a3bd7f05Smrg        pd = _XtGetPerDisplay(dpy);
277a3bd7f05Smrg        tm_context = pd->tm_context;
278a3bd7f05Smrg        TRANSLATE(tm_context, pd, dpy, (KeyCode) eventSeq->event.eventCode,
279a3bd7f05Smrg                  (unsigned) 0, modifiers_return, keysym_return);
280a3bd7f05Smrg
281a3bd7f05Smrg        if ((keysym_return & typeMatch->eventCodeMask) == typeMatch->eventCode) {
282a3bd7f05Smrg            tm_context->event = eventSeq->xev;
283a3bd7f05Smrg            tm_context->serial = eventSeq->xev->xany.serial;
284a3bd7f05Smrg            tm_context->keysym = keysym_return;
285a3bd7f05Smrg            tm_context->modifiers = (Modifiers) 0;
286a3bd7f05Smrg            return TRUE;
287a3bd7f05Smrg        }
288444c061aSmrg        useful_mods = ~computedMask & modifiers_return;
289a3bd7f05Smrg        if (useful_mods == 0)
290a3bd7f05Smrg            return FALSE;
291a3bd7f05Smrg
292a3bd7f05Smrg        switch (num_modbits = (int) num_bits(useful_mods)) {
293a3bd7f05Smrg        case 1:
294a3bd7f05Smrg        case 8:
295a3bd7f05Smrg            /*
296a3bd7f05Smrg             * one modbit should never happen, in fact the implementation
297a3bd7f05Smrg             * of XtTranslateKey and XmTranslateKey guarantee that it
298a3bd7f05Smrg             * won't, so don't care if the loop is set up for the case
299a3bd7f05Smrg             * when one modbit is set.
300a3bd7f05Smrg             * The performance implications of all eight modbits being
301a3bd7f05Smrg             * set is horrendous. This isn't a problem with Xt/Xaw based
302a3bd7f05Smrg             * applications. We can only hope that Motif's virtual
303a3bd7f05Smrg             * modifiers won't result in all eight modbits being set.
304a3bd7f05Smrg             */
305a3bd7f05Smrg            for (i = (int) useful_mods; i > 0; i--) {
306a3bd7f05Smrg                TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
307a3bd7f05Smrg                          (Modifiers) i, modifiers_return, keysym_return);
308a3bd7f05Smrg                if (keysym_return ==
309a3bd7f05Smrg                    (typeMatch->eventCode & typeMatch->eventCodeMask)) {
310a3bd7f05Smrg                    tm_context->event = eventSeq->xev;
311a3bd7f05Smrg                    tm_context->serial = eventSeq->xev->xany.serial;
312a3bd7f05Smrg                    tm_context->keysym = keysym_return;
313a3bd7f05Smrg                    tm_context->modifiers = (Modifiers) i;
314a3bd7f05Smrg                    return TRUE;
315a3bd7f05Smrg                }
316a3bd7f05Smrg            }
317a3bd7f05Smrg            break;
318a3bd7f05Smrg        default:               /* (2..7) */
319a3bd7f05Smrg        {
320a3bd7f05Smrg            /*
321a3bd7f05Smrg             * Only translate using combinations of the useful modifiers.
322a3bd7f05Smrg             * to minimize the chance of invalidating the cache.
323a3bd7f05Smrg             */
324a3bd7f05Smrg            static char pows[] = { 0, 1, 3, 7, 15, 31, 63, 127 };
325a3bd7f05Smrg            Modifiers tmod, mod_masks[8];
326a3bd7f05Smrg            int j;
327a3bd7f05Smrg
328a3bd7f05Smrg            for (tmod = 1, i = 0; tmod <= (Mod5Mask << 1); tmod <<= 1)
329a3bd7f05Smrg                if (tmod & useful_mods)
330a3bd7f05Smrg                    mod_masks[i++] = tmod;
331a3bd7f05Smrg            for (j = (int) pows[num_modbits]; j > 0; j--) {
332a3bd7f05Smrg                tmod = 0;
333a3bd7f05Smrg                for (i = 0; i < num_modbits; i++)
334a3bd7f05Smrg                    if (j & (1 << i))
335a3bd7f05Smrg                        tmod |= mod_masks[i];
336a3bd7f05Smrg                TRANSLATE(tm_context, pd, dpy, eventSeq->event.eventCode,
337a3bd7f05Smrg                          tmod, modifiers_return, keysym_return);
338a3bd7f05Smrg                if (keysym_return ==
339a3bd7f05Smrg                    (typeMatch->eventCode & typeMatch->eventCodeMask)) {
340a3bd7f05Smrg                    tm_context->event = eventSeq->xev;
341a3bd7f05Smrg                    tm_context->serial = eventSeq->xev->xany.serial;
342a3bd7f05Smrg                    tm_context->keysym = keysym_return;
343a3bd7f05Smrg                    tm_context->modifiers = (Modifiers) i;
344a3bd7f05Smrg                    return TRUE;
345a3bd7f05Smrg                }
346a3bd7f05Smrg            }
347a3bd7f05Smrg        }
348a3bd7f05Smrg            break;
349a3bd7f05Smrg        }                       /* switch (num_modbits) */
350444c061aSmrg    }
351444c061aSmrg    return FALSE;
352444c061aSmrg}
353444c061aSmrg
354a3bd7f05Smrgvoid
355a3bd7f05SmrgXtConvertCase(Display *dpy,
356a3bd7f05Smrg              KeySym keysym,
357a3bd7f05Smrg              KeySym *lower_return,
358a3bd7f05Smrg              KeySym *upper_return)
359444c061aSmrg{
360444c061aSmrg    XtPerDisplay pd;
361444c061aSmrg    CaseConverterPtr ptr;
362a3bd7f05Smrg
363444c061aSmrg    DPY_TO_APPCON(dpy);
364444c061aSmrg
365444c061aSmrg    LOCK_APP(app);
366444c061aSmrg    pd = _XtGetPerDisplay(dpy);
367444c061aSmrg
368444c061aSmrg    *lower_return = *upper_return = keysym;
369a3bd7f05Smrg    for (ptr = pd->case_cvt; ptr; ptr = ptr->next)
370a3bd7f05Smrg        if (ptr->start <= keysym && keysym <= ptr->stop) {
371a3bd7f05Smrg            (*ptr->proc) (dpy, keysym, lower_return, upper_return);
372a3bd7f05Smrg            return;
373a3bd7f05Smrg        }
374444c061aSmrg    XConvertCase(keysym, lower_return, upper_return);
375444c061aSmrg    UNLOCK_APP(app);
376444c061aSmrg}
377444c061aSmrg
378a3bd7f05SmrgBoolean
379a3bd7f05Smrg_XtMatchUsingStandardMods(TMTypeMatch typeMatch,
380a3bd7f05Smrg                          TMModifierMatch modMatch,
381a3bd7f05Smrg                          TMEventPtr eventSeq)
382444c061aSmrg{
383444c061aSmrg    Modifiers modifiers_return;
384444c061aSmrg    KeySym keysym_return;
385a3bd7f05Smrg    Modifiers computed = 0;
386444c061aSmrg    Modifiers computedMask = 0;
387444c061aSmrg    Display *dpy = eventSeq->xev->xany.display;
388444c061aSmrg    XtPerDisplay pd = _XtGetPerDisplay(dpy);
389444c061aSmrg    TMKeyContext tm_context = pd->tm_context;
390444c061aSmrg    Modifiers translateModifiers;
391444c061aSmrg
392444c061aSmrg    /* To maximize cache utilization, we mask off nonstandard modifiers
393444c061aSmrg       before cache lookup.  For a given key translator, standard modifiers
394444c061aSmrg       are constant per KeyCode.  If a key translator uses no standard
395444c061aSmrg       modifiers this implementation will never reference the cache.
396444c061aSmrg     */
397444c061aSmrg
398444c061aSmrg    modifiers_return = MOD_RETURN(tm_context, eventSeq->event.eventCode);
399444c061aSmrg    if (!modifiers_return) {
400a3bd7f05Smrg        XtTranslateKeycode(dpy, (KeyCode) eventSeq->event.eventCode,
401a3bd7f05Smrg                           (Modifiers) eventSeq->event.modifiers,
402a3bd7f05Smrg                           &modifiers_return, &keysym_return);
403a3bd7f05Smrg        translateModifiers =
404a3bd7f05Smrg            (Modifiers) (eventSeq->event.modifiers & modifiers_return);
405a3bd7f05Smrg        UPDATE_CACHE(tm_context, pd, eventSeq->event.eventCode,
406a3bd7f05Smrg                     translateModifiers, modifiers_return, keysym_return);
407a3bd7f05Smrg    }
408a3bd7f05Smrg    else {
409a3bd7f05Smrg        translateModifiers =
410a3bd7f05Smrg            (Modifiers) (eventSeq->event.modifiers & modifiers_return);
411a3bd7f05Smrg        TRANSLATE(tm_context, pd, dpy, (KeyCode) eventSeq->event.eventCode,
412a3bd7f05Smrg                  translateModifiers, modifiers_return, keysym_return);
413444c061aSmrg    }
414444c061aSmrg
415444c061aSmrg    if ((typeMatch->eventCode & typeMatch->eventCodeMask) ==
416a3bd7f05Smrg        (keysym_return & typeMatch->eventCodeMask)) {
417a3bd7f05Smrg        Boolean resolved = TRUE;
4180568f49bSmrg
419444c061aSmrg        if (modMatch->lateModifiers != NULL)
420444c061aSmrg            resolved = _XtComputeLateBindings(dpy, modMatch->lateModifiers,
421a3bd7f05Smrg                                              &computed, &computedMask);
422a3bd7f05Smrg        if (!resolved)
423a3bd7f05Smrg            return FALSE;
4240568f49bSmrg        computed = (Modifiers) (computed | modMatch->modifiers);
4250568f49bSmrg        computedMask = (Modifiers) (computedMask | modMatch->modifierMask);
426444c061aSmrg
427444c061aSmrg        if ((computed & computedMask) ==
428a3bd7f05Smrg            (eventSeq->event.modifiers & ~modifiers_return & computedMask)) {
429a3bd7f05Smrg            tm_context->event = eventSeq->xev;
430a3bd7f05Smrg            tm_context->serial = eventSeq->xev->xany.serial;
431a3bd7f05Smrg            tm_context->keysym = keysym_return;
432a3bd7f05Smrg            tm_context->modifiers = translateModifiers;
433a3bd7f05Smrg            return TRUE;
434a3bd7f05Smrg        }
435444c061aSmrg    }
436444c061aSmrg    return FALSE;
437444c061aSmrg}
438444c061aSmrg
439a3bd7f05Smrgvoid
440a3bd7f05Smrg_XtBuildKeysymTables(Display *dpy, register XtPerDisplay pd)
441444c061aSmrg{
442444c061aSmrg    ModToKeysymTable *table;
443a3bd7f05Smrg    int maxCount, i, j, k, tempCount, idx;
444a3bd7f05Smrg    KeySym keysym, tempKeysym;
445a3bd7f05Smrg    XModifierKeymap *modKeymap;
446444c061aSmrg    KeyCode keycode;
447a3bd7f05Smrg
448444c061aSmrg#define KeysymTableSize 16
449444c061aSmrg
450444c061aSmrg    FLUSHKEYCACHE(pd->tm_context);
4510568f49bSmrg
452a3bd7f05Smrg    XFree((char *) pd->keysyms);
453444c061aSmrg    pd->keysyms_serial = NextRequest(dpy);
4540568f49bSmrg    pd->keysyms = XGetKeyboardMapping(dpy, (KeyCode) pd->min_keycode,
455a3bd7f05Smrg                                      pd->max_keycode - pd->min_keycode + 1,
456a3bd7f05Smrg                                      &pd->keysyms_per_keycode);
457a3bd7f05Smrg    XtFree((char *) pd->modKeysyms);
4580568f49bSmrg
459fdf6a26fSmrg    pd->modKeysyms = XtMallocArray(KeysymTableSize, (Cardinal) sizeof(KeySym));
460444c061aSmrg    maxCount = KeysymTableSize;
461444c061aSmrg    tempCount = 0;
462444c061aSmrg
463a3bd7f05Smrg    XtFree((char *) pd->modsToKeysyms);
464fdf6a26fSmrg    table = XtMallocArray(8, (Cardinal) sizeof(ModToKeysymTable));
465444c061aSmrg    pd->modsToKeysyms = table;
466444c061aSmrg
467444c061aSmrg    table[0].mask = ShiftMask;
468444c061aSmrg    table[1].mask = LockMask;
469444c061aSmrg    table[2].mask = ControlMask;
470444c061aSmrg    table[3].mask = Mod1Mask;
471444c061aSmrg    table[4].mask = Mod2Mask;
472444c061aSmrg    table[5].mask = Mod3Mask;
473444c061aSmrg    table[6].mask = Mod4Mask;
474444c061aSmrg    table[7].mask = Mod5Mask;
475444c061aSmrg    tempKeysym = 0;
476444c061aSmrg
477444c061aSmrg    modKeymap = XGetModifierMapping(dpy);
478a3bd7f05Smrg    for (i = 0; i < 32; i++)
479a3bd7f05Smrg        pd->isModifier[i] = 0;
480444c061aSmrg    pd->mode_switch = 0;
481444c061aSmrg    pd->num_lock = 0;
482a3bd7f05Smrg    for (i = 0; i < 8; i++) {
483444c061aSmrg        table[i].idx = tempCount;
484444c061aSmrg        table[i].count = 0;
485a3bd7f05Smrg        for (j = 0; j < modKeymap->max_keypermod; j++) {
486a3bd7f05Smrg            keycode = modKeymap->modifiermap[i * modKeymap->max_keypermod + j];
487444c061aSmrg            if (keycode != 0) {
488a3bd7f05Smrg                pd->isModifier[keycode >> 3] |=
489a3bd7f05Smrg                    (unsigned char) (1 << (keycode & 7));
490a3bd7f05Smrg                for (k = 0; k < pd->keysyms_per_keycode; k++) {
491a3bd7f05Smrg                    idx = ((keycode - pd->min_keycode) *
492a3bd7f05Smrg                           pd->keysyms_per_keycode) + k;
493444c061aSmrg                    keysym = pd->keysyms[idx];
494a3bd7f05Smrg                    if ((keysym == XK_Mode_switch) && (i > 2))
495a3bd7f05Smrg                        pd->mode_switch =
496a3bd7f05Smrg                            (pd->mode_switch | (Modifiers) (1 << i));
497a3bd7f05Smrg                    if ((keysym == XK_Num_Lock) && (i > 2))
498a3bd7f05Smrg                        pd->num_lock = (pd->num_lock | (Modifiers) (1 << i));
499a3bd7f05Smrg                    if (keysym != 0 && keysym != tempKeysym) {
500a3bd7f05Smrg                        if (tempCount == maxCount) {
501444c061aSmrg                            maxCount += KeysymTableSize;
502fdf6a26fSmrg                            pd->modKeysyms =
503fdf6a26fSmrg                                XtReallocArray(pd->modKeysyms,
504fdf6a26fSmrg                                               (Cardinal) maxCount,
505fdf6a26fSmrg                                               (Cardinal) sizeof(KeySym));
506444c061aSmrg                        }
507444c061aSmrg                        pd->modKeysyms[tempCount++] = keysym;
508444c061aSmrg                        table[i].count++;
509444c061aSmrg                        tempKeysym = keysym;
510444c061aSmrg                    }
511444c061aSmrg                }
512444c061aSmrg            }
513444c061aSmrg        }
514444c061aSmrg    }
515444c061aSmrg    pd->lock_meaning = NoSymbol;
516444c061aSmrg    for (i = 0; i < table[1].count; i++) {
517a3bd7f05Smrg        keysym = pd->modKeysyms[table[1].idx + i];
518a3bd7f05Smrg        if (keysym == XK_Caps_Lock) {
519a3bd7f05Smrg            pd->lock_meaning = XK_Caps_Lock;
520a3bd7f05Smrg            break;
521a3bd7f05Smrg        }
522a3bd7f05Smrg        else if (keysym == XK_Shift_Lock) {
523a3bd7f05Smrg            pd->lock_meaning = XK_Shift_Lock;
524a3bd7f05Smrg        }
525444c061aSmrg    }
526444c061aSmrg    XFreeModifiermap(modKeymap);
527444c061aSmrg}
528444c061aSmrg
529a3bd7f05Smrgvoid
530a3bd7f05SmrgXtTranslateKeycode(Display *dpy,
531a3bd7f05Smrg                   _XtKeyCode keycode,
532a3bd7f05Smrg                   Modifiers modifiers,
533a3bd7f05Smrg                   Modifiers *modifiers_return,
534a3bd7f05Smrg                   KeySym *keysym_return)
535444c061aSmrg{
536444c061aSmrg    XtPerDisplay pd;
537a3bd7f05Smrg
538444c061aSmrg    DPY_TO_APPCON(dpy);
539444c061aSmrg
540444c061aSmrg    LOCK_APP(app);
541444c061aSmrg    pd = _XtGetPerDisplay(dpy);
542444c061aSmrg    _InitializeKeysymTables(dpy, pd);
543a3bd7f05Smrg    (*pd->defaultKeycodeTranslator) (dpy, keycode, modifiers, modifiers_return,
544a3bd7f05Smrg                                     keysym_return);
545444c061aSmrg    UNLOCK_APP(app);
546444c061aSmrg}
547444c061aSmrg
548444c061aSmrg/* This code should match XTranslateKey (internal, sigh) in Xlib */
549a3bd7f05Smrgvoid
550a3bd7f05SmrgXtTranslateKey(register Display *dpy,
551a3bd7f05Smrg               _XtKeyCode keycode,
552a3bd7f05Smrg               Modifiers modifiers,
553a3bd7f05Smrg               Modifiers *modifiers_return,
554a3bd7f05Smrg               KeySym *keysym_return)
555444c061aSmrg{
556444c061aSmrg#ifndef XKB
557444c061aSmrg    XtPerDisplay pd;
558444c061aSmrg    int per;
559444c061aSmrg    register KeySym *syms;
560444c061aSmrg    KeySym sym, lsym, usym;
561a3bd7f05Smrg
562444c061aSmrg    DPY_TO_APPCON(dpy);
563444c061aSmrg
564444c061aSmrg    LOCK_APP(app);
565444c061aSmrg    pd = _XtGetPerDisplay(dpy);
566a3bd7f05Smrg    *modifiers_return = (ShiftMask | LockMask) | pd->mode_switch | pd->num_lock;
567a3bd7f05Smrg    if (((int) keycode < pd->min_keycode) || ((int) keycode > pd->max_keycode)) {
568a3bd7f05Smrg        *keysym_return = NoSymbol;
569a3bd7f05Smrg        UNLOCK_APP(app);
570a3bd7f05Smrg        return;
571444c061aSmrg    }
572444c061aSmrg    per = pd->keysyms_per_keycode;
573444c061aSmrg    syms = &pd->keysyms[(keycode - pd->min_keycode) * per];
574444c061aSmrg    while ((per > 2) && (syms[per - 1] == NoSymbol))
575a3bd7f05Smrg        per--;
576444c061aSmrg    if ((per > 2) && (modifiers & pd->mode_switch)) {
577a3bd7f05Smrg        syms += 2;
578a3bd7f05Smrg        per -= 2;
579444c061aSmrg    }
580444c061aSmrg    if ((modifiers & pd->num_lock) &&
581a3bd7f05Smrg        (per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) {
582a3bd7f05Smrg        if ((modifiers & ShiftMask) ||
583a3bd7f05Smrg            ((modifiers & LockMask) && (pd->lock_meaning == XK_Shift_Lock)))
584a3bd7f05Smrg            *keysym_return = syms[0];
585a3bd7f05Smrg        else
586a3bd7f05Smrg            *keysym_return = syms[1];
587a3bd7f05Smrg    }
588a3bd7f05Smrg    else if (!(modifiers & ShiftMask) &&
589a3bd7f05Smrg             (!(modifiers & LockMask) || (pd->lock_meaning == NoSymbol))) {
590a3bd7f05Smrg        if ((per == 1) || (syms[1] == NoSymbol))
591a3bd7f05Smrg            XtConvertCase(dpy, syms[0], keysym_return, &usym);
592a3bd7f05Smrg        else
593a3bd7f05Smrg            *keysym_return = syms[0];
594a3bd7f05Smrg    }
595a3bd7f05Smrg    else if (!(modifiers & LockMask) || (pd->lock_meaning != XK_Caps_Lock)) {
596a3bd7f05Smrg        if ((per == 1) || ((usym = syms[1]) == NoSymbol))
597a3bd7f05Smrg            XtConvertCase(dpy, syms[0], &lsym, &usym);
598a3bd7f05Smrg        *keysym_return = usym;
599a3bd7f05Smrg    }
600a3bd7f05Smrg    else {
601a3bd7f05Smrg        if ((per == 1) || ((sym = syms[1]) == NoSymbol))
602a3bd7f05Smrg            sym = syms[0];
603a3bd7f05Smrg        XtConvertCase(dpy, sym, &lsym, &usym);
604a3bd7f05Smrg        if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
605a3bd7f05Smrg            ((sym != usym) || (lsym == usym)))
606a3bd7f05Smrg            XtConvertCase(dpy, syms[0], &lsym, &usym);
607a3bd7f05Smrg        *keysym_return = usym;
608444c061aSmrg    }
609444c061aSmrg
610444c061aSmrg    if (*keysym_return == XK_VoidSymbol)
611a3bd7f05Smrg        *keysym_return = NoSymbol;
612444c061aSmrg    UNLOCK_APP(app);
613444c061aSmrg#else
614a3bd7f05Smrg    XkbLookupKeySym(dpy, (KeyCode) keycode, modifiers, modifiers_return,
615a3bd7f05Smrg                    keysym_return);
616444c061aSmrg#endif
617444c061aSmrg}
618444c061aSmrg
619a3bd7f05Smrgvoid
620a3bd7f05SmrgXtSetKeyTranslator(Display *dpy, XtKeyProc translator)
621444c061aSmrg{
622444c061aSmrg    XtPerDisplay pd;
623a3bd7f05Smrg
624444c061aSmrg    DPY_TO_APPCON(dpy);
625444c061aSmrg
626444c061aSmrg    LOCK_APP(app);
627444c061aSmrg    pd = _XtGetPerDisplay(dpy);
628444c061aSmrg
629444c061aSmrg    pd->defaultKeycodeTranslator = translator;
630444c061aSmrg    FLUSHKEYCACHE(pd->tm_context);
631444c061aSmrg    /* XXX should now redo grabs */
632444c061aSmrg    UNLOCK_APP(app);
633444c061aSmrg}
634444c061aSmrg
635a3bd7f05Smrgvoid
636a3bd7f05SmrgXtRegisterCaseConverter(Display *dpy,
637a3bd7f05Smrg                        XtCaseProc proc,
638a3bd7f05Smrg                        KeySym start,
639a3bd7f05Smrg                        KeySym stop)
640444c061aSmrg{
641444c061aSmrg    XtPerDisplay pd;
642444c061aSmrg    CaseConverterPtr ptr, prev;
643a3bd7f05Smrg
644444c061aSmrg    DPY_TO_APPCON(dpy);
645444c061aSmrg
646444c061aSmrg    LOCK_APP(app);
647444c061aSmrg    pd = _XtGetPerDisplay(dpy);
648444c061aSmrg
649444c061aSmrg    ptr = (CaseConverterPtr) __XtMalloc(sizeof(CaseConverterRec));
650444c061aSmrg    ptr->start = start;
651444c061aSmrg    ptr->stop = stop;
652444c061aSmrg    ptr->proc = proc;
653444c061aSmrg    ptr->next = pd->case_cvt;
654444c061aSmrg    pd->case_cvt = ptr;
655444c061aSmrg
656444c061aSmrg    /* Remove obsolete case converters from the list */
657444c061aSmrg    prev = ptr;
658a3bd7f05Smrg    for (ptr = ptr->next; ptr; ptr = prev->next) {
659a3bd7f05Smrg        if (start <= ptr->start && stop >= ptr->stop) {
660a3bd7f05Smrg            prev->next = ptr->next;
661a3bd7f05Smrg            XtFree((char *) ptr);
662a3bd7f05Smrg        }
663a3bd7f05Smrg        else
664a3bd7f05Smrg            prev = ptr;
665444c061aSmrg    }
666444c061aSmrg    FLUSHKEYCACHE(pd->tm_context);
667444c061aSmrg    /* XXX should now redo grabs */
668444c061aSmrg    UNLOCK_APP(app);
669444c061aSmrg}
670444c061aSmrg
671a3bd7f05SmrgKeySym *
672a3bd7f05SmrgXtGetKeysymTable(Display *dpy,
673a3bd7f05Smrg                 KeyCode *min_keycode_return,
674a3bd7f05Smrg                 int *keysyms_per_keycode_return)
675444c061aSmrg{
676444c061aSmrg    XtPerDisplay pd;
677a3bd7f05Smrg    KeySym *retval;
678a3bd7f05Smrg
679444c061aSmrg    DPY_TO_APPCON(dpy);
680444c061aSmrg
681444c061aSmrg    LOCK_APP(app);
682444c061aSmrg    pd = _XtGetPerDisplay(dpy);
683444c061aSmrg    _InitializeKeysymTables(dpy, pd);
684a3bd7f05Smrg    *min_keycode_return = (KeyCode) pd->min_keycode;    /* %%% */
685444c061aSmrg    *keysyms_per_keycode_return = pd->keysyms_per_keycode;
686444c061aSmrg    retval = pd->keysyms;
687444c061aSmrg    UNLOCK_APP(app);
688444c061aSmrg    return retval;
689444c061aSmrg}
690444c061aSmrg
691a3bd7f05Smrgvoid
692a3bd7f05SmrgXtKeysymToKeycodeList(Display *dpy,
693a3bd7f05Smrg                      KeySym keysym,
694a3bd7f05Smrg                      KeyCode **keycodes_return,
695a3bd7f05Smrg                      Cardinal *keycount_return)
696444c061aSmrg{
697444c061aSmrg    XtPerDisplay pd;
698444c061aSmrg    unsigned keycode;
6990568f49bSmrg    int per;
700444c061aSmrg    register KeySym *syms;
701444c061aSmrg    register int i, j;
702444c061aSmrg    KeySym lsym, usym;
703444c061aSmrg    unsigned maxcodes = 0;
704444c061aSmrg    unsigned ncodes = 0;
705444c061aSmrg    KeyCode *keycodes, *codeP = NULL;
706a3bd7f05Smrg
707444c061aSmrg    DPY_TO_APPCON(dpy);
708444c061aSmrg
709444c061aSmrg    LOCK_APP(app);
710444c061aSmrg    pd = _XtGetPerDisplay(dpy);
711444c061aSmrg    _InitializeKeysymTables(dpy, pd);
712444c061aSmrg    keycodes = NULL;
713444c061aSmrg    per = pd->keysyms_per_keycode;
714444c061aSmrg    for (syms = pd->keysyms, keycode = (unsigned) pd->min_keycode;
715a3bd7f05Smrg         (int) keycode <= pd->max_keycode; syms += per, keycode++) {
716a3bd7f05Smrg        int match = 0;
717a3bd7f05Smrg
718a3bd7f05Smrg        for (j = 0; j < per; j++) {
719a3bd7f05Smrg            if (syms[j] == keysym) {
720a3bd7f05Smrg                match = 1;
721a3bd7f05Smrg                break;
722a3bd7f05Smrg            }
723a3bd7f05Smrg        }
724a3bd7f05Smrg        if (!match)
725a3bd7f05Smrg            for (i = 1; i < 5; i += 2) {
726a3bd7f05Smrg                if ((per == i) || ((per > i) && (syms[i] == NoSymbol))) {
727a3bd7f05Smrg                    XtConvertCase(dpy, syms[i - 1], &lsym, &usym);
728a3bd7f05Smrg                    if ((lsym == keysym) || (usym == keysym)) {
729a3bd7f05Smrg                        match = 1;
730a3bd7f05Smrg                        break;
731a3bd7f05Smrg                    }
732a3bd7f05Smrg                }
733a3bd7f05Smrg            }
734a3bd7f05Smrg        if (match) {
735a3bd7f05Smrg            if (ncodes == maxcodes) {
736a3bd7f05Smrg                KeyCode *old = keycodes;
737a3bd7f05Smrg
738a3bd7f05Smrg                maxcodes += KEYCODE_ARRAY_SIZE;
739fdf6a26fSmrg                keycodes = XtMallocArray(maxcodes, (Cardinal) sizeof(KeyCode));
740a3bd7f05Smrg                if (ncodes) {
741fdf6a26fSmrg                    (void) memcpy(keycodes, old, ncodes * sizeof(KeyCode));
742a3bd7f05Smrg                    XtFree((char *) old);
743a3bd7f05Smrg                }
744a3bd7f05Smrg                codeP = &keycodes[ncodes];
745a3bd7f05Smrg            }
746a3bd7f05Smrg            *codeP++ = (KeyCode) keycode;
747a3bd7f05Smrg            ncodes++;
748a3bd7f05Smrg        }
749444c061aSmrg    }
750444c061aSmrg    *keycodes_return = keycodes;
751444c061aSmrg    *keycount_return = ncodes;
752444c061aSmrg    UNLOCK_APP(app);
753444c061aSmrg}
754