KeyBind.c revision 818534a1
1/*
2
3Copyright 1985, 1987, 1998  The Open Group
4
5Permission to use, copy, modify, distribute, and sell this software and its
6documentation for any purpose is hereby granted without fee, provided that
7the above copyright notice appear in all copies and that both that
8copyright notice and this permission notice appear in supporting
9documentation.
10
11The above copyright notice and this permission notice shall be included in
12all copies or substantial portions of the Software.
13
14THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
17OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN
18AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
19CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
20
21Except as contained in this notice, the name of The Open Group shall not be
22used in advertising or otherwise to promote the sale, use or other dealings
23in this Software without prior written authorization from The Open Group.
24
25*/
26
27/* Beware, here be monsters (still under construction... - JG */
28
29#ifdef HAVE_CONFIG_H
30#include <config.h>
31#endif
32#include <X11/Xlibint.h>
33#include <X11/Xutil.h>
34#define XK_MISCELLANY
35#define XK_LATIN1
36#define XK_LATIN2
37#define XK_LATIN3
38#define XK_LATIN4
39#define XK_LATIN8
40#define XK_LATIN9
41#define XK_CYRILLIC
42#define XK_GREEK
43#define XK_ARMENIAN
44#define XK_CAUCASUS
45#define XK_VIETNAMESE
46#define XK_XKB_KEYS
47#define XK_SINHALA
48#include <X11/keysymdef.h>
49#include <stdio.h>
50
51#ifdef USE_OWN_COMPOSE
52#include "imComp.h"
53
54#endif
55
56#include "Xresource.h"
57#include "Key.h"
58
59#ifdef XKB
60#include "XKBlib.h"
61#include "XKBlibint.h"
62#define	XKeycodeToKeysym	_XKeycodeToKeysym
63#define	XKeysymToKeycode	_XKeysymToKeycode
64#define	XLookupKeysym		_XLookupKeysym
65#define	XRefreshKeyboardMapping	_XRefreshKeyboardMapping
66#define	XLookupString		_XLookupString
67/* XKBBind.c */
68#else
69#define	XkbKeysymToModifiers	_XKeysymToModifiers
70#endif
71
72#define AllMods (ShiftMask|LockMask|ControlMask| \
73		 Mod1Mask|Mod2Mask|Mod3Mask|Mod4Mask|Mod5Mask)
74
75static void
76ComputeMaskFromKeytrans(
77    Display *dpy,
78    register struct _XKeytrans *p);
79
80struct _XKeytrans {
81	struct _XKeytrans *next;/* next on list */
82	char *string;		/* string to return when the time comes */
83	int len;		/* length of string (since NULL is legit)*/
84	KeySym key;		/* keysym rebound */
85	unsigned int state;	/* modifier state */
86	KeySym *modifiers;	/* modifier keysyms you want */
87	int mlen;		/* length of modifier list */
88};
89
90static KeySym
91KeyCodetoKeySym(register Display *dpy, KeyCode keycode, int col)
92{
93    register int per = dpy->keysyms_per_keycode;
94    register KeySym *syms;
95    KeySym lsym, usym;
96
97    if ((col < 0) || ((col >= per) && (col > 3)) ||
98	((int)keycode < dpy->min_keycode) || ((int)keycode > dpy->max_keycode))
99      return NoSymbol;
100
101    syms = &dpy->keysyms[(keycode - dpy->min_keycode) * per];
102    if (col < 4) {
103	if (col > 1) {
104	    while ((per > 2) && (syms[per - 1] == NoSymbol))
105		per--;
106	    if (per < 3)
107		col -= 2;
108	}
109	if ((per <= (col|1)) || (syms[col|1] == NoSymbol)) {
110	    XConvertCase(syms[col&~1], &lsym, &usym);
111	    if (!(col & 1))
112		return lsym;
113	    else if (usym == lsym)
114		return NoSymbol;
115	    else
116		return usym;
117	}
118    }
119    return syms[col];
120}
121
122KeySym
123XKeycodeToKeysym(Display *dpy,
124#if NeedWidePrototypes
125		 unsigned int kc,
126#else
127		 KeyCode kc,
128#endif
129		 int col)
130{
131    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
132	return NoSymbol;
133    return KeyCodetoKeySym(dpy, kc, col);
134}
135
136KeyCode
137XKeysymToKeycode(
138    Display *dpy,
139    KeySym ks)
140{
141    register int i, j;
142
143    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
144	return (KeyCode) 0;
145    for (j = 0; j < dpy->keysyms_per_keycode; j++) {
146	for (i = dpy->min_keycode; i <= dpy->max_keycode; i++) {
147	    if (KeyCodetoKeySym(dpy, (KeyCode) i, j) == ks)
148		return i;
149	}
150    }
151    return 0;
152}
153
154KeySym
155XLookupKeysym(
156    register XKeyEvent *event,
157    int col)
158{
159    if ((! event->display->keysyms) && (! _XKeyInitialize(event->display)))
160	return NoSymbol;
161    return KeyCodetoKeySym(event->display, event->keycode, col);
162}
163
164static void
165ResetModMap(
166    Display *dpy)
167{
168    register XModifierKeymap *map;
169    register int i, j, n;
170    KeySym sym;
171    register struct _XKeytrans *p;
172
173    map = dpy->modifiermap;
174    /* If any Lock key contains Caps_Lock, then interpret as Caps_Lock,
175     * else if any contains Shift_Lock, then interpret as Shift_Lock,
176     * else ignore Lock altogether.
177     */
178    dpy->lock_meaning = NoSymbol;
179    /* Lock modifiers are in the second row of the matrix */
180    n = 2 * map->max_keypermod;
181    for (i = map->max_keypermod; i < n; i++) {
182	for (j = 0; j < dpy->keysyms_per_keycode; j++) {
183	    sym = KeyCodetoKeySym(dpy, map->modifiermap[i], j);
184	    if (sym == XK_Caps_Lock) {
185		dpy->lock_meaning = XK_Caps_Lock;
186		break;
187	    } else if (sym == XK_Shift_Lock) {
188		dpy->lock_meaning = XK_Shift_Lock;
189	    }
190	    else if (sym == XK_ISO_Lock) {
191		dpy->lock_meaning = XK_Caps_Lock;
192		break;
193	    }
194	}
195    }
196    /* Now find any Mod<n> modifier acting as the Group or Numlock modifier */
197    dpy->mode_switch = 0;
198    dpy->num_lock = 0;
199    n *= 4;
200    for (i = 3*map->max_keypermod; i < n; i++) {
201	for (j = 0; j < dpy->keysyms_per_keycode; j++) {
202	    sym = KeyCodetoKeySym(dpy, map->modifiermap[i], j);
203	    if (sym == XK_Mode_switch)
204		dpy->mode_switch |= 1 << (i / map->max_keypermod);
205	    if (sym == XK_Num_Lock)
206		dpy->num_lock |= 1 << (i / map->max_keypermod);
207	}
208    }
209    for (p = dpy->key_bindings; p; p = p->next)
210	ComputeMaskFromKeytrans(dpy, p);
211}
212
213static int
214InitModMap(
215    Display *dpy)
216{
217    register XModifierKeymap *map;
218
219    if (! (map = XGetModifierMapping(dpy)))
220	return 0;
221    LockDisplay(dpy);
222    if (dpy->modifiermap)
223	XFreeModifiermap(dpy->modifiermap);
224    dpy->modifiermap = map;
225    dpy->free_funcs->modifiermap = XFreeModifiermap;
226    if (dpy->keysyms)
227	ResetModMap(dpy);
228    UnlockDisplay(dpy);
229    return 1;
230}
231
232int
233XRefreshKeyboardMapping(register XMappingEvent *event)
234{
235
236    if(event->request == MappingKeyboard) {
237	/* XXX should really only refresh what is necessary
238	 * for now, make initialize test fail
239	 */
240	LockDisplay(event->display);
241	if (event->display->keysyms) {
242	     Xfree (event->display->keysyms);
243	     event->display->keysyms = NULL;
244	}
245	UnlockDisplay(event->display);
246    }
247    if(event->request == MappingModifier) {
248	LockDisplay(event->display);
249	if (event->display->modifiermap) {
250	    XFreeModifiermap(event->display->modifiermap);
251	    event->display->modifiermap = NULL;
252	}
253	UnlockDisplay(event->display);
254	/* go ahead and get it now, since initialize test may not fail */
255	if (event->display->keysyms)
256	    (void) InitModMap(event->display);
257    }
258    return 1;
259}
260
261int
262_XKeyInitialize(
263    Display *dpy)
264{
265    int per, n;
266    KeySym *keysyms;
267
268    /*
269     * lets go get the keysyms from the server.
270     */
271    if (!dpy->keysyms) {
272	n = dpy->max_keycode - dpy->min_keycode + 1;
273	keysyms = XGetKeyboardMapping (dpy, (KeyCode) dpy->min_keycode,
274				       n, &per);
275	/* keysyms may be NULL */
276	if (! keysyms) return 0;
277
278	LockDisplay(dpy);
279	if (dpy->keysyms)
280	    Xfree (dpy->keysyms);
281	dpy->keysyms = keysyms;
282	dpy->keysyms_per_keycode = per;
283	if (dpy->modifiermap)
284	    ResetModMap(dpy);
285	UnlockDisplay(dpy);
286    }
287    if (!dpy->modifiermap)
288        return InitModMap(dpy);
289    return 1;
290}
291
292static void
293UCSConvertCase( register unsigned code,
294                KeySym *lower,
295                KeySym *upper )
296{
297    /* Case conversion for UCS, as in Unicode Data version 4.0.0 */
298    /* NB: Only converts simple one-to-one mappings. */
299
300    /* Tables are used where they take less space than     */
301    /* the code to work out the mappings. Zero values mean */
302    /* undefined code points.                              */
303
304    static unsigned short const IPAExt_upper_mapping[] = { /* part only */
305                            0x0181, 0x0186, 0x0255, 0x0189, 0x018A,
306    0x0258, 0x018F, 0x025A, 0x0190, 0x025C, 0x025D, 0x025E, 0x025F,
307    0x0193, 0x0261, 0x0262, 0x0194, 0x0264, 0x0265, 0x0266, 0x0267,
308    0x0197, 0x0196, 0x026A, 0x026B, 0x026C, 0x026D, 0x026E, 0x019C,
309    0x0270, 0x0271, 0x019D, 0x0273, 0x0274, 0x019F, 0x0276, 0x0277,
310    0x0278, 0x0279, 0x027A, 0x027B, 0x027C, 0x027D, 0x027E, 0x027F,
311    0x01A6, 0x0281, 0x0282, 0x01A9, 0x0284, 0x0285, 0x0286, 0x0287,
312    0x01AE, 0x0289, 0x01B1, 0x01B2, 0x028C, 0x028D, 0x028E, 0x028F,
313    0x0290, 0x0291, 0x01B7
314    };
315
316    static unsigned short const LatinExtB_upper_mapping[] = { /* first part only */
317    0x0180, 0x0181, 0x0182, 0x0182, 0x0184, 0x0184, 0x0186, 0x0187,
318    0x0187, 0x0189, 0x018A, 0x018B, 0x018B, 0x018D, 0x018E, 0x018F,
319    0x0190, 0x0191, 0x0191, 0x0193, 0x0194, 0x01F6, 0x0196, 0x0197,
320    0x0198, 0x0198, 0x019A, 0x019B, 0x019C, 0x019D, 0x0220, 0x019F,
321    0x01A0, 0x01A0, 0x01A2, 0x01A2, 0x01A4, 0x01A4, 0x01A6, 0x01A7,
322    0x01A7, 0x01A9, 0x01AA, 0x01AB, 0x01AC, 0x01AC, 0x01AE, 0x01AF,
323    0x01AF, 0x01B1, 0x01B2, 0x01B3, 0x01B3, 0x01B5, 0x01B5, 0x01B7,
324    0x01B8, 0x01B8, 0x01BA, 0x01BB, 0x01BC, 0x01BC, 0x01BE, 0x01F7,
325    0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C4, 0x01C4, 0x01C4, 0x01C7,
326    0x01C7, 0x01C7, 0x01CA, 0x01CA, 0x01CA
327    };
328
329    static unsigned short const LatinExtB_lower_mapping[] = { /* first part only */
330    0x0180, 0x0253, 0x0183, 0x0183, 0x0185, 0x0185, 0x0254, 0x0188,
331    0x0188, 0x0256, 0x0257, 0x018C, 0x018C, 0x018D, 0x01DD, 0x0259,
332    0x025B, 0x0192, 0x0192, 0x0260, 0x0263, 0x0195, 0x0269, 0x0268,
333    0x0199, 0x0199, 0x019A, 0x019B, 0x026F, 0x0272, 0x019E, 0x0275,
334    0x01A1, 0x01A1, 0x01A3, 0x01A3, 0x01A5, 0x01A5, 0x0280, 0x01A8,
335    0x01A8, 0x0283, 0x01AA, 0x01AB, 0x01AD, 0x01AD, 0x0288, 0x01B0,
336    0x01B0, 0x028A, 0x028B, 0x01B4, 0x01B4, 0x01B6, 0x01B6, 0x0292,
337    0x01B9, 0x01B9, 0x01BA, 0x01BB, 0x01BD, 0x01BD, 0x01BE, 0x01BF,
338    0x01C0, 0x01C1, 0x01C2, 0x01C3, 0x01C6, 0x01C6, 0x01C6, 0x01C9,
339    0x01C9, 0x01C9, 0x01CC, 0x01CC, 0x01CC
340    };
341
342    static unsigned short const Greek_upper_mapping[] = {
343    0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000,
344    0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000,
345    0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x0386, 0x0387,
346    0x0388, 0x0389, 0x038A, 0x0000, 0x038C, 0x0000, 0x038E, 0x038F,
347    0x0390, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
348    0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
349    0x03A0, 0x03A1, 0x0000, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
350    0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x0386, 0x0388, 0x0389, 0x038A,
351    0x03B0, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397,
352    0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F,
353    0x03A0, 0x03A1, 0x03A3, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7,
354    0x03A8, 0x03A9, 0x03AA, 0x03AB, 0x038C, 0x038E, 0x038F, 0x0000,
355    0x0392, 0x0398, 0x03D2, 0x03D3, 0x03D4, 0x03A6, 0x03A0, 0x03D7,
356    0x03D8, 0x03D8, 0x03DA, 0x03DA, 0x03DC, 0x03DC, 0x03DE, 0x03DE,
357    0x03E0, 0x03E0, 0x03E2, 0x03E2, 0x03E4, 0x03E4, 0x03E6, 0x03E6,
358    0x03E8, 0x03E8, 0x03EA, 0x03EA, 0x03EC, 0x03EC, 0x03EE, 0x03EE,
359    0x039A, 0x03A1, 0x03F9, 0x03F3, 0x03F4, 0x0395, 0x03F6, 0x03F7,
360    0x03F7, 0x03F9, 0x03FA, 0x03FA, 0x0000, 0x0000, 0x0000, 0x0000
361    };
362
363    static unsigned short const Greek_lower_mapping[] = {
364    0x0000, 0x0000, 0x0000, 0x0000, 0x0374, 0x0375, 0x0000, 0x0000,
365    0x0000, 0x0000, 0x037A, 0x0000, 0x0000, 0x0000, 0x037E, 0x0000,
366    0x0000, 0x0000, 0x0000, 0x0000, 0x0384, 0x0385, 0x03AC, 0x0387,
367    0x03AD, 0x03AE, 0x03AF, 0x0000, 0x03CC, 0x0000, 0x03CD, 0x03CE,
368    0x0390, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
369    0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
370    0x03C0, 0x03C1, 0x0000, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
371    0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03AC, 0x03AD, 0x03AE, 0x03AF,
372    0x03B0, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7,
373    0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF,
374    0x03C0, 0x03C1, 0x03C2, 0x03C3, 0x03C4, 0x03C5, 0x03C6, 0x03C7,
375    0x03C8, 0x03C9, 0x03CA, 0x03CB, 0x03CC, 0x03CD, 0x03CE, 0x0000,
376    0x03D0, 0x03D1, 0x03D2, 0x03D3, 0x03D4, 0x03D5, 0x03D6, 0x03D7,
377    0x03D9, 0x03D9, 0x03DB, 0x03DB, 0x03DD, 0x03DD, 0x03DF, 0x03DF,
378    0x03E1, 0x03E1, 0x03E3, 0x03E3, 0x03E5, 0x03E5, 0x03E7, 0x03E7,
379    0x03E9, 0x03E9, 0x03EB, 0x03EB, 0x03ED, 0x03ED, 0x03EF, 0x03EF,
380    0x03F0, 0x03F1, 0x03F2, 0x03F3, 0x03B8, 0x03F5, 0x03F6, 0x03F8,
381    0x03F8, 0x03F2, 0x03FB, 0x03FB, 0x0000, 0x0000, 0x0000, 0x0000
382    };
383
384    static unsigned short const GreekExt_lower_mapping[] = {
385    0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,
386    0x1F00, 0x1F01, 0x1F02, 0x1F03, 0x1F04, 0x1F05, 0x1F06, 0x1F07,
387    0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000,
388    0x1F10, 0x1F11, 0x1F12, 0x1F13, 0x1F14, 0x1F15, 0x0000, 0x0000,
389    0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,
390    0x1F20, 0x1F21, 0x1F22, 0x1F23, 0x1F24, 0x1F25, 0x1F26, 0x1F27,
391    0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,
392    0x1F30, 0x1F31, 0x1F32, 0x1F33, 0x1F34, 0x1F35, 0x1F36, 0x1F37,
393    0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000,
394    0x1F40, 0x1F41, 0x1F42, 0x1F43, 0x1F44, 0x1F45, 0x0000, 0x0000,
395    0x1F50, 0x1F51, 0x1F52, 0x1F53, 0x1F54, 0x1F55, 0x1F56, 0x1F57,
396    0x0000, 0x1F51, 0x0000, 0x1F53, 0x0000, 0x1F55, 0x0000, 0x1F57,
397    0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
398    0x1F60, 0x1F61, 0x1F62, 0x1F63, 0x1F64, 0x1F65, 0x1F66, 0x1F67,
399    0x1F70, 0x1F71, 0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1F76, 0x1F77,
400    0x1F78, 0x1F79, 0x1F7A, 0x1F7B, 0x1F7C, 0x1F7D, 0x0000, 0x0000,
401    0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,
402    0x1F80, 0x1F81, 0x1F82, 0x1F83, 0x1F84, 0x1F85, 0x1F86, 0x1F87,
403    0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,
404    0x1F90, 0x1F91, 0x1F92, 0x1F93, 0x1F94, 0x1F95, 0x1F96, 0x1F97,
405    0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,
406    0x1FA0, 0x1FA1, 0x1FA2, 0x1FA3, 0x1FA4, 0x1FA5, 0x1FA6, 0x1FA7,
407    0x1FB0, 0x1FB1, 0x1FB2, 0x1FB3, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7,
408    0x1FB0, 0x1FB1, 0x1F70, 0x1F71, 0x1FB3, 0x1FBD, 0x1FBE, 0x1FBF,
409    0x1FC0, 0x1FC1, 0x1FC2, 0x1FC3, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7,
410    0x1F72, 0x1F73, 0x1F74, 0x1F75, 0x1FC3, 0x1FCD, 0x1FCE, 0x1FCF,
411    0x1FD0, 0x1FD1, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7,
412    0x1FD0, 0x1FD1, 0x1F76, 0x1F77, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF,
413    0x1FE0, 0x1FE1, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FE5, 0x1FE6, 0x1FE7,
414    0x1FE0, 0x1FE1, 0x1F7A, 0x1F7B, 0x1FE5, 0x1FED, 0x1FEE, 0x1FEF,
415    0x0000, 0x0000, 0x1FF2, 0x1FF3, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7,
416    0x1F78, 0x1F79, 0x1F7C, 0x1F7D, 0x1FF3, 0x1FFD, 0x1FFE, 0x0000
417    };
418
419    static unsigned short const GreekExt_upper_mapping[] = {
420    0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,
421    0x1F08, 0x1F09, 0x1F0A, 0x1F0B, 0x1F0C, 0x1F0D, 0x1F0E, 0x1F0F,
422    0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000,
423    0x1F18, 0x1F19, 0x1F1A, 0x1F1B, 0x1F1C, 0x1F1D, 0x0000, 0x0000,
424    0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,
425    0x1F28, 0x1F29, 0x1F2A, 0x1F2B, 0x1F2C, 0x1F2D, 0x1F2E, 0x1F2F,
426    0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,
427    0x1F38, 0x1F39, 0x1F3A, 0x1F3B, 0x1F3C, 0x1F3D, 0x1F3E, 0x1F3F,
428    0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000,
429    0x1F48, 0x1F49, 0x1F4A, 0x1F4B, 0x1F4C, 0x1F4D, 0x0000, 0x0000,
430    0x1F50, 0x1F59, 0x1F52, 0x1F5B, 0x1F54, 0x1F5D, 0x1F56, 0x1F5F,
431    0x0000, 0x1F59, 0x0000, 0x1F5B, 0x0000, 0x1F5D, 0x0000, 0x1F5F,
432    0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
433    0x1F68, 0x1F69, 0x1F6A, 0x1F6B, 0x1F6C, 0x1F6D, 0x1F6E, 0x1F6F,
434    0x1FBA, 0x1FBB, 0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FDA, 0x1FDB,
435    0x1FF8, 0x1FF9, 0x1FEA, 0x1FEB, 0x1FFA, 0x1FFB, 0x0000, 0x0000,
436    0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,
437    0x1F88, 0x1F89, 0x1F8A, 0x1F8B, 0x1F8C, 0x1F8D, 0x1F8E, 0x1F8F,
438    0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,
439    0x1F98, 0x1F99, 0x1F9A, 0x1F9B, 0x1F9C, 0x1F9D, 0x1F9E, 0x1F9F,
440    0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,
441    0x1FA8, 0x1FA9, 0x1FAA, 0x1FAB, 0x1FAC, 0x1FAD, 0x1FAE, 0x1FAF,
442    0x1FB8, 0x1FB9, 0x1FB2, 0x1FBC, 0x1FB4, 0x0000, 0x1FB6, 0x1FB7,
443    0x1FB8, 0x1FB9, 0x1FBA, 0x1FBB, 0x1FBC, 0x1FBD, 0x0399, 0x1FBF,
444    0x1FC0, 0x1FC1, 0x1FC2, 0x1FCC, 0x1FC4, 0x0000, 0x1FC6, 0x1FC7,
445    0x1FC8, 0x1FC9, 0x1FCA, 0x1FCB, 0x1FCC, 0x1FCD, 0x1FCE, 0x1FCF,
446    0x1FD8, 0x1FD9, 0x1FD2, 0x1FD3, 0x0000, 0x0000, 0x1FD6, 0x1FD7,
447    0x1FD8, 0x1FD9, 0x1FDA, 0x1FDB, 0x0000, 0x1FDD, 0x1FDE, 0x1FDF,
448    0x1FE8, 0x1FE9, 0x1FE2, 0x1FE3, 0x1FE4, 0x1FEC, 0x1FE6, 0x1FE7,
449    0x1FE8, 0x1FE9, 0x1FEA, 0x1FEB, 0x1FEC, 0x1FED, 0x1FEE, 0x1FEF,
450    0x0000, 0x0000, 0x1FF2, 0x1FFC, 0x1FF4, 0x0000, 0x1FF6, 0x1FF7,
451    0x1FF8, 0x1FF9, 0x1FFA, 0x1FFB, 0x1FFC, 0x1FFD, 0x1FFE, 0x0000
452    };
453
454    *lower = code;
455    *upper = code;
456
457    /* Basic Latin and Latin-1 Supplement, U+0000 to U+00FF */
458    if (code <= 0x00ff) {
459        if (code >= 0x0041 && code <= 0x005a)             /* A-Z */
460            *lower += 0x20;
461        else if (code >= 0x0061 && code <= 0x007a)        /* a-z */
462            *upper -= 0x20;
463        else if ( (code >= 0x00c0 && code <= 0x00d6) ||
464	          (code >= 0x00d8 && code <= 0x00de) )
465            *lower += 0x20;
466        else if ( (code >= 0x00e0 && code <= 0x00f6) ||
467	          (code >= 0x00f8 && code <= 0x00fe) )
468            *upper -= 0x20;
469        else if (code == 0x00ff)      /* y with diaeresis */
470            *upper = 0x0178;
471        else if (code == 0x00b5)      /* micro sign */
472            *upper = 0x039c;
473	return;
474    }
475
476    /* Latin Extended-A, U+0100 to U+017F */
477    if (code >= 0x0100 && code <= 0x017f) {
478        if ( (code >= 0x0100 && code <= 0x012f) ||
479             (code >= 0x0132 && code <= 0x0137) ||
480             (code >= 0x014a && code <= 0x0177) ) {
481            *upper = code & ~1;
482            *lower = code | 1;
483        }
484        else if ( (code >= 0x0139 && code <= 0x0148) ||
485                  (code >= 0x0179 && code <= 0x017e) ) {
486            if (code & 1)
487	        *lower += 1;
488            else
489	        *upper -= 1;
490        }
491        else if (code == 0x0130)
492            *lower = 0x0069;
493        else if (code == 0x0131)
494            *upper = 0x0049;
495        else if (code == 0x0178)
496            *lower = 0x00ff;
497        else if (code == 0x017f)
498            *upper = 0x0053;
499        return;
500    }
501
502    /* Latin Extended-B, U+0180 to U+024F */
503    if (code >= 0x0180 && code <= 0x024f) {
504        if (code >= 0x01cd && code <= 0x01dc) {
505	    if (code & 1)
506	       *lower += 1;
507	    else
508	       *upper -= 1;
509        }
510        else if ( (code >= 0x01de && code <= 0x01ef) ||
511                  (code >= 0x01f4 && code <= 0x01f5) ||
512                  (code >= 0x01f8 && code <= 0x021f) ||
513                  (code >= 0x0222 && code <= 0x0233) ) {
514            *lower |= 1;
515            *upper &= ~1;
516        }
517        else if (code >= 0x0180 && code <= 0x01cc) {
518            *lower = LatinExtB_lower_mapping[code - 0x0180];
519            *upper = LatinExtB_upper_mapping[code - 0x0180];
520        }
521        else if (code == 0x01dd)
522            *upper = 0x018e;
523        else if (code == 0x01f1 || code == 0x01f2) {
524            *lower = 0x01f3;
525            *upper = 0x01f1;
526        }
527        else if (code == 0x01f3)
528            *upper = 0x01f1;
529        else if (code == 0x01f6)
530            *lower = 0x0195;
531        else if (code == 0x01f7)
532            *lower = 0x01bf;
533        else if (code == 0x0220)
534            *lower = 0x019e;
535        return;
536    }
537
538    /* IPA Extensions, U+0250 to U+02AF */
539    if (code >= 0x0253 && code <= 0x0292) {
540        *upper = IPAExt_upper_mapping[code - 0x0253];
541    }
542
543    /* Combining Diacritical Marks, U+0300 to U+036F */
544    if (code == 0x0345) {
545        *upper = 0x0399;
546    }
547
548    /* Greek and Coptic, U+0370 to U+03FF */
549    if (code >= 0x0370 && code <= 0x03ff) {
550        *lower = Greek_lower_mapping[code - 0x0370];
551        *upper = Greek_upper_mapping[code - 0x0370];
552        if (*upper == 0)
553            *upper = code;
554        if (*lower == 0)
555            *lower = code;
556    }
557
558    /* Cyrillic and Cyrillic Supplementary, U+0400 to U+052F */
559    if ( (code >= 0x0400 && code <= 0x04ff) ||
560         (code >= 0x0500 && code <= 0x052f) ) {
561        if (code >= 0x0400 && code <= 0x040f)
562            *lower += 0x50;
563        else if (code >= 0x0410 && code <= 0x042f)
564            *lower += 0x20;
565        else if (code >= 0x0430 && code <= 0x044f)
566            *upper -= 0x20;
567        else if (code >= 0x0450 && code <= 0x045f)
568            *upper -= 0x50;
569        else if ( (code >= 0x0460 && code <= 0x0481) ||
570                  (code >= 0x048a && code <= 0x04bf) ||
571	          (code >= 0x04d0 && code <= 0x04f5) ||
572	          (code >= 0x04f8 && code <= 0x04f9) ||
573                  (code >= 0x0500 && code <= 0x050f) ) {
574            *upper &= ~1;
575            *lower |= 1;
576        }
577        else if (code >= 0x04c1 && code <= 0x04ce) {
578	    if (code & 1)
579	        *lower += 1;
580	    else
581	        *upper -= 1;
582        }
583    }
584
585    /* Armenian, U+0530 to U+058F */
586    if (code >= 0x0530 && code <= 0x058f) {
587        if (code >= 0x0531 && code <= 0x0556)
588            *lower += 0x30;
589        else if (code >=0x0561 && code <= 0x0586)
590            *upper -= 0x30;
591    }
592
593    /* Latin Extended Additional, U+1E00 to U+1EFF */
594    if (code >= 0x1e00 && code <= 0x1eff) {
595        if ( (code >= 0x1e00 && code <= 0x1e95) ||
596             (code >= 0x1ea0 && code <= 0x1ef9) ) {
597            *upper &= ~1;
598            *lower |= 1;
599        }
600        else if (code == 0x1e9b)
601            *upper = 0x1e60;
602    }
603
604    /* Greek Extended, U+1F00 to U+1FFF */
605    if (code >= 0x1f00 && code <= 0x1fff) {
606        *lower = GreekExt_lower_mapping[code - 0x1f00];
607        *upper = GreekExt_upper_mapping[code - 0x1f00];
608        if (*upper == 0)
609            *upper = code;
610        if (*lower == 0)
611            *lower = code;
612    }
613
614    /* Letterlike Symbols, U+2100 to U+214F */
615    if (code >= 0x2100 && code <= 0x214f) {
616        switch (code) {
617        case 0x2126: *lower = 0x03c9; break;
618        case 0x212a: *lower = 0x006b; break;
619        case 0x212b: *lower = 0x00e5; break;
620        }
621    }
622    /* Number Forms, U+2150 to U+218F */
623    else if (code >= 0x2160 && code <= 0x216f)
624        *lower += 0x10;
625    else if (code >= 0x2170 && code <= 0x217f)
626        *upper -= 0x10;
627    /* Enclosed Alphanumerics, U+2460 to U+24FF */
628    else if (code >= 0x24b6 && code <= 0x24cf)
629        *lower += 0x1a;
630    else if (code >= 0x24d0 && code <= 0x24e9)
631        *upper -= 0x1a;
632    /* Halfwidth and Fullwidth Forms, U+FF00 to U+FFEF */
633    else if (code >= 0xff21 && code <= 0xff3a)
634        *lower += 0x20;
635    else if (code >= 0xff41 && code <= 0xff5a)
636        *upper -= 0x20;
637    /* Deseret, U+10400 to U+104FF */
638    else if (code >= 0x10400 && code <= 0x10427)
639        *lower += 0x28;
640    else if (code >= 0x10428 && code <= 0x1044f)
641        *upper -= 0x28;
642}
643
644void
645XConvertCase(
646    register KeySym sym,
647    KeySym *lower,
648    KeySym *upper)
649{
650    /* Latin 1 keysym */
651    if (sym < 0x100) {
652        UCSConvertCase(sym, lower, upper);
653	return;
654    }
655
656    /* Unicode keysym */
657    if ((sym & 0xff000000) == 0x01000000) {
658        UCSConvertCase((sym & 0x00ffffff), lower, upper);
659        *upper |= 0x01000000;
660        *lower |= 0x01000000;
661        return;
662    }
663
664    /* Legacy keysym */
665
666    *lower = sym;
667    *upper = sym;
668
669    switch(sym >> 8) {
670    case 1: /* Latin 2 */
671	/* Assume the KeySym is a legal value (ignore discontinuities) */
672	if (sym == XK_Aogonek)
673	    *lower = XK_aogonek;
674	else if (sym >= XK_Lstroke && sym <= XK_Sacute)
675	    *lower += (XK_lstroke - XK_Lstroke);
676	else if (sym >= XK_Scaron && sym <= XK_Zacute)
677	    *lower += (XK_scaron - XK_Scaron);
678	else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
679	    *lower += (XK_zcaron - XK_Zcaron);
680	else if (sym == XK_aogonek)
681	    *upper = XK_Aogonek;
682	else if (sym >= XK_lstroke && sym <= XK_sacute)
683	    *upper -= (XK_lstroke - XK_Lstroke);
684	else if (sym >= XK_scaron && sym <= XK_zacute)
685	    *upper -= (XK_scaron - XK_Scaron);
686	else if (sym >= XK_zcaron && sym <= XK_zabovedot)
687	    *upper -= (XK_zcaron - XK_Zcaron);
688	else if (sym >= XK_Racute && sym <= XK_Tcedilla)
689	    *lower += (XK_racute - XK_Racute);
690	else if (sym >= XK_racute && sym <= XK_tcedilla)
691	    *upper -= (XK_racute - XK_Racute);
692	break;
693    case 2: /* Latin 3 */
694	/* Assume the KeySym is a legal value (ignore discontinuities) */
695	if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
696	    *lower += (XK_hstroke - XK_Hstroke);
697	else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
698	    *lower += (XK_gbreve - XK_Gbreve);
699	else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
700	    *upper -= (XK_hstroke - XK_Hstroke);
701	else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
702	    *upper -= (XK_gbreve - XK_Gbreve);
703	else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
704	    *lower += (XK_cabovedot - XK_Cabovedot);
705	else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
706	    *upper -= (XK_cabovedot - XK_Cabovedot);
707	break;
708    case 3: /* Latin 4 */
709	/* Assume the KeySym is a legal value (ignore discontinuities) */
710	if (sym >= XK_Rcedilla && sym <= XK_Tslash)
711	    *lower += (XK_rcedilla - XK_Rcedilla);
712	else if (sym >= XK_rcedilla && sym <= XK_tslash)
713	    *upper -= (XK_rcedilla - XK_Rcedilla);
714	else if (sym == XK_ENG)
715	    *lower = XK_eng;
716	else if (sym == XK_eng)
717	    *upper = XK_ENG;
718	else if (sym >= XK_Amacron && sym <= XK_Umacron)
719	    *lower += (XK_amacron - XK_Amacron);
720	else if (sym >= XK_amacron && sym <= XK_umacron)
721	    *upper -= (XK_amacron - XK_Amacron);
722	break;
723    case 6: /* Cyrillic */
724	/* Assume the KeySym is a legal value (ignore discontinuities) */
725	if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
726	    *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
727	else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
728	    *upper += (XK_Serbian_DJE - XK_Serbian_dje);
729	else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
730	    *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
731	else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
732	    *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
733        break;
734    case 7: /* Greek */
735	/* Assume the KeySym is a legal value (ignore discontinuities) */
736	if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
737	    *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
738	else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
739		 sym != XK_Greek_iotaaccentdieresis &&
740		 sym != XK_Greek_upsilonaccentdieresis)
741	    *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
742	else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
743	    *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
744	else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega &&
745		 sym != XK_Greek_finalsmallsigma)
746	    *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
747        break;
748    case 0x13: /* Latin 9 */
749        if (sym == XK_OE)
750            *lower = XK_oe;
751        else if (sym == XK_oe)
752            *upper = XK_OE;
753        else if (sym == XK_Ydiaeresis)
754            *lower = XK_ydiaeresis;
755        break;
756    }
757}
758
759int
760_XTranslateKey(	register Display *dpy,
761		KeyCode keycode,
762		register unsigned int modifiers,
763		unsigned int *modifiers_return,
764		KeySym *keysym_return)
765{
766    int per;
767    register KeySym *syms;
768    KeySym sym, lsym, usym;
769
770    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
771	return 0;
772    *modifiers_return = ((ShiftMask|LockMask)
773			 | dpy->mode_switch | dpy->num_lock);
774    if (((int)keycode < dpy->min_keycode) || ((int)keycode > dpy->max_keycode))
775    {
776	*keysym_return = NoSymbol;
777	return 1;
778    }
779    per = dpy->keysyms_per_keycode;
780    syms = &dpy->keysyms[(keycode - dpy->min_keycode) * per];
781    while ((per > 2) && (syms[per - 1] == NoSymbol))
782	per--;
783    if ((per > 2) && (modifiers & dpy->mode_switch)) {
784	syms += 2;
785	per -= 2;
786    }
787    if ((modifiers & dpy->num_lock) &&
788	(per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) {
789	if ((modifiers & ShiftMask) ||
790	    ((modifiers & LockMask) && (dpy->lock_meaning == XK_Shift_Lock)))
791	    *keysym_return = syms[0];
792	else
793	    *keysym_return = syms[1];
794    } else if (!(modifiers & ShiftMask) &&
795	(!(modifiers & LockMask) || (dpy->lock_meaning == NoSymbol))) {
796	if ((per == 1) || (syms[1] == NoSymbol))
797	    XConvertCase(syms[0], keysym_return, &usym);
798	else
799	    *keysym_return = syms[0];
800    } else if (!(modifiers & LockMask) ||
801	       (dpy->lock_meaning != XK_Caps_Lock)) {
802	if ((per == 1) || ((usym = syms[1]) == NoSymbol))
803	    XConvertCase(syms[0], &lsym, &usym);
804	*keysym_return = usym;
805    } else {
806	if ((per == 1) || ((sym = syms[1]) == NoSymbol))
807	    sym = syms[0];
808	XConvertCase(sym, &lsym, &usym);
809	if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
810	    ((sym != usym) || (lsym == usym)))
811	    XConvertCase(syms[0], &lsym, &usym);
812	*keysym_return = usym;
813    }
814    if (*keysym_return == XK_VoidSymbol)
815	*keysym_return = NoSymbol;
816    return 1;
817}
818
819int
820_XTranslateKeySym(
821    Display *dpy,
822    register KeySym symbol,
823    unsigned int modifiers,
824    char *buffer,
825    int nbytes)
826{
827    register struct _XKeytrans *p;
828    int length;
829    unsigned long hiBytes;
830    register unsigned char c;
831
832    if (!symbol)
833	return 0;
834    /* see if symbol rebound, if so, return that string. */
835    for (p = dpy->key_bindings; p; p = p->next) {
836	if (((modifiers & AllMods) == p->state) && (symbol == p->key)) {
837	    length = p->len;
838	    if (length > nbytes) length = nbytes;
839	    memcpy (buffer, p->string, length);
840	    return length;
841	}
842    }
843    /* try to convert to Latin-1, handling control */
844    hiBytes = symbol >> 8;
845    if (!(nbytes &&
846	  ((hiBytes == 0) ||
847	   ((hiBytes == 0xFF) &&
848	    (((symbol >= XK_BackSpace) && (symbol <= XK_Clear)) ||
849	     (symbol == XK_Return) ||
850	     (symbol == XK_Escape) ||
851	     (symbol == XK_KP_Space) ||
852	     (symbol == XK_KP_Tab) ||
853	     (symbol == XK_KP_Enter) ||
854	     ((symbol >= XK_KP_Multiply) && (symbol <= XK_KP_9)) ||
855	     (symbol == XK_KP_Equal) ||
856	     (symbol == XK_Delete))))))
857	return 0;
858
859    /* if X keysym, convert to ascii by grabbing low 7 bits */
860    if (symbol == XK_KP_Space)
861	c = XK_space & 0x7F; /* patch encoding botch */
862    else if (hiBytes == 0xFF)
863	c = symbol & 0x7F;
864    else
865	c = symbol & 0xFF;
866    /* only apply Control key if it makes sense, else ignore it */
867    if (modifiers & ControlMask) {
868	if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
869	else if (c == '2') c = '\000';
870	else if (c >= '3' && c <= '7') c -= ('3' - '\033');
871	else if (c == '8') c = '\177';
872	else if (c == '/') c = '_' & 0x1F;
873    }
874    buffer[0] = c;
875    return 1;
876}
877
878/*ARGSUSED*/
879int
880XLookupString (
881    register XKeyEvent *event,
882    char *buffer,	/* buffer */
883    int nbytes,	/* space in buffer for characters */
884    KeySym *keysym,
885    XComposeStatus *status)	/* not implemented */
886{
887    unsigned int modifiers;
888    KeySym symbol;
889
890    if (! _XTranslateKey(event->display, event->keycode, event->state,
891		  &modifiers, &symbol))
892	return 0;
893
894#ifdef USE_OWN_COMPOSE
895    if ( status ) {
896	static int been_here= 0;
897	if ( !been_here ) {
898	    XimCompInitTables();
899	    been_here = 1;
900	}
901	if ( !XimCompLegalStatus(status) ) {
902	    status->compose_ptr = NULL;
903	    status->chars_matched = 0;
904	}
905	if ( ((status->chars_matched>0)&&(status->compose_ptr!=NULL)) ||
906		XimCompIsComposeKey(symbol,event->keycode,status) ) {
907	    XimCompRtrn rtrn;
908	    switch (XimCompProcessSym(status,symbol,&rtrn)) {
909		case XIM_COMP_IGNORE:
910		    break;
911		case XIM_COMP_IN_PROGRESS:
912		    if ( keysym!=NULL )
913			*keysym = NoSymbol;
914		    return 0;
915		case XIM_COMP_FAIL:
916		{
917		    int n = 0, len= 0;
918		    for (n=len=0;rtrn.sym[n]!=XK_VoidSymbol;n++) {
919			if ( nbytes-len > 0 ) {
920			    len+= _XTranslateKeySym(event->display,rtrn.sym[n],
921							event->state,
922							buffer+len,nbytes-len);
923			}
924		    }
925		    if ( keysym!=NULL ) {
926			if ( n==1 )	*keysym = rtrn.sym[0];
927			else		*keysym = NoSymbol;
928		    }
929		    return len;
930		}
931		case XIM_COMP_SUCCEED:
932		{
933		    int len,n = 0;
934
935		    symbol = rtrn.matchSym;
936		    if ( keysym!=NULL )	*keysym = symbol;
937		    if ( rtrn.str[0]!='\0' ) {
938			strncpy(buffer,rtrn.str,nbytes-1);
939			buffer[nbytes-1]= '\0';
940			len = strlen(buffer);
941		    }
942		    else {
943			len = _XTranslateKeySym(event->display,symbol,
944							event->state,
945							buffer,nbytes);
946		    }
947		    for (n=0;rtrn.sym[n]!=XK_VoidSymbol;n++) {
948			if ( nbytes-len > 0 ) {
949			    len+= _XTranslateKeySym(event->display,rtrn.sym[n],
950							event->state,
951							buffer+len,nbytes-len);
952			}
953		    }
954		    return len;
955		}
956	    }
957	}
958    }
959#endif
960
961    if (keysym)
962	*keysym = symbol;
963    /* arguable whether to use (event->state & ~modifiers) here */
964    return _XTranslateKeySym(event->display, symbol, event->state,
965			     buffer, nbytes);
966}
967
968static void
969_XFreeKeyBindings(
970    Display *dpy)
971{
972    register struct _XKeytrans *p, *np;
973
974    for (p = dpy->key_bindings; p; p = np) {
975	np = p->next;
976	Xfree(p->string);
977	Xfree(p->modifiers);
978	Xfree(p);
979    }
980}
981
982int
983XRebindKeysym (
984    Display *dpy,
985    KeySym keysym,
986    KeySym *mlist,
987    int nm,		/* number of modifiers in mlist */
988    _Xconst unsigned char *str,
989    int nbytes)
990{
991    register struct _XKeytrans *tmp, *p;
992    int nb;
993
994    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
995	return 0;
996    LockDisplay(dpy);
997    tmp = dpy->key_bindings;
998    nb = sizeof(KeySym) * nm;
999
1000    if ((! (p = Xcalloc( 1, sizeof(struct _XKeytrans)))) ||
1001	((! (p->string = Xmalloc(nbytes))) && (nbytes > 0)) ||
1002	((! (p->modifiers = Xmalloc(nb))) && (nb > 0))) {
1003	if (p) {
1004	    if (p->string) Xfree(p->string);
1005	    if (p->modifiers) Xfree(p->modifiers);
1006	    Xfree(p);
1007	}
1008	UnlockDisplay(dpy);
1009	return 0;
1010    }
1011
1012    dpy->key_bindings = p;
1013    dpy->free_funcs->key_bindings = _XFreeKeyBindings;
1014    p->next = tmp;	/* chain onto list */
1015    memcpy (p->string, str, nbytes);
1016    p->len = nbytes;
1017    memcpy ((char *) p->modifiers, (char *) mlist, nb);
1018    p->key = keysym;
1019    p->mlen = nm;
1020    ComputeMaskFromKeytrans(dpy, p);
1021    UnlockDisplay(dpy);
1022    return 0;
1023}
1024
1025unsigned
1026_XKeysymToModifiers(
1027    Display *dpy,
1028    KeySym ks)
1029{
1030    CARD8 code,mods;
1031    register KeySym *kmax;
1032    register KeySym *k;
1033    register XModifierKeymap *m;
1034
1035    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
1036	return 0;
1037    kmax = dpy->keysyms +
1038	   (dpy->max_keycode - dpy->min_keycode + 1) * dpy->keysyms_per_keycode;
1039    k = dpy->keysyms;
1040    m = dpy->modifiermap;
1041    mods= 0;
1042    while (k<kmax) {
1043	if (*k == ks ) {
1044	    register int j = m->max_keypermod<<3;
1045
1046	    code=(((k-dpy->keysyms)/dpy->keysyms_per_keycode)+dpy->min_keycode);
1047
1048	    while (--j >= 0) {
1049		if (code == m->modifiermap[j])
1050		    mods|= (1<<(j/m->max_keypermod));
1051	    }
1052	}
1053	k++;
1054    }
1055    return mods;
1056}
1057
1058/*
1059 * given a list of modifiers, computes the mask necessary for later matching.
1060 * This routine must lookup the key in the Keymap and then search to see
1061 * what modifier it is bound to, if any.  Sets the AnyModifier bit if it
1062 * can't map some keysym to a modifier.
1063 */
1064static void
1065ComputeMaskFromKeytrans(
1066    Display *dpy,
1067    register struct _XKeytrans *p)
1068{
1069    register int i;
1070
1071    p->state = AnyModifier;
1072    for (i = 0; i < p->mlen; i++) {
1073	p->state|= XkbKeysymToModifiers(dpy,p->modifiers[i]);
1074    }
1075    p->state &= AllMods;
1076}
1077