1 /*
2  * tkWinKey.c --
3  *
4  *	This file contains X emulation routines for keyboard related
5  *	functions.
6  *
7  * Copyright (c) 1995 Sun Microsystems, Inc.
8  *
9  * See the file "license.terms" for information on usage and redistribution
10  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
11  *
12  * RCS: @(#) $Id: tkWinKey.c,v 1.14 2001/05/30 22:41:11 hobbs Exp $
13  */
14 
15 #include "tkWinInt.h"
16 /*
17  * The keymap table holds mappings of Windows keycodes to X keysyms.
18  * If Windows ever comes along and changes the value of their keycodes,
19  * this will break all kinds of things.  However, this table lookup is much
20  * faster than the alternative, in which we walked a list of keycodes looking
21  * for a match.  Since this lookup is performed for every Windows keypress
22  * event, it seems like a worthwhile improvement to use the table.
23  */
24 #define MAX_KEYCODE 145 /* VK_SCROLL is the last entry in our table below */
25 static KeySym keymap[] = {
26     NoSymbol, NoSymbol, NoSymbol, XK_Cancel, NoSymbol,
27 	NoSymbol, NoSymbol, NoSymbol, XK_BackSpace, XK_Tab,
28 	NoSymbol, NoSymbol, XK_Clear, XK_Return, NoSymbol,
29 	NoSymbol, XK_Shift_L, XK_Control_L, XK_Alt_L, XK_Pause,
30 	XK_Caps_Lock, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
31 	NoSymbol, NoSymbol, XK_Escape, NoSymbol, NoSymbol,
32 	NoSymbol, NoSymbol, XK_space, XK_Prior, XK_Next,
33 	XK_End, XK_Home, XK_Left, XK_Up, XK_Right,
34 	XK_Down, XK_Select, XK_Print, XK_Execute, NoSymbol,
35 	XK_Insert, XK_Delete, XK_Help, NoSymbol, NoSymbol,
36 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
37 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
38 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
39 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
40 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
41 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
42 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
43 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
44 	NoSymbol, XK_Win_L, XK_Win_R, XK_App, NoSymbol,
45 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
46 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
47 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol,
48 	NoSymbol, NoSymbol, XK_F1, XK_F2, XK_F3,
49 	XK_F4, XK_F5, XK_F6, XK_F7, XK_F8,
50 	XK_F9, XK_F10, XK_F11, XK_F12, XK_F13,
51 	XK_F14, XK_F15, XK_F16, XK_F17, XK_F18,
52 	XK_F19,	XK_F20, XK_F21, XK_F22, XK_F23,
53 	XK_F24,	NoSymbol, NoSymbol, NoSymbol, NoSymbol,
54 	NoSymbol, NoSymbol, NoSymbol, NoSymbol, XK_Num_Lock,
55 	XK_Scroll_Lock
56 };
57 
58 /*
59  * Prototypes for local procedures defined in this file:
60  */
61 
62 static KeySym		KeycodeToKeysym _ANSI_ARGS_((unsigned int keycode,
63 			    int state, int noascii));
64 
65 /*
66  *----------------------------------------------------------------------
67  *
68  * TkpGetString --
69  *
70  *	Retrieve the UTF string equivalent for the given keyboard event.
71  *
72  * Results:
73  *	Returns the UTF string.
74  *
75  * Side effects:
76  *	None.
77  *
78  *----------------------------------------------------------------------
79  */
80 
81 char *
TkpGetString(winPtr,eventPtr,dsPtr)82 TkpGetString(winPtr, eventPtr, dsPtr)
83     TkWindow *winPtr;		/* Window where event occurred:  needed to
84 				 * get input context. */
85     XEvent *eventPtr;		/* X keyboard event. */
86     Tcl_DString *dsPtr;		/* Uninitialized or empty string to hold
87 				 * result. */
88 {
89     KeySym keysym;
90     XKeyEvent* keyEv = &eventPtr->xkey;
91 
92     Tcl_DStringInit(dsPtr);
93     if (eventPtr->xkey.send_event == -1) {
94         if (eventPtr->xkey.nbytes > 0) {
95 	    Tcl_ExternalToUtfDString(TkWinGetKeyInputEncoding(),
96                     eventPtr->xkey.trans_chars, eventPtr->xkey.nbytes, dsPtr);
97         }
98     } else if (eventPtr->xkey.send_event == -2) {
99         /*
100          * Special case for win2000 multi-lingal IME input.
101          * xkey.trans_chars[] already contains a UNICODE char.
102          */
103 
104         int unichar;
105         char buf[TCL_UTF_MAX];
106         int len;
107 
108         unichar = (eventPtr->xkey.trans_chars[1] & 0xff);
109         unichar <<= 8;
110         unichar |= (eventPtr->xkey.trans_chars[0] & 0xff);
111 
112         len = Tcl_UniCharToUtf((Tcl_UniChar) unichar, buf);
113 
114         Tcl_DStringAppend(dsPtr, buf, len);
115     } else  {
116 	/*
117 	 * This is an event generated from generic code.  It has no
118 	 * nchars or trans_chars members.
119 	 */
120 
121 	keysym = KeycodeToKeysym(eventPtr->xkey.keycode,
122 		eventPtr->xkey.state, 0);
123 	if (((keysym != NoSymbol) && (keysym > 0) && (keysym < 256))
124 		|| (keysym == XK_Return)
125 		|| (keysym == XK_Tab)) {
126 	    char buf[TCL_UTF_MAX];
127 	    int len = Tcl_UniCharToUtf((Tcl_UniChar) (keysym & 255), buf);
128 	    Tcl_DStringAppend(dsPtr, buf, len);
129 	}
130     }
131     return Tcl_DStringValue(dsPtr);
132 }
133 
134 /*
135  *----------------------------------------------------------------------
136  *
137  * XKeycodeToKeysym --
138  *
139  *	Translate from a system-dependent keycode to a
140  *	system-independent keysym.
141  *
142  * Results:
143  *	Returns the translated keysym, or NoSymbol on failure.
144  *
145  * Side effects:
146  *	None.
147  *
148  *----------------------------------------------------------------------
149  */
150 
151 KeySym
XKeycodeToKeysym(display,keycode,index)152 XKeycodeToKeysym(display, keycode, index)
153     Display* display;
154     unsigned int keycode;
155     int index;
156 {
157     int state = 0;
158 
159     if (index & 0x01) {
160 	state |= ShiftMask;
161     }
162     return KeycodeToKeysym(keycode, state, 0);
163 }
164 
165 
166 
167 /*
168  *----------------------------------------------------------------------
169  *
170  * KeycodeToKeysym --
171  *
172  *	Translate from a system-dependent keycode to a
173  *	system-independent keysym.
174  *
175  * Results:
176  *	Returns the translated keysym, or NoSymbol on failure.
177  *
178  * Side effects:
179  *	It may affect the internal state of the keyboard, such as
180  *      remembered dead key or lock indicator lamps.
181  *
182  *----------------------------------------------------------------------
183  */
184 
185 static KeySym
KeycodeToKeysym(keycode,state,noascii)186 KeycodeToKeysym(keycode, state, noascii)
187     unsigned int keycode;
188     int state;
189     int noascii;
190 {
191     BYTE keys[256];
192     int result, deadkey, shift;
193     char buf[4];
194     unsigned int scancode = MapVirtualKey(keycode, 0);
195 
196     /*
197      * Do not run keycodes of lock keys through ToAscii().
198      * One of ToAscii()'s side effects is to handle the lights
199      * on the keyboard, and we don't want to mess that up.
200      */
201 
202     if (noascii || keycode == VK_CAPITAL || keycode == VK_SCROLL ||
203 	    keycode == VK_NUMLOCK)
204         goto skipToAscii;
205 
206     /*
207      * Use MapVirtualKey() to detect some dead keys.
208      */
209 
210     if (MapVirtualKey(keycode, 2) > 0x7fffUL)
211         return XK_Multi_key;
212 
213     /*
214      * Set up a keyboard with correct modifiers
215      */
216 
217     memset(keys, 0, 256);
218     if (state & ShiftMask)
219         keys[VK_SHIFT] = 0x80;
220     if (state & ControlMask)
221 	keys[VK_CONTROL] = 0x80;
222     if (state & Mod2Mask)
223 	keys[VK_MENU] = 0x80;
224 
225     /*
226      * Make sure all lock button info is correct so we don't mess up the
227      * lights
228      */
229 
230     if (state & LockMask)
231 	keys[VK_CAPITAL] = 1;
232     if (state & Mod3Mask)
233 	keys[VK_SCROLL] = 1;
234     if (state & Mod1Mask)
235 	keys[VK_NUMLOCK] = 1;
236 
237     result = ToAscii(keycode, scancode, keys, (LPWORD) buf, 0);
238 
239     if (result < 0) {
240         /*
241          * Win95/98:
242          * This was a dead char, which is now remembered by the keyboard.
243          * Call ToAscii() again to forget it.
244          * WinNT:
245          * This was a dead char, overwriting any previously remembered
246          * key. Calling ToAscii() again does not affect anything.
247          */
248 
249         ToAscii(keycode, scancode, keys, (LPWORD) buf, 0);
250         return XK_Multi_key;
251     }
252     if (result == 2) {
253         /*
254          * This was a dead char, and there were one previously remembered
255          * by the keyboard.
256          * Call ToAscii() again with proper parameters to restore it.
257          */
258 
259         /*
260 	 * Get information about the old char
261 	 */
262 
263         deadkey = VkKeyScan(buf[0]);
264         shift = deadkey >> 8;
265         deadkey &= 255;
266         scancode = MapVirtualKey(deadkey, 0);
267 
268         /*
269 	 * Set up a keyboard with proper modifier keys
270 	 */
271 
272         memset(keys, 0, 256);
273         if (shift & 1)
274             keys[VK_SHIFT] = 0x80;
275         if (shift & 2)
276             keys[VK_CONTROL] = 0x80;
277         if (shift & 4)
278             keys[VK_MENU] = 0x80;
279         ToAscii(deadkey, scancode, keys, (LPWORD) buf, 0);
280         return XK_Multi_key;
281     }
282 
283     /*
284      * Keycode mapped to a valid Latin-1 character.  Since the keysyms
285      * for alphanumeric characters map onto Latin-1, we just return it.
286      *
287      * We treat 0x7F as a special case mostly for backwards compatibility.
288      * In versions of Tk<=8.2, Control-Backspace returned "XK_BackSpace"
289      * as the X Keysym.  This was due to the fact that we did not
290      * initialize the keys array properly when we passed it to ToAscii, above.
291      * We had previously not been setting the state bit for the Control key.
292      * When we fixed that, we found that Control-Backspace on Windows is
293      * interpreted as ASCII-127 (0x7F), which corresponds to the Delete key.
294      *
295      * Upon discovering this, we realized we had two choices:  return XK_Delete
296      * or return XK_BackSpace.  If we returned XK_Delete, that could be
297      * considered "more correct" (although the correctness would be dependant
298      * on whether you believe that ToAscii is doing the right thing in that
299      * case); however, this would break backwards compatibility, and worse,
300      * it would limit application programmers -- they would effectively be
301      * unable to bind to <Control-Backspace> on Windows.  We therefore chose
302      * instead to return XK_BackSpace (handled here by letting the code
303      * "fall-through" to the return statement below, which works because the
304      * keycode for this event is VK_BACKSPACE, and the keymap table maps that
305      * keycode to XK_BackSpace).
306      */
307 
308     if (result == 1 && UCHAR(buf[0]) >= 0x20 && UCHAR(buf[0]) != 0x7F) {
309 	return (KeySym) UCHAR(buf[0]);
310     }
311 
312     /*
313      * Keycode is a non-alphanumeric key, so we have to do the lookup.
314      */
315 
316     skipToAscii:
317     if (keycode < 0 || keycode > MAX_KEYCODE) {
318 	return NoSymbol;
319     }
320     switch (keycode) {
321 	/*
322 	 * Windows only gives us an undifferentiated VK_CONTROL
323 	 * code (for example) when either Control key is pressed.
324 	 * To distinguish between left and right, we have to query the
325 	 * state of one of the two to determine which was actually
326 	 * pressed.  So if the keycode indicates Control, Shift, or Menu
327 	 * (the key that everybody else calls Alt), do this extra test.
328 	 * If the right-side key was pressed, return the appropriate
329 	 * keycode.  Otherwise, we fall through and rely on the
330 	 * keymap table to hold the correct keysym value.
331 	 */
332 	case VK_CONTROL: {
333 	    if (GetKeyState(VK_RCONTROL) & 0x80) {
334 		return XK_Control_R;
335 	    }
336 	    break;
337 	}
338 	case VK_SHIFT: {
339 	    if (GetKeyState(VK_RSHIFT) & 0x80) {
340 		return XK_Shift_R;
341 	    }
342 	    break;
343 	}
344 	case VK_MENU: {
345 	    if (GetKeyState(VK_RMENU) & 0x80) {
346 		return XK_Alt_R;
347 	    }
348 	    break;
349 	}
350     }
351     return keymap[keycode];
352 }
353 
354 
355 /*
356  *----------------------------------------------------------------------
357  *
358  * TkpGetKeySym --
359  *
360  *	Given an X KeyPress or KeyRelease event, map the
361  *	keycode in the event into a KeySym.
362  *
363  * Results:
364  *	The return value is the KeySym corresponding to
365  *	eventPtr, or NoSymbol if no matching Keysym could be
366  *	found.
367  *
368  * Side effects:
369  *	In the first call for a given display, keycode-to-
370  *	KeySym maps get loaded.
371  *
372  *----------------------------------------------------------------------
373  */
374 
375 KeySym
TkpGetKeySym(dispPtr,eventPtr)376 TkpGetKeySym(dispPtr, eventPtr)
377     TkDisplay *dispPtr;		/* Display in which to map keycode. */
378     XEvent *eventPtr;		/* Description of X event. */
379 {
380     KeySym sym;
381     int state = eventPtr->xkey.state;
382 
383     /*
384      * Refresh the mapping information if it's stale
385      */
386 
387     if (dispPtr->bindInfoStale) {
388 	TkpInitKeymapInfo(dispPtr);
389     }
390 
391     sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0);
392 
393     /*
394      * Special handling: if this is a ctrl-alt or shifted key, and there
395      * is no keysym defined, try without the modifiers.
396      */
397 
398     if ((sym == NoSymbol) && ((state & ControlMask) || (state & Mod2Mask))) {
399         state &=  ~(ControlMask | Mod2Mask);
400         sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0);
401     }
402     if ((sym == NoSymbol) && (state & ShiftMask)) {
403         state &=  ~ShiftMask;
404         sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0);
405     }
406     return sym;
407 }
408 
409 /*
410  *--------------------------------------------------------------
411  *
412  * TkpInitKeymapInfo --
413  *
414  *	This procedure is invoked to scan keymap information
415  *	to recompute stuff that's important for binding, such
416  *	as the modifier key (if any) that corresponds to "mode
417  *	switch".
418  *
419  * Results:
420  *	None.
421  *
422  * Side effects:
423  *	Keymap-related information in dispPtr is updated.
424  *
425  *--------------------------------------------------------------
426  */
427 
428 void
TkpInitKeymapInfo(dispPtr)429 TkpInitKeymapInfo(dispPtr)
430     TkDisplay *dispPtr;		/* Display for which to recompute keymap
431 				 * information. */
432 {
433     XModifierKeymap *modMapPtr;
434     KeyCode *codePtr;
435     KeySym keysym;
436     int count, i, j, max, arraySize;
437 #define KEYCODE_ARRAY_SIZE 20
438 
439     dispPtr->bindInfoStale = 0;
440     modMapPtr = XGetModifierMapping(dispPtr->display);
441 
442     /*
443      * Check the keycodes associated with the Lock modifier.  If
444      * any of them is associated with the XK_Shift_Lock modifier,
445      * then Lock has to be interpreted as Shift Lock, not Caps Lock.
446      */
447 
448     dispPtr->lockUsage = LU_IGNORE;
449     codePtr = modMapPtr->modifiermap + modMapPtr->max_keypermod*LockMapIndex;
450     for (count = modMapPtr->max_keypermod; count > 0; count--, codePtr++) {
451 	if (*codePtr == 0) {
452 	    continue;
453 	}
454 	keysym = KeycodeToKeysym(*codePtr, 0, 1);
455 	if (keysym == XK_Shift_Lock) {
456 	    dispPtr->lockUsage = LU_SHIFT;
457 	    break;
458 	}
459 	if (keysym == XK_Caps_Lock) {
460 	    dispPtr->lockUsage = LU_CAPS;
461 	    break;
462 	}
463     }
464 
465     /*
466      * Look through the keycodes associated with modifiers to see if
467      * the the "mode switch", "meta", or "alt" keysyms are associated
468      * with any modifiers.  If so, remember their modifier mask bits.
469      */
470 
471     dispPtr->modeModMask = 0;
472     dispPtr->metaModMask = 0;
473     dispPtr->altModMask = 0;
474     codePtr = modMapPtr->modifiermap;
475     max = 8*modMapPtr->max_keypermod;
476     for (i = 0; i < max; i++, codePtr++) {
477 	if (*codePtr == 0) {
478 	    continue;
479 	}
480 	keysym = KeycodeToKeysym(*codePtr, 0, 1);
481 	if (keysym == XK_Mode_switch) {
482 	    dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
483 	}
484 	if ((keysym == XK_Meta_L) || (keysym == XK_Meta_R)) {
485 	    dispPtr->metaModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
486 	}
487 	if ((keysym == XK_Alt_L) || (keysym == XK_Alt_R)) {
488 	    dispPtr->altModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
489 	}
490     }
491 
492     /*
493      * Create an array of the keycodes for all modifier keys.
494      */
495 
496     if (dispPtr->modKeyCodes != NULL) {
497 	ckfree((char *) dispPtr->modKeyCodes);
498     }
499     dispPtr->numModKeyCodes = 0;
500     arraySize = KEYCODE_ARRAY_SIZE;
501     dispPtr->modKeyCodes = (KeyCode *) ckalloc((unsigned)
502 	    (KEYCODE_ARRAY_SIZE * sizeof(KeyCode)));
503     for (i = 0, codePtr = modMapPtr->modifiermap; i < max; i++, codePtr++) {
504 	if (*codePtr == 0) {
505 	    continue;
506 	}
507 
508 	/*
509 	 * Make sure that the keycode isn't already in the array.
510 	 */
511 
512 	for (j = 0; j < dispPtr->numModKeyCodes; j++) {
513 	    if (dispPtr->modKeyCodes[j] == *codePtr) {
514 		goto nextModCode;
515 	    }
516 	}
517 	if (dispPtr->numModKeyCodes >= arraySize) {
518 	    KeyCode *new;
519 
520 	    /*
521 	     * Ran out of space in the array;  grow it.
522 	     */
523 
524 	    arraySize *= 2;
525 	    new = (KeyCode *) ckalloc((unsigned)
526 		    (arraySize * sizeof(KeyCode)));
527 	    memcpy((VOID *) new, (VOID *) dispPtr->modKeyCodes,
528 		    (dispPtr->numModKeyCodes * sizeof(KeyCode)));
529 	    ckfree((char *) dispPtr->modKeyCodes);
530 	    dispPtr->modKeyCodes = new;
531 	}
532 	dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr;
533 	dispPtr->numModKeyCodes++;
534 	nextModCode: continue;
535     }
536     XFreeModifiermap(modMapPtr);
537 }
538 
539 /*
540  * When mapping from a keysym to a keycode, need
541  * information about the modifier state that should be used
542  * so that when they call XKeycodeToKeysym taking into
543  * account the xkey.state, they will get back the original
544  * keysym.
545  */
546 
547 void
TkpSetKeycodeAndState(tkwin,keySym,eventPtr)548 TkpSetKeycodeAndState(tkwin, keySym, eventPtr)
549     Tk_Window tkwin;
550     KeySym keySym;
551     XEvent *eventPtr;
552 {
553     int i;
554     SHORT result;
555     int shift;
556 
557     eventPtr->xkey.keycode = 0;
558     if (keySym == NoSymbol) {
559         return;
560     }
561 
562     /*
563      * We check our private map first for a virtual keycode,
564      * as VkKeyScan will return values that don't map to X
565      * for the "extended" Syms.  This may be due to just casting
566      * problems below, but this works.
567      */
568     for (i = 0; i <= MAX_KEYCODE; i++) {
569 	if (keymap[i] == keySym) {
570             eventPtr->xkey.keycode = i;
571             return;
572 	}
573     }
574     if (keySym >= 0x20) {
575 	result = VkKeyScan((char) keySym);
576 	if (result != -1) {
577             shift = result >> 8;
578             if (shift & 1)
579                 eventPtr->xkey.state |= ShiftMask;
580             if (shift & 2)
581                 eventPtr->xkey.state |= ControlMask;
582             if (shift & 4)
583                 eventPtr->xkey.state |= Mod2Mask;
584             eventPtr->xkey.keycode = (KeyCode) (result & 0xff);
585 	}
586     }
587 }
588 
589 /*
590  *----------------------------------------------------------------------
591  *
592  * XKeysymToKeycode --
593  *
594  *	Translate a keysym back into a keycode.
595  *
596  * Results:
597  *	Returns the keycode that would generate the specified keysym.
598  *
599  * Side effects:
600  *	None.
601  *
602  *----------------------------------------------------------------------
603  */
604 
605 KeyCode
XKeysymToKeycode(display,keysym)606 XKeysymToKeycode(display, keysym)
607     Display* display;
608     KeySym keysym;
609 {
610     int i;
611     SHORT result;
612 
613     /*
614      * We check our private map first for a virtual keycode,
615      * as VkKeyScan will return values that don't map to X
616      * for the "extended" Syms.  This may be due to just casting
617      * problems below, but this works.
618      */
619     if (keysym == NoSymbol) {
620 	return 0;
621     }
622     for (i = 0; i <= MAX_KEYCODE; i++) {
623 	if (keymap[i] == keysym) {
624 	    return ((KeyCode) i);
625 	}
626     }
627     if (keysym >= 0x20) {
628 	result = VkKeyScan((char) keysym);
629 	if (result != -1) {
630 	    return (KeyCode) (result & 0xff);
631 	}
632     }
633 
634     return 0;
635 }
636 
637 /*
638  *----------------------------------------------------------------------
639  *
640  * XGetModifierMapping --
641  *
642  *	Fetch the current keycodes used as modifiers.
643  *
644  * Results:
645  *	Returns a new modifier map.
646  *
647  * Side effects:
648  *	Allocates a new modifier map data structure.
649  *
650  *----------------------------------------------------------------------
651  */
652 
653 XModifierKeymap	*
XGetModifierMapping(display)654 XGetModifierMapping(display)
655     Display* display;
656 {
657     XModifierKeymap *map = (XModifierKeymap *)ckalloc(sizeof(XModifierKeymap));
658 
659     map->max_keypermod = 1;
660     map->modifiermap = (KeyCode *) ckalloc(sizeof(KeyCode)*8);
661     map->modifiermap[ShiftMapIndex] = VK_SHIFT;
662     map->modifiermap[LockMapIndex] = VK_CAPITAL;
663     map->modifiermap[ControlMapIndex] = VK_CONTROL;
664     map->modifiermap[Mod1MapIndex] = VK_NUMLOCK;
665     map->modifiermap[Mod2MapIndex] = VK_MENU;
666     map->modifiermap[Mod3MapIndex] = VK_SCROLL;
667     map->modifiermap[Mod4MapIndex] = 0;
668     map->modifiermap[Mod5MapIndex] = 0;
669     return map;
670 }
671 
672 /*
673  *----------------------------------------------------------------------
674  *
675  * XFreeModifiermap --
676  *
677  *	Deallocate a modifier map that was created by
678  *	XGetModifierMapping.
679  *
680  * Results:
681  *	None.
682  *
683  * Side effects:
684  *	Frees the datastructure referenced by modmap.
685  *
686  *----------------------------------------------------------------------
687  */
688 
689 void
XFreeModifiermap(modmap)690 XFreeModifiermap(modmap)
691     XModifierKeymap* modmap;
692 {
693     ckfree((char *) modmap->modifiermap);
694     ckfree((char *) modmap);
695 }
696 
697 /*
698  *----------------------------------------------------------------------
699  *
700  * XStringToKeysym --
701  *
702  *	Translate a keysym name to the matching keysym.
703  *
704  * Results:
705  *	Returns the keysym.  Since this is already handled by
706  *	Tk's StringToKeysym function, we just return NoSymbol.
707  *
708  * Side effects:
709  *	None.
710  *
711  *----------------------------------------------------------------------
712  */
713 
714 KeySym
XStringToKeysym(string)715 XStringToKeysym(string)
716     _Xconst char *string;
717 {
718     return NoSymbol;
719 }
720 
721 /*
722  *----------------------------------------------------------------------
723  *
724  * XKeysymToString --
725  *
726  *	Convert a keysym to character form.
727  *
728  * Results:
729  *	Returns NULL, since Tk will have handled this already.
730  *
731  * Side effects:
732  *	None.
733  *
734  *----------------------------------------------------------------------
735  */
736 
737 char *
XKeysymToString(keysym)738 XKeysymToString(keysym)
739     KeySym keysym;
740 {
741     return NULL;
742 }
743