summaryrefslogtreecommitdiffstats
path: root/unix/tkUnixKey.c
diff options
context:
space:
mode:
Diffstat (limited to 'unix/tkUnixKey.c')
-rw-r--r--unix/tkUnixKey.c331
1 files changed, 207 insertions, 124 deletions
diff --git a/unix/tkUnixKey.c b/unix/tkUnixKey.c
index 8753fdb..030e472 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,53 +6,71 @@
*
* 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"
/*
- * 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, (void *) NULL);
+ XSetICValues(winPtr->inputContext,
+ XNPreeditAttributes, preedit_attr,
+ (void *) NULL);
+ XFree(preedit_attr);
+ }
+#endif
}
/*
@@ -66,47 +84,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);
+ Tcl_DStringValue(&buf), Tcl_DStringLength(&buf),
+ &kePtr->keysym, &status);
+
/*
* If the buffer wasn't big enough, grow the buffer and try again.
*/
@@ -114,64 +154,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 XKeycodeToKeysym 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 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;
+TkpSetKeycodeAndState(
+ Tk_Window tkwin,
+ KeySym keySym,
+ XEvent *eventPtr)
{
Display *display;
int state;
KeyCode keycode;
-
+
display = Tk_Display(tkwin);
-
+
if (keySym == NoSymbol) {
keycode = 0;
} else {
@@ -201,29 +256,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
@@ -234,9 +310,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;
@@ -251,10 +327,9 @@ TkpGetKeySym(dispPtr, eventPtr)
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.
+ * 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)
@@ -269,8 +344,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)) {
@@ -285,10 +360,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.
@@ -300,8 +374,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;
@@ -314,9 +388,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;
@@ -337,9 +411,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;
@@ -372,8 +446,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;
@@ -392,20 +466,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:
+ */