tkUnixKey.c
上传用户:rrhhcc
上传日期:2015-12-11
资源大小:54129k
文件大小:11k
源码类别:

通讯编程

开发平台:

Visual C++

  1. /* 
  2.  * tkUnixKey.c --
  3.  *
  4.  * This file contains routines for dealing with international keyboard
  5.  * input.
  6.  *
  7.  * Copyright (c) 1997 by Sun Microsystems, Inc.
  8.  *
  9.  * See the file "license.terms" for information on usage and redistribution
  10.  * of this file, and for a DISCLAIMER OF ALL WARRANTIES.
  11.  *
  12.  * RCS: @(#) $Id: tkUnixKey.c,v 1.10 2002/06/17 20:09:01 hobbs Exp $
  13.  */
  14. #include "tkInt.h"
  15. /*
  16.  * Prototypes for local procedures defined in this file:
  17.  */
  18. /*
  19.  *----------------------------------------------------------------------
  20.  *
  21.  * Tk_SetCaretPos --
  22.  *
  23.  * This enables correct placement of the XIM caret.  This is called
  24.  * by widgets to indicate their cursor placement, and the caret
  25.  * location is used by TkpGetString to place the XIM caret.
  26.  * This is currently only used for over-the-spot XIM.
  27.  *
  28.  * Results:
  29.  * None
  30.  *
  31.  * Side effects:
  32.  * None
  33.  *
  34.  *----------------------------------------------------------------------
  35.  */
  36. void
  37. Tk_SetCaretPos(tkwin, x, y, height)
  38.     Tk_Window tkwin;
  39.     int       x;
  40.     int       y;
  41.     int       height;
  42. {
  43.     TkCaret *caretPtr = &(((TkWindow *) tkwin)->dispPtr->caret);
  44.     /*
  45.      * Use height for best placement of the XIM over-the-spot box.
  46.      */
  47.     caretPtr->winPtr = ((TkWindow *) tkwin);
  48.     caretPtr->x = x;
  49.     caretPtr->y = y;
  50.     caretPtr->height = height;
  51. }
  52. /*
  53.  *----------------------------------------------------------------------
  54.  *
  55.  * TkpGetString --
  56.  *
  57.  * Retrieve the UTF string associated with a keyboard event.
  58.  *
  59.  * Results:
  60.  * Returns the UTF string.
  61.  *
  62.  * Side effects:
  63.  * Stores the input string in the specified Tcl_DString.  Modifies
  64.  * the internal input state.  This routine can only be called
  65.  * once for a given event.
  66.  *
  67.  *----------------------------------------------------------------------
  68.  */
  69. char *
  70. TkpGetString(winPtr, eventPtr, dsPtr)
  71.     TkWindow *winPtr; /* Window where event occurred:  needed to
  72.  * get input context. */
  73.     XEvent *eventPtr; /* X keyboard event. */
  74.     Tcl_DString *dsPtr; /* Uninitialized or empty string to hold
  75.  * result. */
  76. {
  77.     int len;
  78.     Tcl_DString buf;
  79.     Status status;
  80. #ifdef TK_USE_INPUT_METHODS
  81.     TkDisplay *dispPtr = winPtr->dispPtr;
  82. #endif
  83.     /*
  84.      * Overallocate the dstring to the maximum stack amount.
  85.      */
  86.     Tcl_DStringInit(&buf);
  87.     Tcl_DStringSetLength(&buf, TCL_DSTRING_STATIC_SIZE-1);
  88. #ifdef TK_USE_INPUT_METHODS
  89.     if ((dispPtr->flags & TK_DISPLAY_USE_IM)
  90.     && (winPtr->inputContext != NULL)
  91.     && (eventPtr->type == KeyPress)) {
  92. #if TK_XIM_SPOT
  93. XVaNestedList preedit_attr;
  94. XPoint spot;
  95. #endif
  96. len = XmbLookupString(winPtr->inputContext, &eventPtr->xkey,
  97. Tcl_DStringValue(&buf), Tcl_DStringLength(&buf),
  98. (KeySym *) NULL, &status);
  99. /*
  100.  * If the buffer wasn't big enough, grow the buffer and try again.
  101.  */
  102. if (status == XBufferOverflow) {
  103.     Tcl_DStringSetLength(&buf, len);
  104.     len = XmbLookupString(winPtr->inputContext, &eventPtr->xkey,
  105.     Tcl_DStringValue(&buf), len, (KeySym *) NULL, &status);
  106. }
  107. if ((status != XLookupChars) && (status != XLookupBoth)) {
  108.     len = 0;
  109. }
  110. #if TK_XIM_SPOT
  111. /*
  112.  * Adjust the XIM caret position.  We might want to check that
  113.  * this is the right caret.winPtr as well.
  114.  */
  115. if (dispPtr->flags & TK_DISPLAY_XIM_SPOT) {
  116.     spot.x = dispPtr->caret.x;
  117.     spot.y = dispPtr->caret.y + dispPtr->caret.height;
  118.     preedit_attr = XVaCreateNestedList(0, XNSpotLocation, &spot, NULL);
  119.     XSetICValues(winPtr->inputContext,
  120.     XNPreeditAttributes, preedit_attr, NULL);
  121.     XFree(preedit_attr);
  122. }
  123. #endif
  124.     } else {
  125. len = XLookupString(&eventPtr->xkey, Tcl_DStringValue(&buf),
  126. Tcl_DStringLength(&buf), (KeySym *) NULL,
  127. (XComposeStatus *) NULL);
  128.     }
  129. #else /* TK_USE_INPUT_METHODS */
  130.     len = XLookupString(&eventPtr->xkey, Tcl_DStringValue(&buf),
  131.     Tcl_DStringLength(&buf), (KeySym *) NULL,
  132.     (XComposeStatus *) NULL);
  133. #endif /* TK_USE_INPUT_METHODS */
  134.     Tcl_DStringSetLength(&buf, len);
  135.     Tcl_ExternalToUtfDString(NULL, Tcl_DStringValue(&buf), len, dsPtr);
  136.     Tcl_DStringFree(&buf);
  137.     return Tcl_DStringValue(dsPtr);
  138. }
  139. /*
  140.  * When mapping from a keysym to a keycode, need
  141.  * information about the modifier state that should be used
  142.  * so that when they call XKeycodeToKeysym taking into
  143.  * account the xkey.state, they will get back the original
  144.  * keysym.
  145.  */
  146. void
  147. TkpSetKeycodeAndState(tkwin, keySym, eventPtr)
  148.     Tk_Window tkwin;
  149.     KeySym keySym;
  150.     XEvent *eventPtr;
  151. {
  152.     Display *display;
  153.     int state;
  154.     KeyCode keycode;
  155.     
  156.     display = Tk_Display(tkwin);
  157.     
  158.     if (keySym == NoSymbol) {
  159. keycode = 0;
  160.     } else {
  161. keycode = XKeysymToKeycode(display, keySym);
  162.     }
  163.     if (keycode != 0) {
  164. for (state = 0; state < 4; state++) {
  165.     if (XKeycodeToKeysym(display, keycode, state) == keySym) {
  166. if (state & 1) {
  167.     eventPtr->xkey.state |= ShiftMask;
  168. }
  169. if (state & 2) {
  170.     TkDisplay *dispPtr;
  171.     dispPtr = ((TkWindow *) tkwin)->dispPtr;
  172.     eventPtr->xkey.state |= dispPtr->modeModMask;
  173. }
  174. break;
  175.     }
  176. }
  177.     }
  178.     eventPtr->xkey.keycode = keycode;
  179. }
  180. /*
  181.  *----------------------------------------------------------------------
  182.  *
  183.  * TkpGetKeySym --
  184.  *
  185.  * Given an X KeyPress or KeyRelease event, map the
  186.  * keycode in the event into a KeySym.
  187.  *
  188.  * Results:
  189.  * The return value is the KeySym corresponding to
  190.  * eventPtr, or NoSymbol if no matching Keysym could be
  191.  * found.
  192.  *
  193.  * Side effects:
  194.  * In the first call for a given display, keycode-to-
  195.  * KeySym maps get loaded.
  196.  *
  197.  *----------------------------------------------------------------------
  198.  */
  199. KeySym
  200. TkpGetKeySym(dispPtr, eventPtr)
  201.     TkDisplay *dispPtr; /* Display in which to
  202.  * map keycode. */
  203.     XEvent *eventPtr; /* Description of X event. */
  204. {
  205.     KeySym sym;
  206.     int index;
  207.     /*
  208.      * Refresh the mapping information if it's stale
  209.      */
  210.     if (dispPtr->bindInfoStale) {
  211. TkpInitKeymapInfo(dispPtr);
  212.     }
  213.     /*
  214.      * Figure out which of the four slots in the keymap vector to
  215.      * use for this key.  Refer to Xlib documentation for more info
  216.      * on how this computation works.
  217.      */
  218.     index = 0;
  219.     if (eventPtr->xkey.state & dispPtr->modeModMask) {
  220. index = 2;
  221.     }
  222.     if ((eventPtr->xkey.state & ShiftMask)
  223.     || ((dispPtr->lockUsage != LU_IGNORE)
  224.     && (eventPtr->xkey.state & LockMask))) {
  225. index += 1;
  226.     }
  227.     sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode, index);
  228.     /*
  229.      * Special handling:  if the key was shifted because of Lock, but
  230.      * lock is only caps lock, not shift lock, and the shifted keysym
  231.      * isn't upper-case alphabetic, then switch back to the unshifted
  232.      * keysym.
  233.      */
  234.     if ((index & 1) && !(eventPtr->xkey.state & ShiftMask)
  235.     && (dispPtr->lockUsage == LU_CAPS)) {
  236. if (!(((sym >= XK_A) && (sym <= XK_Z))
  237. || ((sym >= XK_Agrave) && (sym <= XK_Odiaeresis))
  238. || ((sym >= XK_Ooblique) && (sym <= XK_Thorn)))) {
  239.     index &= ~1;
  240.     sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
  241.     index);
  242. }
  243.     }
  244.     /*
  245.      * Another bit of special handling:  if this is a shifted key and there
  246.      * is no keysym defined, then use the keysym for the unshifted key.
  247.      */
  248.     if ((index & 1) && (sym == NoSymbol)) {
  249. sym = XKeycodeToKeysym(dispPtr->display, eventPtr->xkey.keycode,
  250. index & ~1);
  251.     }
  252.     return sym;
  253. }
  254. /*
  255.  *--------------------------------------------------------------
  256.  *
  257.  * TkpInitKeymapInfo --
  258.  *
  259.  * This procedure is invoked to scan keymap information
  260.  * to recompute stuff that's important for binding, such
  261.  * as the modifier key (if any) that corresponds to "mode
  262.  * switch".
  263.  *
  264.  * Results:
  265.  * None.
  266.  *
  267.  * Side effects:
  268.  * Keymap-related information in dispPtr is updated.
  269.  *
  270.  *--------------------------------------------------------------
  271.  */
  272. void
  273. TkpInitKeymapInfo(dispPtr)
  274.     TkDisplay *dispPtr; /* Display for which to recompute keymap
  275.  * information. */
  276. {
  277.     XModifierKeymap *modMapPtr;
  278.     KeyCode *codePtr;
  279.     KeySym keysym;
  280.     int count, i, j, max, arraySize;
  281. #define KEYCODE_ARRAY_SIZE 20
  282.     dispPtr->bindInfoStale = 0;
  283.     modMapPtr = XGetModifierMapping(dispPtr->display);
  284.     /*
  285.      * Check the keycodes associated with the Lock modifier.  If
  286.      * any of them is associated with the XK_Shift_Lock modifier,
  287.      * then Lock has to be interpreted as Shift Lock, not Caps Lock.
  288.      */
  289.     dispPtr->lockUsage = LU_IGNORE;
  290.     codePtr = modMapPtr->modifiermap + modMapPtr->max_keypermod*LockMapIndex;
  291.     for (count = modMapPtr->max_keypermod; count > 0; count--, codePtr++) {
  292. if (*codePtr == 0) {
  293.     continue;
  294. }
  295. keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0);
  296. if (keysym == XK_Shift_Lock) {
  297.     dispPtr->lockUsage = LU_SHIFT;
  298.     break;
  299. }
  300. if (keysym == XK_Caps_Lock) {
  301.     dispPtr->lockUsage = LU_CAPS;
  302.     break;
  303. }
  304.     }
  305.     /*
  306.      * Look through the keycodes associated with modifiers to see if
  307.      * the the "mode switch", "meta", or "alt" keysyms are associated
  308.      * with any modifiers.  If so, remember their modifier mask bits.
  309.      */
  310.     dispPtr->modeModMask = 0;
  311.     dispPtr->metaModMask = 0;
  312.     dispPtr->altModMask = 0;
  313.     codePtr = modMapPtr->modifiermap;
  314.     max = 8*modMapPtr->max_keypermod;
  315.     for (i = 0; i < max; i++, codePtr++) {
  316. if (*codePtr == 0) {
  317.     continue;
  318. }
  319. keysym = XKeycodeToKeysym(dispPtr->display, *codePtr, 0);
  320. if (keysym == XK_Mode_switch) {
  321.     dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
  322. }
  323. if ((keysym == XK_Meta_L) || (keysym == XK_Meta_R)) {
  324.     dispPtr->metaModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
  325. }
  326. if ((keysym == XK_Alt_L) || (keysym == XK_Alt_R)) {
  327.     dispPtr->altModMask |= ShiftMask << (i/modMapPtr->max_keypermod);
  328. }
  329.     }
  330.     /*
  331.      * Create an array of the keycodes for all modifier keys.
  332.      */
  333.     if (dispPtr->modKeyCodes != NULL) {
  334. ckfree((char *) dispPtr->modKeyCodes);
  335.     }
  336.     dispPtr->numModKeyCodes = 0;
  337.     arraySize = KEYCODE_ARRAY_SIZE;
  338.     dispPtr->modKeyCodes = (KeyCode *) ckalloc((unsigned)
  339.     (KEYCODE_ARRAY_SIZE * sizeof(KeyCode)));
  340.     for (i = 0, codePtr = modMapPtr->modifiermap; i < max; i++, codePtr++) {
  341. if (*codePtr == 0) {
  342.     continue;
  343. }
  344. /*
  345.  * Make sure that the keycode isn't already in the array.
  346.  */
  347. for (j = 0; j < dispPtr->numModKeyCodes; j++) {
  348.     if (dispPtr->modKeyCodes[j] == *codePtr) {
  349. goto nextModCode;
  350.     }
  351. }
  352. if (dispPtr->numModKeyCodes >= arraySize) {
  353.     KeyCode *new;
  354.     /*
  355.      * Ran out of space in the array;  grow it.
  356.      */
  357.     arraySize *= 2;
  358.     new = (KeyCode *) ckalloc((unsigned)
  359.     (arraySize * sizeof(KeyCode)));
  360.     memcpy((VOID *) new, (VOID *) dispPtr->modKeyCodes,
  361.     (dispPtr->numModKeyCodes * sizeof(KeyCode)));
  362.     ckfree((char *) dispPtr->modKeyCodes);
  363.     dispPtr->modKeyCodes = new;
  364. }
  365. dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr;
  366. dispPtr->numModKeyCodes++;
  367. nextModCode: continue;
  368.     }
  369.     XFreeModifiermap(modMapPtr);
  370. }