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