diff options
-rw-r--r-- | macosx/tkMacOSXKeyboard.c | 1648 |
1 files changed, 824 insertions, 824 deletions
diff --git a/macosx/tkMacOSXKeyboard.c b/macosx/tkMacOSXKeyboard.c index c79a2d0..f1c2f12 100644 --- a/macosx/tkMacOSXKeyboard.c +++ b/macosx/tkMacOSXKeyboard.c @@ -1,824 +1,824 @@ -/*
- * tkMacOSXKeyboard.c --
- *
- * Routines to support keyboard events on the Macintosh.
- *
- * Copyright (c) 1995-1997 Sun Microsystems, Inc.
- * Copyright 2001, Apple Computer, Inc.
- *
- * See the file "license.terms" for information on usage and redistribution
- * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
- *
- * RCS: @(#) $Id: tkMacOSXKeyboard.c,v 1.15 2004/02/07 16:21:08 cc_benny Exp $
- */
-
-#include "tkInt.h"
-#include "X11/Xlib.h"
-#include "X11/keysym.h"
-#include <Carbon/Carbon.h>
-#include "tkMacOSXInt.h"
-#include "tkMacOSXEvent.h" /* TkMacOSXKeycodeToUnicode() FIXME: That
- * function should probably move here. */
-
-/*
- * A couple of simple definitions to make code a bit more self-explaining.
- *
- * For the assignments of Mod1==alt==command and Mod2==meta==option, see also
- * tkMacOSXMouseEvent.c.
- */
-
-#define LATIN1_MAX 255
-#define MAC_KEYCODE_MAX 0x7F
-#define MAC_KEYCODE_MASK 0x7F
-#define ALT_MASK Mod1Mask
-#define OPTION_MASK Mod2Mask
-
-
-/*
- * Tables enumerating the special keys defined on Mac keyboards. These are
- * necessary for correct keysym mappings for all keys where the keysyms are
- * not identical with their ASCII or Latin-1 code points.
- */
-
-typedef struct {
- int keycode; /* Macintosh keycode. */
- KeySym keysym; /* X windows keysym. */
-} KeyInfo;
-
-/*
- * Notes on keyArray:
- *
- * 0x34, XK_Return - Powerbooks use this and some keymaps define it.
- *
- * 0x4C, XK_Return - XFree86 and Apple's X11 call this one XK_KP_Enter.
- *
- * 0x47, XK_Clear - This key is NumLock when used on PCs, but Mac
- * applications don't use it like that, nor does Apple's X11.
- *
- * All other keycodes are taken from the published ADB keyboard layouts.
- */
-
-static KeyInfo keyArray[] = {
- {0x24, XK_Return},
- {0x30, XK_Tab},
- {0x33, XK_BackSpace},
- {0x34, XK_Return},
- {0x35, XK_Escape},
-
- {0x47, XK_Clear},
- {0x4C, XK_Return},
-
- {0x72, XK_Help},
- {0x73, XK_Home},
- {0x74, XK_Page_Up},
- {0x75, XK_Delete},
- {0x77, XK_End},
- {0x79, XK_Page_Down},
-
- {0x7B, XK_Left},
- {0x7C, XK_Right},
- {0x7D, XK_Down},
- {0x7E, XK_Up},
-
- {0, 0}
-};
-
-static KeyInfo virtualkeyArray[] = {
- {122, XK_F1},
- {120, XK_F2},
- {99, XK_F3},
- {118, XK_F4},
- {96, XK_F5},
- {97, XK_F6},
- {98, XK_F7},
- {100, XK_F8},
- {101, XK_F9},
- {109, XK_F10},
- {103, XK_F11},
- {111, XK_F12},
- {105, XK_F13},
- {107, XK_F14},
- {113, XK_F15},
- {0, 0}
-};
-
-static int initialized = 0;
-static Tcl_HashTable keycodeTable; /* keyArray hashed by keycode value. */
-static Tcl_HashTable vkeyTable; /* virtualkeyArray hashed by virtual
- * keycode value. */
-
-static int latin1Table[LATIN1_MAX+1]; /* Reverse mapping table for
- * controls, ASCII and Latin-1. */
-
-/*
- * Prototypes for static functions used in this file.
- */
-
-static void InitKeyMaps (void);
-static void InitLatin1Table(Display *display);
-static int XKeysymToMacKeycode(Display *display, KeySym keysym);
-
-
-/*
- *----------------------------------------------------------------------
- *
- * InitKeyMaps --
- *
- * Creates hash tables used by some of the functions in this file.
- *
- * FIXME: As keycodes are defined to be in the limited range 0-127, it
- * would be easier and more efficient to use directly initialized plain
- * arrays and drop this function.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Allocates memory & creates some hash tables.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-InitKeyMaps()
-{
- Tcl_HashEntry *hPtr;
- KeyInfo *kPtr;
- int dummy;
-
- Tcl_InitHashTable(&keycodeTable, TCL_ONE_WORD_KEYS);
- for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) {
- hPtr = Tcl_CreateHashEntry(&keycodeTable, (char *) kPtr->keycode,
- &dummy);
- Tcl_SetHashValue(hPtr, kPtr->keysym);
- }
- Tcl_InitHashTable(&vkeyTable, TCL_ONE_WORD_KEYS);
- for (kPtr = virtualkeyArray; kPtr->keycode != 0; kPtr++) {
- hPtr = Tcl_CreateHashEntry(&vkeyTable, (char *) kPtr->keycode,
- &dummy);
- Tcl_SetHashValue(hPtr, kPtr->keysym);
- }
- initialized = 1;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * InitLatin1Table --
- *
- * Creates a simple table to be used for mapping from keysyms to
- * keycodes. Always needs to be called before using latin1Table,
- * because the keyboard layout may have changed, and than the table must
- * be re-computed.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Sets the global latin1Table.
- *
- *----------------------------------------------------------------------
- */
-
-static void
-InitLatin1Table(
- Display *display)
-{
- static Boolean latin1_initialized = false;
- static SInt16 lastKeyLayoutID = -1;
-
- SInt16 keyScript;
- SInt16 keyLayoutID;
-
- keyScript = GetScriptManagerVariable(smKeyScript);
- keyLayoutID = GetScriptVariable(keyScript,smScriptKeys);
-
- if (!latin1_initialized || (lastKeyLayoutID != keyLayoutID)) {
- int keycode;
- KeySym keysym;
- int state;
- int modifiers;
-
- latin1_initialized = true;
- lastKeyLayoutID = keyLayoutID;
-
- memset(latin1Table, 0, sizeof(latin1Table));
-
- /*
- * In the common X11 implementations, a keymap has four columns
- * "plain", "Shift", "Mode_switch" and "Mode_switch + Shift". We
- * don't use "Mode_switch", but we use "Option" instead. (This is
- * similar to Apple's X11 implementation, where "Mode_switch" is used
- * as an alias for "Option".)
- *
- * So here we go through all 4 columns of the keymap and find all
- * Latin-1 compatible keycodes. We go through the columns
- * back-to-front from the more exotic columns to the more simple, so
- * that simple keycode-modifier combinations are preferred in the
- * resulting table.
- */
-
- for (state = 3; state >= 0; state--) {
- modifiers = 0;
- if (state & 1) {
- modifiers |= shiftKey;
- }
- if (state & 2) {
- modifiers |= optionKey;
- }
-
- for (keycode = 0; keycode <= MAC_KEYCODE_MAX; keycode++) {
- keysym = XKeycodeToKeysym(display,keycode<<16,state);
- if (keysym <= LATIN1_MAX) {
- latin1Table[keysym] = keycode | modifiers;
- }
- }
- }
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * XKeycodeToKeysym --
- *
- * Translate from a system-dependent keycode to a system-independent
- * keysym.
- *
- * Results:
- * Returns the translated keysym, or NoSymbol on failure.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-KeySym
-XKeycodeToKeysym(
- Display* display,
- KeyCode keycode,
- int index)
-{
- register Tcl_HashEntry *hPtr;
- int newKeycode;
- UniChar newChar;
-
- (void) display; /*unused*/
-
- if (!initialized) {
- InitKeyMaps();
- }
-
- /*
- * When determining what keysym to produce we first check to see if the
- * key is a function key. We then check to see if the character is
- * another non-printing key. Finally, we return the key syms for all
- * ASCII and Latin-1 chars.
- */
-
- newKeycode = keycode >> 16;
-
- if ((keycode & 0xFFFF) == 0x10) {
- hPtr = Tcl_FindHashEntry(&vkeyTable, (char *) newKeycode);
- if (hPtr != NULL) {
- return (KeySym) Tcl_GetHashValue(hPtr);
- }
- }
- hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) newKeycode);
- if (hPtr != NULL) {
- return (KeySym) Tcl_GetHashValue(hPtr);
- }
-
- /*
- * Add in the Mac modifier flags for shift and option.
- */
-
- if (index & 1) {
- newKeycode |= shiftKey;
- }
- if (index & 2) {
- newKeycode |= optionKey;
- }
-
- newChar = 0;
- TkMacOSXKeycodeToUnicode(
- &newChar, 1, kEventRawKeyDown,
- newKeycode & 0x00FF, newKeycode & 0xFF00, NULL);
-
- /*
- * X11 keysyms are identical to Unicode for ASCII and Latin-1. Give up
- * for other characters for now.
- */
-
- if ((newChar >= XK_space) && (newChar <= LATIN1_MAX)) {
- return newChar;
- }
-
- return NoSymbol;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpGetString --
- *
- * Retrieve the string equivalent for the given keyboard event.
- *
- * Results:
- * Returns the UTF string.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-char *
-TkpGetString(
- TkWindow *winPtr, /* Window where event occurred: Needed to get
- * input context. */
- XEvent *eventPtr, /* X keyboard event. */
- Tcl_DString *dsPtr) /* Uninitialized or empty string to hold
- * result. */
-{
- (void) winPtr; /*unused*/
- Tcl_DStringInit(dsPtr);
- return Tcl_DStringAppend(dsPtr, eventPtr->xkey.trans_chars, -1);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * XGetModifierMapping --
- *
- * Fetch the current keycodes used as modifiers.
- *
- * Results:
- * Returns a new modifier map.
- *
- * Side effects:
- * Allocates a new modifier map data structure.
- *
- *----------------------------------------------------------------------
- */
-
-XModifierKeymap *
-XGetModifierMapping(
- Display* display)
-{
- XModifierKeymap * modmap;
-
- (void) display; /*unused*/
-
- /*
- * MacOSX doesn't use the key codes for the modifiers for anything, and
- * we don't generate them either. So there is no modifier map.
- */
-
- modmap = (XModifierKeymap *) ckalloc(sizeof(XModifierKeymap));
- modmap->max_keypermod = 0;
- modmap->modifiermap = NULL;
- return modmap;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * XFreeModifiermap --
- *
- * Deallocate a modifier map that was created by XGetModifierMapping.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Frees the datastructure referenced by modmap.
- *
- *----------------------------------------------------------------------
- */
-
-void
-XFreeModifiermap(
- XModifierKeymap *modmap)
-{
- if (modmap->modifiermap != NULL) {
- ckfree((char *) modmap->modifiermap);
- }
- ckfree((char *) modmap);
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * XKeysymToString, XStringToKeysym --
- *
- * These X window functions map keysyms to strings & strings to keysyms.
- * However, Tk already does this for the most common keysyms.
- * Therefore, these functions only need to support keysyms that will be
- * specific to the Macintosh. Currently, there are none.
- *
- * Results:
- * None.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-char *
-XKeysymToString(
- KeySym keysym)
-{
- return NULL;
-}
-
-KeySym
-XStringToKeysym(
- const char* string)
-{
- return NoSymbol;
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * XKeysymToMacKeycode --
- *
- * An internal function like XKeysymToKeycode but only generating the
- * Mac specific keycode plus the modifiers Shift and Option.
- *
- * Results:
- * A Mac keycode with the actual keycode in the low byte and Mac-style
- * modifier bits in the high byte.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-static int
-XKeysymToMacKeycode(
- Display *display,
- KeySym keysym)
-{
- if (keysym <= LATIN1_MAX) {
-
- /*
- * Handle keysyms in the Latin-1 range where keysym and Unicode
- * character code point are the same.
- */
-
- InitLatin1Table(display);
- return latin1Table[keysym];
-
- } else {
-
- /*
- * Handle special keys from our exception tables. Don't mind if this
- * is slow, neither the test suite nor [event generate] need to be
- * optimized (we hope).
- */
-
- KeyInfo *kPtr;
-
- for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) {
- if (kPtr->keysym == keysym) {
- return kPtr->keycode;
- }
- }
- for (kPtr = virtualkeyArray; kPtr->keycode != 0; kPtr++) {
- if (kPtr->keysym == keysym) {
- return kPtr->keycode;
- }
- }
-
- /*
- * For other keysyms (not Latin-1 and not special keys), we'd need a
- * generic keysym-to-unicode table. We don't have that, so we give
- * up here.
- */
-
- return 0;
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * XKeysymToKeycode --
- *
- * The function XKeysymToKeycode takes an X11 keysym and converts it
- * into a Mac keycode. It is in the stubs table for compatibility but
- * not used anywhere in the core.
- *
- * Results:
- * A 32 bit keycode with the the mac keycode (without modifiers) in the
- * higher 16 bits of the keycode and the ASCII or Latin-1 code in the
- * lower 8 bits of the keycode.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-KeyCode
-XKeysymToKeycode(
- Display* display,
- KeySym keysym)
-{
- int macKeycode = XKeysymToMacKeycode(display, keysym);
- KeyCode result;
-
- /*
- * See also TkpSetKeycodeAndState. The 0x0010 magic is used in
- * XKeycodeToKeysym. For special keys like XK_Return the lower 8 bits of
- * the keysym are usually a related ASCII control code.
- */
-
- if ((keysym >= XK_F1) && (keysym <= XK_F35)) {
- result = 0x0010;
- } else {
- result = 0x00FF & keysym;
- }
- result |= (macKeycode & MAC_KEYCODE_MASK) << 16;
-
- return result;
-}
-
-/*
-NB: Keep this commented code for a moment for reference.
-
- if ((keysym >= XK_space) && (XK_asciitilde)) {
- if (keysym == 'a') {
- virtualKeyCode = 0x00;
- } else if (keysym == 'b' || keysym == 'B') {
- virtualKeyCode = 0x0B;
- } else if (keysym == 'c') {
- virtualKeyCode = 0x08;
- } else if (keysym == 'x' || keysym == 'X') {
- virtualKeyCode = 0x07;
- } else if (keysym == 'z') {
- virtualKeyCode = 0x06;
- } else if (keysym == ' ') {
- virtualKeyCode = 0x31;
- } else if (keysym == XK_Return) {
- virtualKeyCode = 0x24;
- keysym = '\r';
- }
- keycode = keysym + (virtualKeyCode <<16);
- }
-
- return keycode;
-*/
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpSetKeycodeAndState --
- *
- * The function TkpSetKeycodeAndState takes a keysym and fills in the
- * appropriate members of an XEvent. It is similar to XKeysymToKeycode,
- * but it also sets the modifier mask in the XEvent. It is used by
- * [event generate] and it is in the stubs table.
- *
- * Results:
- * Fills an XEvent, sets the member xkey.keycode with a keycode
- * formatted the same as XKeysymToKeycode and the member xkey.state with
- * the modifiers implied by the keysym. Also fills in xkey.trans_chars,
- * so that the actual characters can be retrieved later.
- *
- * Side effects:
- * None.
- *
- *----------------------------------------------------------------------
- */
-
-void
-TkpSetKeycodeAndState(
- Tk_Window tkwin,
- KeySym keysym,
- XEvent *eventPtr)
-{
- if (keysym == NoSymbol) {
- eventPtr->xkey.keycode = 0;
- } else {
- Display *display = Tk_Display(tkwin);
- int macKeycode = XKeysymToMacKeycode(display, keysym);
-
- /*
- * See also XKeysymToKeycode.
- */
-
- if ((keysym >= XK_F1) && (keysym <= XK_F35)) {
- eventPtr->xkey.keycode = 0x0010;
- } else {
- eventPtr->xkey.keycode = 0x00FF & keysym;
- }
- eventPtr->xkey.keycode |= (macKeycode & MAC_KEYCODE_MASK) << 16;
-
- if (shiftKey & macKeycode) {
- eventPtr->xkey.state |= ShiftMask;
- }
- if (optionKey & macKeycode) {
- eventPtr->xkey.state |= OPTION_MASK;
- }
-
- if (keysym <= LATIN1_MAX) {
- int done;
- done = Tcl_UniCharToUtf(keysym,eventPtr->xkey.trans_chars);
- eventPtr->xkey.trans_chars[done] = 0;
- } else {
- eventPtr->xkey.trans_chars[0] = 0;
- }
- }
-}
-
-/*
- *----------------------------------------------------------------------
- *
- * TkpGetKeySym --
- *
- * Given an X KeyPress or KeyRelease event, map the keycode in the event
- * into a keysym.
- *
- * Results:
- * The return value is the keysym corresponding to eventPtr, or NoSymbol
- * if no matching keysym could be found.
- *
- * Side effects:
- * In the first call for a given display, keycode-to-keysym maps get
- * loaded.
- *
- *----------------------------------------------------------------------
- */
-
-KeySym
-TkpGetKeySym(
- TkDisplay *dispPtr, /* Display in which to map keycode. */
- XEvent *eventPtr) /* Description of X event. */
-{
- KeySym sym;
- int index;
-
- /*
- * Refresh the mapping information if it's stale.
- */
-
- if (dispPtr->bindInfoStale) {
- TkpInitKeymapInfo(dispPtr);
- }
-
- /*
- * Handle pure modifier keys specially. We use -1 as a signal for
- * this.
- */
-
- if (eventPtr->xany.send_event == -1) {
- int modifier = eventPtr->xkey.keycode;
- if (modifier == cmdKey) {
- return XK_Alt_L;
- } else if (modifier == shiftKey) {
- return XK_Shift_L;
- } else if (modifier == alphaLock) {
- return XK_Caps_Lock;
- } else if (modifier == optionKey) {
- return XK_Meta_L;
- } else if (modifier == controlKey) {
- return XK_Control_L;
- } else if (modifier == rightShiftKey) {
- return XK_Shift_R;
- } else if (modifier == rightOptionKey) {
- return XK_Meta_R;
- } else if (modifier == rightControlKey) {
- return XK_Control_R;
- } else {
-
- /*
- * If we get here, we probably need to implement something new.
- */
-
- return NoSymbol;
- }
- }
-
- /*
- * Figure out which of the four slots in the keymap vector to use for
- * this key. Refer to Xlib documentation for more info on how this
- * computation works. (Note: We use "Option" in keymap columns 2 and 3
- * where other implementations have "Mode_switch".)
- */
-
- index = 0;
-
- /*
- * We want Option key combinations to use their base chars as keysyms, so
- * we ignore the option modifier here.
- */
-
-#if 0
- if (eventPtr->xkey.state & OPTION_MASK) {
- index |= 2;
- }
-#endif
-
- if ((eventPtr->xkey.state & ShiftMask)
- || (/* (dispPtr->lockUsage != LU_IGNORE)
- && */ (eventPtr->xkey.state & LockMask))) {
- index |= 1;
- }
-
- /*
- * First try of the actual translation.
- */
-
- sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index);
-
- /*
- * Special handling: If the key was shifted because of Lock, but lock is
- * only caps lock, not shift lock, and the shifted keysym isn't
- * upper-case alphabetic, then switch back to the unshifted keysym.
- */
-
- if ((index & 1) && !(eventPtr->xkey.state & ShiftMask)
- /*&& (dispPtr->lockUsage == LU_CAPS)*/ ) {
-
- /*
- * FIXME: Keysyms are only identical to Unicode for ASCII and
- * Latin-1, so we can't use Tcl_UniCharIsUpper() for keysyms outside
- * that range. This may be a serious problem here.
- */
-
- if ((sym == NoSymbol) || (sym > LATIN1_MAX)
- || !Tcl_UniCharIsUpper(sym)) {
- index &= ~1;
- sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
- index);
- }
- }
-
- /*
- * Another bit of special handling: If this is a shifted key and there is
- * no keysym defined, then use the keysym for the unshifted key.
- */
-
- if ((index & 1) && (sym == NoSymbol)) {
- sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
- index & ~1);
- }
- return sym;
-}
-
-/*
- *--------------------------------------------------------------
- *
- * TkpInitKeymapInfo --
- *
- * This procedure is invoked to scan keymap information to recompute
- * stuff that's important for binding, such as the modifier key (if any)
- * that corresponds to the "Mode_switch" keysym.
- *
- * Results:
- * None.
- *
- * Side effects:
- * Keymap-related information in dispPtr is updated.
- *
- *--------------------------------------------------------------
- */
-
-void
-TkpInitKeymapInfo(
- TkDisplay *dispPtr) /* Display for which to recompute keymap
- * information. */
-{
- dispPtr->bindInfoStale = 0;
-
- /*
- * Behaviours that are variable on X11 are defined constant on MacOSX.
- * lockUsage is only used above in TkpGetKeySym(), nowhere else
- * currently. There is no offical "Mode_switch" key.
- */
-
- dispPtr->lockUsage = LU_CAPS;
- dispPtr->modeModMask = 0;
- dispPtr->altModMask = ALT_MASK;
- dispPtr->metaModMask = OPTION_MASK;
-
- /*
- * MacOSX doesn't use the keycodes for the modifiers for anything, and we
- * don't generate them either (the keycodes actually given in the
- * simulated modifier events are bogus). So there is no modifier map.
- * If we ever want to simulate real modifier keycodes, the list will be
- * constant in the Carbon implementation.
- */
-
- if (dispPtr->modKeyCodes != NULL) {
- ckfree((char *) dispPtr->modKeyCodes);
- }
- dispPtr->numModKeyCodes = 0;
- dispPtr->modKeyCodes = NULL;
-}
+/* + * tkMacOSXKeyboard.c -- + * + * Routines to support keyboard events on the Macintosh. + * + * Copyright (c) 1995-1997 Sun Microsystems, Inc. + * Copyright 2001, Apple Computer, Inc. + * + * See the file "license.terms" for information on usage and redistribution + * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * + * RCS: @(#) $Id: tkMacOSXKeyboard.c,v 1.16 2004/02/14 16:32:39 cc_benny Exp $ + */ + +#include "tkInt.h" +#include "X11/Xlib.h" +#include "X11/keysym.h" +#include <Carbon/Carbon.h> +#include "tkMacOSXInt.h" +#include "tkMacOSXEvent.h" /* TkMacOSXKeycodeToUnicode() FIXME: That + * function should probably move here. */ + +/* + * A couple of simple definitions to make code a bit more self-explaining. + * + * For the assignments of Mod1==alt==command and Mod2==meta==option, see also + * tkMacOSXMouseEvent.c. + */ + +#define LATIN1_MAX 255 +#define MAC_KEYCODE_MAX 0x7F +#define MAC_KEYCODE_MASK 0x7F +#define ALT_MASK Mod1Mask +#define OPTION_MASK Mod2Mask + + +/* + * Tables enumerating the special keys defined on Mac keyboards. These are + * necessary for correct keysym mappings for all keys where the keysyms are + * not identical with their ASCII or Latin-1 code points. + */ + +typedef struct { + int keycode; /* Macintosh keycode. */ + KeySym keysym; /* X windows keysym. */ +} KeyInfo; + +/* + * Notes on keyArray: + * + * 0x34, XK_Return - Powerbooks use this and some keymaps define it. + * + * 0x4C, XK_Return - XFree86 and Apple's X11 call this one XK_KP_Enter. + * + * 0x47, XK_Clear - This key is NumLock when used on PCs, but Mac + * applications don't use it like that, nor does Apple's X11. + * + * All other keycodes are taken from the published ADB keyboard layouts. + */ + +static KeyInfo keyArray[] = { + {0x24, XK_Return}, + {0x30, XK_Tab}, + {0x33, XK_BackSpace}, + {0x34, XK_Return}, + {0x35, XK_Escape}, + + {0x47, XK_Clear}, + {0x4C, XK_Return}, + + {0x72, XK_Help}, + {0x73, XK_Home}, + {0x74, XK_Page_Up}, + {0x75, XK_Delete}, + {0x77, XK_End}, + {0x79, XK_Page_Down}, + + {0x7B, XK_Left}, + {0x7C, XK_Right}, + {0x7D, XK_Down}, + {0x7E, XK_Up}, + + {0, 0} +}; + +static KeyInfo virtualkeyArray[] = { + {122, XK_F1}, + {120, XK_F2}, + {99, XK_F3}, + {118, XK_F4}, + {96, XK_F5}, + {97, XK_F6}, + {98, XK_F7}, + {100, XK_F8}, + {101, XK_F9}, + {109, XK_F10}, + {103, XK_F11}, + {111, XK_F12}, + {105, XK_F13}, + {107, XK_F14}, + {113, XK_F15}, + {0, 0} +}; + +static int initialized = 0; +static Tcl_HashTable keycodeTable; /* keyArray hashed by keycode value. */ +static Tcl_HashTable vkeyTable; /* virtualkeyArray hashed by virtual + * keycode value. */ + +static int latin1Table[LATIN1_MAX+1]; /* Reverse mapping table for + * controls, ASCII and Latin-1. */ + +/* + * Prototypes for static functions used in this file. + */ + +static void InitKeyMaps (void); +static void InitLatin1Table(Display *display); +static int XKeysymToMacKeycode(Display *display, KeySym keysym); + + +/* + *---------------------------------------------------------------------- + * + * InitKeyMaps -- + * + * Creates hash tables used by some of the functions in this file. + * + * FIXME: As keycodes are defined to be in the limited range 0-127, it + * would be easier and more efficient to use directly initialized plain + * arrays and drop this function. + * + * Results: + * None. + * + * Side effects: + * Allocates memory & creates some hash tables. + * + *---------------------------------------------------------------------- + */ + +static void +InitKeyMaps() +{ + Tcl_HashEntry *hPtr; + KeyInfo *kPtr; + int dummy; + + Tcl_InitHashTable(&keycodeTable, TCL_ONE_WORD_KEYS); + for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) { + hPtr = Tcl_CreateHashEntry(&keycodeTable, (char *) kPtr->keycode, + &dummy); + Tcl_SetHashValue(hPtr, kPtr->keysym); + } + Tcl_InitHashTable(&vkeyTable, TCL_ONE_WORD_KEYS); + for (kPtr = virtualkeyArray; kPtr->keycode != 0; kPtr++) { + hPtr = Tcl_CreateHashEntry(&vkeyTable, (char *) kPtr->keycode, + &dummy); + Tcl_SetHashValue(hPtr, kPtr->keysym); + } + initialized = 1; +} + +/* + *---------------------------------------------------------------------- + * + * InitLatin1Table -- + * + * Creates a simple table to be used for mapping from keysyms to + * keycodes. Always needs to be called before using latin1Table, + * because the keyboard layout may have changed, and than the table must + * be re-computed. + * + * Results: + * None. + * + * Side effects: + * Sets the global latin1Table. + * + *---------------------------------------------------------------------- + */ + +static void +InitLatin1Table( + Display *display) +{ + static Boolean latin1_initialized = false; + static SInt16 lastKeyLayoutID = -1; + + SInt16 keyScript; + SInt16 keyLayoutID; + + keyScript = GetScriptManagerVariable(smKeyScript); + keyLayoutID = GetScriptVariable(keyScript,smScriptKeys); + + if (!latin1_initialized || (lastKeyLayoutID != keyLayoutID)) { + int keycode; + KeySym keysym; + int state; + int modifiers; + + latin1_initialized = true; + lastKeyLayoutID = keyLayoutID; + + memset(latin1Table, 0, sizeof(latin1Table)); + + /* + * In the common X11 implementations, a keymap has four columns + * "plain", "Shift", "Mode_switch" and "Mode_switch + Shift". We + * don't use "Mode_switch", but we use "Option" instead. (This is + * similar to Apple's X11 implementation, where "Mode_switch" is used + * as an alias for "Option".) + * + * So here we go through all 4 columns of the keymap and find all + * Latin-1 compatible keycodes. We go through the columns + * back-to-front from the more exotic columns to the more simple, so + * that simple keycode-modifier combinations are preferred in the + * resulting table. + */ + + for (state = 3; state >= 0; state--) { + modifiers = 0; + if (state & 1) { + modifiers |= shiftKey; + } + if (state & 2) { + modifiers |= optionKey; + } + + for (keycode = 0; keycode <= MAC_KEYCODE_MAX; keycode++) { + keysym = XKeycodeToKeysym(display,keycode<<16,state); + if (keysym <= LATIN1_MAX) { + latin1Table[keysym] = keycode | modifiers; + } + } + } + } +} + +/* + *---------------------------------------------------------------------- + * + * XKeycodeToKeysym -- + * + * Translate from a system-dependent keycode to a system-independent + * keysym. + * + * Results: + * Returns the translated keysym, or NoSymbol on failure. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +KeySym +XKeycodeToKeysym( + Display* display, + KeyCode keycode, + int index) +{ + register Tcl_HashEntry *hPtr; + int newKeycode; + UniChar newChar; + + (void) display; /*unused*/ + + if (!initialized) { + InitKeyMaps(); + } + + /* + * When determining what keysym to produce we first check to see if the + * key is a function key. We then check to see if the character is + * another non-printing key. Finally, we return the key syms for all + * ASCII and Latin-1 chars. + */ + + newKeycode = keycode >> 16; + + if ((keycode & 0xFFFF) == 0x10) { + hPtr = Tcl_FindHashEntry(&vkeyTable, (char *) newKeycode); + if (hPtr != NULL) { + return (KeySym) Tcl_GetHashValue(hPtr); + } + } + hPtr = Tcl_FindHashEntry(&keycodeTable, (char *) newKeycode); + if (hPtr != NULL) { + return (KeySym) Tcl_GetHashValue(hPtr); + } + + /* + * Add in the Mac modifier flags for shift and option. + */ + + if (index & 1) { + newKeycode |= shiftKey; + } + if (index & 2) { + newKeycode |= optionKey; + } + + newChar = 0; + TkMacOSXKeycodeToUnicode( + &newChar, 1, kEventRawKeyDown, + newKeycode & 0x00FF, newKeycode & 0xFF00, NULL); + + /* + * X11 keysyms are identical to Unicode for ASCII and Latin-1. Give up + * for other characters for now. + */ + + if ((newChar >= XK_space) && (newChar <= LATIN1_MAX)) { + return newChar; + } + + return NoSymbol; +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetString -- + * + * Retrieve the string equivalent for the given keyboard event. + * + * Results: + * Returns the UTF string. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +TkpGetString( + TkWindow *winPtr, /* Window where event occurred: Needed to get + * input context. */ + XEvent *eventPtr, /* X keyboard event. */ + Tcl_DString *dsPtr) /* Uninitialized or empty string to hold + * result. */ +{ + (void) winPtr; /*unused*/ + Tcl_DStringInit(dsPtr); + return Tcl_DStringAppend(dsPtr, eventPtr->xkey.trans_chars, -1); +} + +/* + *---------------------------------------------------------------------- + * + * XGetModifierMapping -- + * + * Fetch the current keycodes used as modifiers. + * + * Results: + * Returns a new modifier map. + * + * Side effects: + * Allocates a new modifier map data structure. + * + *---------------------------------------------------------------------- + */ + +XModifierKeymap * +XGetModifierMapping( + Display* display) +{ + XModifierKeymap * modmap; + + (void) display; /*unused*/ + + /* + * MacOSX doesn't use the key codes for the modifiers for anything, and + * we don't generate them either. So there is no modifier map. + */ + + modmap = (XModifierKeymap *) ckalloc(sizeof(XModifierKeymap)); + modmap->max_keypermod = 0; + modmap->modifiermap = NULL; + return modmap; +} + +/* + *---------------------------------------------------------------------- + * + * XFreeModifiermap -- + * + * Deallocate a modifier map that was created by XGetModifierMapping. + * + * Results: + * None. + * + * Side effects: + * Frees the datastructure referenced by modmap. + * + *---------------------------------------------------------------------- + */ + +void +XFreeModifiermap( + XModifierKeymap *modmap) +{ + if (modmap->modifiermap != NULL) { + ckfree((char *) modmap->modifiermap); + } + ckfree((char *) modmap); +} + +/* + *---------------------------------------------------------------------- + * + * XKeysymToString, XStringToKeysym -- + * + * These X window functions map keysyms to strings & strings to keysyms. + * However, Tk already does this for the most common keysyms. + * Therefore, these functions only need to support keysyms that will be + * specific to the Macintosh. Currently, there are none. + * + * Results: + * None. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +char * +XKeysymToString( + KeySym keysym) +{ + return NULL; +} + +KeySym +XStringToKeysym( + const char* string) +{ + return NoSymbol; +} + +/* + *---------------------------------------------------------------------- + * + * XKeysymToMacKeycode -- + * + * An internal function like XKeysymToKeycode but only generating the + * Mac specific keycode plus the modifiers Shift and Option. + * + * Results: + * A Mac keycode with the actual keycode in the low byte and Mac-style + * modifier bits in the high byte. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +static int +XKeysymToMacKeycode( + Display *display, + KeySym keysym) +{ + if (keysym <= LATIN1_MAX) { + + /* + * Handle keysyms in the Latin-1 range where keysym and Unicode + * character code point are the same. + */ + + InitLatin1Table(display); + return latin1Table[keysym]; + + } else { + + /* + * Handle special keys from our exception tables. Don't mind if this + * is slow, neither the test suite nor [event generate] need to be + * optimized (we hope). + */ + + KeyInfo *kPtr; + + for (kPtr = keyArray; kPtr->keycode != 0; kPtr++) { + if (kPtr->keysym == keysym) { + return kPtr->keycode; + } + } + for (kPtr = virtualkeyArray; kPtr->keycode != 0; kPtr++) { + if (kPtr->keysym == keysym) { + return kPtr->keycode; + } + } + + /* + * For other keysyms (not Latin-1 and not special keys), we'd need a + * generic keysym-to-unicode table. We don't have that, so we give + * up here. + */ + + return 0; + } +} + +/* + *---------------------------------------------------------------------- + * + * XKeysymToKeycode -- + * + * The function XKeysymToKeycode takes an X11 keysym and converts it + * into a Mac keycode. It is in the stubs table for compatibility but + * not used anywhere in the core. + * + * Results: + * A 32 bit keycode with the the mac keycode (without modifiers) in the + * higher 16 bits of the keycode and the ASCII or Latin-1 code in the + * lower 8 bits of the keycode. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +KeyCode +XKeysymToKeycode( + Display* display, + KeySym keysym) +{ + int macKeycode = XKeysymToMacKeycode(display, keysym); + KeyCode result; + + /* + * See also TkpSetKeycodeAndState. The 0x0010 magic is used in + * XKeycodeToKeysym. For special keys like XK_Return the lower 8 bits of + * the keysym are usually a related ASCII control code. + */ + + if ((keysym >= XK_F1) && (keysym <= XK_F35)) { + result = 0x0010; + } else { + result = 0x00FF & keysym; + } + result |= (macKeycode & MAC_KEYCODE_MASK) << 16; + + return result; +} + +/* +NB: Keep this commented code for a moment for reference. + + if ((keysym >= XK_space) && (XK_asciitilde)) { + if (keysym == 'a') { + virtualKeyCode = 0x00; + } else if (keysym == 'b' || keysym == 'B') { + virtualKeyCode = 0x0B; + } else if (keysym == 'c') { + virtualKeyCode = 0x08; + } else if (keysym == 'x' || keysym == 'X') { + virtualKeyCode = 0x07; + } else if (keysym == 'z') { + virtualKeyCode = 0x06; + } else if (keysym == ' ') { + virtualKeyCode = 0x31; + } else if (keysym == XK_Return) { + virtualKeyCode = 0x24; + keysym = '\r'; + } + keycode = keysym + (virtualKeyCode <<16); + } + + return keycode; +*/ + +/* + *---------------------------------------------------------------------- + * + * TkpSetKeycodeAndState -- + * + * The function TkpSetKeycodeAndState takes a keysym and fills in the + * appropriate members of an XEvent. It is similar to XKeysymToKeycode, + * but it also sets the modifier mask in the XEvent. It is used by + * [event generate] and it is in the stubs table. + * + * Results: + * Fills an XEvent, sets the member xkey.keycode with a keycode + * formatted the same as XKeysymToKeycode and the member xkey.state with + * the modifiers implied by the keysym. Also fills in xkey.trans_chars, + * so that the actual characters can be retrieved later. + * + * Side effects: + * None. + * + *---------------------------------------------------------------------- + */ + +void +TkpSetKeycodeAndState( + Tk_Window tkwin, + KeySym keysym, + XEvent *eventPtr) +{ + if (keysym == NoSymbol) { + eventPtr->xkey.keycode = 0; + } else { + Display *display = Tk_Display(tkwin); + int macKeycode = XKeysymToMacKeycode(display, keysym); + + /* + * See also XKeysymToKeycode. + */ + + if ((keysym >= XK_F1) && (keysym <= XK_F35)) { + eventPtr->xkey.keycode = 0x0010; + } else { + eventPtr->xkey.keycode = 0x00FF & keysym; + } + eventPtr->xkey.keycode |= (macKeycode & MAC_KEYCODE_MASK) << 16; + + if (shiftKey & macKeycode) { + eventPtr->xkey.state |= ShiftMask; + } + if (optionKey & macKeycode) { + eventPtr->xkey.state |= OPTION_MASK; + } + + if (keysym <= LATIN1_MAX) { + int done; + done = Tcl_UniCharToUtf(keysym,eventPtr->xkey.trans_chars); + eventPtr->xkey.trans_chars[done] = 0; + } else { + eventPtr->xkey.trans_chars[0] = 0; + } + } +} + +/* + *---------------------------------------------------------------------- + * + * TkpGetKeySym -- + * + * Given an X KeyPress or KeyRelease event, map the keycode in the event + * into a keysym. + * + * Results: + * The return value is the keysym corresponding to eventPtr, or NoSymbol + * if no matching keysym could be found. + * + * Side effects: + * In the first call for a given display, keycode-to-keysym maps get + * loaded. + * + *---------------------------------------------------------------------- + */ + +KeySym +TkpGetKeySym( + TkDisplay *dispPtr, /* Display in which to map keycode. */ + XEvent *eventPtr) /* Description of X event. */ +{ + KeySym sym; + int index; + + /* + * Refresh the mapping information if it's stale. + */ + + if (dispPtr->bindInfoStale) { + TkpInitKeymapInfo(dispPtr); + } + + /* + * Handle pure modifier keys specially. We use -1 as a signal for + * this. + */ + + if (eventPtr->xany.send_event == -1) { + int modifier = eventPtr->xkey.keycode; + if (modifier == cmdKey) { + return XK_Alt_L; + } else if (modifier == shiftKey) { + return XK_Shift_L; + } else if (modifier == alphaLock) { + return XK_Caps_Lock; + } else if (modifier == optionKey) { + return XK_Meta_L; + } else if (modifier == controlKey) { + return XK_Control_L; + } else if (modifier == rightShiftKey) { + return XK_Shift_R; + } else if (modifier == rightOptionKey) { + return XK_Meta_R; + } else if (modifier == rightControlKey) { + return XK_Control_R; + } else { + + /* + * If we get here, we probably need to implement something new. + */ + + return NoSymbol; + } + } + + /* + * Figure out which of the four slots in the keymap vector to use for + * this key. Refer to Xlib documentation for more info on how this + * computation works. (Note: We use "Option" in keymap columns 2 and 3 + * where other implementations have "Mode_switch".) + */ + + index = 0; + + /* + * We want Option key combinations to use their base chars as keysyms, so + * we ignore the option modifier here. + */ + +#if 0 + if (eventPtr->xkey.state & OPTION_MASK) { + index |= 2; + } +#endif + + if ((eventPtr->xkey.state & ShiftMask) + || (/* (dispPtr->lockUsage != LU_IGNORE) + && */ (eventPtr->xkey.state & LockMask))) { + index |= 1; + } + + /* + * First try of the actual translation. + */ + + sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index); + + /* + * Special handling: If the key was shifted because of Lock, but lock is + * only caps lock, not shift lock, and the shifted keysym isn't + * upper-case alphabetic, then switch back to the unshifted keysym. + */ + + if ((index & 1) && !(eventPtr->xkey.state & ShiftMask) + /*&& (dispPtr->lockUsage == LU_CAPS)*/ ) { + + /* + * FIXME: Keysyms are only identical to Unicode for ASCII and + * Latin-1, so we can't use Tcl_UniCharIsUpper() for keysyms outside + * that range. This may be a serious problem here. + */ + + if ((sym == NoSymbol) || (sym > LATIN1_MAX) + || !Tcl_UniCharIsUpper(sym)) { + index &= ~1; + sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, + index); + } + } + + /* + * Another bit of special handling: If this is a shifted key and there is + * no keysym defined, then use the keysym for the unshifted key. + */ + + if ((index & 1) && (sym == NoSymbol)) { + sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, + index & ~1); + } + return sym; +} + +/* + *-------------------------------------------------------------- + * + * TkpInitKeymapInfo -- + * + * This procedure is invoked to scan keymap information to recompute + * stuff that's important for binding, such as the modifier key (if any) + * that corresponds to the "Mode_switch" keysym. + * + * Results: + * None. + * + * Side effects: + * Keymap-related information in dispPtr is updated. + * + *-------------------------------------------------------------- + */ + +void +TkpInitKeymapInfo( + TkDisplay *dispPtr) /* Display for which to recompute keymap + * information. */ +{ + dispPtr->bindInfoStale = 0; + + /* + * Behaviours that are variable on X11 are defined constant on MacOSX. + * lockUsage is only used above in TkpGetKeySym(), nowhere else + * currently. There is no offical "Mode_switch" key. + */ + + dispPtr->lockUsage = LU_CAPS; + dispPtr->modeModMask = 0; + dispPtr->altModMask = ALT_MASK; + dispPtr->metaModMask = OPTION_MASK; + + /* + * MacOSX doesn't use the keycodes for the modifiers for anything, and we + * don't generate them either (the keycodes actually given in the + * simulated modifier events are bogus). So there is no modifier map. + * If we ever want to simulate real modifier keycodes, the list will be + * constant in the Carbon implementation. + */ + + if (dispPtr->modKeyCodes != NULL) { + ckfree((char *) dispPtr->modKeyCodes); + } + dispPtr->numModKeyCodes = 0; + dispPtr->modKeyCodes = NULL; +} |