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