diff options
author | ericm <ericm> | 2000-04-14 01:36:35 (GMT) |
---|---|---|
committer | ericm <ericm> | 2000-04-14 01:36:35 (GMT) |
commit | 5ba98e6cb49a88e28c0ed8953b9bc369faabdd26 (patch) | |
tree | b6ca2c47c8b9700dce3c2fbe36735f978cfec402 /win/tkWinKey.c | |
parent | 632bd53901793dc9ae455dd2d727d322b42ba814 (diff) | |
download | tk-5ba98e6cb49a88e28c0ed8953b9bc369faabdd26.zip tk-5ba98e6cb49a88e28c0ed8953b9bc369faabdd26.tar.gz tk-5ba98e6cb49a88e28c0ed8953b9bc369faabdd26.tar.bz2 |
* win/tkWinKey.c: Added smarts to check whether the left or right
Control, Shift, or Alt key was pressed. [Bug: 870].
* win/tkWin3d.c:
* unix/tkUnix3d.c: Tweaked threshhold for using different highlight
computation.
Diffstat (limited to 'win/tkWinKey.c')
-rw-r--r-- | win/tkWinKey.c | 1461 |
1 files changed, 746 insertions, 715 deletions
diff --git a/win/tkWinKey.c b/win/tkWinKey.c index 9e3687e..6a7a6a9 100644 --- a/win/tkWinKey.c +++ b/win/tkWinKey.c @@ -1,715 +1,746 @@ -/* - * tkWinKey.c -- - * - * This file contains X emulation routines for keyboard related - * functions. - * - * Copyright (c) 1995 Sun Microsystems, Inc. - * - * 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.8 2000/04/10 22:43:13 ericm Exp $ - */ - -#include "tkWinInt.h" - -typedef struct { - unsigned int keycode; - KeySym keysym; -} Keys; - -static Keys keymap[] = { - VK_CANCEL, XK_Cancel, - VK_BACK, XK_BackSpace, - VK_TAB, XK_Tab, - VK_CLEAR, XK_Clear, - VK_RETURN, XK_Return, - VK_SHIFT, XK_Shift_L, - VK_CONTROL, XK_Control_L, - VK_MENU, XK_Alt_L, - VK_PAUSE, XK_Pause, - VK_CAPITAL, XK_Caps_Lock, - VK_ESCAPE, XK_Escape, - VK_SPACE, XK_space, - VK_PRIOR, XK_Prior, - VK_NEXT, XK_Next, - VK_END, XK_End, - VK_HOME, XK_Home, - VK_LEFT, XK_Left, - VK_UP, XK_Up, - VK_RIGHT, XK_Right, - VK_DOWN, XK_Down, - VK_SELECT, XK_Select, - VK_PRINT, XK_Print, - VK_EXECUTE, XK_Execute, - VK_INSERT, XK_Insert, - VK_DELETE, XK_Delete, - VK_HELP, XK_Help, - VK_F1, XK_F1, - VK_F2, XK_F2, - VK_F3, XK_F3, - VK_F4, XK_F4, - VK_F5, XK_F5, - VK_F6, XK_F6, - VK_F7, XK_F7, - VK_F8, XK_F8, - VK_F9, XK_F9, - VK_F10, XK_F10, - VK_F11, XK_F11, - VK_F12, XK_F12, - VK_F13, XK_F13, - VK_F14, XK_F14, - VK_F15, XK_F15, - VK_F16, XK_F16, - VK_F17, XK_F17, - VK_F18, XK_F18, - VK_F19, XK_F19, - VK_F20, XK_F20, - VK_F21, XK_F21, - VK_F22, XK_F22, - VK_F23, XK_F23, - VK_F24, XK_F24, - VK_NUMLOCK, XK_Num_Lock, - VK_SCROLL, XK_Scroll_Lock, - - /* - * The following support the new keys in the Microsoft keyboard. - * Win_L and Win_R have the windows logo. App has the menu. - */ - - VK_LWIN, XK_Win_L, - VK_RWIN, XK_Win_R, - VK_APPS, XK_App, - - 0, NoSymbol -}; - -/* - * Prototypes for local procedures defined in this file: - */ - -static KeySym KeycodeToKeysym _ANSI_ARGS_((unsigned int keycode, - int state, int noascii)); - -/* - *---------------------------------------------------------------------- - * - * TkpGetString -- - * - * Retrieve the UTF string equivalent for the given keyboard event. - * - * Results: - * Returns the UTF string. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -char * -TkpGetString(winPtr, eventPtr, dsPtr) - 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. */ -{ - KeySym keysym; - XKeyEvent* keyEv = &eventPtr->xkey; - - Tcl_DStringInit(dsPtr); - if (eventPtr->xkey.send_event != -1) { - /* - * This is an event generated from generic code. It has no - * nchars or trans_chars members. - */ - - 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 & 255), buf); - Tcl_DStringAppend(dsPtr, buf, len); - } - } else if (eventPtr->xkey.nbytes > 0) { - Tcl_ExternalToUtfDString(NULL, eventPtr->xkey.trans_chars, - eventPtr->xkey.nbytes, dsPtr); - } - return Tcl_DStringValue(dsPtr); -} - -/* - *---------------------------------------------------------------------- - * - * 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, keycode, index) - Display* display; - 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, 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 (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 (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; - } - - /* - * Keycode mapped to a valid Latin-1 character. Since the keysyms - * for alphanumeric characters map onto Latin-1, we just return it. - */ - - if (result == 1 && UCHAR(buf[0]) >= 0x20) { - return (KeySym) UCHAR(buf[0]); - } - - /* - * 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; - } - } - - 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) { - TkpInitKeymapInfo(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; -} - -/* - *-------------------------------------------------------------- - * - * 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 "mode - * switch". - * - * Results: - * None. - * - * Side effects: - * Keymap-related information in dispPtr is updated. - * - *-------------------------------------------------------------- - */ - -void -TkpInitKeymapInfo(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); - } - } -} - -/* - *---------------------------------------------------------------------- - * - * XKeysymToKeycode -- - * - * Translate a keysym back into a keycode. - * - * Results: - * Returns the keycode that would generate the specified keysym. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -KeyCode -XKeysymToKeycode(display, keysym) - Display* display; - KeySym keysym; -{ - Keys* key; - SHORT result; - - /* - * 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) { - return key->keycode; - } - } - - if (keysym >= 0x20) { - result = VkKeyScan((char) keysym); - if (result != -1) { - return (KeyCode) (result & 0xff); - } - } - - return 0; -} - -/* - *---------------------------------------------------------------------- - * - * 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* display; -{ - XModifierKeymap *map = (XModifierKeymap *)ckalloc(sizeof(XModifierKeymap)); - - map->max_keypermod = 1; - map->modifiermap = (KeyCode *) ckalloc(sizeof(KeyCode)*8); - map->modifiermap[ShiftMapIndex] = VK_SHIFT; - map->modifiermap[LockMapIndex] = VK_CAPITAL; - map->modifiermap[ControlMapIndex] = VK_CONTROL; - map->modifiermap[Mod1MapIndex] = VK_NUMLOCK; - map->modifiermap[Mod2MapIndex] = VK_MENU; - map->modifiermap[Mod3MapIndex] = VK_SCROLL; - map->modifiermap[Mod4MapIndex] = 0; - map->modifiermap[Mod5MapIndex] = 0; - return map; -} - -/* - *---------------------------------------------------------------------- - * - * XFreeModifiermap -- - * - * Deallocate a modifier map that was created by - * XGetModifierMapping. - * - * Results: - * None. - * - * Side effects: - * Frees the datastructure referenced by modmap. - * - *---------------------------------------------------------------------- - */ - -void -XFreeModifiermap(modmap) - XModifierKeymap* modmap; -{ - ckfree((char *) modmap->modifiermap); - ckfree((char *) modmap); -} - -/* - *---------------------------------------------------------------------- - * - * XStringToKeysym -- - * - * Translate a keysym name to the matching keysym. - * - * Results: - * Returns the keysym. Since this is already handled by - * Tk's StringToKeysym function, we just return NoSymbol. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -KeySym -XStringToKeysym(string) - _Xconst char *string; -{ - return NoSymbol; -} - -/* - *---------------------------------------------------------------------- - * - * XKeysymToString -- - * - * Convert a keysym to character form. - * - * Results: - * Returns NULL, since Tk will have handled this already. - * - * Side effects: - * None. - * - *---------------------------------------------------------------------- - */ - -char * -XKeysymToString(keysym) - KeySym keysym; -{ - return NULL; -} +/*
+ * tkWinKey.c --
+ *
+ * This file contains X emulation routines for keyboard related
+ * functions.
+ *
+ * Copyright (c) 1995 Sun Microsystems, Inc.
+ *
+ * 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.9 2000/04/14 01:36:35 ericm Exp $
+ */
+
+#include "tkWinInt.h"
+
+typedef struct {
+ unsigned int keycode;
+ KeySym keysym;
+} Keys;
+
+static Keys keymap[] = {
+ VK_CANCEL, XK_Cancel,
+ VK_BACK, XK_BackSpace,
+ VK_TAB, XK_Tab,
+ VK_CLEAR, XK_Clear,
+ VK_RETURN, XK_Return,
+ VK_SHIFT, XK_Shift_L,
+ VK_CONTROL, XK_Control_L,
+ VK_MENU, XK_Alt_L,
+ VK_PAUSE, XK_Pause,
+ VK_CAPITAL, XK_Caps_Lock,
+ VK_ESCAPE, XK_Escape,
+ VK_SPACE, XK_space,
+ VK_PRIOR, XK_Prior,
+ VK_NEXT, XK_Next,
+ VK_END, XK_End,
+ VK_HOME, XK_Home,
+ VK_LEFT, XK_Left,
+ VK_UP, XK_Up,
+ VK_RIGHT, XK_Right,
+ VK_DOWN, XK_Down,
+ VK_SELECT, XK_Select,
+ VK_PRINT, XK_Print,
+ VK_EXECUTE, XK_Execute,
+ VK_INSERT, XK_Insert,
+ VK_DELETE, XK_Delete,
+ VK_HELP, XK_Help,
+ VK_F1, XK_F1,
+ VK_F2, XK_F2,
+ VK_F3, XK_F3,
+ VK_F4, XK_F4,
+ VK_F5, XK_F5,
+ VK_F6, XK_F6,
+ VK_F7, XK_F7,
+ VK_F8, XK_F8,
+ VK_F9, XK_F9,
+ VK_F10, XK_F10,
+ VK_F11, XK_F11,
+ VK_F12, XK_F12,
+ VK_F13, XK_F13,
+ VK_F14, XK_F14,
+ VK_F15, XK_F15,
+ VK_F16, XK_F16,
+ VK_F17, XK_F17,
+ VK_F18, XK_F18,
+ VK_F19, XK_F19,
+ VK_F20, XK_F20,
+ VK_F21, XK_F21,
+ VK_F22, XK_F22,
+ VK_F23, XK_F23,
+ VK_F24, XK_F24,
+ VK_NUMLOCK, XK_Num_Lock,
+ VK_SCROLL, XK_Scroll_Lock,
+
+ /*
+ * The following support the new keys in the Microsoft keyboard.
+ * Win_L and Win_R have the windows logo. App has the menu.
+ */
+
+ VK_LWIN, XK_Win_L,
+ VK_RWIN, XK_Win_R,
+ VK_APPS, XK_App,
+
+ 0, NoSymbol
+};
+
+/*
+ * Prototypes for local procedures defined in this file:
+ */
+
+static KeySym KeycodeToKeysym _ANSI_ARGS_((unsigned int keycode,
+ int state, int noascii));
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * TkpGetString --
+ *
+ * Retrieve the UTF string equivalent for the given keyboard event.
+ *
+ * Results:
+ * Returns the UTF string.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+TkpGetString(winPtr, eventPtr, dsPtr)
+ 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. */
+{
+ KeySym keysym;
+ XKeyEvent* keyEv = &eventPtr->xkey;
+
+ Tcl_DStringInit(dsPtr);
+ if (eventPtr->xkey.send_event != -1) {
+ /*
+ * This is an event generated from generic code. It has no
+ * nchars or trans_chars members.
+ */
+
+ 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 & 255), buf);
+ Tcl_DStringAppend(dsPtr, buf, len);
+ }
+ } else if (eventPtr->xkey.nbytes > 0) {
+ Tcl_ExternalToUtfDString(NULL, eventPtr->xkey.trans_chars,
+ eventPtr->xkey.nbytes, dsPtr);
+ }
+ return Tcl_DStringValue(dsPtr);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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, keycode, index)
+ Display* display;
+ 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, 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 (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 (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;
+ }
+
+ /*
+ * Keycode mapped to a valid Latin-1 character. Since the keysyms
+ * for alphanumeric characters map onto Latin-1, we just return it.
+ */
+
+ if (result == 1 && UCHAR(buf[0]) >= 0x20) {
+ return (KeySym) UCHAR(buf[0]);
+ }
+
+ /*
+ * 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) {
+ /*
+ * Windows only gives us an undifferentiated VK_CONTROL
+ * code (for example) when either Control key is pressed.
+ * To distinguish between left and right, we have to query the
+ * state of one of the two to determine which was actually
+ * pressed. So if the keycode indicates Control, Shift, or Menu
+ * (the key that everybody else calls Alt), do this extra test.
+ * If the right-side key was pressed, return the appropriate
+ * keycode. Otherwise, we fall through and rely on the
+ * keymap table to hold the correct keysym value.
+ */
+ switch (keycode) {
+ case VK_CONTROL: {
+ if (GetKeyState(VK_RCONTROL) & 0x80) {
+ return XK_Control_R;
+ }
+ break;
+ }
+ case VK_SHIFT: {
+ if (GetKeyState(VK_RSHIFT) & 0x80) {
+ return XK_Shift_R;
+ }
+ break;
+ }
+ case VK_MENU: {
+ if (GetKeyState(VK_RMENU) & 0x80) {
+ return XK_Alt_R;
+ }
+ break;
+ }
+ }
+ return key->keysym;
+ }
+ }
+
+ 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) {
+ TkpInitKeymapInfo(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;
+}
+
+/*
+ *--------------------------------------------------------------
+ *
+ * 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 "mode
+ * switch".
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Keymap-related information in dispPtr is updated.
+ *
+ *--------------------------------------------------------------
+ */
+
+void
+TkpInitKeymapInfo(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);
+ }
+ }
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XKeysymToKeycode --
+ *
+ * Translate a keysym back into a keycode.
+ *
+ * Results:
+ * Returns the keycode that would generate the specified keysym.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+KeyCode
+XKeysymToKeycode(display, keysym)
+ Display* display;
+ KeySym keysym;
+{
+ Keys* key;
+ SHORT result;
+
+ /*
+ * 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) {
+ return key->keycode;
+ }
+ }
+
+ if (keysym >= 0x20) {
+ result = VkKeyScan((char) keysym);
+ if (result != -1) {
+ return (KeyCode) (result & 0xff);
+ }
+ }
+
+ return 0;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * 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* display;
+{
+ XModifierKeymap *map = (XModifierKeymap *)ckalloc(sizeof(XModifierKeymap));
+
+ map->max_keypermod = 1;
+ map->modifiermap = (KeyCode *) ckalloc(sizeof(KeyCode)*8);
+ map->modifiermap[ShiftMapIndex] = VK_SHIFT;
+ map->modifiermap[LockMapIndex] = VK_CAPITAL;
+ map->modifiermap[ControlMapIndex] = VK_CONTROL;
+ map->modifiermap[Mod1MapIndex] = VK_NUMLOCK;
+ map->modifiermap[Mod2MapIndex] = VK_MENU;
+ map->modifiermap[Mod3MapIndex] = VK_SCROLL;
+ map->modifiermap[Mod4MapIndex] = 0;
+ map->modifiermap[Mod5MapIndex] = 0;
+ return map;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XFreeModifiermap --
+ *
+ * Deallocate a modifier map that was created by
+ * XGetModifierMapping.
+ *
+ * Results:
+ * None.
+ *
+ * Side effects:
+ * Frees the datastructure referenced by modmap.
+ *
+ *----------------------------------------------------------------------
+ */
+
+void
+XFreeModifiermap(modmap)
+ XModifierKeymap* modmap;
+{
+ ckfree((char *) modmap->modifiermap);
+ ckfree((char *) modmap);
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XStringToKeysym --
+ *
+ * Translate a keysym name to the matching keysym.
+ *
+ * Results:
+ * Returns the keysym. Since this is already handled by
+ * Tk's StringToKeysym function, we just return NoSymbol.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+KeySym
+XStringToKeysym(string)
+ _Xconst char *string;
+{
+ return NoSymbol;
+}
+
+/*
+ *----------------------------------------------------------------------
+ *
+ * XKeysymToString --
+ *
+ * Convert a keysym to character form.
+ *
+ * Results:
+ * Returns NULL, since Tk will have handled this already.
+ *
+ * Side effects:
+ * None.
+ *
+ *----------------------------------------------------------------------
+ */
+
+char *
+XKeysymToString(keysym)
+ KeySym keysym;
+{
+ return NULL;
+}
|