input.c revision a1f3da82
1/* $XTermId: input.c,v 1.327 2011/02/09 10:15:07 tom Exp $ */ 2 3/* 4 * Copyright 1999-2010,2011 by Thomas E. Dickey 5 * 6 * All Rights Reserved 7 * 8 * Permission is hereby granted, free of charge, to any person obtaining a 9 * copy of this software and associated documentation files (the 10 * "Software"), to deal in the Software without restriction, including 11 * without limitation the rights to use, copy, modify, merge, publish, 12 * distribute, sublicense, and/or sell copies of the Software, and to 13 * permit persons to whom the Software is furnished to do so, subject to 14 * the following conditions: 15 * 16 * The above copyright notice and this permission notice shall be included 17 * in all copies or substantial portions of the Software. 18 * 19 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22 * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26 * 27 * Except as contained in this notice, the name(s) of the above copyright 28 * holders shall not be used in advertising or otherwise to promote the 29 * sale, use or other dealings in this Software without prior written 30 * authorization. 31 * 32 * 33 * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34 * 35 * All Rights Reserved 36 * 37 * Permission to use, copy, modify, and distribute this software and its 38 * documentation for any purpose and without fee is hereby granted, 39 * provided that the above copyright notice appear in all copies and that 40 * both that copyright notice and this permission notice appear in 41 * supporting documentation, and that the name of Digital Equipment 42 * Corporation not be used in advertising or publicity pertaining to 43 * distribution of the software without specific, written prior permission. 44 * 45 * 46 * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47 * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48 * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49 * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50 * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51 * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52 * SOFTWARE. 53 */ 54 55/* input.c */ 56 57#include <xterm.h> 58 59#include <X11/keysym.h> 60 61#ifdef VMS 62#include <X11/keysymdef.h> 63#endif 64 65#if HAVE_X11_DECKEYSYM_H 66#include <X11/DECkeysym.h> 67#endif 68 69#if HAVE_X11_SUNKEYSYM_H 70#include <X11/Sunkeysym.h> 71#endif 72 73#if HAVE_X11_XF86KEYSYM_H 74#include <X11/XF86keysym.h> 75#endif 76 77#include <X11/Xutil.h> 78#include <stdio.h> 79#include <ctype.h> 80 81#include <xutf8.h> 82 83#include <data.h> 84#include <fontutils.h> 85#include <xstrings.h> 86#include <xtermcap.h> 87 88/* 89 * Xutil.h has no macro to check for the complete set of function- and 90 * modifier-keys that might be returned. Fake it. 91 */ 92#ifdef XK_ISO_Lock 93#define IsPredefinedKey(n) ((n) >= XK_ISO_Lock && (n) <= XK_Delete) 94#else 95#define IsPredefinedKey(n) ((n) >= XK_BackSpace && (n) <= XK_Delete) 96#endif 97 98#ifdef XK_ISO_Left_Tab 99#define IsTabKey(n) ((n) == XK_Tab || (n) == XK_ISO_Left_Tab) 100#else 101#define IsTabKey(n) ((n) == XK_Tab) 102#endif 103 104#ifndef IsPrivateKeypadKey 105#define IsPrivateKeypadKey(k) (0) 106#endif 107 108#define IsBackarrowToggle(keyboard, keysym, state) \ 109 ((((keyboard->flags & MODE_DECBKM) == 0) \ 110 ^ ((state & ControlMask) != 0)) \ 111 && (keysym == XK_BackSpace)) 112 113#define MAP(from, to) case from: result = to; break 114#define Masked(value,mask) ((value) & (unsigned) (~(mask))) 115 116#define KEYSYM_FMT "0x%04lX" /* simplify matching <X11/keysymdef.h> */ 117 118#define TEK4014_GIN(tw) (tw != 0 && TekScreenOf(tw)->TekGIN) 119 120typedef struct { 121 KeySym keysym; 122 Bool is_fkey; 123 int nbytes; 124#define STRBUFSIZE 500 125 char strbuf[STRBUFSIZE]; 126} KEY_DATA; 127 128static 129const char *kypd_num = " XXXXXXXX\tXXX\rXXXxxxxXXXXXXXXXXXXXXXXXXXXX*+,-./0123456789XXX="; 130/* 0123456789 abc def0123456789abcdef0123456789abcdef0123456789abcd */ 131static 132const char *kypd_apl = " ABCDEFGHIJKLMNOPQRSTUVWXYZ??????abcdefghijklmnopqrstuvwxyzXXX"; 133/* 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd */ 134static 135const char *curfinal = "HDACB FE"; 136 137static int decfuncvalue(KEY_DATA *); 138static void sunfuncvalue(ANSI *, KEY_DATA *); 139static void hpfuncvalue(ANSI *, KEY_DATA *); 140static void scofuncvalue(ANSI *, KEY_DATA *); 141 142#if OPT_TRACE 143static const char * 144ModifierName(unsigned modifier) 145{ 146 const char *s = ""; 147 if (modifier & ShiftMask) 148 s = " Shift"; 149 else if (modifier & LockMask) 150 s = " Lock"; 151 else if (modifier & ControlMask) 152 s = " Control"; 153 else if (modifier & Mod1Mask) 154 s = " Mod1"; 155 else if (modifier & Mod2Mask) 156 s = " Mod2"; 157 else if (modifier & Mod3Mask) 158 s = " Mod3"; 159 else if (modifier & Mod4Mask) 160 s = " Mod4"; 161 else if (modifier & Mod5Mask) 162 s = " Mod5"; 163 return s; 164} 165 166#define FMT_MODIFIER_NAMES "%s%s%s%s%s%s%s%s" 167#define ARG_MODIFIER_NAMES(state) \ 168 ModifierName(state & ShiftMask), \ 169 ModifierName(state & LockMask), \ 170 ModifierName(state & ControlMask), \ 171 ModifierName(state & Mod1Mask), \ 172 ModifierName(state & Mod2Mask), \ 173 ModifierName(state & Mod3Mask), \ 174 ModifierName(state & Mod4Mask), \ 175 ModifierName(state & Mod5Mask) 176#endif 177 178static void 179AdjustAfterInput(XtermWidget xw) 180{ 181 TScreen *screen = TScreenOf(xw); 182 183 if (screen->scrollkey && screen->topline != 0) 184 WindowScroll(xw, 0, False); 185 if (screen->marginbell) { 186 int col = screen->max_col - screen->nmarginbell; 187 if (screen->bellArmed >= 0) { 188 if (screen->bellArmed == screen->cur_row) { 189 if (screen->cur_col >= col) { 190 Bell(xw, XkbBI_MarginBell, 0); 191 screen->bellArmed = -1; 192 } 193 } else { 194 screen->bellArmed = 195 screen->cur_col < col ? screen->cur_row : -1; 196 } 197 } else if (screen->cur_col < col) 198 screen->bellArmed = screen->cur_row; 199 } 200} 201 202/* 203 * Return true if the key is on the editing keypad. This overlaps with 204 * IsCursorKey() and IsKeypadKey() and must be tested before those macro to 205 * distinguish it from them. 206 */ 207static Bool 208IsEditFunctionKey(KeySym keysym) 209{ 210 switch (keysym) { 211 case XK_Prior: /* editing keypad */ 212 case XK_Next: /* editing keypad */ 213 case XK_Insert: /* editing keypad */ 214 case XK_Find: /* editing keypad */ 215 case XK_Select: /* editing keypad */ 216#ifdef DXK_Remove 217 case DXK_Remove: /* editing keypad */ 218#endif 219#ifdef XK_KP_Delete 220 case XK_KP_Delete: /* editing key on numeric keypad */ 221 case XK_KP_Insert: /* editing key on numeric keypad */ 222#endif 223#ifdef XK_ISO_Left_Tab 224 case XK_ISO_Left_Tab: 225#endif 226 return True; 227 default: 228 return False; 229 } 230} 231 232#if OPT_MOD_FKEYS 233#define IS_CTRL(n) ((n) < ANSI_SPA || ((n) >= 0x7f && (n) <= 0x9f)) 234 235/* 236 * Return true if the keysym corresponds to one of the control characters, 237 * or one of the common ASCII characters that is combined with control to 238 * make a control character. 239 */ 240static Bool 241IsControlInput(KEY_DATA * kd) 242{ 243 return ((kd->keysym) >= 0x40 && (kd->keysym) <= 0x7f); 244} 245 246static Bool 247IsControlOutput(KEY_DATA * kd) 248{ 249 return IS_CTRL(kd->keysym); 250} 251 252/* 253 * X "normally" has some built-in translations, which the user may want to 254 * suppress when processing the modifyOtherKeys resource. In particular, the 255 * control modifier applied to some of the keyboard digits gives results for 256 * control characters. 257 * 258 * control 2 0 NUL 259 * control SPC 0 NUL 260 * control @ 0 NUL 261 * control ` 0 NUL 262 * control 3 0x1b ESC 263 * control 4 0x1c FS 264 * control \ 0x1c FS 265 * control 5 0x1d GS 266 * control 6 0x1e RS 267 * control ^ 0x1e RS 268 * control ~ 0x1e RS 269 * control 7 0x1f US 270 * control / 0x1f US 271 * control _ 0x1f US 272 * control 8 0x7f DEL 273 * 274 * It is possible that some other keyboards do not work for these combinations, 275 * but they do work with modifyOtherKeys=2 for the US keyboard: 276 * 277 * control ` 0 NUL 278 * control [ 0x1b ESC 279 * control \ 0x1c FS 280 * control ] 0x1d GS 281 * control ? 0x7f DEL 282 */ 283static Bool 284IsControlAlias(KEY_DATA * kd) 285{ 286 Bool result = False; 287 288 if (kd->nbytes == 1) { 289 result = IS_CTRL(CharOf(kd->strbuf[0])); 290 } 291 return result; 292} 293 294/* 295 * If we are in the non-VT220/VT52 keyboard state, allow modifiers to add a 296 * parameter to the function-key control sequences. 297 * 298 * Note that we generally cannot capture the Shift-modifier for the numeric 299 * keypad since this is commonly used to act as a type of NumLock, e.g., 300 * making the keypad send "7" (actually XK_KP_7) where the unshifted code 301 * would be Home (XK_KP_Home). The other modifiers work, subject to the 302 * usual window-manager assignments. 303 */ 304static Bool 305allowModifierParm(XtermWidget xw, KEY_DATA * kd) 306{ 307 TKeyboard *keyboard = &(xw->keyboard); 308 TScreen *screen = TScreenOf(xw); 309 int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0); 310 311 Bool result = False; 312 313 (void) screen; 314 if (!(IsKeypadKey(kd->keysym) && keypad_mode) 315#if OPT_SUNPC_KBD 316 && keyboard->type != keyboardIsVT220 317#endif 318#if OPT_VT52_MODE 319 && screen->vtXX_level != 0 320#endif 321 ) { 322 result = True; 323 } 324 return result; 325} 326 327/* 328* Modifier codes: 329* None 1 330* Shift 2 = 1(None)+1(Shift) 331* Alt 3 = 1(None)+2(Alt) 332* Alt+Shift 4 = 1(None)+1(Shift)+2(Alt) 333* Ctrl 5 = 1(None)+4(Ctrl) 334* Ctrl+Shift 6 = 1(None)+1(Shift)+4(Ctrl) 335* Ctrl+Alt 7 = 1(None)+2(Alt)+4(Ctrl) 336* Ctrl+Alt+Shift 8 = 1(None)+1(Shift)+2(Alt)+4(Ctrl) 337* Meta 9 = 1(None)+8(Meta) 338* Meta+Shift 10 = 1(None)+8(Meta)+1(Shift) 339* Meta+Alt 11 = 1(None)+8(Meta)+2(Alt) 340* Meta+Alt+Shift 12 = 1(None)+8(Meta)+1(Shift)+2(Alt) 341* Meta+Ctrl 13 = 1(None)+8(Meta)+4(Ctrl) 342* Meta+Ctrl+Shift 14 = 1(None)+8(Meta)+1(Shift)+4(Ctrl) 343* Meta+Ctrl+Alt 15 = 1(None)+8(Meta)+2(Alt)+4(Ctrl) 344* Meta+Ctrl+Alt+Shift 16 = 1(None)+8(Meta)+1(Shift)+2(Alt)+4(Ctrl) 345*/ 346 347unsigned 348xtermParamToState(XtermWidget xw, unsigned param) 349{ 350 unsigned result = 0; 351#if OPT_NUM_LOCK 352 if (param > MOD_NONE 353 && ((ShiftMask 354 | ControlMask 355 | xw->misc.alt_mods 356 | xw->misc.meta_mods) & xw->misc.other_mods) == 0) { 357 if ((param - MOD_NONE) & MOD_SHIFT) 358 UIntSet(result, ShiftMask); 359 if ((param - MOD_NONE) & MOD_CTRL) 360 UIntSet(result, ControlMask); 361 if ((param - MOD_NONE) & MOD_ALT) 362 UIntSet(result, xw->misc.alt_mods); 363 if ((param - MOD_NONE) & MOD_META) 364 UIntSet(result, xw->misc.meta_mods); 365 } 366#else 367 (void) xw; 368 (void) param; 369#endif 370 TRACE(("xtermParamToState(%d) %s%s%s%s -> %#x\n", param, 371 MODIFIER_NAME(param, MOD_SHIFT), 372 MODIFIER_NAME(param, MOD_ALT), 373 MODIFIER_NAME(param, MOD_CTRL), 374 MODIFIER_NAME(param, MOD_META), 375 result)); 376 return result; 377} 378 379unsigned 380xtermStateToParam(XtermWidget xw, unsigned state) 381{ 382 unsigned modify_parm = MOD_NONE; 383 384 TRACE(("xtermStateToParam %#x\n", state)); 385#if OPT_NUM_LOCK 386 if ((state & xw->misc.other_mods) == 0) { 387 if (state & ShiftMask) { 388 modify_parm += MOD_SHIFT; 389 UIntClr(state, ShiftMask); 390 } 391 if (state & ControlMask) { 392 modify_parm += MOD_CTRL; 393 UIntClr(state, ControlMask); 394 } 395 if ((state & xw->misc.alt_mods) != 0) { 396 modify_parm += MOD_ALT; 397 UIntClr(state, xw->misc.alt_mods); 398 } 399 if ((state & xw->misc.meta_mods) != 0) { 400 modify_parm += MOD_META; 401 UIntClr(state, xw->misc.meta_mods); 402 } 403 } 404 if (modify_parm == MOD_NONE) 405 modify_parm = 0; 406#else 407 (void) xw; 408 (void) state; 409#endif 410 TRACE(("...xtermStateToParam %d%s%s%s%s\n", modify_parm, 411 MODIFIER_NAME(modify_parm, MOD_SHIFT), 412 MODIFIER_NAME(modify_parm, MOD_ALT), 413 MODIFIER_NAME(modify_parm, MOD_CTRL), 414 MODIFIER_NAME(modify_parm, MOD_META))); 415 return modify_parm; 416} 417 418#define computeMaskedModifier(xw, state, mask) \ 419 xtermStateToParam(xw, Masked(state, mask)) 420 421#if OPT_NUM_LOCK 422static unsigned 423filterAltMeta(unsigned result, unsigned mask, Bool enable, KEY_DATA * kd) 424{ 425 if ((result & mask) != 0) { 426 /* 427 * metaSendsEscape makes the meta key independent of 428 * modifyOtherKeys. 429 */ 430 if (enable) { 431 result &= ~mask; 432 } 433 /* 434 * A bare meta-modifier is independent of modifyOtherKeys. If it 435 * is combined with other modifiers, make it depend. 436 */ 437 if ((result & ~(mask)) == 0) { 438 result &= ~mask; 439 } 440 /* 441 * Check for special cases of control+meta which are used by some 442 * applications, e.g., emacs. 443 */ 444 if ((IsControlInput(kd) 445 || IsControlOutput(kd)) 446 && (result & ControlMask) != 0) { 447 result &= ~(mask | ControlMask); 448 } 449 if (kd->keysym == XK_Return || kd->keysym == XK_Tab) { 450 result &= ~(mask | ControlMask); 451 } 452 } 453 return result; 454} 455#endif /* OPT_NUM_LOCK */ 456 457/* 458 * Single characters (not function-keys) are allowed fewer modifiers when 459 * interpreting modifyOtherKeys due to pre-existing associations with some 460 * modifiers. 461 */ 462static unsigned 463allowedCharModifiers(XtermWidget xw, unsigned state, KEY_DATA * kd) 464{ 465#if OPT_NUM_LOCK 466 unsigned a_or_m = (state & (xw->misc.meta_mods | xw->misc.alt_mods)); 467#else 468 unsigned a_or_m = 0; 469#endif 470 /* 471 * Start by limiting the result to the modifiers we might want to use. 472 */ 473 unsigned result = (state & (ControlMask 474 | ShiftMask 475 | a_or_m)); 476 477 /* 478 * If modifyOtherKeys is off or medium (0 or 1), moderate its effects by 479 * excluding the common cases for modifiers. 480 */ 481 if (xw->keyboard.modify_now.other_keys <= 1) { 482 if (IsControlInput(kd) 483 && Masked(result, ControlMask) == 0) { 484 /* These keys are already associated with the control-key */ 485 if (xw->keyboard.modify_now.other_keys == 0) { 486 UIntClr(result, ControlMask); 487 } 488 } else if (kd->keysym == XK_Tab || kd->keysym == XK_Return) { 489 /* EMPTY */ ; 490 } else if (IsControlAlias(kd)) { 491 /* Things like "^_" work here... */ 492 if (Masked(result, (ControlMask | ShiftMask)) == 0) { 493 result = 0; 494 } 495 } else if (!IsControlOutput(kd) && !IsPredefinedKey(kd->keysym)) { 496 /* Printable keys are already associated with the shift-key */ 497 if (!(result & ControlMask)) { 498 UIntClr(result, ShiftMask); 499 } 500 } 501#if OPT_NUM_LOCK 502 result = filterAltMeta(result, 503 xw->misc.meta_mods, 504 TScreenOf(xw)->meta_sends_esc, kd); 505 if (TScreenOf(xw)->alt_is_not_meta) { 506 result = filterAltMeta(result, 507 xw->misc.alt_mods, 508 TScreenOf(xw)->alt_sends_esc, kd); 509 } 510#endif 511 } 512 TRACE(("...allowedCharModifiers(state=%u" FMT_MODIFIER_NAMES 513 ", ch=" KEYSYM_FMT ") ->" 514 "%u" FMT_MODIFIER_NAMES "\n", 515 state, ARG_MODIFIER_NAMES(state), kd->keysym, 516 result, ARG_MODIFIER_NAMES(result))); 517 return result; 518} 519 520/* 521 * Decide if we should generate a special escape sequence for "other" keys 522 * than cursor-, function-keys, etc., as per the modifyOtherKeys resource. 523 */ 524static Bool 525ModifyOtherKeys(XtermWidget xw, 526 unsigned state, 527 KEY_DATA * kd, 528 unsigned modify_parm) 529{ 530 TKeyboard *keyboard = &(xw->keyboard); 531 Bool result = False; 532 533 /* 534 * Exclude the keys already covered by a modifier. 535 */ 536 if (kd->is_fkey 537 || IsEditFunctionKey(kd->keysym) 538 || IsKeypadKey(kd->keysym) 539 || IsCursorKey(kd->keysym) 540 || IsPFKey(kd->keysym) 541 || IsMiscFunctionKey(kd->keysym) 542 || IsPrivateKeypadKey(kd->keysym) 543#if OPT_NUM_LOCK 544 || (state & xw->misc.other_mods) != 0 545#endif 546 ) { 547 result = False; 548 } else if (modify_parm != 0) { 549 if (IsBackarrowToggle(keyboard, kd->keysym, state)) { 550 kd->keysym = XK_Delete; 551 UIntClr(state, ControlMask); 552 } 553 if (!IsPredefinedKey(kd->keysym)) { 554 state = allowedCharModifiers(xw, state, kd); 555 } 556 if (state != 0) { 557 switch (keyboard->modify_now.other_keys) { 558 default: 559 break; 560 case 1: 561 switch (kd->keysym) { 562 case XK_BackSpace: 563 case XK_Delete: 564 result = False; 565 break; 566#ifdef XK_ISO_Left_Tab 567 case XK_ISO_Left_Tab: 568 if (computeMaskedModifier(xw, state, ShiftMask)) 569 result = True; 570 break; 571#endif 572 case XK_Return: 573 case XK_Tab: 574 result = (modify_parm != 0); 575 break; 576 default: 577 if (IsControlInput(kd)) { 578 if (state == ControlMask || state == ShiftMask) { 579 result = False; 580 } else { 581 result = (modify_parm != 0); 582 } 583 } else if (IsControlAlias(kd)) { 584 if (state == ShiftMask) 585 result = False; 586 else if (computeMaskedModifier(xw, state, ControlMask)) { 587 result = True; 588 } 589 } else { 590 result = True; 591 } 592 break; 593 } 594 break; 595 case 2: 596 switch (kd->keysym) { 597 case XK_BackSpace: 598 /* strip ControlMask as per IsBackarrowToggle() */ 599 if (computeMaskedModifier(xw, state, ControlMask)) 600 result = True; 601 break; 602 case XK_Delete: 603 result = (xtermStateToParam(xw, state) != 0); 604 break; 605#ifdef XK_ISO_Left_Tab 606 case XK_ISO_Left_Tab: 607 if (computeMaskedModifier(xw, state, ShiftMask)) 608 result = True; 609 break; 610#endif 611 case XK_Return: 612 case XK_Tab: 613 result = (modify_parm != 0); 614 break; 615 default: 616 if (IsControlInput(kd)) { 617 result = True; 618 } else if (state == ShiftMask) { 619 result = (kd->keysym == ' ' || kd->keysym == XK_Return); 620 } else if (computeMaskedModifier(xw, state, ShiftMask)) { 621 result = True; 622 } 623 break; 624 } 625 break; 626 } 627 } 628 } 629 TRACE(("...ModifyOtherKeys(%d,%d) %s\n", 630 keyboard->modify_now.other_keys, 631 modify_parm, 632 BtoS(result))); 633 return result; 634} 635 636#define APPEND_PARM(number) \ 637 reply->a_param[reply->a_nparam] = (ParmType) number; \ 638 reply->a_nparam++ 639 640/* 641 * Function-key code 27 happens to not be used in the vt220-style encoding. 642 * xterm uses this to represent modified non-function-keys such as control/+ in 643 * the Sun/PC keyboard layout. See the modifyOtherKeys resource in the manpage 644 * for more information. 645 */ 646static Bool 647modifyOtherKey(ANSI * reply, int input_char, unsigned modify_parm, int format_keys) 648{ 649 Bool result = False; 650 651 if (input_char >= 0) { 652 reply->a_type = ANSI_CSI; 653 if (format_keys) { 654 APPEND_PARM(input_char); 655 APPEND_PARM(modify_parm); 656 reply->a_final = 'u'; 657 } else { 658 APPEND_PARM(27); 659 APPEND_PARM(modify_parm); 660 APPEND_PARM(input_char); 661 reply->a_final = '~'; 662 } 663 664 result = True; 665 } 666 return result; 667} 668 669static void 670modifyCursorKey(ANSI * reply, int modify, unsigned *modify_parm) 671{ 672 if (*modify_parm != 0) { 673 if (modify < 0) { 674 *modify_parm = 0; 675 } 676 if (modify > 0) { 677 reply->a_type = ANSI_CSI; /* SS3 should not have params */ 678 } 679 if (modify > 1 && reply->a_nparam == 0) { 680 APPEND_PARM(1); /* force modifier to 2nd param */ 681 } 682 if (modify > 2) { 683 reply->a_pintro = '>'; /* mark this as "private" */ 684 } 685 } 686} 687#else 688#define modifyCursorKey(reply, modify, parm) /* nothing */ 689#endif /* OPT_MOD_FKEYS */ 690 691#if OPT_SUNPC_KBD 692/* 693 * If we have told xterm that our keyboard is really a Sun/PC keyboard, this is 694 * enough to make a reasonable approximation to DEC vt220 numeric and editing 695 * keypads. 696 */ 697static KeySym 698TranslateFromSUNPC(KeySym keysym) 699{ 700 /* *INDENT-OFF* */ 701 static struct { 702 KeySym before, after; 703 } table[] = { 704#ifdef DXK_Remove 705 { XK_Delete, DXK_Remove }, 706#endif 707 { XK_Home, XK_Find }, 708 { XK_End, XK_Select }, 709#ifdef XK_KP_Home 710 { XK_Delete, XK_KP_Decimal }, 711 { XK_KP_Delete, XK_KP_Decimal }, 712 { XK_KP_Insert, XK_KP_0 }, 713 { XK_KP_End, XK_KP_1 }, 714 { XK_KP_Down, XK_KP_2 }, 715 { XK_KP_Next, XK_KP_3 }, 716 { XK_KP_Left, XK_KP_4 }, 717 { XK_KP_Begin, XK_KP_5 }, 718 { XK_KP_Right, XK_KP_6 }, 719 { XK_KP_Home, XK_KP_7 }, 720 { XK_KP_Up, XK_KP_8 }, 721 { XK_KP_Prior, XK_KP_9 }, 722#endif 723 }; 724 /* *INDENT-ON* */ 725 726 unsigned n; 727 728 for (n = 0; n < sizeof(table) / sizeof(table[0]); n++) { 729 if (table[n].before == keysym) { 730 TRACE(("...Input keypad before was " KEYSYM_FMT "\n", keysym)); 731 keysym = table[n].after; 732 TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", keysym)); 733 break; 734 } 735 } 736 return keysym; 737} 738#endif /* OPT_SUNPC_KBD */ 739 740#define VT52_KEYPAD \ 741 if_OPT_VT52_MODE(screen,{ \ 742 reply.a_type = ANSI_ESC; \ 743 reply.a_pintro = '?'; \ 744 }) 745 746#define VT52_CURSOR_KEYS \ 747 if_OPT_VT52_MODE(screen,{ \ 748 reply.a_type = ANSI_ESC; \ 749 }) 750 751#undef APPEND_PARM 752#define APPEND_PARM(number) \ 753 reply.a_param[reply.a_nparam] = (ParmType) number, \ 754 reply.a_nparam++ 755 756#if OPT_MOD_FKEYS 757#define MODIFIER_PARM \ 758 if (modify_parm != 0) APPEND_PARM(modify_parm) 759#else 760#define MODIFIER_PARM /*nothing */ 761#endif 762 763/* 764 * Determine if we use the \E[3~ sequence for Delete, or the legacy ^?. We 765 * maintain the delete_is_del value as 3 states: unspecified(2), true and 766 * false. If unspecified, it is handled differently according to whether the 767 * legacy keyboard support is enabled, or if xterm emulates a VT220. 768 * 769 * Once the user (or application) has specified delete_is_del via resource 770 * setting, popup menu or escape sequence, it overrides the keyboard type 771 * rather than the reverse. 772 */ 773Bool 774xtermDeleteIsDEL(XtermWidget xw) 775{ 776 Bool result = True; 777 778 if (xw->keyboard.type == keyboardIsDefault 779 || xw->keyboard.type == keyboardIsVT220) 780 result = (TScreenOf(xw)->delete_is_del == True); 781 782 if (xw->keyboard.type == keyboardIsLegacy) 783 result = (TScreenOf(xw)->delete_is_del != False); 784 785 TRACE(("xtermDeleteIsDEL(%d/%d) = %d\n", 786 xw->keyboard.type, 787 TScreenOf(xw)->delete_is_del, 788 result)); 789 790 return result; 791} 792 793void 794Input(XtermWidget xw, 795 XKeyEvent * event, 796 Bool eightbit) 797{ 798 Char *string; 799 800 TKeyboard *keyboard = &(xw->keyboard); 801 TScreen *screen = TScreenOf(xw); 802 803 int j; 804 int key = False; 805 ANSI reply; 806 int dec_code; 807 unsigned modify_parm = 0; 808 int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0); 809 unsigned evt_state = event->state; 810 unsigned mod_state; 811 KEY_DATA kd; 812 813 /* Ignore characters typed at the keyboard */ 814 if (keyboard->flags & MODE_KAM) 815 return; 816 817 kd.keysym = 0; 818 kd.is_fkey = False; 819#if OPT_TCAP_QUERY 820 if (screen->tc_query_code >= 0) { 821 kd.keysym = (KeySym) screen->tc_query_code; 822 kd.is_fkey = screen->tc_query_fkey; 823 if (kd.keysym != XK_BackSpace) { 824 kd.nbytes = 0; 825 kd.strbuf[0] = 0; 826 } else { 827 kd.nbytes = 1; 828 kd.strbuf[0] = 8; 829 } 830 } else 831#endif 832 { 833#if OPT_I18N_SUPPORT 834 if (screen->xic) { 835 Status status_return; 836#if OPT_WIDE_CHARS 837 if (screen->utf8_mode) { 838 kd.nbytes = Xutf8LookupString(screen->xic, event, 839 kd.strbuf, (int) sizeof(kd.strbuf), 840 &kd.keysym, &status_return); 841 } else 842#endif 843 { 844 kd.nbytes = XmbLookupString(screen->xic, event, 845 kd.strbuf, (int) sizeof(kd.strbuf), 846 &kd.keysym, &status_return); 847 } 848#if OPT_MOD_FKEYS 849 /* 850 * Fill-in some code useful with IsControlAlias(): 851 */ 852 if (status_return == XLookupBoth 853 && kd.nbytes <= 1 854 && !IsPredefinedKey(kd.keysym) 855 && (keyboard->modify_now.other_keys > 1) 856 && !IsControlInput(&kd)) { 857 kd.nbytes = 1; 858 kd.strbuf[0] = (char) kd.keysym; 859 } 860#endif /* OPT_MOD_FKEYS */ 861 } else 862#endif /* OPT_I18N_SUPPORT */ 863 { 864 static XComposeStatus compose_status = 865 {NULL, 0}; 866 kd.nbytes = XLookupString(event, kd.strbuf, (int) sizeof(kd.strbuf), 867 &kd.keysym, &compose_status); 868 } 869 kd.is_fkey = IsFunctionKey(kd.keysym); 870 } 871 872 memset(&reply, 0, sizeof(reply)); 873 874 TRACE(("Input keysym " 875 KEYSYM_FMT 876 ", %d:'%s'%s" FMT_MODIFIER_NAMES "%s%s%s%s%s%s\n", 877 kd.keysym, 878 kd.nbytes, 879 visibleChars((Char *) kd.strbuf, 880 ((kd.nbytes > 0) 881 ? (unsigned) kd.nbytes 882 : 0)), 883 ARG_MODIFIER_NAMES(evt_state), 884 eightbit ? " 8bit" : " 7bit", 885 IsKeypadKey(kd.keysym) ? " KeypadKey" : "", 886 IsCursorKey(kd.keysym) ? " CursorKey" : "", 887 IsPFKey(kd.keysym) ? " PFKey" : "", 888 kd.is_fkey ? " FKey" : "", 889 IsMiscFunctionKey(kd.keysym) ? " MiscFKey" : "", 890 IsEditFunctionKey(kd.keysym) ? " EditFkey" : "")); 891 892#if OPT_SUNPC_KBD 893 /* 894 * DEC keyboards don't have keypad(+), but do have keypad(,) instead. 895 * Other (Sun, PC) keyboards commonly have keypad(+), but no keypad(,) 896 * - it's a pain for users to work around. 897 */ 898 if (keyboard->type == keyboardIsVT220 899 && (evt_state & ShiftMask) == 0) { 900 if (kd.keysym == XK_KP_Add) { 901 kd.keysym = XK_KP_Separator; 902 UIntClr(evt_state, ShiftMask); 903 TRACE(("...Input keypad(+), change keysym to " 904 KEYSYM_FMT 905 "\n", 906 kd.keysym)); 907 } 908 if ((evt_state & ControlMask) != 0 909 && kd.keysym == XK_KP_Separator) { 910 kd.keysym = XK_KP_Subtract; 911 UIntClr(evt_state, ControlMask); 912 TRACE(("...Input control/keypad(,), change keysym to " 913 KEYSYM_FMT 914 "\n", 915 kd.keysym)); 916 } 917 } 918#endif 919 920 /* 921 * The keyboard tables may give us different keypad codes according to 922 * whether NumLock is pressed. Use this check to simplify the process 923 * of determining whether we generate an escape sequence for a keypad 924 * key, or force it to the value kypd_num[]. There is no fixed 925 * modifier for this feature, so we assume that it is the one assigned 926 * to the NumLock key. 927 * 928 * This check used to try to return the contents of strbuf, but that 929 * does not work properly when a control modifier is given (trash is 930 * returned in the buffer in some cases -- perhaps an X bug). 931 */ 932#if OPT_NUM_LOCK 933 if (kd.nbytes == 1 934 && IsKeypadKey(kd.keysym) 935 && xw->misc.real_NumLock 936 && (xw->misc.num_lock & evt_state) != 0) { 937 keypad_mode = 0; 938 TRACE(("...Input num_lock, force keypad_mode off\n")); 939 } 940#endif 941 942#if OPT_MOD_FKEYS 943 if (evt_state != 0 944 && allowModifierParm(xw, &kd)) { 945 modify_parm = xtermStateToParam(xw, evt_state); 946 } 947 948 /* 949 * Shift-tab is often mapped to XK_ISO_Left_Tab which is classified as 950 * IsEditFunctionKey(), and the conversion does not produce any bytes. 951 * Check for this special case so we have data when handling the 952 * modifyOtherKeys resource. 953 */ 954 if (keyboard->modify_now.other_keys > 1) { 955 if (IsTabKey(kd.keysym) && kd.nbytes == 0) { 956 kd.nbytes = 1; 957 kd.strbuf[0] = '\t'; 958 } 959 } 960#endif /* OPT_MOD_FKEYS */ 961 962 /* VT300 & up: backarrow toggle */ 963 if ((kd.nbytes == 1) 964 && IsBackarrowToggle(keyboard, kd.keysym, evt_state)) { 965 kd.strbuf[0] = ANSI_DEL; 966 TRACE(("...Input backarrow changed to %d\n", kd.strbuf[0])); 967 } 968#if OPT_SUNPC_KBD 969 /* make an DEC editing-keypad from a Sun or PC editing-keypad */ 970 if (keyboard->type == keyboardIsVT220 971 && (kd.keysym != XK_Delete || !xtermDeleteIsDEL(xw))) 972 kd.keysym = TranslateFromSUNPC(kd.keysym); 973 else 974#endif 975 { 976#ifdef XK_KP_Home 977 if (kd.keysym >= XK_KP_Home && kd.keysym <= XK_KP_Begin) { 978 TRACE(("...Input keypad before was " KEYSYM_FMT "\n", kd.keysym)); 979 kd.keysym += (KeySym) (XK_Home - XK_KP_Home); 980 TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", kd.keysym)); 981 } 982#endif 983 } 984 985 /* 986 * Map the Sun afterthought-keys in as F36 and F37. 987 */ 988#ifdef SunXK_F36 989 if (!kd.is_fkey) { 990 if (kd.keysym == SunXK_F36) { 991 kd.keysym = XK_Fn(36); 992 kd.is_fkey = True; 993 } 994 if (kd.keysym == SunXK_F37) { 995 kd.keysym = XK_Fn(37); 996 kd.is_fkey = True; 997 } 998 } 999#endif 1000 1001 /* 1002 * Use the control- and shift-modifiers to obtain more function keys than 1003 * the keyboard provides. We can do this if there is no conflicting use of 1004 * those modifiers: 1005 * 1006 * a) for VT220 keyboard, we use only the control-modifier. The keyboard 1007 * uses shift-modifier for UDK's. 1008 * 1009 * b) for non-VT220 keyboards, we only have to check if the 1010 * modifyFunctionKeys resource is inactive. 1011 * 1012 * Thereafter, we note when we have a function-key and keep that 1013 * distinction when testing for "function-key" values. 1014 */ 1015 if ((evt_state & (ControlMask | ShiftMask)) != 0 1016 && kd.is_fkey) { 1017 1018 /* VT220 keyboard uses shift for UDK */ 1019 if (keyboard->type == keyboardIsVT220 1020 || keyboard->type == keyboardIsLegacy) { 1021 1022 TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1)); 1023 if (evt_state & ControlMask) { 1024 kd.keysym += (KeySym) xw->misc.ctrl_fkeys; 1025 UIntClr(evt_state, ControlMask); 1026 } 1027 TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1)); 1028 1029 } 1030#if OPT_MOD_FKEYS 1031 else if (keyboard->modify_now.function_keys < 0) { 1032 1033 TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1)); 1034 if (evt_state & ShiftMask) { 1035 kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 1); 1036 UIntClr(evt_state, ShiftMask); 1037 } 1038 if (evt_state & ControlMask) { 1039 kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 2); 1040 UIntClr(evt_state, ControlMask); 1041 } 1042 TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1)); 1043 1044 } 1045 /* 1046 * Reevaluate the modifier parameter, stripping off the modifiers 1047 * that we just used. 1048 */ 1049 if (modify_parm) 1050 modify_parm = xtermStateToParam(xw, evt_state); 1051#endif /* OPT_MOD_FKEYS */ 1052 } 1053 1054 /* 1055 * Test for one of the keyboard variants. 1056 */ 1057 switch (keyboard->type) { 1058 case keyboardIsHP: 1059 hpfuncvalue(&reply, &kd); 1060 break; 1061 case keyboardIsSCO: 1062 scofuncvalue(&reply, &kd); 1063 break; 1064 case keyboardIsSun: 1065 sunfuncvalue(&reply, &kd); 1066 break; 1067 case keyboardIsTermcap: 1068#if OPT_TCAP_FKEYS 1069 if (xtermcapString(xw, (int) kd.keysym, evt_state)) 1070 return; 1071#endif 1072 break; 1073 case keyboardIsDefault: 1074 case keyboardIsLegacy: 1075 case keyboardIsVT220: 1076 break; 1077 } 1078 1079 if (reply.a_final) { 1080 /* 1081 * The key symbol matches one of the variants. Most of those are 1082 * function-keys, though some cursor- and editing-keys are mixed in. 1083 */ 1084 modifyCursorKey(&reply, 1085 ((kd.is_fkey 1086 || IsMiscFunctionKey(kd.keysym) 1087 || IsEditFunctionKey(kd.keysym)) 1088 ? keyboard->modify_now.function_keys 1089 : keyboard->modify_now.cursor_keys), 1090 &modify_parm); 1091 MODIFIER_PARM; 1092 unparseseq(xw, &reply); 1093 } else if (((kd.is_fkey 1094 || IsMiscFunctionKey(kd.keysym) 1095 || IsEditFunctionKey(kd.keysym)) 1096#if OPT_MOD_FKEYS 1097 && !ModifyOtherKeys(xw, evt_state, &kd, modify_parm) 1098#endif 1099 ) || (kd.keysym == XK_Delete 1100 && ((modify_parm != 0) 1101 || !xtermDeleteIsDEL(xw)))) { 1102 dec_code = decfuncvalue(&kd); 1103 if ((evt_state & ShiftMask) 1104#if OPT_SUNPC_KBD 1105 && keyboard->type == keyboardIsVT220 1106#endif 1107 && ((string = (Char *) udk_lookup(dec_code, &kd.nbytes)) != 0)) { 1108 UIntClr(evt_state, ShiftMask); 1109 while (kd.nbytes-- > 0) 1110 unparseputc(xw, CharOf(*string++)); 1111 } 1112 /* 1113 * Interpret F1-F4 as PF1-PF4 for VT52, VT100 1114 */ 1115 else if (keyboard->type != keyboardIsLegacy 1116 && (dec_code >= 11 && dec_code <= 14)) { 1117 reply.a_type = ANSI_SS3; 1118 VT52_CURSOR_KEYS; 1119 reply.a_final = (Char) A2E(dec_code - 11 + E2A('P')); 1120 modifyCursorKey(&reply, 1121 keyboard->modify_now.function_keys, 1122 &modify_parm); 1123 MODIFIER_PARM; 1124 unparseseq(xw, &reply); 1125 } else { 1126 reply.a_type = ANSI_CSI; 1127 reply.a_final = 0; 1128 1129#ifdef XK_ISO_Left_Tab 1130 if (kd.keysym == XK_ISO_Left_Tab) { 1131 reply.a_nparam = 0; 1132 reply.a_final = 'Z'; 1133#if OPT_MOD_FKEYS 1134 if (keyboard->modify_now.other_keys > 1 1135 && computeMaskedModifier(xw, evt_state, ShiftMask)) 1136 modifyOtherKey(&reply, '\t', modify_parm, keyboard->format_keys); 1137#endif 1138 } else 1139#endif /* XK_ISO_Left_Tab */ 1140 { 1141 reply.a_nparam = 1; 1142#if OPT_MOD_FKEYS 1143 if (kd.is_fkey) { 1144 modifyCursorKey(&reply, 1145 keyboard->modify_now.function_keys, 1146 &modify_parm); 1147 } 1148 MODIFIER_PARM; 1149#endif 1150 reply.a_param[0] = (ParmType) dec_code; 1151 reply.a_final = '~'; 1152 } 1153 if (reply.a_final != 0 1154 && (reply.a_nparam == 0 || reply.a_param[0] >= 0)) 1155 unparseseq(xw, &reply); 1156 } 1157 key = True; 1158 } else if (IsPFKey(kd.keysym)) { 1159 reply.a_type = ANSI_SS3; 1160 reply.a_final = (Char) ((kd.keysym - XK_KP_F1) + 'P'); 1161 VT52_CURSOR_KEYS; 1162 MODIFIER_PARM; 1163 unparseseq(xw, &reply); 1164 key = True; 1165 } else if (IsKeypadKey(kd.keysym)) { 1166 if (keypad_mode) { 1167 reply.a_type = ANSI_SS3; 1168 reply.a_final = (Char) (kypd_apl[kd.keysym - XK_KP_Space]); 1169 VT52_KEYPAD; 1170 MODIFIER_PARM; 1171 unparseseq(xw, &reply); 1172 } else { 1173 unparseputc(xw, kypd_num[kd.keysym - XK_KP_Space]); 1174 } 1175 key = True; 1176 } else if (IsCursorKey(kd.keysym)) { 1177 if (keyboard->flags & MODE_DECCKM) { 1178 reply.a_type = ANSI_SS3; 1179 } else { 1180 reply.a_type = ANSI_CSI; 1181 } 1182 modifyCursorKey(&reply, keyboard->modify_now.cursor_keys, &modify_parm); 1183 reply.a_final = (Char) (curfinal[kd.keysym - XK_Home]); 1184 VT52_CURSOR_KEYS; 1185 MODIFIER_PARM; 1186 unparseseq(xw, &reply); 1187 key = True; 1188 } else if (kd.nbytes > 0) { 1189 int prefix = 0; 1190 1191#if OPT_TEK4014 1192 if (TEK4014_GIN(tekWidget)) { 1193 TekEnqMouse(tekWidget, kd.strbuf[0]); 1194 TekGINoff(tekWidget); 1195 kd.nbytes--; 1196 for (j = 0; j < kd.nbytes; ++j) { 1197 kd.strbuf[j] = kd.strbuf[j + 1]; 1198 } 1199 } 1200#endif 1201#if OPT_MOD_FKEYS 1202 if ((keyboard->modify_now.other_keys > 0) 1203 && ModifyOtherKeys(xw, evt_state, &kd, modify_parm) 1204 && (mod_state = allowedCharModifiers(xw, evt_state, &kd)) != 0) { 1205 int input_char; 1206 1207 evt_state = mod_state; 1208 1209 modify_parm = xtermStateToParam(xw, evt_state); 1210 1211 /* 1212 * We want to show a keycode that corresponds to the 8-bit value 1213 * of the key. If the keysym is less than 256, that is good 1214 * enough. Special keys such as Tab may result in a value that 1215 * is usable as well. For the latter (special cases), try to use 1216 * the result from the X library lookup. 1217 */ 1218 input_char = ((kd.keysym < 256) 1219 ? (int) kd.keysym 1220 : ((kd.nbytes == 1) 1221 ? CharOf(kd.strbuf[0]) 1222 : -1)); 1223 1224 TRACE(("...modifyOtherKeys %d;%d\n", modify_parm, input_char)); 1225 if (modifyOtherKey(&reply, input_char, modify_parm, keyboard->format_keys)) { 1226 unparseseq(xw, &reply); 1227 } else { 1228 Bell(xw, XkbBI_MinorError, 0); 1229 } 1230 } else 1231#endif /* OPT_MOD_FKEYS */ 1232 { 1233#if OPT_NUM_LOCK 1234 /* 1235 * Send ESC if we have a META modifier and metaSendsEcape is true. 1236 * Like eightBitInput, except that it is not associated with 1237 * terminal settings. 1238 */ 1239 if (kd.nbytes != 0) { 1240 if (screen->meta_sends_esc 1241 && (evt_state & xw->misc.meta_mods) != 0) { 1242 TRACE(("...input-char is modified by META\n")); 1243 UIntClr(evt_state, xw->misc.meta_mods); 1244 eightbit = False; 1245 prefix = ANSI_ESC; 1246 } else if (eightbit) { 1247 /* it might be overridden, but this helps for debugging */ 1248 TRACE(("...input-char is shifted by META\n")); 1249 } 1250 if (screen->alt_is_not_meta 1251 && (evt_state & xw->misc.alt_mods) != 0) { 1252 UIntClr(evt_state, xw->misc.alt_mods); 1253 if (screen->alt_sends_esc) { 1254 TRACE(("...input-char is modified by ALT\n")); 1255 eightbit = False; 1256 prefix = ANSI_ESC; 1257 } else if (!eightbit) { 1258 TRACE(("...input-char is shifted by ALT\n")); 1259 eightbit = True; 1260 } 1261 } 1262 } 1263#endif 1264 /* 1265 * If metaSendsEscape is false, fall through to this chunk, which 1266 * implements the eightBitInput resource. 1267 * 1268 * It is normally executed when the user presses Meta plus a 1269 * printable key, e.g., Meta+space. The presence of the Meta 1270 * modifier is not guaranteed since what really happens is the 1271 * "insert-eight-bit" or "insert-seven-bit" action, which we 1272 * distinguish by the eightbit parameter to this function. So the 1273 * eightBitInput resource really means that we use this shifting 1274 * logic in the "insert-eight-bit" action. 1275 */ 1276 if (eightbit && (kd.nbytes == 1) && screen->input_eight_bits) { 1277 IChar ch = CharOf(kd.strbuf[0]); 1278 if (ch < 128) { 1279 kd.strbuf[0] |= (char) 0x80; 1280 TRACE(("...input shift from %d to %d (%#x to %#x)\n", 1281 ch, CharOf(kd.strbuf[0]), 1282 ch, CharOf(kd.strbuf[0]))); 1283#if OPT_WIDE_CHARS 1284 if (screen->utf8_mode) { 1285 /* 1286 * We could interpret the incoming code as "in the 1287 * current locale", but it's simpler to treat it as 1288 * a Unicode value to translate to UTF-8. 1289 */ 1290 ch = CharOf(kd.strbuf[0]); 1291 kd.nbytes = 2; 1292 kd.strbuf[0] = (char) (0xc0 | ((ch >> 6) & 0x3)); 1293 kd.strbuf[1] = (char) (0x80 | (ch & 0x3f)); 1294 TRACE(("...encoded %#x in UTF-8 as %#x,%#x\n", 1295 ch, CharOf(kd.strbuf[0]), CharOf(kd.strbuf[1]))); 1296 } 1297#endif 1298 } 1299 eightbit = False; 1300 } 1301#if OPT_WIDE_CHARS 1302 if (kd.nbytes == 1) /* cannot do NRC on UTF-8, for instance */ 1303#endif 1304 { 1305 /* VT220 & up: National Replacement Characters */ 1306 if ((xw->flags & NATIONAL) != 0) { 1307 unsigned cmp = xtermCharSetIn(CharOf(kd.strbuf[0]), 1308 screen->keyboard_dialect[0]); 1309 TRACE(("...input NRC %d, %s %d\n", 1310 CharOf(kd.strbuf[0]), 1311 (CharOf(kd.strbuf[0]) == cmp) 1312 ? "unchanged" 1313 : "changed to", 1314 CharOf(cmp))); 1315 kd.strbuf[0] = (char) cmp; 1316 } else if (eightbit) { 1317 prefix = ANSI_ESC; 1318 } else if (kd.strbuf[0] == '?' 1319 && (evt_state & ControlMask) != 0) { 1320 kd.strbuf[0] = ANSI_DEL; 1321 UIntClr(evt_state, ControlMask); 1322 } 1323 } 1324 if (prefix != 0) 1325 unparseputc(xw, prefix); /* escape */ 1326 for (j = 0; j < kd.nbytes; ++j) 1327 unparseputc(xw, CharOf(kd.strbuf[j])); 1328 } 1329 key = ((kd.keysym != ANSI_XOFF) && (kd.keysym != ANSI_XON)); 1330 } 1331 unparse_end(xw); 1332 1333 if (key && !TEK4014_ACTIVE(xw)) 1334 AdjustAfterInput(xw); 1335 1336 xtermShowPointer(xw, False); 1337 return; 1338} 1339 1340void 1341StringInput(XtermWidget xw, const Char * string, size_t nbytes) 1342{ 1343 TRACE(("InputString (%s,%lu)\n", 1344 visibleChars(string, (unsigned) nbytes), 1345 (unsigned long) nbytes)); 1346#if OPT_TEK4014 1347 if (nbytes && TEK4014_GIN(tekWidget)) { 1348 TekEnqMouse(tekWidget, *string++); 1349 TekGINoff(tekWidget); 1350 nbytes--; 1351 } 1352#endif 1353 while (nbytes-- != 0) 1354 unparseputc(xw, *string++); 1355 if (!TEK4014_ACTIVE(xw)) 1356 AdjustAfterInput(xw); 1357 unparse_end(xw); 1358} 1359 1360/* These definitions are DEC-style (e.g., vt320) */ 1361static int 1362decfuncvalue(KEY_DATA * kd) 1363{ 1364 int result; 1365 1366 if (kd->is_fkey) { 1367 switch (kd->keysym) { 1368 MAP(XK_Fn(1), 11); 1369 MAP(XK_Fn(2), 12); 1370 MAP(XK_Fn(3), 13); 1371 MAP(XK_Fn(4), 14); 1372 MAP(XK_Fn(5), 15); 1373 MAP(XK_Fn(6), 17); 1374 MAP(XK_Fn(7), 18); 1375 MAP(XK_Fn(8), 19); 1376 MAP(XK_Fn(9), 20); 1377 MAP(XK_Fn(10), 21); 1378 MAP(XK_Fn(11), 23); 1379 MAP(XK_Fn(12), 24); 1380 MAP(XK_Fn(13), 25); 1381 MAP(XK_Fn(14), 26); 1382 MAP(XK_Fn(15), 28); 1383 MAP(XK_Fn(16), 29); 1384 MAP(XK_Fn(17), 31); 1385 MAP(XK_Fn(18), 32); 1386 MAP(XK_Fn(19), 33); 1387 MAP(XK_Fn(20), 34); 1388 default: 1389 /* after F20 the codes are made up and do not correspond to any 1390 * real terminal. So they are simply numbered sequentially. 1391 */ 1392 result = 42 + (int) (kd->keysym - XK_Fn(21)); 1393 break; 1394 } 1395 } else { 1396 switch (kd->keysym) { 1397 MAP(XK_Find, 1); 1398 MAP(XK_Insert, 2); 1399 MAP(XK_Delete, 3); 1400#ifdef XK_KP_Insert 1401 MAP(XK_KP_Insert, 2); 1402 MAP(XK_KP_Delete, 3); 1403#endif 1404#ifdef DXK_Remove 1405 MAP(DXK_Remove, 3); 1406#endif 1407 MAP(XK_Select, 4); 1408 MAP(XK_Prior, 5); 1409 MAP(XK_Next, 6); 1410#ifdef XK_ISO_Left_Tab 1411 MAP(XK_ISO_Left_Tab, 'Z'); 1412#endif 1413 MAP(XK_Help, 28); 1414 MAP(XK_Menu, 29); 1415 default: 1416 result = -1; 1417 break; 1418 } 1419 } 1420 return result; 1421} 1422 1423static void 1424hpfuncvalue(ANSI * reply, KEY_DATA * kd) 1425{ 1426#if OPT_HP_FUNC_KEYS 1427 int result; 1428 1429 if (kd->is_fkey) { 1430 switch (kd->keysym) { 1431 MAP(XK_Fn(1), 'p'); 1432 MAP(XK_Fn(2), 'q'); 1433 MAP(XK_Fn(3), 'r'); 1434 MAP(XK_Fn(4), 's'); 1435 MAP(XK_Fn(5), 't'); 1436 MAP(XK_Fn(6), 'u'); 1437 MAP(XK_Fn(7), 'v'); 1438 MAP(XK_Fn(8), 'w'); 1439 default: 1440 result = -1; 1441 break; 1442 } 1443 } else { 1444 switch (kd->keysym) { 1445 MAP(XK_Up, 'A'); 1446 MAP(XK_Down, 'B'); 1447 MAP(XK_Right, 'C'); 1448 MAP(XK_Left, 'D'); 1449 MAP(XK_End, 'F'); 1450 MAP(XK_Clear, 'J'); 1451 MAP(XK_Delete, 'P'); 1452 MAP(XK_Insert, 'Q'); 1453 MAP(XK_Next, 'S'); 1454 MAP(XK_Prior, 'T'); 1455 MAP(XK_Home, 'h'); 1456#ifdef XK_KP_Insert 1457 MAP(XK_KP_Delete, 'P'); 1458 MAP(XK_KP_Insert, 'Q'); 1459#endif 1460#ifdef DXK_Remove 1461 MAP(DXK_Remove, 'P'); 1462#endif 1463 MAP(XK_Select, 'F'); 1464 MAP(XK_Find, 'h'); 1465 default: 1466 result = -1; 1467 break; 1468 } 1469 } 1470 if (result > 0) { 1471 reply->a_type = ANSI_ESC; 1472 reply->a_final = (Char) result; 1473 } 1474#else 1475 (void) reply; 1476 (void) kd; 1477#endif /* OPT_HP_FUNC_KEYS */ 1478} 1479 1480static void 1481scofuncvalue(ANSI * reply, KEY_DATA * kd) 1482{ 1483#if OPT_SCO_FUNC_KEYS 1484 int result; 1485 1486 if (kd->is_fkey) { 1487 switch (kd->keysym) { 1488 MAP(XK_Fn(1), 'M'); 1489 MAP(XK_Fn(2), 'N'); 1490 MAP(XK_Fn(3), 'O'); 1491 MAP(XK_Fn(4), 'P'); 1492 MAP(XK_Fn(5), 'Q'); 1493 MAP(XK_Fn(6), 'R'); 1494 MAP(XK_Fn(7), 'S'); 1495 MAP(XK_Fn(8), 'T'); 1496 MAP(XK_Fn(9), 'U'); 1497 MAP(XK_Fn(10), 'V'); 1498 MAP(XK_Fn(11), 'W'); 1499 MAP(XK_Fn(12), 'X'); 1500 MAP(XK_Fn(13), 'Y'); 1501 MAP(XK_Fn(14), 'Z'); 1502 MAP(XK_Fn(15), 'a'); 1503 MAP(XK_Fn(16), 'b'); 1504 MAP(XK_Fn(17), 'c'); 1505 MAP(XK_Fn(18), 'd'); 1506 MAP(XK_Fn(19), 'e'); 1507 MAP(XK_Fn(20), 'f'); 1508 MAP(XK_Fn(21), 'g'); 1509 MAP(XK_Fn(22), 'h'); 1510 MAP(XK_Fn(23), 'i'); 1511 MAP(XK_Fn(24), 'j'); 1512 MAP(XK_Fn(25), 'k'); 1513 MAP(XK_Fn(26), 'l'); 1514 MAP(XK_Fn(27), 'm'); 1515 MAP(XK_Fn(28), 'n'); 1516 MAP(XK_Fn(29), 'o'); 1517 MAP(XK_Fn(30), 'p'); 1518 MAP(XK_Fn(31), 'q'); 1519 MAP(XK_Fn(32), 'r'); 1520 MAP(XK_Fn(33), 's'); 1521 MAP(XK_Fn(34), 't'); 1522 MAP(XK_Fn(35), 'u'); 1523 MAP(XK_Fn(36), 'v'); 1524 MAP(XK_Fn(37), 'w'); 1525 MAP(XK_Fn(38), 'x'); 1526 MAP(XK_Fn(39), 'y'); 1527 MAP(XK_Fn(40), 'z'); 1528 MAP(XK_Fn(41), '@'); 1529 MAP(XK_Fn(42), '['); 1530 MAP(XK_Fn(43), '\\'); 1531 MAP(XK_Fn(44), ']'); 1532 MAP(XK_Fn(45), '^'); 1533 MAP(XK_Fn(46), '_'); 1534 MAP(XK_Fn(47), '`'); 1535 MAP(XK_Fn(48), '{'); /* no matching '}' */ 1536 default: 1537 result = -1; 1538 break; 1539 } 1540 } else { 1541 switch (kd->keysym) { 1542 MAP(XK_Up, 'A'); 1543 MAP(XK_Down, 'B'); 1544 MAP(XK_Right, 'C'); 1545 MAP(XK_Left, 'D'); 1546 MAP(XK_Begin, 'E'); 1547 MAP(XK_End, 'F'); 1548 MAP(XK_Insert, 'L'); 1549 MAP(XK_Next, 'G'); 1550 MAP(XK_Prior, 'I'); 1551 MAP(XK_Home, 'H'); 1552#ifdef XK_KP_Insert 1553 MAP(XK_KP_Insert, 'L'); 1554#endif 1555 default: 1556 result = -1; 1557 break; 1558 } 1559 } 1560 if (result > 0) { 1561 reply->a_type = ANSI_CSI; 1562 reply->a_final = (Char) result; 1563 } 1564#else 1565 (void) reply; 1566 (void) kd; 1567#endif /* OPT_SCO_FUNC_KEYS */ 1568} 1569 1570static void 1571sunfuncvalue(ANSI * reply, KEY_DATA * kd) 1572{ 1573#if OPT_SUN_FUNC_KEYS 1574 ParmType result; 1575 1576 if (kd->is_fkey) { 1577 switch (kd->keysym) { 1578 /* kf1-kf20 are numbered sequentially */ 1579 MAP(XK_Fn(1), 224); 1580 MAP(XK_Fn(2), 225); 1581 MAP(XK_Fn(3), 226); 1582 MAP(XK_Fn(4), 227); 1583 MAP(XK_Fn(5), 228); 1584 MAP(XK_Fn(6), 229); 1585 MAP(XK_Fn(7), 230); 1586 MAP(XK_Fn(8), 231); 1587 MAP(XK_Fn(9), 232); 1588 MAP(XK_Fn(10), 233); 1589 MAP(XK_Fn(11), 192); 1590 MAP(XK_Fn(12), 193); 1591 MAP(XK_Fn(13), 194); 1592 MAP(XK_Fn(14), 195); /* kund */ 1593 MAP(XK_Fn(15), 196); 1594 MAP(XK_Fn(16), 197); /* kcpy */ 1595 MAP(XK_Fn(17), 198); 1596 MAP(XK_Fn(18), 199); 1597 MAP(XK_Fn(19), 200); /* kfnd */ 1598 MAP(XK_Fn(20), 201); 1599 1600 /* kf31-kf36 are numbered sequentially */ 1601 MAP(XK_Fn(21), 208); /* kf31 */ 1602 MAP(XK_Fn(22), 209); 1603 MAP(XK_Fn(23), 210); 1604 MAP(XK_Fn(24), 211); 1605 MAP(XK_Fn(25), 212); 1606 MAP(XK_Fn(26), 213); /* kf36 */ 1607 1608 /* kf37-kf47 are interspersed with keypad keys */ 1609 MAP(XK_Fn(27), 214); /* khome */ 1610 MAP(XK_Fn(28), 215); /* kf38 */ 1611 MAP(XK_Fn(29), 216); /* kpp */ 1612 MAP(XK_Fn(30), 217); /* kf40 */ 1613 MAP(XK_Fn(31), 218); /* kb2 */ 1614 MAP(XK_Fn(32), 219); /* kf42 */ 1615 MAP(XK_Fn(33), 220); /* kend */ 1616 MAP(XK_Fn(34), 221); /* kf44 */ 1617 MAP(XK_Fn(35), 222); /* knp */ 1618 MAP(XK_Fn(36), 234); /* kf46 */ 1619 MAP(XK_Fn(37), 235); /* kf47 */ 1620 default: 1621 result = -1; 1622 break; 1623 } 1624 } else { 1625 switch (kd->keysym) { 1626 MAP(XK_Help, 196); /* khlp */ 1627 MAP(XK_Menu, 197); 1628 1629 MAP(XK_Find, 1); 1630 MAP(XK_Insert, 2); /* kich1 */ 1631 MAP(XK_Delete, 3); 1632#ifdef XK_KP_Insert 1633 MAP(XK_KP_Insert, 2); 1634 MAP(XK_KP_Delete, 3); 1635#endif 1636#ifdef DXK_Remove 1637 MAP(DXK_Remove, 3); 1638#endif 1639 MAP(XK_Select, 4); 1640 1641 MAP(XK_Prior, 216); 1642 MAP(XK_Next, 222); 1643 MAP(XK_Home, 214); 1644 MAP(XK_End, 220); 1645 MAP(XK_Begin, 218); /* kf41=kb2 */ 1646 1647 default: 1648 result = -1; 1649 break; 1650 } 1651 } 1652 if (result > 0) { 1653 reply->a_type = ANSI_CSI; 1654 reply->a_nparam = 1; 1655 reply->a_param[0] = result; 1656 reply->a_final = 'z'; 1657 } else if (IsCursorKey(kd->keysym)) { 1658 reply->a_type = ANSI_SS3; 1659 reply->a_final = (Char) curfinal[kd->keysym - XK_Home]; 1660 } 1661#else 1662 (void) reply; 1663 (void) kd; 1664#endif /* OPT_SUN_FUNC_KEYS */ 1665} 1666 1667#if OPT_NUM_LOCK 1668#define isName(c) ((c) == '_' || (c) == '-' || isalnum(CharOf(c))) 1669 1670static const char * 1671skipName(const char *s) 1672{ 1673 while (*s != '\0' && isName(CharOf(*s))) 1674 ++s; 1675 return s; 1676} 1677 1678/* 1679 * Found a ":" in a translation, check what is past it to see if it contains 1680 * any of the insert-text action names. 1681 */ 1682static Boolean 1683keyCanInsert(const char *parse) 1684{ 1685 Boolean result = False; 1686 int ch; 1687 Boolean escape = False; 1688 Boolean quoted = False; 1689 1690 static const char *table[] = 1691 { 1692 "insert", 1693 "insert-seven-bit", 1694 "insert-eight-bit", 1695 "string", 1696 }; 1697 Cardinal n; 1698 1699 while (*parse != '\0' && *parse != '\n') { 1700 ch = CharOf(*parse++); 1701 if (escape) { 1702 escape = False; 1703 } else if (ch == '\\') { 1704 escape = True; 1705 } else if (ch == '"') { 1706 quoted = (Boolean) ! quoted; 1707 } else if (!quoted && isName(ch)) { 1708 const char *next = skipName(--parse); 1709 size_t need = (size_t) (next - parse); 1710 1711 for (n = 0; n < XtNumber(table); ++n) { 1712 if (need == strlen(table[n]) 1713 && !strncmp(parse, table[n], need)) { 1714 result = True; 1715 break; 1716 } 1717 } 1718 parse = next; 1719 } 1720 1721 } 1722 return result; 1723} 1724 1725/* 1726 * Strip the entire action, to avoid matching it. 1727 */ 1728static char * 1729stripAction(char *base, char *last) 1730{ 1731 while (last != base) { 1732 if (*--last == '\n') { 1733 break; 1734 } 1735 } 1736 return last; 1737} 1738 1739static char * 1740stripBlanks(char *base, char *last) 1741{ 1742 while (last != base) { 1743 int ch = CharOf(last[-1]); 1744 if (ch != ' ' && ch != '\t') 1745 break; 1746 --last; 1747 } 1748 return last; 1749} 1750 1751/* 1752 * Strip unneeded whitespace from a translations resource, mono-casing and 1753 * returning a malloc'd copy of the result. 1754 */ 1755static char * 1756stripTranslations(const char *s, Bool onlyInsert) 1757{ 1758 char *dst = 0; 1759 1760 if (s != 0) { 1761 dst = TypeMallocN(char, strlen(s) + 1); 1762 1763 if (dst != 0) { 1764 int state = 0; 1765 int ch = 0; 1766 int prv = 0; 1767 char *d = dst; 1768 1769 TRACE(("stripping:\n%s\n", s)); 1770 while (*s != '\0') { 1771 ch = *s++; 1772 if (ch == '\n') { 1773 if (d != dst) 1774 *d++ = (char) ch; 1775 state = 0; 1776 } else if (strchr(":!#", ch) != 0) { 1777 d = stripBlanks(dst, d); 1778 if (onlyInsert && (ch == ':') && !keyCanInsert(s)) { 1779 d = stripAction(dst, d); 1780 } 1781 state = -1; 1782 } else if (state >= 0) { 1783 if (isspace(CharOf(ch))) { 1784 if (state == 0 || strchr("<>~ \t", prv)) 1785 continue; 1786 } else if (strchr("<>~", ch)) { 1787 d = stripBlanks(dst, d); 1788 } 1789 *d++ = x_toupper(ch); 1790 ++state; 1791 } 1792 prv = ch; 1793 } 1794 *d = '\0'; 1795 TRACE(("...result:\n%s\n", dst)); 1796 } 1797 } 1798 return dst; 1799} 1800 1801/* 1802 * Make a simple check to see if a given translations keyword appears in 1803 * xterm's translations resource. It does not attempt to parse the strings, 1804 * just makes a case-independent check and ensures that the ends of the match 1805 * are on token-boundaries. 1806 * 1807 * That this can only retrieve translations that are given as resource values; 1808 * the default translations in charproc.c for example are not retrievable by 1809 * any interface to X. 1810 * 1811 * Also: We can retrieve only the most-specified translation resource. For 1812 * example, if the resource file specifies both "*translations" and 1813 * "XTerm*translations", we see only the latter. 1814 */ 1815static Bool 1816TranslationsUseKeyword(Widget w, char **cache, const char *keyword, Bool onlyInsert) 1817{ 1818 static String data; 1819 static XtResource key_resources[] = 1820 { 1821 {XtNtranslations, XtCTranslations, XtRString, 1822 sizeof(data), 0, XtRString, (XtPointer) NULL} 1823 }; 1824 Bool result = False; 1825 char *copy; 1826 char *test; 1827 1828 if ((test = stripTranslations(keyword, onlyInsert)) != 0) { 1829 if (*cache == 0) { 1830 XtGetSubresources(w, 1831 (XtPointer) &data, 1832 "vt100", 1833 "VT100", 1834 key_resources, 1835 XtNumber(key_resources), 1836 NULL, 1837 (Cardinal) 0); 1838 if (data != 0 && (copy = stripTranslations(data, onlyInsert)) != 0) { 1839 *cache = copy; 1840 } 1841 } 1842 1843 if (*cache != 0) { 1844 char *p = *cache; 1845 int state = 0; 1846 int now = ' ', prv; 1847 1848 while (*p != 0) { 1849 prv = now; 1850 now = *p++; 1851 if (now == ':' 1852 || now == '!') { 1853 state = -1; 1854 } else if (now == '\n') { 1855 state = 0; 1856 } else if (state >= 0) { 1857 if (now == test[state]) { 1858 if ((state != 0 1859 || !isName(prv)) 1860 && ((test[++state] == 0) 1861 && !isName(*p))) { 1862 result = True; 1863 break; 1864 } 1865 } else { 1866 state = 0; 1867 } 1868 } 1869 } 1870 } 1871 free(test); 1872 } 1873 TRACE(("TranslationsUseKeyword(%p, %s) = %d\n", 1874 (void *) w, keyword, result)); 1875 return result; 1876} 1877 1878static Bool 1879xtermHasTranslation(XtermWidget xw, const char *keyword, Bool onlyInsert) 1880{ 1881 return (TranslationsUseKeyword(SHELL_OF(xw), 1882 &(xw->keyboard.shell_translations), 1883 keyword, 1884 onlyInsert) 1885 || TranslationsUseKeyword((Widget) xw, 1886 &(xw->keyboard.xterm_translations), 1887 keyword, 1888 onlyInsert)); 1889} 1890 1891#if OPT_EXTRA_PASTE 1892static void 1893addTranslation(XtermWidget xw, const char *fromString, const char *toString) 1894{ 1895 size_t have = (xw->keyboard.extra_translations 1896 ? strlen(xw->keyboard.extra_translations) 1897 : 0); 1898 size_t need = (((have != 0) ? (have + 4) : 0) 1899 + strlen(fromString) 1900 + strlen(toString) 1901 + 6); 1902 1903 if (!xtermHasTranslation(xw, fromString, False)) { 1904 xw->keyboard.extra_translations 1905 = TypeRealloc(char, need, xw->keyboard.extra_translations); 1906 if ((xw->keyboard.extra_translations) != 0) { 1907 TRACE(("adding %s: %s\n", fromString, toString)); 1908 if (have) 1909 strcat(xw->keyboard.extra_translations, " \\n\\"); 1910 sprintf(xw->keyboard.extra_translations, "%s: %s", 1911 fromString, toString); 1912 TRACE(("...{%s}\n", xw->keyboard.extra_translations)); 1913 } 1914 } 1915} 1916#endif 1917 1918#define SaveMask(name) xw->misc.name |= (unsigned) mask;\ 1919 TRACE(("SaveMask(%s) %#x (%#x is%s modifier)\n", \ 1920 #name, \ 1921 xw->misc.name, (unsigned) mask, \ 1922 ModifierName((unsigned) mask))); 1923/* 1924 * Determine which modifier mask (if any) applies to the Num_Lock keysym. 1925 * 1926 * Also, determine which modifiers are associated with the ALT keys, so we can 1927 * send that information as a parameter for special keys in Sun/PC keyboard 1928 * mode. However, if the ALT modifier is used in translations, we do not want 1929 * to confuse things by sending the parameter. 1930 */ 1931void 1932VTInitModifiers(XtermWidget xw) 1933{ 1934 Display *dpy = XtDisplay(xw); 1935 XModifierKeymap *keymap = XGetModifierMapping(dpy); 1936 int i, j, k, l; 1937 KeySym keysym; 1938 unsigned long mask; 1939 int min_keycode, max_keycode, keysyms_per_keycode = 0; 1940 1941 if (keymap != 0) { 1942 KeySym *theMap; 1943 int keycode_count; 1944 1945 TRACE(("VTInitModifiers\n")); 1946 1947 XDisplayKeycodes(dpy, &min_keycode, &max_keycode); 1948 keycode_count = (max_keycode - min_keycode + 1); 1949 theMap = XGetKeyboardMapping(dpy, 1950 (KeyCode) min_keycode, 1951 keycode_count, 1952 &keysyms_per_keycode); 1953 1954 if (theMap != 0) { 1955 1956#if OPT_EXTRA_PASTE 1957 /* 1958 * Assume that if we can find the paste keysym in the X keyboard 1959 * mapping that the server allows the corresponding translations 1960 * resource. 1961 */ 1962 int limit = (max_keycode - min_keycode) * keysyms_per_keycode; 1963 for (i = 0; i < limit; ++i) { 1964#ifdef XF86XK_Paste 1965 if (theMap[i] == XF86XK_Paste) { 1966 TRACE(("keyboard has XF86XK_Paste\n")); 1967 addTranslation(xw, 1968 "<KeyPress> XF86Paste", 1969 "insert-selection(SELECT, CUT_BUFFER0)"); 1970 } 1971#endif 1972#ifdef SunXK_Paste 1973 if (theMap[i] == SunXK_Paste) { 1974 TRACE(("keyboard has SunXK_Paste\n")); 1975 addTranslation(xw, 1976 "<KeyPress> SunPaste", 1977 "insert-selection(SELECT, CUT_BUFFER0)"); 1978 } 1979#endif 1980 } 1981#endif /* OPT_EXTRA_PASTE */ 1982 1983 for (i = k = 0, mask = 1; i < 8; i++, mask <<= 1) { 1984 for (j = 0; j < keymap->max_keypermod; j++) { 1985 KeyCode code = keymap->modifiermap[k++]; 1986 if (code == 0) 1987 continue; 1988 1989 for (l = 0; l < keysyms_per_keycode; ++l) { 1990 keysym = XKeycodeToKeysym(dpy, code, l); 1991 if (keysym == NoSymbol) { 1992 /* EMPTY */ ; 1993 } else if (keysym == XK_Num_Lock) { 1994 SaveMask(num_lock); 1995 } else if (keysym == XK_Alt_L || keysym == XK_Alt_R) { 1996 SaveMask(alt_mods); 1997 } else if (keysym == XK_Meta_L || keysym == XK_Meta_R) { 1998 SaveMask(meta_mods); 1999 } else if (mask == ShiftMask 2000 && (keysym == XK_Shift_L 2001 || keysym == XK_Shift_R)) { 2002 /* EMPTY */ ; 2003 } else if (mask == ControlMask 2004 && (keysym == XK_Control_L 2005 || keysym == XK_Control_R)) { 2006 /* EMPTY */ ; 2007 } else if (mask == LockMask 2008 && (keysym == XK_Caps_Lock)) { 2009 /* EMPTY */ ; 2010 } else if (keysym == XK_Mode_switch 2011#ifdef XK_ISO_Level3_Shift 2012 || keysym == XK_ISO_Level3_Shift 2013#endif 2014 ) { 2015 SaveMask(other_mods); 2016 } 2017 } 2018 } 2019 } 2020 XFree(theMap); 2021 } 2022 2023 /* Don't disable any mods if "alwaysUseMods" is true. */ 2024 if (!xw->misc.alwaysUseMods) { 2025 2026 /* 2027 * Force TranslationsUseKeyword() to reload. 2028 */ 2029 if (xw->keyboard.shell_translations) { 2030 free(xw->keyboard.shell_translations); 2031 xw->keyboard.shell_translations = 0; 2032 } 2033 if (xw->keyboard.xterm_translations) { 2034 free(xw->keyboard.xterm_translations); 2035 xw->keyboard.xterm_translations = 0; 2036 } 2037 2038 /* 2039 * If the Alt modifier is used in translations, we would rather not 2040 * use it to modify function-keys when NumLock is active. 2041 */ 2042 if ((xw->misc.alt_mods != 0) 2043 && xtermHasTranslation(xw, "alt", True)) { 2044 TRACE(("ALT is used as a modifier in translations (ignore mask)\n")); 2045 xw->misc.alt_mods = 0; 2046 } 2047 2048 /* 2049 * If the Meta modifier is used in translations, we would rather not 2050 * use it to modify function-keys. 2051 */ 2052 if ((xw->misc.meta_mods != 0) 2053 && xtermHasTranslation(xw, "meta", True)) { 2054 TRACE(("META is used as a modifier in translations\n")); 2055 xw->misc.meta_mods = 0; 2056 } 2057 } 2058 2059 XFreeModifiermap(keymap); 2060 } 2061} 2062#endif /* OPT_NUM_LOCK */ 2063