diff options
Diffstat (limited to 'unix/tkUnixKey.c')
-rw-r--r-- | unix/tkUnixKey.c | 329 |
1 files changed, 206 insertions, 123 deletions
diff --git a/unix/tkUnixKey.c b/unix/tkUnixKey.c index ee77cab..b7fc97f 100644 --- a/unix/tkUnixKey.c +++ b/unix/tkUnixKey.c @@ -1,4 +1,4 @@ -/* +/* * tkUnixKey.c -- * * This file contains routines for dealing with international keyboard @@ -6,54 +6,72 @@ * * Copyright (c) 1997 by Sun Microsystems, Inc. * - * See the file "license.terms" for information on usage and redistribution - * of this file, and for a DISCLAIMER OF ALL WARRANTIES. + * See the file "license.terms" for information on usage and redistribution of + * this file, and for a DISCLAIMER OF ALL WARRANTIES. */ #include "tkInt.h" #include <X11/XKBlib.h> /* - * Prototypes for local procedures defined in this file: + * Prototypes for local functions defined in this file: */ - /* *---------------------------------------------------------------------- * * Tk_SetCaretPos -- * - * This enables correct placement of the XIM caret. This is called - * by widgets to indicate their cursor placement, and the caret - * location is used by TkpGetString to place the XIM caret. - * This is currently only used for over-the-spot XIM. - * - * Results: - * None - * - * Side effects: - * None + * This enables correct placement of the XIM caret. This is called by + * widgets to indicate their cursor placement. This is currently only + * used for over-the-spot XIM. * *---------------------------------------------------------------------- */ void -Tk_SetCaretPos(tkwin, x, y, height) - Tk_Window tkwin; - int x; - int y; - int height; +Tk_SetCaretPos( + Tk_Window tkwin, + int x, + int y, + int height) { - TkCaret *caretPtr = &(((TkWindow *) tkwin)->dispPtr->caret); + TkWindow *winPtr = (TkWindow *) tkwin; + TkDisplay *dispPtr = winPtr->dispPtr; + if ( dispPtr->caret.winPtr == winPtr + && dispPtr->caret.x == x + && dispPtr->caret.y == y + && dispPtr->caret.height == height) + { + return; + } + + dispPtr->caret.winPtr = winPtr; + dispPtr->caret.x = x; + dispPtr->caret.y = y; + dispPtr->caret.height = height; + +#ifdef TK_USE_INPUT_METHODS /* - * Use height for best placement of the XIM over-the-spot box. + * Adjust the XIM caret position. */ + if ( (dispPtr->flags & TK_DISPLAY_USE_IM) + && (dispPtr->inputStyle & XIMPreeditPosition) + && (winPtr->inputContext != NULL) ) + { + XVaNestedList preedit_attr; + XPoint spot; - caretPtr->winPtr = ((TkWindow *) tkwin); - caretPtr->x = x; - caretPtr->y = y; - caretPtr->height = height; + spot.x = dispPtr->caret.x; + spot.y = dispPtr->caret.y + dispPtr->caret.height; + preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); + XSetICValues(winPtr->inputContext, + XNPreeditAttributes, preedit_attr, + NULL); + XFree(preedit_attr); + } +#endif } /* @@ -67,47 +85,69 @@ Tk_SetCaretPos(tkwin, x, y, height) * Returns the UTF string. * * Side effects: - * Stores the input string in the specified Tcl_DString. Modifies - * the internal input state. This routine can only be called - * once for a given event. + * Stores the input string in the specified Tcl_DString. Modifies the + * internal input state. This routine can only be called once for a given + * event. * *---------------------------------------------------------------------- */ char * -TkpGetString(winPtr, eventPtr, dsPtr) - TkWindow *winPtr; /* Window where event occurred: needed to - * get input context. */ - XEvent *eventPtr; /* X keyboard event. */ - Tcl_DString *dsPtr; /* Uninitialized or empty string to hold - * result. */ +TkpGetString( + TkWindow *winPtr, /* Window where event occurred */ + XEvent *eventPtr, /* X keyboard event. */ + Tcl_DString *dsPtr) /* Initialized, empty string to hold result. */ { int len; Tcl_DString buf; - Status status; -#ifdef TK_USE_INPUT_METHODS - TkDisplay *dispPtr = winPtr->dispPtr; -#endif + TkKeyEvent *kePtr = (TkKeyEvent *) eventPtr; /* - * Overallocate the dstring to the maximum stack amount. + * If we have the value cached already, use it now. [Bug 1373712] */ - Tcl_DStringInit(&buf); - Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1); + if (kePtr->charValuePtr != NULL) { + Tcl_DStringSetLength(dsPtr, kePtr->charValueLen); + memcpy(Tcl_DStringValue(dsPtr), kePtr->charValuePtr, + (unsigned) kePtr->charValueLen+1); + return Tcl_DStringValue(dsPtr); + } #ifdef TK_USE_INPUT_METHODS - if ((dispPtr->flags & TK_DISPLAY_USE_IM) + if ((winPtr->dispPtr->flags & TK_DISPLAY_USE_IM) && (winPtr->inputContext != NULL) - && (eventPtr->type == KeyPress)) { -#if TK_XIM_SPOT - XVaNestedList preedit_attr; - XPoint spot; -#endif + && (eventPtr->type == KeyPress)) + { + Status status; + +#if X_HAVE_UTF8_STRING + Tcl_DStringSetLength(dsPtr, TCL_DSTRING_STATIC_SIZE-1); + len = Xutf8LookupString(winPtr->inputContext, &eventPtr->xkey, + Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr), + &kePtr->keysym, &status); + + if (status == XBufferOverflow) { /* Expand buffer and try again */ + Tcl_DStringSetLength(dsPtr, len); + len = Xutf8LookupString(winPtr->inputContext, &eventPtr->xkey, + Tcl_DStringValue(dsPtr), Tcl_DStringLength(dsPtr), + &kePtr->keysym, &status); + } + if ((status != XLookupChars) && (status != XLookupBoth)) { + len = 0; + } + Tcl_DStringSetLength(dsPtr, len); +#else /* !X_HAVE_UTF8_STRING */ + /* + * Overallocate the dstring to the maximum stack amount. + */ + + Tcl_DStringInit(&buf); + Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1); len = XmbLookupString(winPtr->inputContext, &eventPtr->xkey, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf), - (KeySym *) NULL, &status); + &kePtr->keysym, &status); + /* * If the buffer wasn't big enough, grow the buffer and try again. */ @@ -115,64 +155,79 @@ TkpGetString(winPtr, eventPtr, dsPtr) if (status == XBufferOverflow) { Tcl_DStringSetLength(&buf, len); len = XmbLookupString(winPtr->inputContext, &eventPtr->xkey, - Tcl_DStringValue(&buf), len, (KeySym *) NULL, &status); + Tcl_DStringValue(&buf), len, &kePtr->keysym, &status); } if ((status != XLookupChars) && (status != XLookupBoth)) { len = 0; } -#if TK_XIM_SPOT + Tcl_DStringSetLength(&buf, len); + Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buf), len, dsPtr); + Tcl_DStringFree(&buf); +#endif /* X_HAVE_UTF8_STRING */ + } else +#endif /* TK_USE_INPUT_METHODS */ + { /* - * Adjust the XIM caret position. We might want to check that - * this is the right caret.winPtr as well. + * Fall back to convert a keyboard event to a UTF-8 string using + * XLookupString. This is used when input methods are turned off and + * for KeyRelease events. + * + * Note: XLookupString() normally returns a single ISO Latin 1 or + * ASCII control character. */ - if (dispPtr->flags & TK_DISPLAY_XIM_SPOT) { - spot.x = dispPtr->caret.x; - spot.y = dispPtr->caret.y + dispPtr->caret.height; - preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL); - XSetICValues(winPtr->inputContext, - XNPreeditAttributes, preedit_attr, NULL); - XFree(preedit_attr); - } -#endif - } else { + + Tcl_DStringInit(&buf); + Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1); len = XLookupString(&eventPtr->xkey, Tcl_DStringValue(&buf), - Tcl_DStringLength(&buf), (KeySym *) NULL, - (XComposeStatus *) NULL); + TCL_DSTRING_STATIC_SIZE, &kePtr->keysym, 0); + Tcl_DStringValue(&buf)[len] = '\0'; + + if (len == 1) { + len = Tcl_UniCharToUtf((unsigned char) Tcl_DStringValue(&buf)[0], + Tcl_DStringValue(dsPtr)); + Tcl_DStringSetLength(dsPtr, len); + } else { + /* + * len > 1 should only happen if someone has called XRebindKeysym. + * Assume UTF-8. + */ + + Tcl_DStringSetLength(dsPtr, len); + strncpy(Tcl_DStringValue(dsPtr), Tcl_DStringValue(&buf), len); + } } -#else /* TK_USE_INPUT_METHODS */ - len = XLookupString(&eventPtr->xkey, Tcl_DStringValue(&buf), - Tcl_DStringLength(&buf), (KeySym *) NULL, - (XComposeStatus *) NULL); -#endif /* TK_USE_INPUT_METHODS */ - Tcl_DStringSetLength(&buf, len); - Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buf), len, dsPtr); - Tcl_DStringFree(&buf); + /* + * Cache the string in the event so that if/when we return to this + * function, we will be able to produce it without asking X. This stops us + * from having to reenter the XIM engine. [Bug 1373712] + */ + kePtr->charValuePtr = ckalloc((unsigned) len + 1); + kePtr->charValueLen = len; + memcpy(kePtr->charValuePtr, Tcl_DStringValue(dsPtr), (unsigned) len + 1); 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 XkbKeycodeToKeysym taking into - * account the xkey.state, they will get back the original - * keysym. + * When mapping from a keysym to a keycode, need information about the + * modifier state to be used so that when they call XkbKeycodeToKeysym 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; +TkpSetKeycodeAndState( + Tk_Window tkwin, + KeySym keySym, + XEvent *eventPtr) { Display *display; int state; KeyCode keycode; - + display = Tk_Display(tkwin); - + if (keySym == NoSymbol) { keycode = 0; } else { @@ -202,29 +257,50 @@ TkpSetKeycodeAndState(tkwin, keySym, eventPtr) * * TkpGetKeySym -- * - * Given an X KeyPress or KeyRelease event, map the - * keycode in the event into a KeySym. + * 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. + * 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. + * 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. */ +TkpGetKeySym( + TkDisplay *dispPtr, /* Display in which to map keycode. */ + XEvent *eventPtr) /* Description of X event. */ { KeySym sym; int index; + TkKeyEvent* kePtr = (TkKeyEvent*) eventPtr; + +#ifdef TK_USE_INPUT_METHODS + /* + * If input methods are active, we may already have determined a keysym. + * Return it. + */ + + if (eventPtr->type == KeyPress && dispPtr + && (dispPtr->flags & TK_DISPLAY_USE_IM)) { + if (kePtr->charValuePtr == NULL) { + Tcl_DString ds; + TkWindow *winPtr = (TkWindow *) + Tk_IdToWindow(eventPtr->xany.display, eventPtr->xany.window); + Tcl_DStringInit(&ds); + (void) TkpGetString(winPtr, eventPtr, &ds); + Tcl_DStringFree(&ds); + } + if (kePtr->charValuePtr != NULL) { + return kePtr->keysym; + } + } +#endif /* * Refresh the mapping information if it's stale @@ -235,9 +311,9 @@ TkpGetKeySym(dispPtr, eventPtr) } /* - * 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. + * 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; @@ -253,10 +329,9 @@ TkpGetKeySym(dispPtr, eventPtr) 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. + * 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) @@ -271,8 +346,8 @@ TkpGetKeySym(dispPtr, eventPtr) } /* - * 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. + * 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)) { @@ -287,10 +362,9 @@ TkpGetKeySym(dispPtr, eventPtr) * * TkpInitKeymapInfo -- * - * This procedure is invoked to scan keymap information - * to recompute stuff that's important for binding, such - * as the modifier key (if any) that corresponds to "mode - * switch". + * This function 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. @@ -302,8 +376,8 @@ TkpGetKeySym(dispPtr, eventPtr) */ void -TkpInitKeymapInfo(dispPtr) - TkDisplay *dispPtr; /* Display for which to recompute keymap +TkpInitKeymapInfo( + TkDisplay *dispPtr) /* Display for which to recompute keymap * information. */ { XModifierKeymap *modMapPtr; @@ -316,9 +390,9 @@ TkpInitKeymapInfo(dispPtr) 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. + * 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; @@ -339,9 +413,9 @@ TkpInitKeymapInfo(dispPtr) } /* - * 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. + * 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; @@ -374,8 +448,8 @@ TkpInitKeymapInfo(dispPtr) } dispPtr->numModKeyCodes = 0; arraySize = KEYCODE_ARRAY_SIZE; - dispPtr->modKeyCodes = (KeyCode *) ckalloc((unsigned) - (KEYCODE_ARRAY_SIZE * sizeof(KeyCode))); + dispPtr->modKeyCodes = (KeyCode *) + ckalloc((unsigned) (KEYCODE_ARRAY_SIZE * sizeof(KeyCode))); for (i = 0, codePtr = modMapPtr->modifiermap; i < max; i++, codePtr++) { if (*codePtr == 0) { continue; @@ -394,20 +468,29 @@ TkpInitKeymapInfo(dispPtr) KeyCode *new; /* - * Ran out of space in the array; grow it. + * Ran out of space in the array; grow it. */ arraySize *= 2; - new = (KeyCode *) ckalloc((unsigned) - (arraySize * sizeof(KeyCode))); - memcpy((VOID *) new, (VOID *) dispPtr->modKeyCodes, + new = (KeyCode *) + ckalloc((unsigned) (arraySize * sizeof(KeyCode))); + memcpy(new, dispPtr->modKeyCodes, (dispPtr->numModKeyCodes * sizeof(KeyCode))); ckfree((char *) dispPtr->modKeyCodes); dispPtr->modKeyCodes = new; } dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr; dispPtr->numModKeyCodes++; - nextModCode: continue; + nextModCode: + continue; } XFreeModifiermap(modMapPtr); } + +/* + * Local Variables: + * mode: c + * c-basic-offset: 4 + * fill-column: 78 + * End: + */ |