OSDN Git Service

touched all tk files to ease next import
[pf3gnuchains/pf3gnuchains3x.git] / tk / mac / tkMacKeyboard.c
1 /* 
2  * tkMacKeyboard.c --
3  *
4  *      Routines to support keyboard events on the Macintosh.
5  *
6  * Copyright (c) 1995-1997 Sun Microsystems, Inc.
7  *
8  * See the file "license.terms" for information on usage and redistribution
9  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
10  *
11  * RCS: @(#) $Id$
12  */
13
14 #include "tkInt.h"
15 #include "Xlib.h"
16 #include "keysym.h"
17
18 #include <Events.h>
19 #include <Script.h>
20
21 typedef struct {
22     short keycode;              /* Macintosh keycode */
23     KeySym keysym;              /* X windows Keysym */
24 } KeyInfo;
25
26 static KeyInfo keyArray[] = {
27     {0x4C,      XK_Return},
28     {0x24,      XK_Return},
29     {0x33,      XK_BackSpace},
30     {0x75,      XK_Delete},
31     {0x30,      XK_Tab},
32     {0x74,      XK_Page_Up},
33     {0x79,      XK_Page_Down},
34     {0x73,      XK_Home},
35     {0x77,      XK_End},
36     {0x7B,      XK_Left},
37     {0x7C,      XK_Right},
38     {0x7E,      XK_Up},
39     {0x7D,      XK_Down},
40     {0x72,      XK_Help},
41     {0x35,      XK_Escape},
42     {0x47,      XK_Clear},
43     {0,         0}
44 };
45
46 static KeyInfo vituralkeyArray[] = {
47     {122,       XK_F1},
48     {120,       XK_F2},
49     {99,        XK_F3},
50     {118,       XK_F4},
51     {96,        XK_F5},
52     {97,        XK_F6},
53     {98,        XK_F7},
54     {100,       XK_F8},
55     {101,       XK_F9},
56     {109,       XK_F10},
57     {103,       XK_F11},
58     {111,       XK_F12},
59     {105,       XK_F13},
60     {107,       XK_F14},
61     {113,       XK_F15},
62     {0,         0}
63 };
64
65 static int initialized = 0;
66 static Tcl_HashTable keycodeTable;      /* keyArray hashed by keycode value. */
67 static Tcl_HashTable vkeyTable;         /* vituralkeyArray hashed by virtual
68                                            keycode value. */
69 static Ptr KCHRPtr;                     /* Pointer to 'KCHR' resource. */
70
71 /*
72  * Prototypes for static functions used in this file.
73  */
74 static void     InitKeyMaps _ANSI_ARGS_((void));
75
76 \f
77 /*
78  *----------------------------------------------------------------------
79  *
80  * InitKeyMaps --
81  *
82  *      Creates hash tables used by some of the functions in this file.
83  *
84  * Results:
85  *      None.
86  *
87  * Side effects:
88  *      Allocates memory & creates some hash tables.
89  *
90  *----------------------------------------------------------------------
91  */
92
93 static void
94 InitKeyMaps()
95 {
96     register Tcl_HashEntry *hPtr;
97     register KeyInfo *kPtr;
98     int dummy;
99                 
100     Tcl_InitHashTable(&keycodeTable, TCL_ONE_WORD_KEYS);
101     for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) {
102         hPtr = Tcl_CreateHashEntry(&keycodeTable, (char *) kPtr->keycode,
103                 &dummy);
104         Tcl_SetHashValue(hPtr, kPtr->keysym);
105     }
106     Tcl_InitHashTable(&vkeyTable, TCL_ONE_WORD_KEYS);
107     for (kPtr = vituralkeyArray; kPtr->keycode != 0; kPtr++) {
108         hPtr = Tcl_CreateHashEntry(&vkeyTable, (char *) kPtr->keycode,
109                 &dummy);
110         Tcl_SetHashValue(hPtr, kPtr->keysym);
111     }
112     KCHRPtr = (Ptr) GetScriptManagerVariable(smKCHRCache);
113     initialized = 1;
114 }
115 \f
116 /*
117  *----------------------------------------------------------------------
118  *
119  * XKeycodeToKeysym --
120  *
121  *      Translate from a system-dependent keycode to a
122  *      system-independent keysym.
123  *
124  * Results:
125  *      Returns the translated keysym, or NoSymbol on failure.
126  *
127  * Side effects:
128  *      None.
129  *
130  *----------------------------------------------------------------------
131  */
132
133 KeySym 
134 XKeycodeToKeysym(
135     Display* display,
136     KeyCode keycode,
137     int index)
138 {
139     register Tcl_HashEntry *hPtr;
140     int c;
141     char virtualKey;
142     int newKeycode;
143     unsigned long dummy, newChar;
144
145     if (!initialized) {
146         InitKeyMaps();
147     }
148         
149     virtualKey = (char) (keycode >> 16);    
150     c = (keycode) & 0xffff;
151     if (c > 255) {
152         return NoSymbol;
153     }
154
155     /*
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.
160      */
161     if (c == 0x10) {
162         hPtr = Tcl_FindHashEntry(&vkeyTable, (char *) virtualKey);
163         if (hPtr != NULL) {
164             return (KeySym) Tcl_GetHashValue(hPtr);
165         }
166     }
167     hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey);
168     if (hPtr != NULL) {
169         return (KeySym) Tcl_GetHashValue(hPtr);
170     }
171
172     /* 
173      * Recompute the character based on the Shift key only.
174      * TODO: The index may also specify the NUM_LOCK.
175      */
176     newKeycode = virtualKey;
177     if (index & 0x01) {
178         newKeycode += 0x0200;
179     }
180     dummy = 0;
181     newChar = KeyTranslate(KCHRPtr, (short) newKeycode, &dummy);
182     c = newChar & charCodeMask;
183     
184     if (c >= XK_space && c < XK_asciitilde) {
185         return c;
186     }
187
188     return NoSymbol; 
189 }
190 \f
191 /*
192  *----------------------------------------------------------------------
193  *
194  * TkpGetString --
195  *
196  *      Retrieve the string equivalent for the given keyboard event.
197  *
198  * Results:
199  *      Returns the UTF string.
200  *
201  * Side effects:
202  *      None.
203  *
204  *----------------------------------------------------------------------
205  */
206
207 char *
208 TkpGetString(
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
213                                  * result. */
214 {
215     register Tcl_HashEntry *hPtr;
216     char string[3];
217     char virtualKey;
218     int c, len;
219
220     if (!initialized) {
221         InitKeyMaps();
222     }
223     
224     Tcl_DStringInit(dsPtr);
225     
226     virtualKey = (char) (eventPtr->xkey.keycode >> 16);    
227     c = (eventPtr->xkey.keycode) & 0xffff;
228     
229     if (c < 256) {
230         string[0] = (char) c;
231         len = 1;
232     } else {
233         string[0] = (char) (c >> 8);
234         string[1] = (char) c;
235         len = 2;
236     }
237     
238     /*
239      * Just return NULL if the character is a function key or another
240      * non-printing key.
241      */
242     if (c == 0x10) {
243         len = 0;
244     } else {
245         hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) virtualKey);
246         if (hPtr != NULL) {
247             len = 0;
248         }
249     }
250     return Tcl_ExternalToUtfDString(NULL, string, len, dsPtr);
251 }
252 \f
253 /*
254  *----------------------------------------------------------------------
255  *
256  * XGetModifierMapping --
257  *
258  *      Fetch the current keycodes used as modifiers.
259  *
260  * Results:
261  *      Returns a new modifier map.
262  *
263  * Side effects:
264  *      Allocates a new modifier map data structure.
265  *
266  *----------------------------------------------------------------------
267  */
268
269 XModifierKeymap * 
270 XGetModifierMapping(
271     Display* display)
272
273     XModifierKeymap * modmap;
274
275     modmap = (XModifierKeymap *) ckalloc(sizeof(XModifierKeymap));
276     modmap->max_keypermod = 0;
277     modmap->modifiermap = NULL;
278     return modmap;
279 }
280 \f
281 /*
282  *----------------------------------------------------------------------
283  *
284  * XFreeModifiermap --
285  *
286  *      Deallocate a modifier map that was created by
287  *      XGetModifierMapping.
288  *
289  * Results:
290  *      None.
291  *
292  * Side effects:
293  *      Frees the datastructure referenced by modmap.
294  *
295  *----------------------------------------------------------------------
296  */
297
298 void 
299 XFreeModifiermap(
300     XModifierKeymap *modmap)
301 {
302     if (modmap->modifiermap != NULL) {
303         ckfree((char *) modmap->modifiermap);
304     }
305     ckfree((char *) modmap);
306 }
307 \f
308 /*
309  *----------------------------------------------------------------------
310  *
311  * XKeysymToString, XStringToKeysym --
312  *
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.
317  *
318  * Results:
319  *      None.
320  *
321  * Side effects:
322  *      None.
323  *
324  *----------------------------------------------------------------------
325  */
326
327 char * 
328 XKeysymToString(
329     KeySym keysym)
330 {
331     return NULL; 
332 }
333
334 KeySym 
335 XStringToKeysym(
336     const char* string)
337
338     return NoSymbol;
339 }
340 \f
341 /*
342  *----------------------------------------------------------------------
343  *
344  * XKeysymToKeycode --
345  *
346  *      The function XKeysymToKeycode is only used by tkTest.c and
347  *      currently only implementes the support for keys used in the
348  *      Tk test suite.
349  *      FIXME - This is no longer true.  This function is now used in
350  *      "event generate" so we really should make it work.
351  *
352  * Results:
353  *      None.
354  *
355  * Side effects:
356  *      None.
357  *
358  *----------------------------------------------------------------------
359  */
360
361 KeyCode
362 XKeysymToKeycode(
363     Display* display,
364     KeySym keysym)
365 {
366     KeyCode keycode = 0;
367     char virtualKeyCode = 0;
368     
369     if ((keysym >= XK_space) && (XK_asciitilde)) {
370         if (keysym == 'a') {
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;
384             keysym = '\r';
385         }
386         keycode = keysym + (virtualKeyCode <<16);
387     }
388
389     return keycode;
390 }
391 \f
392 /*
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
397  * keysym.
398  */
399
400 void
401 TkpSetKeycodeAndState(tkwin, keySym, eventPtr)
402     Tk_Window tkwin;
403     KeySym keySym;
404     XEvent *eventPtr;
405 {
406     Display *display;
407     int state;
408     KeyCode keycode;
409     
410     display = Tk_Display(tkwin);
411     
412     if (keySym == NoSymbol) {
413         keycode = 0;
414     } else {
415         keycode = XKeysymToKeycode(display, keySym);
416     }
417     if (keycode != 0) {
418         for (state = 0; state < 4; state++) {
419             if (XKeycodeToKeysym(display, keycode, state) == keySym) {
420                 if (state & 1) {
421                     eventPtr->xkey.state |= ShiftMask;
422                 }
423                 if (state & 2) {
424                     TkDisplay *dispPtr;
425
426                     dispPtr = ((TkWindow *) tkwin)->dispPtr; 
427                     eventPtr->xkey.state |= dispPtr->modeModMask;
428                 }
429                 break;
430             }
431         }
432     }
433     eventPtr->xkey.keycode = keycode;
434 }
435 \f
436 /*
437  *----------------------------------------------------------------------
438  *
439  * TkpGetKeySym --
440  *
441  *      Given an X KeyPress or KeyRelease event, map the
442  *      keycode in the event into a KeySym.
443  *
444  * Results:
445  *      The return value is the KeySym corresponding to
446  *      eventPtr, or NoSymbol if no matching Keysym could be
447  *      found.
448  *
449  * Side effects:
450  *      In the first call for a given display, keycode-to-
451  *      KeySym maps get loaded.
452  *
453  *----------------------------------------------------------------------
454  */
455
456 KeySym
457 TkpGetKeySym(dispPtr, eventPtr)
458     TkDisplay *dispPtr; /* Display in which to
459                                          * map keycode. */
460     XEvent *eventPtr;           /* Description of X event. */
461 {
462     KeySym sym;
463     int index;
464
465     /*
466      * Refresh the mapping information if it's stale
467      */
468
469     if (dispPtr->bindInfoStale) {
470         TkpInitKeymapInfo(dispPtr);
471     }
472
473     /*
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.
477      */
478
479     index = 0;
480     if (eventPtr->xkey.state & dispPtr->modeModMask) {
481         index = 2;
482     }
483     if ((eventPtr->xkey.state & ShiftMask)
484             || ((dispPtr->lockUsage != LU_IGNORE)
485             && (eventPtr->xkey.state & LockMask))) {
486         index += 1;
487     }
488     sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index);
489
490     /*
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
494      * keysym.
495      */
496
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)))) {
502             index &= ~1;
503             sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
504                     index);
505         }
506     }
507
508     /*
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.
511      */
512
513     if ((index & 1) && (sym == NoSymbol)) {
514         sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
515                 index & ~1);
516     }
517     return sym;
518 }
519 \f
520 /*
521  *--------------------------------------------------------------
522  *
523  * TkpInitKeymapInfo --
524  *
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
528  *      switch".
529  *
530  * Results:
531  *      None.
532  *
533  * Side effects:
534  *      Keymap-related information in dispPtr is updated.
535  *
536  *--------------------------------------------------------------
537  */
538
539 void
540 TkpInitKeymapInfo(dispPtr)
541     TkDisplay *dispPtr;         /* Display for which to recompute keymap
542                                  * information. */
543 {
544     XModifierKeymap *modMapPtr;
545     KeyCode *codePtr;
546     KeySym keysym;
547     int count, i, j, max, arraySize;
548 #define KEYCODE_ARRAY_SIZE 20
549
550     dispPtr->bindInfoStale = 0;
551     modMapPtr = XGetModifierMapping(dispPtr->display);
552
553     /*
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.
557      */
558
559     dispPtr->lockUsage = LU_IGNORE;
560     codePtr = modMapPtr->modifiermap + modMapPtr->max_keypermod*LockMapIndex;
561     for (count = modMapPtr->max_keypermod; count > 0; count--, codePtr++) {
562         if (*codePtr == 0) {
563             continue;
564         }
565         keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0);
566         if (keysym == XK_Shift_Lock) {
567             dispPtr->lockUsage = LU_SHIFT;
568             break;
569         }
570         if (keysym == XK_Caps_Lock) {
571             dispPtr->lockUsage = LU_CAPS;
572             break;
573         }
574     }
575
576     /*
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.
580      */
581
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++) {
588         if (*codePtr == 0) {
589             continue;
590         }
591         keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0);
592         if (keysym == XK_Mode_switch) {
593             dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
594         }
595         if ((keysym == XK_Meta_L) || (keysym == XK_Meta_R)) {
596             dispPtr->metaModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
597         }
598         if ((keysym == XK_Alt_L) || (keysym == XK_Alt_R)) {
599             dispPtr->altModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
600         }
601     }
602
603     /*
604      * Create an array of the keycodes for all modifier keys.
605      */
606
607     if (dispPtr->modKeyCodes != NULL) {
608         ckfree((char *) dispPtr->modKeyCodes);
609     }
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++) {
615         if (*codePtr == 0) {
616             continue;
617         }
618
619         /*
620          * Make sure that the keycode isn't already in the array.
621          */
622
623         for (j = 0; j < dispPtr->numModKeyCodes; j++) {
624             if (dispPtr->modKeyCodes[j] == *codePtr) {
625                 goto nextModCode;
626             }
627         }
628         if (dispPtr->numModKeyCodes >= arraySize) {
629             KeyCode *new;
630
631             /*
632              * Ran out of space in the array;  grow it.
633              */
634
635             arraySize *= 2;
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;
642         }
643         dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr;
644         dispPtr->numModKeyCodes++;
645         nextModCode: continue;
646     }
647     XFreeModifiermap(modMapPtr);
648 }
649
650