4 * Routines to support keyboard events on the Macintosh.
6 * Copyright (c) 1995-1997 Sun Microsystems, Inc.
8 * See the file "license.terms" for information on usage and redistribution
9 * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
22 short keycode; /* Macintosh keycode */
23 KeySym keysym; /* X windows Keysym */
26 static KeyInfo keyArray[] = {
46 static KeyInfo vituralkeyArray[] = {
65 static int initialized = 0;
66 static Tcl_HashTable keycodeTable; /* keyArray hashed by keycode value. */
67 static Tcl_HashTable vkeyTable; /* vituralkeyArray hashed by virtual
69 static Ptr KCHRPtr; /* Pointer to 'KCHR' resource. */
72 * Prototypes for static functions used in this file.
74 static void InitKeyMaps _ANSI_ARGS_((void));
78 *----------------------------------------------------------------------
82 * Creates hash tables used by some of the functions in this file.
88 * Allocates memory & creates some hash tables.
90 *----------------------------------------------------------------------
96 register Tcl_HashEntry *hPtr;
97 register KeyInfo *kPtr;
100 Tcl_InitHashTable(&keycodeTable, TCL_ONE_WORD_KEYS);
101 for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) {
102 hPtr = Tcl_CreateHashEntry(&keycodeTable, (char *) kPtr->keycode,
104 Tcl_SetHashValue(hPtr, kPtr->keysym);
106 Tcl_InitHashTable(&vkeyTable, TCL_ONE_WORD_KEYS);
107 for (kPtr = vituralkeyArray; kPtr->keycode != 0; kPtr++) {
108 hPtr = Tcl_CreateHashEntry(&vkeyTable, (char *) kPtr->keycode,
110 Tcl_SetHashValue(hPtr, kPtr->keysym);
112 KCHRPtr = (Ptr) GetScriptManagerVariable(smKCHRCache);
117 *----------------------------------------------------------------------
119 * XKeycodeToKeysym --
121 * Translate from a system-dependent keycode to a
122 * system-independent keysym.
125 * Returns the translated keysym, or NoSymbol on failure.
130 *----------------------------------------------------------------------
139 register Tcl_HashEntry *hPtr;
143 unsigned long dummy, newChar;
149 virtualKey = (char) (keycode >> 16);
150 c = (keycode) & 0xffff;
156 * When determining what keysym to produce we firt check to see if
157 * the key is a function key. We then check to see if the character
158 * is another non-printing key. Finally, we return the key syms
159 * for all ASCI chars.
162 hPtr = Tcl_FindHashEntry(&vkeyTable, (char *) virtualKey);
164 return (KeySym) Tcl_GetHashValue(hPtr);
167 hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey);
169 return (KeySym) Tcl_GetHashValue(hPtr);
173 * Recompute the character based on the Shift key only.
174 * TODO: The index may also specify the NUM_LOCK.
176 newKeycode = virtualKey;
178 newKeycode += 0x0200;
181 newChar = KeyTranslate(KCHRPtr, (short) newKeycode, &dummy);
182 c = newChar & charCodeMask;
184 if (c >= XK_space && c < XK_asciitilde) {
192 *----------------------------------------------------------------------
196 * Retrieve the string equivalent for the given keyboard event.
199 * Returns the UTF string.
204 *----------------------------------------------------------------------
209 TkWindow *winPtr, /* Window where event occurred: needed to
210 * get input context. */
211 XEvent *eventPtr, /* X keyboard event. */
212 Tcl_DString *dsPtr) /* Uninitialized or empty string to hold
215 register Tcl_HashEntry *hPtr;
224 Tcl_DStringInit(dsPtr);
226 virtualKey = (char) (eventPtr->xkey.keycode >> 16);
227 c = (eventPtr->xkey.keycode) & 0xffff;
230 string[0] = (char) c;
233 string[0] = (char) (c >> 8);
234 string[1] = (char) c;
239 * Just return NULL if the character is a function key or another
245 hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey);
250 return Tcl_ExternalToUtfDString(NULL, string, len, dsPtr);
254 *----------------------------------------------------------------------
256 * XGetModifierMapping --
258 * Fetch the current keycodes used as modifiers.
261 * Returns a new modifier map.
264 * Allocates a new modifier map data structure.
266 *----------------------------------------------------------------------
273 XModifierKeymap * modmap;
275 modmap = (XModifierKeymap *) ckalloc(sizeof(XModifierKeymap));
276 modmap->max_keypermod = 0;
277 modmap->modifiermap = NULL;
282 *----------------------------------------------------------------------
284 * XFreeModifiermap --
286 * Deallocate a modifier map that was created by
287 * XGetModifierMapping.
293 * Frees the datastructure referenced by modmap.
295 *----------------------------------------------------------------------
300 XModifierKeymap *modmap)
302 if (modmap->modifiermap != NULL) {
303 ckfree((char *) modmap->modifiermap);
305 ckfree((char *) modmap);
309 *----------------------------------------------------------------------
311 * XKeysymToString, XStringToKeysym --
313 * These X window functions map Keysyms to strings & strings to
314 * keysyms. However, Tk already does this for the most common keysyms.
315 * Therefor, these functions only need to support keysyms that will be
316 * specific to the Macintosh. Currently, there are none.
324 *----------------------------------------------------------------------
342 *----------------------------------------------------------------------
344 * XKeysymToKeycode --
346 * The function XKeysymToKeycode is only used by tkTest.c and
347 * currently only implementes the support for keys used in the
349 * FIXME - This is no longer true. This function is now used in
350 * "event generate" so we really should make it work.
358 *----------------------------------------------------------------------
367 char virtualKeyCode = 0;
369 if ((keysym >= XK_space) && (XK_asciitilde)) {
371 virtualKeyCode = 0x00;
372 } else if (keysym == 'b' || keysym == 'B') {
373 virtualKeyCode = 0x0B;
374 } else if (keysym == 'c') {
375 virtualKeyCode = 0x08;
376 } else if (keysym == 'x' || keysym == 'X') {
377 virtualKeyCode = 0x07;
378 } else if (keysym == 'z') {
379 virtualKeyCode = 0x06;
380 } else if (keysym == ' ') {
381 virtualKeyCode = 0x31;
382 } else if (keysym == XK_Return) {
383 virtualKeyCode = 0x24;
386 keycode = keysym + (virtualKeyCode <<16);
393 * When mapping from a keysym to a keycode, need
394 * information about the modifier state that should be used
395 * so that when they call XKeycodeToKeysym taking into
396 * account the xkey.state, they will get back the original
401 TkpSetKeycodeAndState(tkwin, keySym, eventPtr)
410 display = Tk_Display(tkwin);
412 if (keySym == NoSymbol) {
415 keycode = XKeysymToKeycode(display, keySym);
418 for (state = 0; state < 4; state++) {
419 if (XKeycodeToKeysym(display, keycode, state) == keySym) {
421 eventPtr->xkey.state |= ShiftMask;
426 dispPtr = ((TkWindow *) tkwin)->dispPtr;
427 eventPtr->xkey.state |= dispPtr->modeModMask;
433 eventPtr->xkey.keycode = keycode;
437 *----------------------------------------------------------------------
441 * Given an X KeyPress or KeyRelease event, map the
442 * keycode in the event into a KeySym.
445 * The return value is the KeySym corresponding to
446 * eventPtr, or NoSymbol if no matching Keysym could be
450 * In the first call for a given display, keycode-to-
451 * KeySym maps get loaded.
453 *----------------------------------------------------------------------
457 TkpGetKeySym(dispPtr, eventPtr)
458 TkDisplay *dispPtr; /* Display in which to
460 XEvent *eventPtr; /* Description of X event. */
466 * Refresh the mapping information if it's stale
469 if (dispPtr->bindInfoStale) {
470 TkpInitKeymapInfo(dispPtr);
474 * Figure out which of the four slots in the keymap vector to
475 * use for this key. Refer to Xlib documentation for more info
476 * on how this computation works.
480 if (eventPtr->xkey.state & dispPtr->modeModMask) {
483 if ((eventPtr->xkey.state & ShiftMask)
484 || ((dispPtr->lockUsage != LU_IGNORE)
485 && (eventPtr->xkey.state & LockMask))) {
488 sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index);
491 * Special handling: if the key was shifted because of Lock, but
492 * lock is only caps lock, not shift lock, and the shifted keysym
493 * isn't upper-case alphabetic, then switch back to the unshifted
497 if ((index & 1) && !(eventPtr->xkey.state & ShiftMask)
498 && (dispPtr->lockUsage == LU_CAPS)) {
499 if (!(((sym >= XK_A) && (sym <= XK_Z))
500 || ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
501 || ((sym >= XK_Ooblique) && (sym <= XK_Thorn)))) {
503 sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
509 * Another bit of special handling: if this is a shifted key and there
510 * is no keysym defined, then use the keysym for the unshifted key.
513 if ((index & 1) && (sym == NoSymbol)) {
514 sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
521 *--------------------------------------------------------------
523 * TkpInitKeymapInfo --
525 * This procedure is invoked to scan keymap information
526 * to recompute stuff that's important for binding, such
527 * as the modifier key (if any) that corresponds to "mode
534 * Keymap-related information in dispPtr is updated.
536 *--------------------------------------------------------------
540 TkpInitKeymapInfo(dispPtr)
541 TkDisplay *dispPtr; /* Display for which to recompute keymap
544 XModifierKeymap *modMapPtr;
547 int count, i, j, max, arraySize;
548 #define KEYCODE_ARRAY_SIZE 20
550 dispPtr->bindInfoStale = 0;
551 modMapPtr = XGetModifierMapping(dispPtr->display);
554 * Check the keycodes associated with the Lock modifier. If
555 * any of them is associated with the XK_Shift_Lock modifier,
556 * then Lock has to be interpreted as Shift Lock, not Caps Lock.
559 dispPtr->lockUsage = LU_IGNORE;
560 codePtr = modMapPtr->modifiermap + modMapPtr->max_keypermod*LockMapIndex;
561 for (count = modMapPtr->max_keypermod; count > 0; count--, codePtr++) {
565 keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0);
566 if (keysym == XK_Shift_Lock) {
567 dispPtr->lockUsage = LU_SHIFT;
570 if (keysym == XK_Caps_Lock) {
571 dispPtr->lockUsage = LU_CAPS;
577 * Look through the keycodes associated with modifiers to see if
578 * the the "mode switch", "meta", or "alt" keysyms are associated
579 * with any modifiers. If so, remember their modifier mask bits.
582 dispPtr->modeModMask = 0;
583 dispPtr->metaModMask = 0;
584 dispPtr->altModMask = 0;
585 codePtr = modMapPtr->modifiermap;
586 max = 8*modMapPtr->max_keypermod;
587 for (i = 0; i < max; i++, codePtr++) {
591 keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0);
592 if (keysym == XK_Mode_switch) {
593 dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
595 if ((keysym == XK_Meta_L) || (keysym == XK_Meta_R)) {
596 dispPtr->metaModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
598 if ((keysym == XK_Alt_L) || (keysym == XK_Alt_R)) {
599 dispPtr->altModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
604 * Create an array of the keycodes for all modifier keys.
607 if (dispPtr->modKeyCodes != NULL) {
608 ckfree((char *) dispPtr->modKeyCodes);
610 dispPtr->numModKeyCodes = 0;
611 arraySize = KEYCODE_ARRAY_SIZE;
612 dispPtr->modKeyCodes = (KeyCode *) ckalloc((unsigned)
613 (KEYCODE_ARRAY_SIZE * sizeof(KeyCode)));
614 for (i = 0, codePtr = modMapPtr->modifiermap; i < max; i++, codePtr++) {
620 * Make sure that the keycode isn't already in the array.
623 for (j = 0; j < dispPtr->numModKeyCodes; j++) {
624 if (dispPtr->modKeyCodes[j] == *codePtr) {
628 if (dispPtr->numModKeyCodes >= arraySize) {
632 * Ran out of space in the array; grow it.
636 new = (KeyCode *) ckalloc((unsigned)
637 (arraySize * sizeof(KeyCode)));
638 memcpy((VOID *) new, (VOID *) dispPtr->modKeyCodes,
639 (dispPtr->numModKeyCodes * sizeof(KeyCode)));
640 ckfree((char *) dispPtr->modKeyCodes);
641 dispPtr->modKeyCodes = new;
643 dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr;
644 dispPtr->numModKeyCodes++;
645 nextModCode: continue;
647 XFreeModifiermap(modMapPtr);