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