diff options
-rw-r--r-- | ChangeLog | 41 | ||||
-rw-r--r-- | generic/tk.decls | 48 | ||||
-rw-r--r-- | generic/tkBind.c | 271 | ||||
-rw-r--r-- | generic/tkInt.decls | 12 | ||||
-rw-r--r-- | generic/tkIntDecls.h | 18 | ||||
-rw-r--r-- | generic/tkStubInit.c | 4 | ||||
-rw-r--r-- | mac/tkMacKeyboard.c | 261 | ||||
-rw-r--r-- | unix/tkUnixKey.c | 266 | ||||
-rw-r--r-- | win/tkWinKey.c | 394 |
9 files changed, 1001 insertions, 314 deletions
@@ -1,5 +1,46 @@ 2000-02-08 Jeff Hobbs <hobbs@scriptics.com> + * generic/tk.decls: + * generic/tkBind.c: + * generic/tkInt.decls: + * generic/tkIntDecls.h: + * generic/tkStubInit.c: + * mac/tkMacKeyboard.c: + * unix/tkUnixKey.c: + * win/tkWinKey.c: Fix for keyboard handling of "dead" keys and + caps lock from Peter Spjuth. + Split functions into platform specific files: + Static functions GetKeySym(), SetKeycodeAndState() and InitKeymapInfo() + from tkBind.c moved into platform files tkWinKey.c tkUnixKey.c and + tkMacKeyboard.c. GetKeySym() and SetKeycodeAndState() renamed to + Tkp* and made public (as private functions) in tkInt.decls. + + Step 2, fixes in tkWinKey.c + New static function: KeycodeToKeysym(), based on XKeycodeToKeysym() + but with different arguments, and a lot of improvements. + TkpGetString() changed to use KeycodeToKeysym() + other fixes. + TkpGetKeySym() changed to use KeycodeToKeysym() + other fixes. + InitKeymapInfo() changed to use KeycodeToKeysym(). + TkpSetKeycodeAndState() rewritten, mostly by copying code from + XKeysymToKeycode(). + XKeycodeToKeysym() rewritten. Preferably it should be removed. + + EXPLANATION: The main problem is ToAscii() which has a lot of side + effects, and also that XKeycodeToKeysym() is not provided enough + input to do a proper job. The changes' main goal is to avoid + calling ToAscii() if not necessary, and to provide it with as + correct information as possible when called. Also some attempts + to clean up what ToAscii() did are done. See the code for details. + + BUGS FIXED: Typing shifted (and AltGr) dead keys did not work. + Keyboard lock lamps did not work on Win98. + Events regarding AltGr-keys behaved badly. + Example: On a Swedish keyboard, $ is typed with AltGr-4. + That keyboard event would get the keysym '4' not 'dollar'. + Also, doing [event generete . <Key-dollar>] would send keysym '4'. + Translation to ascii in TkpGetString did not handle return and + tab correctly. I.e. [event generate . <Key-Return>] gave wrong %A + * generic/tkDecls.h: * generic/tk.decls: * generic/tk.h: moved new public functions created in dash patch diff --git a/generic/tk.decls b/generic/tk.decls index f152cbd..fe8b72e 100644 --- a/generic/tk.decls +++ b/generic/tk.decls @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution # of this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: tk.decls,v 1.6 2000/02/08 11:31:32 hobbs Exp $ +# RCS: @(#) $Id: tk.decls,v 1.7 2000/02/09 02:13:50 hobbs Exp $ library tk @@ -1033,92 +1033,92 @@ declare 214 generic { } declare 215 generic { - void Tk_InitConsoleChannels(Tcl_Interp *interp) + void Tk_InitConsoleChannels (Tcl_Interp *interp) } declare 216 generic { - int Tk_CreateConsoleWindow(Tcl_Interp *interp) + int Tk_CreateConsoleWindow (Tcl_Interp *interp) } declare 217 generic { - void Tk_CreateSmoothMethod(Tcl_Interp *interp, Tk_SmoothMethod *method) + void Tk_CreateSmoothMethod (Tcl_Interp *interp, Tk_SmoothMethod *method) } #declare 218 generic { -# void Tk_CreateCanvasVisitor(Tcl_Interp *interp, VOID *typePtr) +# void Tk_CreateCanvasVisitor (Tcl_Interp *interp, VOID *typePtr) #} #declare 219 generic { -# VOID *Tk_GetCanvasVisitor(Tcl_Interp *interp, CONST char *name) +# VOID *Tk_GetCanvasVisitor (Tcl_Interp *interp, CONST char *name) #} declare 220 generic { - int Tk_GetDash(Tcl_Interp *interp, CONST char *value, Tk_Dash *dash) + int Tk_GetDash (Tcl_Interp *interp, CONST char *value, Tk_Dash *dash) } declare 221 generic { - void Tk_CreateOutline(Tk_Outline *outline) + void Tk_CreateOutline (Tk_Outline *outline) } declare 222 generic { - void Tk_DeleteOutline(Display *display, Tk_Outline *outline) + void Tk_DeleteOutline (Display *display, Tk_Outline *outline) } declare 223 generic { - int Tk_ConfigOutlineGC(XGCValues *gcValues, Tk_Canvas canvas, \ + int Tk_ConfigOutlineGC (XGCValues *gcValues, Tk_Canvas canvas, \ Tk_Item *item, Tk_Outline *outline) } declare 224 generic { - int Tk_ChangeOutlineGC(Tk_Canvas canvas, Tk_Item *item, \ + int Tk_ChangeOutlineGC (Tk_Canvas canvas, Tk_Item *item, \ Tk_Outline *outline) } declare 225 generic { - int Tk_ResetOutlineGC(Tk_Canvas canvas, Tk_Item *item, \ + int Tk_ResetOutlineGC (Tk_Canvas canvas, Tk_Item *item, \ Tk_Outline *outline) } declare 226 generic { - int Tk_CanvasPsOutline(Tk_Canvas canvas, Tk_Item *item, \ + int Tk_CanvasPsOutline (Tk_Canvas canvas, Tk_Item *item, \ Tk_Outline *outline) } declare 227 generic { - void Tk_SetTSOrigin(Tk_Window tkwin, GC gc, int x, int y) + void Tk_SetTSOrigin (Tk_Window tkwin, GC gc, int x, int y) } declare 228 generic { - int Tk_CanvasGetCoordFromObj(Tcl_Interp *interp, Tk_Canvas canvas, \ + int Tk_CanvasGetCoordFromObj (Tcl_Interp *interp, Tk_Canvas canvas, \ Tcl_Obj *obj, double *doublePtr) } declare 229 generic { - void Tk_CanvasSetOffset(Tk_Canvas canvas, GC gc, Tk_TSOffset *offset) + void Tk_CanvasSetOffset (Tk_Canvas canvas, GC gc, Tk_TSOffset *offset) } declare 230 generic { - void Tk_DitherPhoto(Tk_PhotoHandle handle, int x, int y, int width, \ + void Tk_DitherPhoto (Tk_PhotoHandle handle, int x, int y, int width, \ int height) } declare 231 generic { - int Tk_PostscriptBitmap(Tcl_Interp *interp, Tk_Window tkwin, \ + int Tk_PostscriptBitmap (Tcl_Interp *interp, Tk_Window tkwin, \ Tk_PostscriptInfo psInfo, Pixmap bitmap, int startX, \ int startY, int width, int height) } declare 232 generic { - int Tk_PostscriptColor(Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ + int Tk_PostscriptColor (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ XColor *colorPtr) } declare 233 generic { - int Tk_PostscriptFont(Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ + int Tk_PostscriptFont (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ Tk_Font font) } declare 234 generic { - int Tk_PostscriptImage(Tk_Image image, Tcl_Interp *interp, \ + int Tk_PostscriptImage (Tk_Image image, Tcl_Interp *interp, \ Tk_Window tkwin, Tk_PostscriptInfo psinfo, int x, int y, \ int width, int height, int prepass) } declare 235 generic { - void Tk_PostscriptPath(Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ + void Tk_PostscriptPath (Tcl_Interp *interp, Tk_PostscriptInfo psInfo, \ double *coordPtr, int numPoints) } declare 236 generic { - int Tk_PostscriptStipple(Tcl_Interp *interp, Tk_Window tkwin, \ + int Tk_PostscriptStipple (Tcl_Interp *interp, Tk_Window tkwin, \ Tk_PostscriptInfo psInfo, Pixmap bitmap) } declare 237 generic { - double Tk_PostscriptY(double y, Tk_PostscriptInfo psInfo) + double Tk_PostscriptY (double y, Tk_PostscriptInfo psInfo) } # Define the platform specific public Tk interface. These functions are diff --git a/generic/tkBind.c b/generic/tkBind.c index 5b53a4e..d54acfa 100644 --- a/generic/tkBind.c +++ b/generic/tkBind.c @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkBind.c,v 1.10 2000/01/13 02:07:10 hobbs Exp $ + * RCS: @(#) $Id: tkBind.c,v 1.11 2000/02/09 02:13:50 hobbs Exp $ */ #include "tkPort.h" @@ -665,8 +665,6 @@ static PatSeq * FindSequence _ANSI_ARGS_((Tcl_Interp *interp, static void GetAllVirtualEvents _ANSI_ARGS_((Tcl_Interp *interp, VirtualEventTable *vetPtr)); static char * GetField _ANSI_ARGS_((char *p, char *copy, int size)); -static KeySym GetKeySym _ANSI_ARGS_((TkDisplay *dispPtr, - XEvent *eventPtr)); static void GetPatternString _ANSI_ARGS_((PatSeq *psPtr, Tcl_DString *dsPtr)); static int GetVirtualEvent _ANSI_ARGS_((Tcl_Interp *interp, @@ -676,7 +674,6 @@ static Tk_Uid GetVirtualEventUid _ANSI_ARGS_((Tcl_Interp *interp, static int HandleEventGenerate _ANSI_ARGS_((Tcl_Interp *interp, Tk_Window main, int objc, Tcl_Obj *CONST objv[])); -static void InitKeymapInfo _ANSI_ARGS_((TkDisplay *dispPtr)); static void InitVirtualEventTable _ANSI_ARGS_(( VirtualEventTable *vetPtr)); static PatSeq * MatchPatterns _ANSI_ARGS_((TkDisplay *dispPtr, @@ -689,8 +686,6 @@ static int NameToWindow _ANSI_ARGS_((Tcl_Interp *interp, static int ParseEventDescription _ANSI_ARGS_((Tcl_Interp *interp, char **eventStringPtr, Pattern *patPtr, unsigned long *eventMaskPtr)); -static void SetKeycodeAndState _ANSI_ARGS_((Tk_Window tkwin, - KeySym keySym, XEvent *eventPtr)); static void DoWarp _ANSI_ARGS_((ClientData clientData)); /* @@ -1537,7 +1532,7 @@ Tk_BindEvent(bindingTable, eventPtr, tkwin, numObjects, objectPtr) detail.clientData = 0; flags = flagArray[ringPtr->type]; if (flags & KEY) { - detail.keySym = GetKeySym(dispPtr, ringPtr); + detail.keySym = TkpGetKeySym(dispPtr, ringPtr); if (detail.keySym == NoSymbol) { detail.keySym = 0; } @@ -3257,7 +3252,7 @@ HandleEventGenerate(interp, mainWin, objc, objv) if (flags & (KEY_BUTTON_MOTION_VIRTUAL)) { event.xkey.state = pat.needMods; if ((flags & KEY) && (event.xany.type != MouseWheelEvent)) { - SetKeycodeAndState(tkwin, pat.detail.keySym, &event); + TkpSetKeycodeAndState(tkwin, pat.detail.keySym, &event); } else if (flags & BUTTON) { event.xbutton.button = pat.detail.button; } else if (flags & VIRTUAL) { @@ -3440,7 +3435,7 @@ HandleEventGenerate(interp, mainWin, objc, objv) return TCL_ERROR; } - SetKeycodeAndState(tkwin, keysym, &event); + TkpSetKeycodeAndState(tkwin, keysym, &event); if (event.xkey.keycode == 0) { Tcl_AppendResult(interp, "no keycode for keysym \"", value, "\"", (char *) NULL); @@ -3737,50 +3732,6 @@ NameToWindow(interp, mainWin, objPtr, tkwinPtr) } return TCL_OK; } - -/* - * 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. - */ - -static void -SetKeycodeAndState(tkwin, keySym, eventPtr) - Tk_Window tkwin; - KeySym keySym; - XEvent *eventPtr; -{ - Display *display; - int state; - KeyCode keycode; - - display = Tk_Display(tkwin); - - if (keySym == NoSymbol) { - keycode = 0; - } else { - keycode = XKeysymToKeycode(display, keySym); - } - if (keycode != 0) { - for (state = 0; state < 4; state++) { - if (XKeycodeToKeysym(display, keycode, state) == keySym) { - if (state & 1) { - eventPtr->xkey.state |= ShiftMask; - } - if (state & 2) { - TkDisplay *dispPtr; - - dispPtr = ((TkWindow *) tkwin)->dispPtr; - eventPtr->xkey.state |= dispPtr->modeModMask; - } - break; - } - } - } - eventPtr->xkey.keycode = keycode; -} /* *------------------------------------------------------------------------- @@ -4431,220 +4382,6 @@ GetPatternString(psPtr, dsPtr) } /* - *---------------------------------------------------------------------- - * - * GetKeySym -- - * - * 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. - * - *---------------------------------------------------------------------- - */ - -static KeySym -GetKeySym(dispPtr, eventPtr) - 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) { - InitKeymapInfo(dispPtr); - } - - /* - * 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. - */ - - index = 0; - if (eventPtr->xkey.state & dispPtr->modeModMask) { - index = 2; - } - if ((eventPtr->xkey.state & ShiftMask) - || ((dispPtr->lockUsage != LU_IGNORE) - && (eventPtr->xkey.state & LockMask))) { - index += 1; - } - 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)) { - if (!(((sym >= XK_A) && (sym <= XK_Z)) - || ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) - || ((sym >= XK_Ooblique) && (sym <= XK_Thorn)))) { - 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; -} - -/* - *-------------------------------------------------------------- - * - * 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 = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); - 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 = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); - 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); -} - -/* *--------------------------------------------------------------------------- * * EvalTclBinding -- diff --git a/generic/tkInt.decls b/generic/tkInt.decls index 2c7def8..6a34794 100644 --- a/generic/tkInt.decls +++ b/generic/tkInt.decls @@ -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: tkInt.decls,v 1.14 2000/01/12 11:45:03 hobbs Exp $ +# RCS: @(#) $Id: tkInt.decls,v 1.15 2000/02/09 02:13:50 hobbs Exp $ library tk @@ -619,6 +619,16 @@ declare 136 generic { void TkSetFocusWin (TkWindow *winPtr, int force) } +declare 137 generic { + void TkpSetKeycodeAndState (Tk_Window tkwin, KeySym keySym, \ + XEvent *eventPtr) +} + +declare 138 generic { + KeySym TkpGetKeySym (TkDisplay *dispPtr, XEvent *eventPtr) +} + + ############################################################################## # Define the platform specific internal Tcl interface. These functions are diff --git a/generic/tkIntDecls.h b/generic/tkIntDecls.h index 8666b6a..fabe813 100644 --- a/generic/tkIntDecls.h +++ b/generic/tkIntDecls.h @@ -11,7 +11,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkIntDecls.h,v 1.8 1999/08/10 16:58:37 hobbs Exp $ + * RCS: @(#) $Id: tkIntDecls.h,v 1.9 2000/02/09 02:13:51 hobbs Exp $ */ #ifndef _TKINTDECLS @@ -506,6 +506,12 @@ EXTERN void TkpDrawHighlightBorder _ANSI_ARGS_((Tk_Window tkwin, /* 136 */ EXTERN void TkSetFocusWin _ANSI_ARGS_((TkWindow * winPtr, int force)); +/* 137 */ +EXTERN void TkpSetKeycodeAndState _ANSI_ARGS_((Tk_Window tkwin, + KeySym keySym, XEvent * eventPtr)); +/* 138 */ +EXTERN KeySym TkpGetKeySym _ANSI_ARGS_((TkDisplay * dispPtr, + XEvent * eventPtr)); typedef struct TkIntStubs { int magic; @@ -808,6 +814,8 @@ typedef struct TkIntStubs { #endif /* MAC_TCL */ void (*tkpDrawHighlightBorder) _ANSI_ARGS_((Tk_Window tkwin, GC fgGC, GC bgGC, int highlightWidth, Drawable drawable)); /* 135 */ void (*tkSetFocusWin) _ANSI_ARGS_((TkWindow * winPtr, int force)); /* 136 */ + void (*tkpSetKeycodeAndState) _ANSI_ARGS_((Tk_Window tkwin, KeySym keySym, XEvent * eventPtr)); /* 137 */ + KeySym (*tkpGetKeySym) _ANSI_ARGS_((TkDisplay * dispPtr, XEvent * eventPtr)); /* 138 */ } TkIntStubs; #ifdef __cplusplus @@ -1448,6 +1456,14 @@ extern TkIntStubs *tkIntStubsPtr; #define TkSetFocusWin \ (tkIntStubsPtr->tkSetFocusWin) /* 136 */ #endif +#ifndef TkpSetKeycodeAndState +#define TkpSetKeycodeAndState \ + (tkIntStubsPtr->tkpSetKeycodeAndState) /* 137 */ +#endif +#ifndef TkpGetKeySym +#define TkpGetKeySym \ + (tkIntStubsPtr->tkpGetKeySym) /* 138 */ +#endif #endif /* defined(USE_TK_STUBS) && !defined(USE_TK_STUB_PROCS) */ diff --git a/generic/tkStubInit.c b/generic/tkStubInit.c index c1f2607..0b8472f 100644 --- a/generic/tkStubInit.c +++ b/generic/tkStubInit.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkStubInit.c,v 1.16 2000/02/08 11:31:33 hobbs Exp $ + * RCS: @(#) $Id: tkStubInit.c,v 1.17 2000/02/09 02:13:51 hobbs Exp $ */ #include "tkInt.h" @@ -344,6 +344,8 @@ TkIntStubs tkIntStubs = { #endif /* MAC_TCL */ TkpDrawHighlightBorder, /* 135 */ TkSetFocusWin, /* 136 */ + TkpSetKeycodeAndState, /* 137 */ + TkpGetKeySym, /* 138 */ }; TkIntPlatStubs tkIntPlatStubs = { diff --git a/mac/tkMacKeyboard.c b/mac/tkMacKeyboard.c index 122cf06..b11afdd 100644 --- a/mac/tkMacKeyboard.c +++ b/mac/tkMacKeyboard.c @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkMacKeyboard.c,v 1.3 1999/04/16 01:51:31 stanton Exp $ + * RCS: @(#) $Id: tkMacKeyboard.c,v 1.4 2000/02/09 02:13:53 hobbs Exp $ */ #include "tkInt.h" @@ -72,6 +72,7 @@ static Ptr KCHRPtr; /* Pointer to 'KCHR' resource. */ * Prototypes for static functions used in this file. */ static void InitKeyMaps _ANSI_ARGS_((void)); +static void InitKeymapInfo _ANSI_ARGS_((TkDisplay *dispPtr)); /* @@ -386,3 +387,261 @@ XKeysymToKeycode( return keycode; } + +/* + * 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; +{ + Display *display; + int state; + KeyCode keycode; + + display = Tk_Display(tkwin); + + if (keySym == NoSymbol) { + keycode = 0; + } else { + keycode = XKeysymToKeycode(display, keySym); + } + if (keycode != 0) { + for (state = 0; state < 4; state++) { + if (XKeycodeToKeysym(display, keycode, state) == keySym) { + if (state & 1) { + eventPtr->xkey.state |= ShiftMask; + } + if (state & 2) { + TkDisplay *dispPtr; + + dispPtr = ((TkWindow *) tkwin)->dispPtr; + eventPtr->xkey.state |= dispPtr->modeModMask; + } + break; + } + } + } + eventPtr->xkey.keycode = 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 index; + + /* + * Refresh the mapping information if it's stale + */ + + if (dispPtr->bindInfoStale) { + InitKeymapInfo(dispPtr); + } + + /* + * 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. + */ + + index = 0; + if (eventPtr->xkey.state & dispPtr->modeModMask) { + index = 2; + } + if ((eventPtr->xkey.state & ShiftMask) + || ((dispPtr->lockUsage != LU_IGNORE) + && (eventPtr->xkey.state & LockMask))) { + index += 1; + } + 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)) { + if (!(((sym >= XK_A) && (sym <= XK_Z)) + || ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) + || ((sym >= XK_Ooblique) && (sym <= XK_Thorn)))) { + 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; +} + +/* + *-------------------------------------------------------------- + * + * 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 = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); + 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 = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); + 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); +} diff --git a/unix/tkUnixKey.c b/unix/tkUnixKey.c index effce2f..efba728 100644 --- a/unix/tkUnixKey.c +++ b/unix/tkUnixKey.c @@ -9,11 +9,17 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tkUnixKey.c,v 1.3 1999/12/16 21:59:13 hobbs Exp $ + * RCS: @(#) $Id: tkUnixKey.c,v 1.4 2000/02/09 02:13:54 hobbs Exp $ */ #include "tkInt.h" +/* + * Prototypes for local procedures defined in this file: + */ + +static void InitKeymapInfo _ANSI_ARGS_((TkDisplay *dispPtr)); + /* *---------------------------------------------------------------------- @@ -88,3 +94,261 @@ TkpGetString(winPtr, eventPtr, dsPtr) return Tcl_DStringValue(dsPtr); } + +/* + * 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; +{ + Display *display; + int state; + KeyCode keycode; + + display = Tk_Display(tkwin); + + if (keySym == NoSymbol) { + keycode = 0; + } else { + keycode = XKeysymToKeycode(display, keySym); + } + if (keycode != 0) { + for (state = 0; state < 4; state++) { + if (XKeycodeToKeysym(display, keycode, state) == keySym) { + if (state & 1) { + eventPtr->xkey.state |= ShiftMask; + } + if (state & 2) { + TkDisplay *dispPtr; + + dispPtr = ((TkWindow *) tkwin)->dispPtr; + eventPtr->xkey.state |= dispPtr->modeModMask; + } + break; + } + } + } + eventPtr->xkey.keycode = 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 index; + + /* + * Refresh the mapping information if it's stale + */ + + if (dispPtr->bindInfoStale) { + InitKeymapInfo(dispPtr); + } + + /* + * 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. + */ + + index = 0; + if (eventPtr->xkey.state & dispPtr->modeModMask) { + index = 2; + } + if ((eventPtr->xkey.state & ShiftMask) + || ((dispPtr->lockUsage != LU_IGNORE) + && (eventPtr->xkey.state & LockMask))) { + index += 1; + } + 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)) { + if (!(((sym >= XK_A) && (sym <= XK_Z)) + || ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis)) + || ((sym >= XK_Ooblique) && (sym <= XK_Thorn)))) { + 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; +} + +/* + *-------------------------------------------------------------- + * + * 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 = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); + 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 = XKeycodeToKeysym(dispPtr->display, *codePtr, 0); + 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); +} 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); } } |