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