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