diff options
author | ericm <ericm> | 2000-04-15 00:33:08 (GMT) |
---|---|---|
committer | ericm <ericm> | 2000-04-15 00:33:08 (GMT) |
commit | dcdda21be28f425fdea2a3b2de1b6f96ba80852e (patch) | |
tree | 2532e6a474edd004a916bcec958ebc82766c0e09 /win | |
parent | a3369712cfd623421640d3efce3d26dc8bfd3955 (diff) | |
download | tk-dcdda21be28f425fdea2a3b2de1b6f96ba80852e.zip tk-dcdda21be28f425fdea2a3b2de1b6f96ba80852e.tar.gz tk-dcdda21be28f425fdea2a3b2de1b6f96ba80852e.tar.bz2 |
* generic/ks_names.h: Added Scroll_Lock and Sys_Req definitions.
* win/tkWinKey.c: Changed implementation of KeycodeToKeysym,
et. al., to use a keycode table for lookups; this will result in
faster keycode -> keysym translations for non-ASCII keys like
Control, Alt, etc.
Diffstat (limited to 'win')
-rw-r--r-- | win/tkWinKey.c | 1457 |
1 files changed, 711 insertions, 746 deletions
diff --git a/win/tkWinKey.c b/win/tkWinKey.c index 6a7a6a9..f197e5a 100644 --- a/win/tkWinKey.c +++ b/win/tkWinKey.c @@ -1,746 +1,711 @@ -/*
- * 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;
-}
+/* + * 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.10 2000/04/15 00:33:08 ericm Exp $ + */ + +#include "tkWinInt.h" +/* + * The keymap table holds mappings of Windows keycodes to X keysyms. + * If Windows ever comes along and changes the value of their keycodes, + * this will break all kinds of things. However, this table lookup is much + * faster than the alternative, in which we walked a list of keycodes looking + * for a match. Since this lookup is performed for every Windows keypress + * event, it seems like a worthwhile improvement to use the table. + */ +#define MAX_KEYCODE 145 /* VK_SCROLL is the last entry in our table below */ +static KeySym keymap[] = { + NoSymbol, NoSymbol, NoSymbol, XK_Cancel, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, XK_BackSpace, XK_Tab, + NoSymbol, NoSymbol, XK_Clear, XK_Return, NoSymbol, + NoSymbol, XK_Shift_L, XK_Control_L, XK_Alt_L, XK_Pause, + XK_Caps_Lock, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, XK_Escape, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, XK_space, XK_Prior, XK_Next, + XK_End, XK_Home, XK_Left, XK_Up, XK_Right, + XK_Down, XK_Select, XK_Print, XK_Execute, NoSymbol, + XK_Insert, XK_Delete, XK_Help, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, XK_Win_L, XK_Win_R, XK_App, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, XK_F1, XK_F2, XK_F3, + XK_F4, XK_F5, XK_F6, XK_F7, XK_F8, + XK_F9, XK_F10, XK_F11, XK_F12, XK_F13, + XK_F14, XK_F15, XK_F16, XK_F17, XK_F18, + XK_F19, XK_F20, XK_F21, XK_F22, XK_F23, + XK_F24, NoSymbol, NoSymbol, NoSymbol, NoSymbol, + NoSymbol, NoSymbol, NoSymbol, NoSymbol, XK_Num_Lock, + XK_Scroll_Lock +}; + +/* + * 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; +{ + 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: + if (keycode < 0 || keycode > MAX_KEYCODE) { + return NoSymbol; + } + switch (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. + */ + 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 keymap[keycode]; +} + + +/* + *---------------------------------------------------------------------- + * + * 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; +{ + int i; + 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 (i = 0; i <= MAX_KEYCODE; i++) { + if (keymap[i] == keySym) { + eventPtr->xkey.keycode = i; + 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; +{ + int i; + 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. + */ + if (keysym == NoSymbol) { + return 0; + } + for (i = 0; i <= MAX_KEYCODE; i++) { + if (keymap[i] == keysym) { + return ((KeyCode) i); + } + } + 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; +} |