From 059c15807f394adcfc695c32df5b50ce2c7e246a Mon Sep 17 00:00:00 2001 From: hobbs Date: Wed, 9 Feb 2000 02:13:43 +0000 Subject: * 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 . ] would send keysym '4'. Translation to ascii in TkpGetString did not handle return and tab correctly. I.e. [event generate . ] gave wrong %A --- ChangeLog | 41 ++++++ generic/tk.decls | 48 +++---- generic/tkBind.c | 271 +---------------------------------- generic/tkInt.decls | 12 +- generic/tkIntDecls.h | 18 ++- generic/tkStubInit.c | 4 +- mac/tkMacKeyboard.c | 261 +++++++++++++++++++++++++++++++++- unix/tkUnixKey.c | 266 +++++++++++++++++++++++++++++++++- win/tkWinKey.c | 394 ++++++++++++++++++++++++++++++++++++++++++++++++--- 9 files changed, 1001 insertions(+), 314 deletions(-) diff --git a/ChangeLog b/ChangeLog index 069265e..b89e1c7 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,46 @@ 2000-02-08 Jeff Hobbs + * 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 . ] would send keysym '4'. + Translation to ascii in TkpGetString did not handle return and + tab correctly. I.e. [event generate . ] 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); } } -- cgit v0.12