KeyBind.c revision e9628295
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[] = { /* updated to UD 14.0 */
339    0x0370, 0x0370, 0x0372, 0x0372, 0x0374, 0x0375, 0x0376, 0x0376,
340    0x0000, 0x0000, 0x037A, 0x03FD, 0x03FE, 0x03FF, 0x037E, 0x037F,
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, 0x03CF,
351    0x0392, 0x0398, 0x03D2, 0x03D3, 0x03D4, 0x03A6, 0x03A0, 0x03CF,
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, 0x037F, 0x03F4, 0x0395, 0x03F6, 0x03F7,
356    0x03F7, 0x03F9, 0x03FA, 0x03FA, 0x03FC, 0x03FD, 0x03FE, 0x03FF
357    };
358
359    static unsigned short const Greek_lower_mapping[] = { /* updated to UD 14.0 */
360    0x0371, 0x0371, 0x0373, 0x0373, 0x0374, 0x0375, 0x0377, 0x0377,
361    0x0000, 0x0000, 0x037A, 0x037B, 0x037C, 0x037D, 0x037E, 0x03F3,
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, 0x03D7,
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, 0x03FC, 0x037B, 0x037C, 0x037D
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 <= 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 <= 0x024f) {
502        if (code >= 0x0180 && code <= 0x01cc) {
503            *lower = LatinExtB_lower_mapping[code - 0x0180];
504            *upper = LatinExtB_upper_mapping[code - 0x0180];
505        }
506        else if (code >= 0x01cd && code <= 0x01dc) {
507	    if (code & 1)
508	       *lower += 1;
509	    else
510	       *upper -= 1;
511        }
512        else if (code == 0x01dd)
513            *upper = 0x018e;
514        else if ( (code >= 0x01de && code <= 0x01ef) ||
515                  (code >= 0x01f4 && code <= 0x01f5) ||
516                  (code >= 0x01f8 && code <= 0x021f) ||
517                  (code >= 0x0222 && code <= 0x0233) ) {
518            *lower |= 1;
519            *upper &= ~1;
520        }
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        return;
540    }
541
542    /* Combining Diacritical Marks, U+0300 to U+036F */
543    if (code == 0x0345) {
544        *upper = 0x0399;
545        return;
546    }
547
548    /* Greek and Coptic, U+0370 to U+03FF */
549    if (code >= 0x0370 && code <= 0x03ff) {
550        *lower = Greek_lower_mapping[code - 0x0370];
551        *upper = Greek_upper_mapping[code - 0x0370];
552        if (*upper == 0)
553            *upper = code;
554        if (*lower == 0)
555            *lower = code;
556        return;
557    }
558
559    /* Cyrillic and Cyrillic Supplementary, U+0400 to U+052F */
560    if ( (code >= 0x0400 && code <= 0x052f) ) {
561        if (code >= 0x0400 && code <= 0x040f)
562            *lower += 0x50;
563        else if (code >= 0x0410 && code <= 0x042f)
564            *lower += 0x20;
565        else if (code >= 0x0430 && code <= 0x044f)
566            *upper -= 0x20;
567        else if (code >= 0x0450 && code <= 0x045f)
568            *upper -= 0x50;
569        else if ( (code >= 0x0460 && code <= 0x0481) ||
570                  (code >= 0x048a && code <= 0x04bf) ||
571	          (code >= 0x04d0 && code <= 0x04f5) ||
572	          (code >= 0x04f8 && code <= 0x04f9) ||
573                  (code >= 0x0500 && code <= 0x050f) ) {
574            *upper &= ~1;
575            *lower |= 1;
576        }
577        else if (code >= 0x04c1 && code <= 0x04ce) {
578	    if (code & 1)
579	        *lower += 1;
580	    else
581	        *upper -= 1;
582        }
583        return;
584    }
585
586    /* Armenian, U+0530 to U+058F */
587    if (code >= 0x0530 && code <= 0x058f) {
588        if (code >= 0x0531 && code <= 0x0556)
589            *lower += 0x30;
590        else if (code >=0x0561 && code <= 0x0586)
591            *upper -= 0x30;
592        return;
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        else if (code == 0x1e9e)
605            *lower = 0x00df;    /* ssharp */
606        return;
607    }
608
609    /* Greek Extended, U+1F00 to U+1FFF */
610    if (code >= 0x1f00 && code <= 0x1fff) {
611        *lower = GreekExt_lower_mapping[code - 0x1f00];
612        *upper = GreekExt_upper_mapping[code - 0x1f00];
613        if (*upper == 0)
614            *upper = code;
615        if (*lower == 0)
616            *lower = code;
617        return;
618    }
619
620    /* Letterlike Symbols, U+2100 to U+214F */
621    if (code >= 0x2100 && code <= 0x214f) {
622        switch (code) {
623        case 0x2126: *lower = 0x03c9; break;
624        case 0x212a: *lower = 0x006b; break;
625        case 0x212b: *lower = 0x00e5; break;
626        }
627    }
628    /* Number Forms, U+2150 to U+218F */
629    else if (code >= 0x2160 && code <= 0x216f)
630        *lower += 0x10;
631    else if (code >= 0x2170 && code <= 0x217f)
632        *upper -= 0x10;
633    /* Enclosed Alphanumerics, U+2460 to U+24FF */
634    else if (code >= 0x24b6 && code <= 0x24cf)
635        *lower += 0x1a;
636    else if (code >= 0x24d0 && code <= 0x24e9)
637        *upper -= 0x1a;
638    /* Halfwidth and Fullwidth Forms, U+FF00 to U+FFEF */
639    else if (code >= 0xff21 && code <= 0xff3a)
640        *lower += 0x20;
641    else if (code >= 0xff41 && code <= 0xff5a)
642        *upper -= 0x20;
643    /* Deseret, U+10400 to U+104FF */
644    else if (code >= 0x10400 && code <= 0x10427)
645        *lower += 0x28;
646    else if (code >= 0x10428 && code <= 0x1044f)
647        *upper -= 0x28;
648}
649
650void
651XConvertCase(
652    register KeySym sym,
653    KeySym *lower,
654    KeySym *upper)
655{
656    /* Latin 1 keysym */
657    if (sym < 0x100) {
658        UCSConvertCase(sym, lower, upper);
659	return;
660    }
661
662    /* Unicode keysym */
663    if ((sym & 0xff000000) == 0x01000000) {
664        UCSConvertCase((sym & 0x00ffffff), lower, upper);
665        *upper |= 0x01000000;
666        *lower |= 0x01000000;
667        return;
668    }
669
670    /* Legacy keysym */
671
672    *lower = sym;
673    *upper = sym;
674
675    switch(sym >> 8) {
676    case 1: /* Latin 2 */
677	/* Assume the KeySym is a legal value (ignore discontinuities) */
678	if (sym == XK_Aogonek)
679	    *lower = XK_aogonek;
680	else if (sym >= XK_Lstroke && sym <= XK_Sacute)
681	    *lower += (XK_lstroke - XK_Lstroke);
682	else if (sym >= XK_Scaron && sym <= XK_Zacute)
683	    *lower += (XK_scaron - XK_Scaron);
684	else if (sym >= XK_Zcaron && sym <= XK_Zabovedot)
685	    *lower += (XK_zcaron - XK_Zcaron);
686	else if (sym == XK_aogonek)
687	    *upper = XK_Aogonek;
688	else if (sym >= XK_lstroke && sym <= XK_sacute)
689	    *upper -= (XK_lstroke - XK_Lstroke);
690	else if (sym >= XK_scaron && sym <= XK_zacute)
691	    *upper -= (XK_scaron - XK_Scaron);
692	else if (sym >= XK_zcaron && sym <= XK_zabovedot)
693	    *upper -= (XK_zcaron - XK_Zcaron);
694	else if (sym >= XK_Racute && sym <= XK_Tcedilla)
695	    *lower += (XK_racute - XK_Racute);
696	else if (sym >= XK_racute && sym <= XK_tcedilla)
697	    *upper -= (XK_racute - XK_Racute);
698	break;
699    case 2: /* Latin 3 */
700	/* Assume the KeySym is a legal value (ignore discontinuities) */
701	if (sym >= XK_Hstroke && sym <= XK_Hcircumflex)
702	    *lower += (XK_hstroke - XK_Hstroke);
703	else if (sym >= XK_Gbreve && sym <= XK_Jcircumflex)
704	    *lower += (XK_gbreve - XK_Gbreve);
705	else if (sym >= XK_hstroke && sym <= XK_hcircumflex)
706	    *upper -= (XK_hstroke - XK_Hstroke);
707	else if (sym >= XK_gbreve && sym <= XK_jcircumflex)
708	    *upper -= (XK_gbreve - XK_Gbreve);
709	else if (sym >= XK_Cabovedot && sym <= XK_Scircumflex)
710	    *lower += (XK_cabovedot - XK_Cabovedot);
711	else if (sym >= XK_cabovedot && sym <= XK_scircumflex)
712	    *upper -= (XK_cabovedot - XK_Cabovedot);
713	break;
714    case 3: /* Latin 4 */
715	/* Assume the KeySym is a legal value (ignore discontinuities) */
716	if (sym >= XK_Rcedilla && sym <= XK_Tslash)
717	    *lower += (XK_rcedilla - XK_Rcedilla);
718	else if (sym >= XK_rcedilla && sym <= XK_tslash)
719	    *upper -= (XK_rcedilla - XK_Rcedilla);
720	else if (sym == XK_ENG)
721	    *lower = XK_eng;
722	else if (sym == XK_eng)
723	    *upper = XK_ENG;
724	else if (sym >= XK_Amacron && sym <= XK_Umacron)
725	    *lower += (XK_amacron - XK_Amacron);
726	else if (sym >= XK_amacron && sym <= XK_umacron)
727	    *upper -= (XK_amacron - XK_Amacron);
728	break;
729    case 6: /* Cyrillic */
730	/* Assume the KeySym is a legal value (ignore discontinuities) */
731	if (sym >= XK_Serbian_DJE && sym <= XK_Serbian_DZE)
732	    *lower -= (XK_Serbian_DJE - XK_Serbian_dje);
733	else if (sym >= XK_Serbian_dje && sym <= XK_Serbian_dze)
734	    *upper += (XK_Serbian_DJE - XK_Serbian_dje);
735	else if (sym >= XK_Cyrillic_YU && sym <= XK_Cyrillic_HARDSIGN)
736	    *lower -= (XK_Cyrillic_YU - XK_Cyrillic_yu);
737	else if (sym >= XK_Cyrillic_yu && sym <= XK_Cyrillic_hardsign)
738	    *upper += (XK_Cyrillic_YU - XK_Cyrillic_yu);
739        break;
740    case 7: /* Greek */
741	/* Assume the KeySym is a legal value (ignore discontinuities) */
742	if (sym >= XK_Greek_ALPHAaccent && sym <= XK_Greek_OMEGAaccent)
743	    *lower += (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
744	else if (sym >= XK_Greek_alphaaccent && sym <= XK_Greek_omegaaccent &&
745		 sym != XK_Greek_iotaaccentdieresis &&
746		 sym != XK_Greek_upsilonaccentdieresis)
747	    *upper -= (XK_Greek_alphaaccent - XK_Greek_ALPHAaccent);
748	else if (sym >= XK_Greek_ALPHA && sym <= XK_Greek_OMEGA)
749	    *lower += (XK_Greek_alpha - XK_Greek_ALPHA);
750	else if (sym == XK_Greek_finalsmallsigma)
751	    *upper = XK_Greek_SIGMA;
752	else if (sym >= XK_Greek_alpha && sym <= XK_Greek_omega)
753	    *upper -= (XK_Greek_alpha - XK_Greek_ALPHA);
754        break;
755    case 0x13: /* Latin 9 */
756        if (sym == XK_OE)
757            *lower = XK_oe;
758        else if (sym == XK_oe)
759            *upper = XK_OE;
760        else if (sym == XK_Ydiaeresis)
761            *lower = XK_ydiaeresis;
762        break;
763    }
764}
765
766int
767_XTranslateKey(	register Display *dpy,
768		KeyCode keycode,
769		register unsigned int modifiers,
770		unsigned int *modifiers_return,
771		KeySym *keysym_return)
772{
773    int per;
774    register KeySym *syms;
775    KeySym sym, lsym, usym;
776
777    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
778	return 0;
779    *modifiers_return = ((ShiftMask|LockMask)
780			 | dpy->mode_switch | dpy->num_lock);
781    if (((int)keycode < dpy->min_keycode) || ((int)keycode > dpy->max_keycode))
782    {
783	*keysym_return = NoSymbol;
784	return 1;
785    }
786    per = dpy->keysyms_per_keycode;
787    syms = &dpy->keysyms[(keycode - dpy->min_keycode) * per];
788    while ((per > 2) && (syms[per - 1] == NoSymbol))
789	per--;
790    if ((per > 2) && (modifiers & dpy->mode_switch)) {
791	syms += 2;
792	per -= 2;
793    }
794    if ((modifiers & dpy->num_lock) &&
795	(per > 1 && (IsKeypadKey(syms[1]) || IsPrivateKeypadKey(syms[1])))) {
796	if ((modifiers & ShiftMask) ||
797	    ((modifiers & LockMask) && (dpy->lock_meaning == XK_Shift_Lock)))
798	    *keysym_return = syms[0];
799	else
800	    *keysym_return = syms[1];
801    } else if (!(modifiers & ShiftMask) &&
802	(!(modifiers & LockMask) || (dpy->lock_meaning == NoSymbol))) {
803	if ((per == 1) || (syms[1] == NoSymbol))
804	    XConvertCase(syms[0], keysym_return, &usym);
805	else
806	    *keysym_return = syms[0];
807    } else if (!(modifiers & LockMask) ||
808	       (dpy->lock_meaning != XK_Caps_Lock)) {
809	if ((per == 1) || ((usym = syms[1]) == NoSymbol))
810	    XConvertCase(syms[0], &lsym, &usym);
811	*keysym_return = usym;
812    } else {
813	if ((per == 1) || ((sym = syms[1]) == NoSymbol))
814	    sym = syms[0];
815	XConvertCase(sym, &lsym, &usym);
816	if (!(modifiers & ShiftMask) && (sym != syms[0]) &&
817	    ((sym != usym) || (lsym == usym)))
818	    XConvertCase(syms[0], &lsym, &usym);
819	*keysym_return = usym;
820    }
821    if (*keysym_return == XK_VoidSymbol)
822	*keysym_return = NoSymbol;
823    return 1;
824}
825
826int
827_XTranslateKeySym(
828    Display *dpy,
829    register KeySym symbol,
830    unsigned int modifiers,
831    char *buffer,
832    int nbytes)
833{
834    register struct _XKeytrans *p;
835    int length;
836    unsigned long hiBytes;
837    register unsigned char c;
838
839    if (!symbol)
840	return 0;
841    /* see if symbol rebound, if so, return that string. */
842    for (p = dpy->key_bindings; p; p = p->next) {
843	if (((modifiers & AllMods) == p->state) && (symbol == p->key)) {
844	    length = p->len;
845	    if (length > nbytes) length = nbytes;
846	    memcpy (buffer, p->string, (size_t) length);
847	    return length;
848	}
849    }
850    /* try to convert to Latin-1, handling control */
851    hiBytes = symbol >> 8;
852    if (!(nbytes &&
853	  ((hiBytes == 0) ||
854	   ((hiBytes == 0xFF) &&
855	    (((symbol >= XK_BackSpace) && (symbol <= XK_Clear)) ||
856	     (symbol == XK_Return) ||
857	     (symbol == XK_Escape) ||
858	     (symbol == XK_KP_Space) ||
859	     (symbol == XK_KP_Tab) ||
860	     (symbol == XK_KP_Enter) ||
861	     ((symbol >= XK_KP_Multiply) && (symbol <= XK_KP_9)) ||
862	     (symbol == XK_KP_Equal) ||
863	     (symbol == XK_Delete))))))
864	return 0;
865
866    /* if X keysym, convert to ascii by grabbing low 7 bits */
867    if (symbol == XK_KP_Space)
868	c = XK_space & 0x7F; /* patch encoding botch */
869    else if (hiBytes == 0xFF)
870	c = symbol & 0x7F;
871    else
872	c = symbol & 0xFF;
873    /* only apply Control key if it makes sense, else ignore it */
874    if (modifiers & ControlMask) {
875	if ((c >= '@' && c < '\177') || c == ' ') c &= 0x1F;
876	else if (c == '2') c = '\000';
877	else if (c >= '3' && c <= '7') c -= ('3' - '\033');
878	else if (c == '8') c = '\177';
879	else if (c == '/') c = '_' & 0x1F;
880    }
881    buffer[0] = c;
882    return 1;
883}
884
885/*ARGSUSED*/
886int
887XLookupString (
888    register XKeyEvent *event,
889    char *buffer,	/* buffer */
890    int nbytes,	/* space in buffer for characters */
891    KeySym *keysym,
892    XComposeStatus *status)	/* not implemented */
893{
894    unsigned int modifiers;
895    KeySym symbol;
896
897    if (! _XTranslateKey(event->display, event->keycode, event->state,
898		  &modifiers, &symbol))
899	return 0;
900
901    if (keysym)
902	*keysym = symbol;
903    /* arguable whether to use (event->state & ~modifiers) here */
904    return _XTranslateKeySym(event->display, symbol, event->state,
905			     buffer, nbytes);
906}
907
908static void
909_XFreeKeyBindings(
910    Display *dpy)
911{
912    register struct _XKeytrans *p, *np;
913
914    for (p = dpy->key_bindings; p; p = np) {
915	np = p->next;
916	Xfree(p->string);
917	Xfree(p->modifiers);
918	Xfree(p);
919    }
920    dpy->key_bindings = NULL;
921}
922
923int
924XRebindKeysym (
925    Display *dpy,
926    KeySym keysym,
927    KeySym *mlist,
928    int nm,		/* number of modifiers in mlist */
929    _Xconst unsigned char *str,
930    int nbytes)
931{
932    register struct _XKeytrans *tmp, *p;
933    int nb;
934
935    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
936	return 0;
937    LockDisplay(dpy);
938    tmp = dpy->key_bindings;
939    nb = sizeof(KeySym) * nm;
940
941    if ((! (p = Xcalloc( 1, sizeof(struct _XKeytrans)))) ||
942	((! (p->string = Xmalloc(nbytes))) && (nbytes > 0)) ||
943	((! (p->modifiers = Xmalloc(nb))) && (nb > 0))) {
944	if (p) {
945	    Xfree(p->string);
946	    Xfree(p->modifiers);
947	    Xfree(p);
948	}
949	UnlockDisplay(dpy);
950	return 0;
951    }
952
953    dpy->key_bindings = p;
954    dpy->free_funcs->key_bindings = _XFreeKeyBindings;
955    p->next = tmp;	/* chain onto list */
956    memcpy (p->string, str, (size_t) nbytes);
957    p->len = nbytes;
958    memcpy ((char *) p->modifiers, (char *) mlist, (size_t) nb);
959    p->key = keysym;
960    p->mlen = nm;
961    ComputeMaskFromKeytrans(dpy, p);
962    UnlockDisplay(dpy);
963    return 0;
964}
965
966unsigned
967_XKeysymToModifiers(
968    Display *dpy,
969    KeySym ks)
970{
971    CARD8 code,mods;
972    register KeySym *kmax;
973    register KeySym *k;
974    register XModifierKeymap *m;
975
976    if ((! dpy->keysyms) && (! _XKeyInitialize(dpy)))
977	return 0;
978    kmax = dpy->keysyms +
979	   (dpy->max_keycode - dpy->min_keycode + 1) * dpy->keysyms_per_keycode;
980    k = dpy->keysyms;
981    m = dpy->modifiermap;
982    mods= 0;
983    while (k<kmax) {
984	if (*k == ks ) {
985	    register int j = m->max_keypermod<<3;
986
987	    code=(((k-dpy->keysyms)/dpy->keysyms_per_keycode)+dpy->min_keycode);
988
989	    while (--j >= 0) {
990		if (code == m->modifiermap[j])
991		    mods|= (1<<(j/m->max_keypermod));
992	    }
993	}
994	k++;
995    }
996    return mods;
997}
998
999/*
1000 * given a list of modifiers, computes the mask necessary for later matching.
1001 * This routine must lookup the key in the Keymap and then search to see
1002 * what modifier it is bound to, if any.  Sets the AnyModifier bit if it
1003 * can't map some keysym to a modifier.
1004 */
1005static void
1006ComputeMaskFromKeytrans(
1007    Display *dpy,
1008    register struct _XKeytrans *p)
1009{
1010    register int i;
1011
1012    p->state = AnyModifier;
1013    for (i = 0; i < p->mlen; i++) {
1014	p->state|= XkbKeysymToModifiers(dpy,p->modifiers[i]);
1015    }
1016    p->state &= AllMods;
1017}
1018