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