diff options
Diffstat (limited to 'unix/tkUnixKey.c')
-rw-r--r-- | unix/tkUnixKey.c | 147 |
1 files changed, 67 insertions, 80 deletions
diff --git a/unix/tkUnixKey.c b/unix/tkUnixKey.c index 2fb8ebc..d482b16 100644 --- a/unix/tkUnixKey.c +++ b/unix/tkUnixKey.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: tkUnixKey.c,v 1.13.2.1 2008/06/11 00:41:25 jenglish Exp $ + * RCS: @(#) $Id: tkUnixKey.c,v 1.13.2.2 2010/01/02 10:43:26 dkf Exp $ */ #include "tkInt.h" @@ -78,48 +78,6 @@ Tk_SetCaretPos( /* *---------------------------------------------------------------------- * - * TkpGetChar -- - * - * Convert a keyboard event to a UTF-8 string using XLookupString. - * - * This is used as a fallback instead of Xutf8LookupString - * or XmbLookupString if input methods are turned off - * and for KeyRelease events. - * - * Notes: - * XLookupString() normally returns a single ISO Latin 1 - * or ASCII control character. - * - *---------------------------------------------------------------------- - */ -static char * -TkpGetChar( - XEvent *eventPtr, /* KeyPress or KeyRelease event */ - Tcl_DString *dsPtr) /* Initialized, empty string to hold result. */ -{ - int len; - char buf[TCL_DSTRING_STATIC_SIZE]; - - len = XLookupString(&eventPtr->xkey, buf, TCL_DSTRING_STATIC_SIZE, 0, 0); - buf[len] = '\0'; - - if (len == 1) { - len = Tcl_UniCharToUtf((unsigned char)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), buf, len); - } - return Tcl_DStringValue(dsPtr); -} - -/* - *---------------------------------------------------------------------- - * * TkpGetString -- * * Retrieve the UTF string associated with a keyboard event. @@ -140,16 +98,30 @@ TkpGetString( TkWindow *winPtr, /* Window where event occurred */ XEvent *eventPtr, /* X keyboard event. */ Tcl_DString *dsPtr) /* Initialized, empty string to hold result. */ -#ifdef TK_USE_INPUT_METHODS -#if X_HAVE_UTF8_STRING { + int len; + Tcl_DString buf; + TkKeyEvent *kePtr = (TkKeyEvent *) eventPtr; + + /* + * If we have the value cached already, use it now. [Bug 1373712] + */ + + 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 ((winPtr->dispPtr->flags & TK_DISPLAY_USE_IM) && (winPtr->inputContext != NULL) && (eventPtr->type == KeyPress)) { - int len; 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), @@ -162,32 +134,16 @@ TkpGetString( NULL, &status); } if ((status != XLookupChars) && (status != XLookupBoth)) { - Tcl_DStringSetLength(dsPtr, 0); len = 0; } Tcl_DStringSetLength(dsPtr, len); - - return Tcl_DStringValue(dsPtr); - } else { - return TkpGetChar(eventPtr, dsPtr); - } -} #else /* !X_HAVE_UTF8_STRING */ -{ - int len; - Tcl_DString buf; - Status status; - - /* - * Overallocate the dstring to the maximum stack amount. - */ - - Tcl_DStringInit(&buf); - Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1); + /* + * Overallocate the dstring to the maximum stack amount. + */ - if ((winPtr->dispPtr->flags & TK_DISPLAY_USE_IM) - && (winPtr->inputContext != NULL) - && (eventPtr->type == KeyPress)) { + Tcl_DStringInit(&buf); + Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1); len = XmbLookupString(winPtr->inputContext, &eventPtr->xkey, Tcl_DStringValue(&buf), Tcl_DStringLength(&buf), NULL, @@ -205,24 +161,55 @@ TkpGetString( if ((status != XLookupChars) && (status != XLookupBoth)) { len = 0; } - } else { - return TkpGetChar(eventPtr, dsPtr); + + 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 */ + { + /* + * 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. + */ + + Tcl_DStringInit(&buf); + Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1); + len = XLookupString(&eventPtr->xkey, Tcl_DStringValue(&buf), + TCL_DSTRING_STATIC_SIZE, 0, 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); + } } - 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); } - -#endif /* X_HAVE_UTF8_STRING */ -#else /* !TK_USE_INPUT_METHODS */ -{ - return TkpGetChar(eventPtr, dsPtr); -} -#endif - /* * When mapping from a keysym to a keycode, need information about the |