diff options
Diffstat (limited to 'win/tkWinKey.c')
-rw-r--r-- | win/tkWinKey.c | 394 |
1 files changed, 376 insertions, 18 deletions
diff --git a/win/tkWinKey.c b/win/tkWinKey.c index af826d5..d46f601 100644 --- a/win/tkWinKey.c +++ b/win/tkWinKey.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkWinKey.c,v 1.6 1999/10/30 09:16:07 hobbs Exp $ + * RCS: @(#) $Id: tkWinKey.c,v 1.7 2000/02/09 02:13:56 hobbs Exp $ */ #include "tkWinInt.h" @@ -85,6 +85,14 @@ static Keys keymap[] = { 0, NoSymbol }; +/* + * Prototypes for local procedures defined in this file: + */ + +static KeySym KeycodeToKeysym _ANSI_ARGS_((unsigned int keycode, + int state, int noascii)); +static void InitKeymapInfo _ANSI_ARGS_((TkDisplay *dispPtr)); + /* *---------------------------------------------------------------------- @@ -110,7 +118,6 @@ TkpGetString(winPtr, eventPtr, dsPtr) Tcl_DString *dsPtr; /* Uninitialized or empty string to hold * result. */ { - int index; KeySym keysym; XKeyEvent* keyEv = &eventPtr->xkey; @@ -121,20 +128,13 @@ TkpGetString(winPtr, eventPtr, dsPtr) * nchars or trans_chars members. */ - index = 0; - if (eventPtr->xkey.state & ShiftMask) { - index |= 1; - } - if (eventPtr->xkey.state & Mod1Mask) { - index |= 2; - } - keysym = XKeycodeToKeysym(eventPtr->xkey.display, - eventPtr->xkey.keycode, index); + keysym = KeycodeToKeysym(eventPtr->xkey.keycode, + eventPtr->xkey.state, 0); if (((keysym != NoSymbol) && (keysym > 0) && (keysym < 256)) || (keysym == XK_Return) || (keysym == XK_Tab)) { char buf[TCL_UTF_MAX]; - int len = Tcl_UniCharToUtf((Tcl_UniChar) keysym, buf); + int len = Tcl_UniCharToUtf((Tcl_UniChar) (keysym & 255), buf); Tcl_DStringAppend(dsPtr, buf, len); } } else if (eventPtr->xkey.nbytes > 0) { @@ -167,20 +167,132 @@ XKeycodeToKeysym(display, keycode, index) unsigned int keycode; int index; { + int state = 0; + + if (index & 0x01) { + state |= ShiftMask; + } + return KeycodeToKeysym(keycode, state, 0); +} + + + +/* + *---------------------------------------------------------------------- + * + * KeycodeToKeysym -- + * + * Translate from a system-dependent keycode to a + * system-independent keysym. + * + * Results: + * Returns the translated keysym, or NoSymbol on failure. + * + * Side effects: + * It may affect the internal state of the keyboard, such as + * remembered dead key or lock indicator lamps. + * + *---------------------------------------------------------------------- + */ + +static KeySym +KeycodeToKeysym(keycode, state, noascii) + unsigned int keycode; + int state; + int noascii; +{ Keys* key; BYTE keys[256]; - int result; + int result, deadkey, shift; char buf[4]; unsigned int scancode = MapVirtualKey(keycode, 0); + /* + * Do not run keycodes of lock keys through ToAscii(). + * One of ToAscii()'s side effects is to handle the lights + * on the keyboard, and we don't want to mess that up. + */ + + if (noascii || keycode == VK_CAPITAL || keycode == VK_SCROLL || + keycode == VK_NUMLOCK) + goto skipToAscii; + + /* + * Use MapVirtualKey() to detect some dead keys. + */ + + if (MapVirtualKey(keycode, 2) > 0x7fffUL) + return XK_Multi_key; + + /* + * Set up a keyboard with correct modifiers + */ + memset(keys, 0, 256); - if (index & 0x02) { + if (state & ShiftMask) + keys[VK_SHIFT] = 0x80; + if (state & ControlMask) + keys[VK_CONTROL] = 0x80; + if (state & Mod2Mask) + keys[VK_MENU] = 0x80; + + /* + * Make sure all lock button info is correct so we don't mess up the + * lights + */ + + if (state & LockMask) + keys[VK_CAPITAL] = 1; + if (state & Mod3Mask) + keys[VK_SCROLL] = 1; + if (state & Mod1Mask) keys[VK_NUMLOCK] = 1; + + result = ToAscii(keycode, scancode, keys, (LPWORD) buf, 0); + + if (result < 0) { + /* + * Win95/98: + * This was a dead char, which is now remembered by the keyboard. + * Call ToAscii() again to forget it. + * WinNT: + * This was a dead char, overwriting any previously remembered + * key. Calling ToAscii() again does not affect anything. + */ + + ToAscii(keycode, scancode, keys, (LPWORD) buf, 0); + return XK_Multi_key; } - if (index & 0x01) { - keys[VK_SHIFT] = 0x80; + if (result == 2) { + /* + * This was a dead char, and there were one previously remembered + * by the keyboard. + * Call ToAscii() again with proper parameters to restore it. + */ + + /* + * Get information about the old char + */ + + deadkey = VkKeyScan(buf[0]); + shift = deadkey >> 8; + deadkey &= 255; + scancode = MapVirtualKey(deadkey, 0); + + /* + * Set up a keyboard with proper modifier keys + */ + + memset(keys, 0, 256); + if (shift & 1) + keys[VK_SHIFT] = 0x80; + if (shift & 2) + keys[VK_CONTROL] = 0x80; + if (shift & 4) + keys[VK_MENU] = 0x80; + ToAscii(deadkey, scancode, keys, (LPWORD) buf, 0); + return XK_Multi_key; } - result = ToAscii(keycode, scancode, keys, (LPWORD) buf, 0); /* * Keycode mapped to a valid Latin-1 character. Since the keysyms @@ -195,6 +307,7 @@ XKeycodeToKeysym(display, keycode, index) * Keycode is a non-alphanumeric key, so we have to do the lookup. */ + skipToAscii: for (key = keymap; key->keycode != 0; key++) { if (key->keycode == keycode) { return key->keysym; @@ -204,6 +317,251 @@ XKeycodeToKeysym(display, keycode, index) return NoSymbol; } + +/* + *---------------------------------------------------------------------- + * + * 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(dispPtr, eventPtr) + TkDisplay *dispPtr; /* Display in which to map keycode. */ + XEvent *eventPtr; /* Description of X event. */ +{ + KeySym sym; + int state = eventPtr->xkey.state; + + /* + * Refresh the mapping information if it's stale + */ + + if (dispPtr->bindInfoStale) { + InitKeymapInfo(dispPtr); + } + + sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0); + + /* + * Special handling: if this is a ctrl-alt or shifted key, and there + * is no keysym defined, try without the modifiers. + */ + + if ((sym == NoSymbol) && ((state & ControlMask) || (state & Mod2Mask))) { + state &= ~(ControlMask | Mod2Mask); + sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0); + } + if ((sym == NoSymbol) && (state & ShiftMask)) { + state &= ~ShiftMask; + sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0); + } + return sym; +} + +/* + *-------------------------------------------------------------- + * + * InitKeymapInfo -- + * + * 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 "mode + * switch". + * + * Results: + * None. + * + * Side effects: + * Keymap-related information in dispPtr is updated. + * + *-------------------------------------------------------------- + */ + +static void +InitKeymapInfo(dispPtr) + TkDisplay *dispPtr; /* Display for which to recompute keymap + * information. */ +{ + XModifierKeymap *modMapPtr; + KeyCode *codePtr; + KeySym keysym; + int count, i, j, max, arraySize; +#define KEYCODE_ARRAY_SIZE 20 + + dispPtr->bindInfoStale = 0; + modMapPtr = XGetModifierMapping(dispPtr->display); + + /* + * Check the keycodes associated with the Lock modifier. If + * any of them is associated with the XK_Shift_Lock modifier, + * then Lock has to be interpreted as Shift Lock, not Caps Lock. + */ + + dispPtr->lockUsage = LU_IGNORE; + codePtr = modMapPtr->modifiermap + modMapPtr->max_keypermod*LockMapIndex; + for (count = modMapPtr->max_keypermod; count > 0; count--, codePtr++) { + if (*codePtr == 0) { + continue; + } + keysym = KeycodeToKeysym(*codePtr, 0, 1); + if (keysym == XK_Shift_Lock) { + dispPtr->lockUsage = LU_SHIFT; + break; + } + if (keysym == XK_Caps_Lock) { + dispPtr->lockUsage = LU_CAPS; + break; + } + } + + /* + * Look through the keycodes associated with modifiers to see if + * the the "mode switch", "meta", or "alt" keysyms are associated + * with any modifiers. If so, remember their modifier mask bits. + */ + + dispPtr->modeModMask = 0; + dispPtr->metaModMask = 0; + dispPtr->altModMask = 0; + codePtr = modMapPtr->modifiermap; + max = 8*modMapPtr->max_keypermod; + for (i = 0; i < max; i++, codePtr++) { + if (*codePtr == 0) { + continue; + } + keysym = KeycodeToKeysym(*codePtr, 0, 1); + if (keysym == XK_Mode_switch) { + dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod); + } + if ((keysym == XK_Meta_L) || (keysym == XK_Meta_R)) { + dispPtr->metaModMask |= ShiftMask << (i/modMapPtr->max_keypermod); + } + if ((keysym == XK_Alt_L) || (keysym == XK_Alt_R)) { + dispPtr->altModMask |= ShiftMask << (i/modMapPtr->max_keypermod); + } + } + + /* + * Create an array of the keycodes for all modifier keys. + */ + + if (dispPtr->modKeyCodes != NULL) { + ckfree((char *) dispPtr->modKeyCodes); + } + dispPtr->numModKeyCodes = 0; + arraySize = KEYCODE_ARRAY_SIZE; + dispPtr->modKeyCodes = (KeyCode *) ckalloc((unsigned) + (KEYCODE_ARRAY_SIZE * sizeof(KeyCode))); + for (i = 0, codePtr = modMapPtr->modifiermap; i < max; i++, codePtr++) { + if (*codePtr == 0) { + continue; + } + + /* + * Make sure that the keycode isn't already in the array. + */ + + for (j = 0; j < dispPtr->numModKeyCodes; j++) { + if (dispPtr->modKeyCodes[j] == *codePtr) { + goto nextModCode; + } + } + if (dispPtr->numModKeyCodes >= arraySize) { + KeyCode *new; + + /* + * Ran out of space in the array; grow it. + */ + + arraySize *= 2; + new = (KeyCode *) ckalloc((unsigned) + (arraySize * sizeof(KeyCode))); + memcpy((VOID *) new, (VOID *) dispPtr->modKeyCodes, + (dispPtr->numModKeyCodes * sizeof(KeyCode))); + ckfree((char *) dispPtr->modKeyCodes); + dispPtr->modKeyCodes = new; + } + dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr; + dispPtr->numModKeyCodes++; + nextModCode: continue; + } + XFreeModifiermap(modMapPtr); +} + +/* + * When mapping from a keysym to a keycode, need + * information about the modifier state that should be used + * so that when they call XKeycodeToKeysym taking into + * account the xkey.state, they will get back the original + * keysym. + */ + +void +TkpSetKeycodeAndState(tkwin, keySym, eventPtr) + Tk_Window tkwin; + KeySym keySym; + XEvent *eventPtr; +{ + Keys* key; + SHORT result; + int shift; + + eventPtr->xkey.keycode = 0; + if (keySym == NoSymbol) { + return; + } + + /* + * We check our private map first for a virtual keycode, + * as VkKeyScan will return values that don't map to X + * for the "extended" Syms. This may be due to just casting + * problems below, but this works. + */ + + for (key = keymap; key->keycode != 0; key++) { + if (key->keysym == keySym) { + eventPtr->xkey.keycode = key->keycode; + return; + } + } + + if (keySym >= 0x20) { + result = VkKeyScan((char) keySym); + if (result != -1) { + shift = result >> 8; + if (shift & 1) + eventPtr->xkey.state |= ShiftMask; + if (shift & 2) + eventPtr->xkey.state |= ControlMask; + if (shift & 4) + eventPtr->xkey.state |= Mod2Mask; + eventPtr->xkey.keycode = (KeyCode) (result & 0xff); + } + } + { + /* Debug log */ + FILE *fp = fopen("c:\\temp\\tklog.txt", "a"); + if (fp != NULL) { + fprintf(fp, "TkpSetKeycode. Keycode %d State %d Keysym %d\n", eventPtr->xkey.keycode, eventPtr->xkey.state, keySym); + fclose(fp); + } + } +} + /* *---------------------------------------------------------------------- * @@ -244,7 +602,7 @@ XKeysymToKeycode(display, keysym) if (keysym >= 0x20) { result = VkKeyScan((char) keysym); if (result != -1) { - return (KeyCode) (result & 0xfff); + return (KeyCode) (result & 0xff); } } |