1/* 2 * tkWinKey.c -- 3 * 4 * This file contains X emulation routines for keyboard related 5 * functions. 6 * 7 * Copyright (c) 1995 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: tkWinKey.c,v 1.14.4.1 2006/08/30 21:53:46 hobbs Exp $ 13 */ 14 15#include "tkWinInt.h" 16/* 17 * The keymap table holds mappings of Windows keycodes to X keysyms. 18 * If Windows ever comes along and changes the value of their keycodes, 19 * this will break all kinds of things. However, this table lookup is much 20 * faster than the alternative, in which we walked a list of keycodes looking 21 * for a match. Since this lookup is performed for every Windows keypress 22 * event, it seems like a worthwhile improvement to use the table. 23 */ 24#define MAX_KEYCODE 145 /* VK_SCROLL is the last entry in our table below */ 25static KeySym keymap[] = { 26 NoSymbol, NoSymbol, NoSymbol, XK_Cancel, NoSymbol, 27 NoSymbol, NoSymbol, NoSymbol, XK_BackSpace, XK_Tab, 28 NoSymbol, NoSymbol, XK_Clear, XK_Return, NoSymbol, 29 NoSymbol, XK_Shift_L, XK_Control_L, XK_Alt_L, XK_Pause, 30 XK_Caps_Lock, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 31 NoSymbol, NoSymbol, XK_Escape, NoSymbol, NoSymbol, 32 NoSymbol, NoSymbol, XK_space, XK_Prior, XK_Next, 33 XK_End, XK_Home, XK_Left, XK_Up, XK_Right, 34 XK_Down, XK_Select, XK_Print, XK_Execute, NoSymbol, 35 XK_Insert, XK_Delete, XK_Help, NoSymbol, NoSymbol, 36 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 37 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 38 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 39 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 40 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 41 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 42 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 43 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 44 NoSymbol, XK_Win_L, XK_Win_R, XK_App, NoSymbol, 45 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 46 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 47 NoSymbol, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 48 NoSymbol, NoSymbol, XK_F1, XK_F2, XK_F3, 49 XK_F4, XK_F5, XK_F6, XK_F7, XK_F8, 50 XK_F9, XK_F10, XK_F11, XK_F12, XK_F13, 51 XK_F14, XK_F15, XK_F16, XK_F17, XK_F18, 52 XK_F19, XK_F20, XK_F21, XK_F22, XK_F23, 53 XK_F24, NoSymbol, NoSymbol, NoSymbol, NoSymbol, 54 NoSymbol, NoSymbol, NoSymbol, NoSymbol, XK_Num_Lock, 55 XK_Scroll_Lock 56}; 57 58/* 59 * Prototypes for local procedures defined in this file: 60 */ 61 62static KeySym KeycodeToKeysym _ANSI_ARGS_((unsigned int keycode, 63 int state, int noascii)); 64 65/* 66 *---------------------------------------------------------------------- 67 * 68 * TkpGetString -- 69 * 70 * Retrieve the UTF string equivalent for the given keyboard event. 71 * 72 * Results: 73 * Returns the UTF string. 74 * 75 * Side effects: 76 * None. 77 * 78 *---------------------------------------------------------------------- 79 */ 80 81char * 82TkpGetString(winPtr, eventPtr, dsPtr) 83 TkWindow *winPtr; /* Window where event occurred: needed to 84 * get input context. */ 85 XEvent *eventPtr; /* X keyboard event. */ 86 Tcl_DString *dsPtr; /* Uninitialized or empty string to hold 87 * result. */ 88{ 89 KeySym keysym; 90 XKeyEvent* keyEv = &eventPtr->xkey; 91 92 Tcl_DStringInit(dsPtr); 93 if (eventPtr->xkey.send_event == -1) { 94 if (eventPtr->xkey.nbytes > 0) { 95 Tcl_ExternalToUtfDString(TkWinGetKeyInputEncoding(), 96 eventPtr->xkey.trans_chars, eventPtr->xkey.nbytes, dsPtr); 97 } 98 } else if (eventPtr->xkey.send_event == -2) { 99 /* 100 * Special case for win2000 multi-lingal IME input. 101 * xkey.trans_chars[] already contains a UNICODE char. 102 */ 103 104 int unichar; 105 char buf[TCL_UTF_MAX]; 106 int len; 107 108 unichar = (eventPtr->xkey.trans_chars[1] & 0xff); 109 unichar <<= 8; 110 unichar |= (eventPtr->xkey.trans_chars[0] & 0xff); 111 112 len = Tcl_UniCharToUtf((Tcl_UniChar) unichar, buf); 113 114 Tcl_DStringAppend(dsPtr, buf, len); 115 } else if (eventPtr->xkey.send_event == -3) { 116 /* 117 * Special case for WM_UNICHAR. 118 * xkey.trans_chars[] already contains a UTF-8 char. 119 */ 120 Tcl_DStringAppend(dsPtr, eventPtr->xkey.trans_chars, 121 eventPtr->xkey.nbytes); 122 } else { 123 /* 124 * This is an event generated from generic code. It has no 125 * nchars or trans_chars members. 126 */ 127 128 keysym = KeycodeToKeysym(eventPtr->xkey.keycode, 129 eventPtr->xkey.state, 0); 130 if (((keysym != NoSymbol) && (keysym > 0) && (keysym < 256)) 131 || (keysym == XK_Return) 132 || (keysym == XK_Tab)) { 133 char buf[TCL_UTF_MAX]; 134 int len = Tcl_UniCharToUtf((Tcl_UniChar) (keysym & 255), buf); 135 Tcl_DStringAppend(dsPtr, buf, len); 136 } 137 } 138 return Tcl_DStringValue(dsPtr); 139} 140 141/* 142 *---------------------------------------------------------------------- 143 * 144 * XKeycodeToKeysym -- 145 * 146 * Translate from a system-dependent keycode to a 147 * system-independent keysym. 148 * 149 * Results: 150 * Returns the translated keysym, or NoSymbol on failure. 151 * 152 * Side effects: 153 * None. 154 * 155 *---------------------------------------------------------------------- 156 */ 157 158KeySym 159XKeycodeToKeysym(display, keycode, index) 160 Display* display; 161 unsigned int keycode; 162 int index; 163{ 164 int state = 0; 165 166 if (index & 0x01) { 167 state |= ShiftMask; 168 } 169 return KeycodeToKeysym(keycode, state, 0); 170} 171 172 173 174/* 175 *---------------------------------------------------------------------- 176 * 177 * KeycodeToKeysym -- 178 * 179 * Translate from a system-dependent keycode to a 180 * system-independent keysym. 181 * 182 * Results: 183 * Returns the translated keysym, or NoSymbol on failure. 184 * 185 * Side effects: 186 * It may affect the internal state of the keyboard, such as 187 * remembered dead key or lock indicator lamps. 188 * 189 *---------------------------------------------------------------------- 190 */ 191 192static KeySym 193KeycodeToKeysym(keycode, state, noascii) 194 unsigned int keycode; 195 int state; 196 int noascii; 197{ 198 BYTE keys[256]; 199 int result, deadkey, shift; 200 char buf[4]; 201 unsigned int scancode = MapVirtualKey(keycode, 0); 202 203 /* 204 * Do not run keycodes of lock keys through ToAscii(). 205 * One of ToAscii()'s side effects is to handle the lights 206 * on the keyboard, and we don't want to mess that up. 207 */ 208 209 if (noascii || keycode == VK_CAPITAL || keycode == VK_SCROLL || 210 keycode == VK_NUMLOCK) 211 goto skipToAscii; 212 213 /* 214 * Use MapVirtualKey() to detect some dead keys. 215 */ 216 217 if (MapVirtualKey(keycode, 2) > 0x7fffUL) 218 return XK_Multi_key; 219 220 /* 221 * Set up a keyboard with correct modifiers 222 */ 223 224 memset(keys, 0, 256); 225 if (state & ShiftMask) 226 keys[VK_SHIFT] = 0x80; 227 if (state & ControlMask) 228 keys[VK_CONTROL] = 0x80; 229 if (state & Mod2Mask) 230 keys[VK_MENU] = 0x80; 231 232 /* 233 * Make sure all lock button info is correct so we don't mess up the 234 * lights 235 */ 236 237 if (state & LockMask) 238 keys[VK_CAPITAL] = 1; 239 if (state & Mod3Mask) 240 keys[VK_SCROLL] = 1; 241 if (state & Mod1Mask) 242 keys[VK_NUMLOCK] = 1; 243 244 result = ToAscii(keycode, scancode, keys, (LPWORD) buf, 0); 245 246 if (result < 0) { 247 /* 248 * Win95/98: 249 * This was a dead char, which is now remembered by the keyboard. 250 * Call ToAscii() again to forget it. 251 * WinNT: 252 * This was a dead char, overwriting any previously remembered 253 * key. Calling ToAscii() again does not affect anything. 254 */ 255 256 ToAscii(keycode, scancode, keys, (LPWORD) buf, 0); 257 return XK_Multi_key; 258 } 259 if (result == 2) { 260 /* 261 * This was a dead char, and there were one previously remembered 262 * by the keyboard. 263 * Call ToAscii() again with proper parameters to restore it. 264 */ 265 266 /* 267 * Get information about the old char 268 */ 269 270 deadkey = VkKeyScan(buf[0]); 271 shift = deadkey >> 8; 272 deadkey &= 255; 273 scancode = MapVirtualKey(deadkey, 0); 274 275 /* 276 * Set up a keyboard with proper modifier keys 277 */ 278 279 memset(keys, 0, 256); 280 if (shift & 1) 281 keys[VK_SHIFT] = 0x80; 282 if (shift & 2) 283 keys[VK_CONTROL] = 0x80; 284 if (shift & 4) 285 keys[VK_MENU] = 0x80; 286 ToAscii(deadkey, scancode, keys, (LPWORD) buf, 0); 287 return XK_Multi_key; 288 } 289 290 /* 291 * Keycode mapped to a valid Latin-1 character. Since the keysyms 292 * for alphanumeric characters map onto Latin-1, we just return it. 293 * 294 * We treat 0x7F as a special case mostly for backwards compatibility. 295 * In versions of Tk<=8.2, Control-Backspace returned "XK_BackSpace" 296 * as the X Keysym. This was due to the fact that we did not 297 * initialize the keys array properly when we passed it to ToAscii, above. 298 * We had previously not been setting the state bit for the Control key. 299 * When we fixed that, we found that Control-Backspace on Windows is 300 * interpreted as ASCII-127 (0x7F), which corresponds to the Delete key. 301 * 302 * Upon discovering this, we realized we had two choices: return XK_Delete 303 * or return XK_BackSpace. If we returned XK_Delete, that could be 304 * considered "more correct" (although the correctness would be dependant 305 * on whether you believe that ToAscii is doing the right thing in that 306 * case); however, this would break backwards compatibility, and worse, 307 * it would limit application programmers -- they would effectively be 308 * unable to bind to <Control-Backspace> on Windows. We therefore chose 309 * instead to return XK_BackSpace (handled here by letting the code 310 * "fall-through" to the return statement below, which works because the 311 * keycode for this event is VK_BACKSPACE, and the keymap table maps that 312 * keycode to XK_BackSpace). 313 */ 314 315 if (result == 1 && UCHAR(buf[0]) >= 0x20 && UCHAR(buf[0]) != 0x7F) { 316 return (KeySym) UCHAR(buf[0]); 317 } 318 319 /* 320 * Keycode is a non-alphanumeric key, so we have to do the lookup. 321 */ 322 323 skipToAscii: 324 if (keycode < 0 || keycode > MAX_KEYCODE) { 325 return NoSymbol; 326 } 327 switch (keycode) { 328 /* 329 * Windows only gives us an undifferentiated VK_CONTROL 330 * code (for example) when either Control key is pressed. 331 * To distinguish between left and right, we have to query the 332 * state of one of the two to determine which was actually 333 * pressed. So if the keycode indicates Control, Shift, or Menu 334 * (the key that everybody else calls Alt), do this extra test. 335 * If the right-side key was pressed, return the appropriate 336 * keycode. Otherwise, we fall through and rely on the 337 * keymap table to hold the correct keysym value. 338 */ 339 case VK_CONTROL: { 340 if (GetKeyState(VK_RCONTROL) & 0x80) { 341 return XK_Control_R; 342 } 343 break; 344 } 345 case VK_SHIFT: { 346 if (GetKeyState(VK_RSHIFT) & 0x80) { 347 return XK_Shift_R; 348 } 349 break; 350 } 351 case VK_MENU: { 352 if (GetKeyState(VK_RMENU) & 0x80) { 353 return XK_Alt_R; 354 } 355 break; 356 } 357 } 358 return keymap[keycode]; 359} 360 361 362/* 363 *---------------------------------------------------------------------- 364 * 365 * TkpGetKeySym -- 366 * 367 * Given an X KeyPress or KeyRelease event, map the 368 * keycode in the event into a KeySym. 369 * 370 * Results: 371 * The return value is the KeySym corresponding to 372 * eventPtr, or NoSymbol if no matching Keysym could be 373 * found. 374 * 375 * Side effects: 376 * In the first call for a given display, keycode-to- 377 * KeySym maps get loaded. 378 * 379 *---------------------------------------------------------------------- 380 */ 381 382KeySym 383TkpGetKeySym(dispPtr, eventPtr) 384 TkDisplay *dispPtr; /* Display in which to map keycode. */ 385 XEvent *eventPtr; /* Description of X event. */ 386{ 387 KeySym sym; 388 int state = eventPtr->xkey.state; 389 390 /* 391 * Refresh the mapping information if it's stale 392 */ 393 394 if (dispPtr->bindInfoStale) { 395 TkpInitKeymapInfo(dispPtr); 396 } 397 398 sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0); 399 400 /* 401 * Special handling: if this is a ctrl-alt or shifted key, and there 402 * is no keysym defined, try without the modifiers. 403 */ 404 405 if ((sym == NoSymbol) && ((state & ControlMask) || (state & Mod2Mask))) { 406 state &= ~(ControlMask | Mod2Mask); 407 sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0); 408 } 409 if ((sym == NoSymbol) && (state & ShiftMask)) { 410 state &= ~ShiftMask; 411 sym = KeycodeToKeysym(eventPtr->xkey.keycode, state, 0); 412 } 413 return sym; 414} 415 416/* 417 *-------------------------------------------------------------- 418 * 419 * TkpInitKeymapInfo -- 420 * 421 * This procedure is invoked to scan keymap information 422 * to recompute stuff that's important for binding, such 423 * as the modifier key (if any) that corresponds to "mode 424 * switch". 425 * 426 * Results: 427 * None. 428 * 429 * Side effects: 430 * Keymap-related information in dispPtr is updated. 431 * 432 *-------------------------------------------------------------- 433 */ 434 435void 436TkpInitKeymapInfo(dispPtr) 437 TkDisplay *dispPtr; /* Display for which to recompute keymap 438 * information. */ 439{ 440 XModifierKeymap *modMapPtr; 441 KeyCode *codePtr; 442 KeySym keysym; 443 int count, i, j, max, arraySize; 444#define KEYCODE_ARRAY_SIZE 20 445 446 dispPtr->bindInfoStale = 0; 447 modMapPtr = XGetModifierMapping(dispPtr->display); 448 449 /* 450 * Check the keycodes associated with the Lock modifier. If 451 * any of them is associated with the XK_Shift_Lock modifier, 452 * then Lock has to be interpreted as Shift Lock, not Caps Lock. 453 */ 454 455 dispPtr->lockUsage = LU_IGNORE; 456 codePtr = modMapPtr->modifiermap + modMapPtr->max_keypermod*LockMapIndex; 457 for (count = modMapPtr->max_keypermod; count > 0; count--, codePtr++) { 458 if (*codePtr == 0) { 459 continue; 460 } 461 keysym = KeycodeToKeysym(*codePtr, 0, 1); 462 if (keysym == XK_Shift_Lock) { 463 dispPtr->lockUsage = LU_SHIFT; 464 break; 465 } 466 if (keysym == XK_Caps_Lock) { 467 dispPtr->lockUsage = LU_CAPS; 468 break; 469 } 470 } 471 472 /* 473 * Look through the keycodes associated with modifiers to see if 474 * the the "mode switch", "meta", or "alt" keysyms are associated 475 * with any modifiers. If so, remember their modifier mask bits. 476 */ 477 478 dispPtr->modeModMask = 0; 479 dispPtr->metaModMask = 0; 480 dispPtr->altModMask = 0; 481 codePtr = modMapPtr->modifiermap; 482 max = 8*modMapPtr->max_keypermod; 483 for (i = 0; i < max; i++, codePtr++) { 484 if (*codePtr == 0) { 485 continue; 486 } 487 keysym = KeycodeToKeysym(*codePtr, 0, 1); 488 if (keysym == XK_Mode_switch) { 489 dispPtr->modeModMask |= ShiftMask << (i/modMapPtr->max_keypermod); 490 } 491 if ((keysym == XK_Meta_L) || (keysym == XK_Meta_R)) { 492 dispPtr->metaModMask |= ShiftMask << (i/modMapPtr->max_keypermod); 493 } 494 if ((keysym == XK_Alt_L) || (keysym == XK_Alt_R)) { 495 dispPtr->altModMask |= ShiftMask << (i/modMapPtr->max_keypermod); 496 } 497 } 498 499 /* 500 * Create an array of the keycodes for all modifier keys. 501 */ 502 503 if (dispPtr->modKeyCodes != NULL) { 504 ckfree((char *) dispPtr->modKeyCodes); 505 } 506 dispPtr->numModKeyCodes = 0; 507 arraySize = KEYCODE_ARRAY_SIZE; 508 dispPtr->modKeyCodes = (KeyCode *) ckalloc((unsigned) 509 (KEYCODE_ARRAY_SIZE * sizeof(KeyCode))); 510 for (i = 0, codePtr = modMapPtr->modifiermap; i < max; i++, codePtr++) { 511 if (*codePtr == 0) { 512 continue; 513 } 514 515 /* 516 * Make sure that the keycode isn't already in the array. 517 */ 518 519 for (j = 0; j < dispPtr->numModKeyCodes; j++) { 520 if (dispPtr->modKeyCodes[j] == *codePtr) { 521 goto nextModCode; 522 } 523 } 524 if (dispPtr->numModKeyCodes >= arraySize) { 525 KeyCode *new; 526 527 /* 528 * Ran out of space in the array; grow it. 529 */ 530 531 arraySize *= 2; 532 new = (KeyCode *) ckalloc((unsigned) 533 (arraySize * sizeof(KeyCode))); 534 memcpy((VOID *) new, (VOID *) dispPtr->modKeyCodes, 535 (dispPtr->numModKeyCodes * sizeof(KeyCode))); 536 ckfree((char *) dispPtr->modKeyCodes); 537 dispPtr->modKeyCodes = new; 538 } 539 dispPtr->modKeyCodes[dispPtr->numModKeyCodes] = *codePtr; 540 dispPtr->numModKeyCodes++; 541 nextModCode: continue; 542 } 543 XFreeModifiermap(modMapPtr); 544} 545 546/* 547 * When mapping from a keysym to a keycode, need 548 * information about the modifier state that should be used 549 * so that when they call XKeycodeToKeysym taking into 550 * account the xkey.state, they will get back the original 551 * keysym. 552 */ 553 554void 555TkpSetKeycodeAndState(tkwin, keySym, eventPtr) 556 Tk_Window tkwin; 557 KeySym keySym; 558 XEvent *eventPtr; 559{ 560 int i; 561 SHORT result; 562 int shift; 563 564 eventPtr->xkey.keycode = 0; 565 if (keySym == NoSymbol) { 566 return; 567 } 568 569 /* 570 * We check our private map first for a virtual keycode, 571 * as VkKeyScan will return values that don't map to X 572 * for the "extended" Syms. This may be due to just casting 573 * problems below, but this works. 574 */ 575 for (i = 0; i <= MAX_KEYCODE; i++) { 576 if (keymap[i] == keySym) { 577 eventPtr->xkey.keycode = i; 578 return; 579 } 580 } 581 if (keySym >= 0x20) { 582 result = VkKeyScan((char) keySym); 583 if (result != -1) { 584 shift = result >> 8; 585 if (shift & 1) 586 eventPtr->xkey.state |= ShiftMask; 587 if (shift & 2) 588 eventPtr->xkey.state |= ControlMask; 589 if (shift & 4) 590 eventPtr->xkey.state |= Mod2Mask; 591 eventPtr->xkey.keycode = (KeyCode) (result & 0xff); 592 } 593 } 594} 595 596/* 597 *---------------------------------------------------------------------- 598 * 599 * XKeysymToKeycode -- 600 * 601 * Translate a keysym back into a keycode. 602 * 603 * Results: 604 * Returns the keycode that would generate the specified keysym. 605 * 606 * Side effects: 607 * None. 608 * 609 *---------------------------------------------------------------------- 610 */ 611 612KeyCode 613XKeysymToKeycode(display, keysym) 614 Display* display; 615 KeySym keysym; 616{ 617 int i; 618 SHORT result; 619 620 /* 621 * We check our private map first for a virtual keycode, 622 * as VkKeyScan will return values that don't map to X 623 * for the "extended" Syms. This may be due to just casting 624 * problems below, but this works. 625 */ 626 if (keysym == NoSymbol) { 627 return 0; 628 } 629 for (i = 0; i <= MAX_KEYCODE; i++) { 630 if (keymap[i] == keysym) { 631 return ((KeyCode) i); 632 } 633 } 634 if (keysym >= 0x20) { 635 result = VkKeyScan((char) keysym); 636 if (result != -1) { 637 return (KeyCode) (result & 0xff); 638 } 639 } 640 641 return 0; 642} 643 644/* 645 *---------------------------------------------------------------------- 646 * 647 * XGetModifierMapping -- 648 * 649 * Fetch the current keycodes used as modifiers. 650 * 651 * Results: 652 * Returns a new modifier map. 653 * 654 * Side effects: 655 * Allocates a new modifier map data structure. 656 * 657 *---------------------------------------------------------------------- 658 */ 659 660XModifierKeymap * 661XGetModifierMapping(display) 662 Display* display; 663{ 664 XModifierKeymap *map = (XModifierKeymap *)ckalloc(sizeof(XModifierKeymap)); 665 666 map->max_keypermod = 1; 667 map->modifiermap = (KeyCode *) ckalloc(sizeof(KeyCode)*8); 668 map->modifiermap[ShiftMapIndex] = VK_SHIFT; 669 map->modifiermap[LockMapIndex] = VK_CAPITAL; 670 map->modifiermap[ControlMapIndex] = VK_CONTROL; 671 map->modifiermap[Mod1MapIndex] = VK_NUMLOCK; 672 map->modifiermap[Mod2MapIndex] = VK_MENU; 673 map->modifiermap[Mod3MapIndex] = VK_SCROLL; 674 map->modifiermap[Mod4MapIndex] = 0; 675 map->modifiermap[Mod5MapIndex] = 0; 676 return map; 677} 678 679/* 680 *---------------------------------------------------------------------- 681 * 682 * XFreeModifiermap -- 683 * 684 * Deallocate a modifier map that was created by 685 * XGetModifierMapping. 686 * 687 * Results: 688 * None. 689 * 690 * Side effects: 691 * Frees the datastructure referenced by modmap. 692 * 693 *---------------------------------------------------------------------- 694 */ 695 696void 697XFreeModifiermap(modmap) 698 XModifierKeymap* modmap; 699{ 700 ckfree((char *) modmap->modifiermap); 701 ckfree((char *) modmap); 702} 703 704/* 705 *---------------------------------------------------------------------- 706 * 707 * XStringToKeysym -- 708 * 709 * Translate a keysym name to the matching keysym. 710 * 711 * Results: 712 * Returns the keysym. Since this is already handled by 713 * Tk's StringToKeysym function, we just return NoSymbol. 714 * 715 * Side effects: 716 * None. 717 * 718 *---------------------------------------------------------------------- 719 */ 720 721KeySym 722XStringToKeysym(string) 723 _Xconst char *string; 724{ 725 return NoSymbol; 726} 727 728/* 729 *---------------------------------------------------------------------- 730 * 731 * XKeysymToString -- 732 * 733 * Convert a keysym to character form. 734 * 735 * Results: 736 * Returns NULL, since Tk will have handled this already. 737 * 738 * Side effects: 739 * None. 740 * 741 *---------------------------------------------------------------------- 742 */ 743 744char * 745XKeysymToString(keysym) 746 KeySym keysym; 747{ 748 return NULL; 749} 750