input.c revision 913cc679
1/* $XTermId: input.c,v 1.357 2017/05/29 20:11:03 tom Exp $ */ 2 3/* 4 * Copyright 1999-2016,2017 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 Boolean result = True; 813#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 814#if OPT_MOD_FKEYS 815 TKeyboard *keyboard = &(xw->keyboard); 816#endif 817#endif 818 819 (void) screen; 820 821 TRACE(("%s %#x\n", visibleEventType(event->type), event->keycode)); 822 823 kd->keysym = 0; 824 kd->is_fkey = False; 825#if OPT_TCAP_QUERY 826 if (screen->tc_query_code >= 0) { 827 kd->keysym = (KeySym) screen->tc_query_code; 828 kd->is_fkey = screen->tc_query_fkey; 829 if (kd->keysym != XK_BackSpace) { 830 kd->nbytes = 0; 831 kd->strbuf[0] = 0; 832 } else { 833 kd->nbytes = 1; 834 kd->strbuf[0] = 8; 835 } 836 } else 837#endif 838 { 839#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD 840 TInput *input = lookupTInput(xw, (Widget) xw); 841 if (input && input->xic) { 842 Status status_return; 843#if OPT_WIDE_CHARS 844 if (screen->utf8_mode) { 845 kd->nbytes = Xutf8LookupString(input->xic, event, 846 kd->strbuf, (int) sizeof(kd->strbuf), 847 &(kd->keysym), &status_return); 848 } else 849#endif 850 { 851 kd->nbytes = XmbLookupString(input->xic, event, 852 kd->strbuf, (int) sizeof(kd->strbuf), 853 &(kd->keysym), &status_return); 854 } 855#if OPT_MOD_FKEYS 856 /* 857 * Fill-in some code useful with IsControlAlias(): 858 */ 859 if (status_return == XLookupBoth 860 && kd->nbytes <= 1 861 && !IsPredefinedKey(kd->keysym) 862 && (keyboard->modify_now.other_keys > 1) 863 && !IsControlInput(kd)) { 864 kd->nbytes = 1; 865 kd->strbuf[0] = (char) kd->keysym; 866 } 867#endif /* OPT_MOD_FKEYS */ 868 } else 869#endif /* OPT_I18N_SUPPORT */ 870 { 871 static XComposeStatus compose_status = 872 {NULL, 0}; 873 kd->nbytes = XLookupString(event, 874 kd->strbuf, (int) sizeof(kd->strbuf), 875 &(kd->keysym), &compose_status); 876 } 877 kd->is_fkey = IsFunctionKey(kd->keysym); 878 } 879 return result; 880} 881 882void 883Input(XtermWidget xw, 884 XKeyEvent *event, 885 Bool eightbit) 886{ 887 Char *string; 888 889 TKeyboard *keyboard = &(xw->keyboard); 890 TScreen *screen = TScreenOf(xw); 891 892 int j; 893 int key = False; 894 ANSI reply; 895 int dec_code; 896 unsigned modify_parm = 0; 897 int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0); 898 unsigned evt_state = event->state; 899 unsigned mod_state; 900 KEY_DATA kd; 901 902 /* Ignore characters typed at the keyboard */ 903 if (keyboard->flags & MODE_KAM) 904 return; 905 906 lookupKeyData(&kd, xw, event); 907 908 memset(&reply, 0, sizeof(reply)); 909 910 TRACE(("Input keysym " 911 KEYSYM_FMT 912 ", %d:'%s'%s" FMT_MODIFIER_NAMES "%s%s%s%s%s%s\n", 913 kd.keysym, 914 kd.nbytes, 915 visibleChars((Char *) kd.strbuf, 916 ((kd.nbytes > 0) 917 ? (unsigned) kd.nbytes 918 : 0)), 919 ARG_MODIFIER_NAMES(evt_state), 920 eightbit ? " 8bit" : " 7bit", 921 IsKeypadKey(kd.keysym) ? " KeypadKey" : "", 922 IsCursorKey(kd.keysym) ? " CursorKey" : "", 923 IsPFKey(kd.keysym) ? " PFKey" : "", 924 kd.is_fkey ? " FKey" : "", 925 IsMiscFunctionKey(kd.keysym) ? " MiscFKey" : "", 926 IsEditFunctionKey(xw, kd.keysym) ? " EditFkey" : "")); 927 928#if OPT_SUNPC_KBD 929 /* 930 * DEC keyboards don't have keypad(+), but do have keypad(,) instead. 931 * Other (Sun, PC) keyboards commonly have keypad(+), but no keypad(,) 932 * - it's a pain for users to work around. 933 */ 934 if (keyboard->type == keyboardIsVT220 935 && (evt_state & ShiftMask) == 0) { 936 if (kd.keysym == XK_KP_Add) { 937 kd.keysym = XK_KP_Separator; 938 UIntClr(evt_state, ShiftMask); 939 TRACE(("...Input keypad(+), change keysym to " 940 KEYSYM_FMT 941 "\n", 942 kd.keysym)); 943 } 944 if ((evt_state & ControlMask) != 0 945 && kd.keysym == XK_KP_Separator) { 946 kd.keysym = XK_KP_Subtract; 947 UIntClr(evt_state, ControlMask); 948 TRACE(("...Input control/keypad(,), change keysym to " 949 KEYSYM_FMT 950 "\n", 951 kd.keysym)); 952 } 953 } 954#endif 955 956 /* 957 * The keyboard tables may give us different keypad codes according to 958 * whether NumLock is pressed. Use this check to simplify the process 959 * of determining whether we generate an escape sequence for a keypad 960 * key, or force it to the value kypd_num[]. There is no fixed 961 * modifier for this feature, so we assume that it is the one assigned 962 * to the NumLock key. 963 * 964 * This check used to try to return the contents of strbuf, but that 965 * does not work properly when a control modifier is given (trash is 966 * returned in the buffer in some cases -- perhaps an X bug). 967 */ 968#if OPT_NUM_LOCK 969 if (kd.nbytes == 1 970 && IsKeypadKey(kd.keysym) 971 && xw->misc.real_NumLock 972 && (xw->work.num_lock & evt_state) != 0) { 973 keypad_mode = 0; 974 TRACE(("...Input num_lock, force keypad_mode off\n")); 975 } 976#endif 977 978#if OPT_MOD_FKEYS 979 if (evt_state != 0 980 && allowModifierParm(xw, &kd)) { 981 modify_parm = xtermStateToParam(xw, evt_state); 982 } 983 984 /* 985 * Shift-tab is often mapped to XK_ISO_Left_Tab which is classified as 986 * IsEditFunctionKey(), and the conversion does not produce any bytes. 987 * Check for this special case so we have data when handling the 988 * modifyOtherKeys resource. 989 */ 990 if (keyboard->modify_now.other_keys > 1) { 991 if (IsTabKey(kd.keysym) && kd.nbytes == 0) { 992 kd.nbytes = 1; 993 kd.strbuf[0] = '\t'; 994 } 995 } 996#ifdef XK_ISO_Left_Tab 997 else if (IsTabKey(kd.keysym) 998 && kd.nbytes <= 1 999 && modify_parm == (MOD_NONE + MOD_SHIFT)) { 1000 kd.keysym = XK_ISO_Left_Tab; 1001 } 1002#endif 1003#endif /* OPT_MOD_FKEYS */ 1004 1005 /* VT300 & up: backarrow toggle */ 1006 if ((kd.nbytes == 1) 1007 && IsBackarrowToggle(keyboard, kd.keysym, evt_state)) { 1008 kd.strbuf[0] = ANSI_DEL; 1009 TRACE(("...Input backarrow changed to %d\n", kd.strbuf[0])); 1010 } 1011#if OPT_SUNPC_KBD 1012 /* make an DEC editing-keypad from a Sun or PC editing-keypad */ 1013 if (keyboard->type == keyboardIsVT220 1014 && (kd.keysym != XK_Delete || !xtermDeleteIsDEL(xw))) 1015 kd.keysym = TranslateFromSUNPC(kd.keysym); 1016 else 1017#endif 1018 { 1019#ifdef XK_KP_Home 1020 if (kd.keysym >= XK_KP_Home && kd.keysym <= XK_KP_Begin) { 1021 TRACE(("...Input keypad before was " KEYSYM_FMT "\n", kd.keysym)); 1022 kd.keysym += (KeySym) (XK_Home - XK_KP_Home); 1023 TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", kd.keysym)); 1024 } 1025#endif 1026 } 1027 1028 /* 1029 * Map the Sun afterthought-keys in as F36 and F37. 1030 */ 1031#ifdef SunXK_F36 1032 if (!kd.is_fkey) { 1033 if (kd.keysym == SunXK_F36) { 1034 kd.keysym = XK_Fn(36); 1035 kd.is_fkey = True; 1036 } 1037 if (kd.keysym == SunXK_F37) { 1038 kd.keysym = XK_Fn(37); 1039 kd.is_fkey = True; 1040 } 1041 } 1042#endif 1043 1044 /* 1045 * Use the control- and shift-modifiers to obtain more function keys than 1046 * the keyboard provides. We can do this if there is no conflicting use of 1047 * those modifiers: 1048 * 1049 * a) for VT220 keyboard, we use only the control-modifier. The keyboard 1050 * uses shift-modifier for UDK's. 1051 * 1052 * b) for non-VT220 keyboards, we only have to check if the 1053 * modifyFunctionKeys resource is inactive. 1054 * 1055 * Thereafter, we note when we have a function-key and keep that 1056 * distinction when testing for "function-key" values. 1057 */ 1058 if ((evt_state & (ControlMask | ShiftMask)) != 0 1059 && kd.is_fkey) { 1060 1061 /* VT220 keyboard uses shift for UDK */ 1062 if (keyboard->type == keyboardIsVT220 1063 || keyboard->type == keyboardIsLegacy) { 1064 1065 TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1)); 1066 if (evt_state & ControlMask) { 1067 kd.keysym += (KeySym) xw->misc.ctrl_fkeys; 1068 UIntClr(evt_state, ControlMask); 1069 } 1070 TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1)); 1071 1072 } 1073#if OPT_MOD_FKEYS 1074 else if (keyboard->modify_now.function_keys < 0) { 1075 1076 TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1)); 1077 if (evt_state & ShiftMask) { 1078 kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 1); 1079 UIntClr(evt_state, ShiftMask); 1080 } 1081 if (evt_state & ControlMask) { 1082 kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 2); 1083 UIntClr(evt_state, ControlMask); 1084 } 1085 TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1)); 1086 1087 } 1088 /* 1089 * Reevaluate the modifier parameter, stripping off the modifiers 1090 * that we just used. 1091 */ 1092 if (modify_parm) { 1093 modify_parm = xtermStateToParam(xw, evt_state); 1094 } 1095#endif /* OPT_MOD_FKEYS */ 1096 } 1097 1098 /* 1099 * Test for one of the keyboard variants. 1100 */ 1101 switch (keyboard->type) { 1102 case keyboardIsHP: 1103 hpfuncvalue(&reply, &kd); 1104 break; 1105 case keyboardIsSCO: 1106 scofuncvalue(&reply, &kd); 1107 break; 1108 case keyboardIsSun: 1109 sunfuncvalue(&reply, &kd); 1110 break; 1111 case keyboardIsTermcap: 1112#if OPT_TCAP_FKEYS 1113 if (xtermcapString(xw, (int) kd.keysym, evt_state)) 1114 return; 1115#endif 1116 break; 1117 case keyboardIsDefault: 1118 case keyboardIsLegacy: 1119 case keyboardIsVT220: 1120 break; 1121 } 1122 1123 if (reply.a_final) { 1124 /* 1125 * The key symbol matches one of the variants. Most of those are 1126 * function-keys, though some cursor- and editing-keys are mixed in. 1127 */ 1128 modifyCursorKey(&reply, 1129 ((kd.is_fkey 1130 || IsMiscFunctionKey(kd.keysym) 1131 || IsEditFunctionKey(xw, kd.keysym)) 1132 ? keyboard->modify_now.function_keys 1133 : keyboard->modify_now.cursor_keys), 1134 &modify_parm); 1135 MODIFIER_PARM; 1136 unparseseq(xw, &reply); 1137 } else if (((kd.is_fkey 1138 || IsMiscFunctionKey(kd.keysym) 1139 || IsEditFunctionKey(xw, kd.keysym)) 1140#if OPT_MOD_FKEYS 1141 && !ModifyOtherKeys(xw, evt_state, &kd, modify_parm) 1142#endif 1143 ) || (kd.keysym == XK_Delete 1144 && ((modify_parm != 0) 1145 || !xtermDeleteIsDEL(xw)))) { 1146 dec_code = decfuncvalue(&kd); 1147 if ((evt_state & ShiftMask) 1148#if OPT_SUNPC_KBD 1149 && keyboard->type == keyboardIsVT220 1150#endif 1151 && ((string = (Char *) udk_lookup(xw, dec_code, &kd.nbytes)) != 0)) { 1152 UIntClr(evt_state, ShiftMask); 1153 while (kd.nbytes-- > 0) 1154 unparseputc(xw, CharOf(*string++)); 1155 } 1156 /* 1157 * Interpret F1-F4 as PF1-PF4 for VT52, VT100 1158 */ 1159 else if (keyboard->type != keyboardIsLegacy 1160 && (dec_code >= 11 && dec_code <= 14)) { 1161 reply.a_type = ANSI_SS3; 1162 VT52_CURSOR_KEYS; 1163 reply.a_final = (Char) A2E(dec_code - 11 + E2A('P')); 1164 modifyCursorKey(&reply, 1165 keyboard->modify_now.function_keys, 1166 &modify_parm); 1167 MODIFIER_PARM; 1168 unparseseq(xw, &reply); 1169 } else { 1170 reply.a_type = ANSI_CSI; 1171 reply.a_final = 0; 1172 1173#ifdef XK_ISO_Left_Tab 1174 if (kd.keysym == XK_ISO_Left_Tab) { 1175 reply.a_nparam = 0; 1176 reply.a_final = 'Z'; 1177#if OPT_MOD_FKEYS 1178 if (keyboard->modify_now.other_keys > 1 1179 && computeMaskedModifier(xw, evt_state, ShiftMask)) 1180 modifyOtherKey(&reply, '\t', modify_parm, keyboard->format_keys); 1181#endif 1182 } else 1183#endif /* XK_ISO_Left_Tab */ 1184 { 1185 reply.a_nparam = 1; 1186#if OPT_MOD_FKEYS 1187 if (kd.is_fkey) { 1188 modifyCursorKey(&reply, 1189 keyboard->modify_now.function_keys, 1190 &modify_parm); 1191 } 1192 MODIFIER_PARM; 1193#endif 1194 reply.a_param[0] = (ParmType) dec_code; 1195 reply.a_final = '~'; 1196 } 1197 if (reply.a_final != 0 1198 && (reply.a_nparam == 0 || reply.a_param[0] >= 0)) 1199 unparseseq(xw, &reply); 1200 } 1201 key = True; 1202 } else if (IsPFKey(kd.keysym)) { 1203 reply.a_type = ANSI_SS3; 1204 reply.a_final = (Char) ((kd.keysym - XK_KP_F1) + 'P'); 1205 VT52_CURSOR_KEYS; 1206 MODIFIER_PARM; 1207 unparseseq(xw, &reply); 1208 key = True; 1209 } else if (IsKeypadKey(kd.keysym)) { 1210 if (keypad_mode) { 1211 reply.a_type = ANSI_SS3; 1212 reply.a_final = (Char) (kypd_apl[kd.keysym - XK_KP_Space]); 1213 VT52_KEYPAD; 1214 MODIFIER_PARM; 1215 unparseseq(xw, &reply); 1216 } else { 1217 unparseputc(xw, kypd_num[kd.keysym - XK_KP_Space]); 1218 } 1219 key = True; 1220 } else if (IsCursorKey(kd.keysym)) { 1221 if (keyboard->flags & MODE_DECCKM) { 1222 reply.a_type = ANSI_SS3; 1223 } else { 1224 reply.a_type = ANSI_CSI; 1225 } 1226 modifyCursorKey(&reply, keyboard->modify_now.cursor_keys, &modify_parm); 1227 reply.a_final = (Char) (curfinal[kd.keysym - XK_Home]); 1228 VT52_CURSOR_KEYS; 1229 MODIFIER_PARM; 1230 unparseseq(xw, &reply); 1231 key = True; 1232 } else if (kd.nbytes > 0) { 1233 1234#if OPT_TEK4014 1235 if (TEK4014_GIN(tekWidget)) { 1236 TekEnqMouse(tekWidget, kd.strbuf[0]); 1237 TekGINoff(tekWidget); 1238 kd.nbytes--; 1239 for (j = 0; j < kd.nbytes; ++j) { 1240 kd.strbuf[j] = kd.strbuf[j + 1]; 1241 } 1242 } 1243#endif 1244#if OPT_MOD_FKEYS 1245 if ((keyboard->modify_now.other_keys > 0) 1246 && ModifyOtherKeys(xw, evt_state, &kd, modify_parm) 1247 && (mod_state = allowedCharModifiers(xw, evt_state, &kd)) != 0) { 1248 int input_char; 1249 1250 evt_state = mod_state; 1251 1252 modify_parm = xtermStateToParam(xw, evt_state); 1253 1254 /* 1255 * We want to show a keycode that corresponds to the 8-bit value 1256 * of the key. If the keysym is less than 256, that is good 1257 * enough. Special keys such as Tab may result in a value that 1258 * is usable as well. For the latter (special cases), try to use 1259 * the result from the X library lookup. 1260 */ 1261 input_char = ((kd.keysym < 256) 1262 ? (int) kd.keysym 1263 : ((kd.nbytes == 1) 1264 ? CharOf(kd.strbuf[0]) 1265 : -1)); 1266 1267 TRACE(("...modifyOtherKeys %d;%d\n", modify_parm, input_char)); 1268 if (modifyOtherKey(&reply, input_char, modify_parm, keyboard->format_keys)) { 1269 unparseseq(xw, &reply); 1270 } else { 1271 Bell(xw, XkbBI_MinorError, 0); 1272 } 1273 } else 1274#endif /* OPT_MOD_FKEYS */ 1275 { 1276 int prefix = 0; 1277 1278#if OPT_NUM_LOCK 1279 /* 1280 * Send ESC if we have a META modifier and metaSendsEcape is true. 1281 * Like eightBitInput, except that it is not associated with 1282 * terminal settings. 1283 */ 1284 if (kd.nbytes != 0) { 1285 if (screen->meta_sends_esc 1286 && (evt_state & xw->work.meta_mods) != 0) { 1287 TRACE(("...input-char is modified by META\n")); 1288 UIntClr(evt_state, xw->work.meta_mods); 1289 eightbit = False; 1290 prefix = ANSI_ESC; 1291 } else if (eightbit) { 1292 /* it might be overridden, but this helps for debugging */ 1293 TRACE(("...input-char is shifted by META\n")); 1294 } 1295 if (screen->alt_is_not_meta 1296 && (evt_state & xw->work.alt_mods) != 0) { 1297 UIntClr(evt_state, xw->work.alt_mods); 1298 if (screen->alt_sends_esc) { 1299 TRACE(("...input-char is modified by ALT\n")); 1300 eightbit = False; 1301 prefix = ANSI_ESC; 1302 } else if (!eightbit) { 1303 TRACE(("...input-char is shifted by ALT\n")); 1304 eightbit = True; 1305 } 1306 } 1307 } 1308#endif 1309 /* 1310 * If metaSendsEscape is false, fall through to this chunk, which 1311 * implements the eightBitInput resource. 1312 * 1313 * It is normally executed when the user presses Meta plus a 1314 * printable key, e.g., Meta+space. The presence of the Meta 1315 * modifier is not guaranteed since what really happens is the 1316 * "insert-eight-bit" or "insert-seven-bit" action, which we 1317 * distinguish by the eightbit parameter to this function. So the 1318 * eightBitInput resource really means that we use this shifting 1319 * logic in the "insert-eight-bit" action. 1320 */ 1321 if (eightbit && (kd.nbytes == 1) && screen->input_eight_bits) { 1322 IChar ch = CharOf(kd.strbuf[0]); 1323 if ((ch < 128) && (screen->eight_bit_meta == ebTrue)) { 1324 kd.strbuf[0] |= (char) 0x80; 1325 TRACE(("...input shift from %d to %d (%#x to %#x)\n", 1326 ch, CharOf(kd.strbuf[0]), 1327 ch, CharOf(kd.strbuf[0]))); 1328#if OPT_WIDE_CHARS 1329 if (screen->utf8_mode) { 1330 /* 1331 * We could interpret the incoming code as "in the 1332 * current locale", but it's simpler to treat it as 1333 * a Unicode value to translate to UTF-8. 1334 */ 1335 ch = CharOf(kd.strbuf[0]); 1336 kd.nbytes = 2; 1337 kd.strbuf[0] = (char) (0xc0 | ((ch >> 6) & 0x3)); 1338 kd.strbuf[1] = (char) (0x80 | (ch & 0x3f)); 1339 TRACE(("...encoded %#x in UTF-8 as %#x,%#x\n", 1340 ch, CharOf(kd.strbuf[0]), CharOf(kd.strbuf[1]))); 1341 } 1342#endif 1343 } 1344 eightbit = False; 1345 } 1346#if OPT_WIDE_CHARS 1347 if (kd.nbytes == 1) /* cannot do NRC on UTF-8, for instance */ 1348#endif 1349 { 1350 /* VT220 & up: National Replacement Characters */ 1351 if ((xw->flags & NATIONAL) != 0) { 1352 unsigned cmp = xtermCharSetIn(screen, 1353 CharOf(kd.strbuf[0]), 1354 screen->keyboard_dialect[0]); 1355 TRACE(("...input NRC %d, %s %d\n", 1356 CharOf(kd.strbuf[0]), 1357 (CharOf(kd.strbuf[0]) == cmp) 1358 ? "unchanged" 1359 : "changed to", 1360 CharOf(cmp))); 1361 kd.strbuf[0] = (char) cmp; 1362 } else if (eightbit) { 1363 prefix = ANSI_ESC; 1364 } else if (kd.strbuf[0] == '?' 1365 && (evt_state & ControlMask) != 0) { 1366 kd.strbuf[0] = ANSI_DEL; 1367 /* UIntClr(evt_state, ControlMask); */ 1368 } 1369 } 1370 if (prefix != 0) 1371 unparseputc(xw, prefix); /* escape */ 1372 for (j = 0; j < kd.nbytes; ++j) 1373 unparseputc(xw, CharOf(kd.strbuf[j])); 1374 } 1375 key = ((kd.keysym != ANSI_XOFF) && (kd.keysym != ANSI_XON)); 1376 } 1377 unparse_end(xw); 1378 1379 if (key && !TEK4014_ACTIVE(xw)) 1380 AdjustAfterInput(xw); 1381 1382 xtermShowPointer(xw, False); 1383 return; 1384} 1385 1386void 1387StringInput(XtermWidget xw, const Char *string, size_t nbytes) 1388{ 1389 TRACE(("InputString (%s,%lu)\n", 1390 visibleChars(string, (unsigned) nbytes), 1391 (unsigned long) nbytes)); 1392#if OPT_TEK4014 1393 if (nbytes && TEK4014_GIN(tekWidget)) { 1394 TekEnqMouse(tekWidget, *string++); 1395 TekGINoff(tekWidget); 1396 nbytes--; 1397 } 1398#endif 1399 while (nbytes-- != 0) 1400 unparseputc(xw, *string++); 1401 if (!TEK4014_ACTIVE(xw)) 1402 AdjustAfterInput(xw); 1403 unparse_end(xw); 1404} 1405 1406/* These definitions are DEC-style (e.g., vt320) */ 1407static int 1408decfuncvalue(KEY_DATA * kd) 1409{ 1410 int result; 1411 1412 if (kd->is_fkey) { 1413 switch (kd->keysym) { 1414 MAP(XK_Fn(1), 11); 1415 MAP(XK_Fn(2), 12); 1416 MAP(XK_Fn(3), 13); 1417 MAP(XK_Fn(4), 14); 1418 MAP(XK_Fn(5), 15); 1419 MAP(XK_Fn(6), 17); 1420 MAP(XK_Fn(7), 18); 1421 MAP(XK_Fn(8), 19); 1422 MAP(XK_Fn(9), 20); 1423 MAP(XK_Fn(10), 21); 1424 MAP(XK_Fn(11), 23); 1425 MAP(XK_Fn(12), 24); 1426 MAP(XK_Fn(13), 25); 1427 MAP(XK_Fn(14), 26); 1428 MAP(XK_Fn(15), 28); 1429 MAP(XK_Fn(16), 29); 1430 MAP(XK_Fn(17), 31); 1431 MAP(XK_Fn(18), 32); 1432 MAP(XK_Fn(19), 33); 1433 MAP(XK_Fn(20), 34); 1434 default: 1435 /* after F20 the codes are made up and do not correspond to any 1436 * real terminal. So they are simply numbered sequentially. 1437 */ 1438 result = 42 + (int) (kd->keysym - XK_Fn(21)); 1439 break; 1440 } 1441 } else { 1442 switch (kd->keysym) { 1443 MAP(XK_Find, 1); 1444 MAP(XK_Insert, 2); 1445 MAP(XK_Delete, 3); 1446#ifdef XK_KP_Insert 1447 MAP(XK_KP_Insert, 2); 1448 MAP(XK_KP_Delete, 3); 1449#endif 1450#ifdef DXK_Remove 1451 MAP(DXK_Remove, 3); 1452#endif 1453 MAP(XK_Select, 4); 1454 MAP(XK_Prior, 5); 1455 MAP(XK_Next, 6); 1456#ifdef XK_ISO_Left_Tab 1457 MAP(XK_ISO_Left_Tab, 'Z'); 1458#endif 1459 MAP(XK_Help, 28); 1460 MAP(XK_Menu, 29); 1461 default: 1462 result = -1; 1463 break; 1464 } 1465 } 1466 return result; 1467} 1468 1469static void 1470hpfuncvalue(ANSI *reply, KEY_DATA * kd) 1471{ 1472#if OPT_HP_FUNC_KEYS 1473 int result; 1474 1475 if (kd->is_fkey) { 1476 switch (kd->keysym) { 1477 MAP(XK_Fn(1), 'p'); 1478 MAP(XK_Fn(2), 'q'); 1479 MAP(XK_Fn(3), 'r'); 1480 MAP(XK_Fn(4), 's'); 1481 MAP(XK_Fn(5), 't'); 1482 MAP(XK_Fn(6), 'u'); 1483 MAP(XK_Fn(7), 'v'); 1484 MAP(XK_Fn(8), 'w'); 1485 default: 1486 result = -1; 1487 break; 1488 } 1489 } else { 1490 switch (kd->keysym) { 1491 MAP(XK_Up, 'A'); 1492 MAP(XK_Down, 'B'); 1493 MAP(XK_Right, 'C'); 1494 MAP(XK_Left, 'D'); 1495 MAP(XK_End, 'F'); 1496 MAP(XK_Clear, 'J'); 1497 MAP(XK_Delete, 'P'); 1498 MAP(XK_Insert, 'Q'); 1499 MAP(XK_Next, 'S'); 1500 MAP(XK_Prior, 'T'); 1501 MAP(XK_Home, 'h'); 1502#ifdef XK_KP_Insert 1503 MAP(XK_KP_Delete, 'P'); 1504 MAP(XK_KP_Insert, 'Q'); 1505#endif 1506#ifdef DXK_Remove 1507 MAP(DXK_Remove, 'P'); 1508#endif 1509 MAP(XK_Select, 'F'); 1510 MAP(XK_Find, 'h'); 1511 default: 1512 result = -1; 1513 break; 1514 } 1515 } 1516 if (result > 0) { 1517 reply->a_type = ANSI_ESC; 1518 reply->a_final = (Char) result; 1519 } 1520#else 1521 (void) reply; 1522 (void) kd; 1523#endif /* OPT_HP_FUNC_KEYS */ 1524} 1525 1526static void 1527scofuncvalue(ANSI *reply, KEY_DATA * kd) 1528{ 1529#if OPT_SCO_FUNC_KEYS 1530 int result; 1531 1532 if (kd->is_fkey) { 1533 switch (kd->keysym) { 1534 MAP(XK_Fn(1), 'M'); 1535 MAP(XK_Fn(2), 'N'); 1536 MAP(XK_Fn(3), 'O'); 1537 MAP(XK_Fn(4), 'P'); 1538 MAP(XK_Fn(5), 'Q'); 1539 MAP(XK_Fn(6), 'R'); 1540 MAP(XK_Fn(7), 'S'); 1541 MAP(XK_Fn(8), 'T'); 1542 MAP(XK_Fn(9), 'U'); 1543 MAP(XK_Fn(10), 'V'); 1544 MAP(XK_Fn(11), 'W'); 1545 MAP(XK_Fn(12), 'X'); 1546 MAP(XK_Fn(13), 'Y'); 1547 MAP(XK_Fn(14), 'Z'); 1548 MAP(XK_Fn(15), 'a'); 1549 MAP(XK_Fn(16), 'b'); 1550 MAP(XK_Fn(17), 'c'); 1551 MAP(XK_Fn(18), 'd'); 1552 MAP(XK_Fn(19), 'e'); 1553 MAP(XK_Fn(20), 'f'); 1554 MAP(XK_Fn(21), 'g'); 1555 MAP(XK_Fn(22), 'h'); 1556 MAP(XK_Fn(23), 'i'); 1557 MAP(XK_Fn(24), 'j'); 1558 MAP(XK_Fn(25), 'k'); 1559 MAP(XK_Fn(26), 'l'); 1560 MAP(XK_Fn(27), 'm'); 1561 MAP(XK_Fn(28), 'n'); 1562 MAP(XK_Fn(29), 'o'); 1563 MAP(XK_Fn(30), 'p'); 1564 MAP(XK_Fn(31), 'q'); 1565 MAP(XK_Fn(32), 'r'); 1566 MAP(XK_Fn(33), 's'); 1567 MAP(XK_Fn(34), 't'); 1568 MAP(XK_Fn(35), 'u'); 1569 MAP(XK_Fn(36), 'v'); 1570 MAP(XK_Fn(37), 'w'); 1571 MAP(XK_Fn(38), 'x'); 1572 MAP(XK_Fn(39), 'y'); 1573 MAP(XK_Fn(40), 'z'); 1574 MAP(XK_Fn(41), '@'); 1575 MAP(XK_Fn(42), '['); 1576 MAP(XK_Fn(43), '\\'); 1577 MAP(XK_Fn(44), ']'); 1578 MAP(XK_Fn(45), '^'); 1579 MAP(XK_Fn(46), '_'); 1580 MAP(XK_Fn(47), '`'); 1581 MAP(XK_Fn(48), L_CURL); 1582 default: 1583 result = -1; 1584 break; 1585 } 1586 } else { 1587 switch (kd->keysym) { 1588 MAP(XK_Up, 'A'); 1589 MAP(XK_Down, 'B'); 1590 MAP(XK_Right, 'C'); 1591 MAP(XK_Left, 'D'); 1592 MAP(XK_Begin, 'E'); 1593 MAP(XK_End, 'F'); 1594 MAP(XK_Insert, 'L'); 1595 MAP(XK_Next, 'G'); 1596 MAP(XK_Prior, 'I'); 1597 MAP(XK_Home, 'H'); 1598#ifdef XK_KP_Insert 1599 MAP(XK_KP_Insert, 'L'); 1600#endif 1601 default: 1602 result = -1; 1603 break; 1604 } 1605 } 1606 if (result > 0) { 1607 reply->a_type = ANSI_CSI; 1608 reply->a_final = (Char) result; 1609 } 1610#else 1611 (void) reply; 1612 (void) kd; 1613#endif /* OPT_SCO_FUNC_KEYS */ 1614} 1615 1616static void 1617sunfuncvalue(ANSI *reply, KEY_DATA * kd) 1618{ 1619#if OPT_SUN_FUNC_KEYS 1620 ParmType result; 1621 1622 if (kd->is_fkey) { 1623 switch (kd->keysym) { 1624 /* kf1-kf20 are numbered sequentially */ 1625 MAP(XK_Fn(1), 224); 1626 MAP(XK_Fn(2), 225); 1627 MAP(XK_Fn(3), 226); 1628 MAP(XK_Fn(4), 227); 1629 MAP(XK_Fn(5), 228); 1630 MAP(XK_Fn(6), 229); 1631 MAP(XK_Fn(7), 230); 1632 MAP(XK_Fn(8), 231); 1633 MAP(XK_Fn(9), 232); 1634 MAP(XK_Fn(10), 233); 1635 MAP(XK_Fn(11), 192); 1636 MAP(XK_Fn(12), 193); 1637 MAP(XK_Fn(13), 194); 1638 MAP(XK_Fn(14), 195); /* kund */ 1639 MAP(XK_Fn(15), 196); 1640 MAP(XK_Fn(16), 197); /* kcpy */ 1641 MAP(XK_Fn(17), 198); 1642 MAP(XK_Fn(18), 199); 1643 MAP(XK_Fn(19), 200); /* kfnd */ 1644 MAP(XK_Fn(20), 201); 1645 1646 /* kf31-kf36 are numbered sequentially */ 1647 MAP(XK_Fn(21), 208); /* kf31 */ 1648 MAP(XK_Fn(22), 209); 1649 MAP(XK_Fn(23), 210); 1650 MAP(XK_Fn(24), 211); 1651 MAP(XK_Fn(25), 212); 1652 MAP(XK_Fn(26), 213); /* kf36 */ 1653 1654 /* kf37-kf47 are interspersed with keypad keys */ 1655 MAP(XK_Fn(27), 214); /* khome */ 1656 MAP(XK_Fn(28), 215); /* kf38 */ 1657 MAP(XK_Fn(29), 216); /* kpp */ 1658 MAP(XK_Fn(30), 217); /* kf40 */ 1659 MAP(XK_Fn(31), 218); /* kb2 */ 1660 MAP(XK_Fn(32), 219); /* kf42 */ 1661 MAP(XK_Fn(33), 220); /* kend */ 1662 MAP(XK_Fn(34), 221); /* kf44 */ 1663 MAP(XK_Fn(35), 222); /* knp */ 1664 MAP(XK_Fn(36), 234); /* kf46 */ 1665 MAP(XK_Fn(37), 235); /* kf47 */ 1666 default: 1667 result = -1; 1668 break; 1669 } 1670 } else { 1671 switch (kd->keysym) { 1672 MAP(XK_Help, 196); /* khlp */ 1673 MAP(XK_Menu, 197); 1674 1675 MAP(XK_Find, 1); 1676 MAP(XK_Insert, 2); /* kich1 */ 1677 MAP(XK_Delete, 3); 1678#ifdef XK_KP_Insert 1679 MAP(XK_KP_Insert, 2); 1680 MAP(XK_KP_Delete, 3); 1681#endif 1682#ifdef DXK_Remove 1683 MAP(DXK_Remove, 3); 1684#endif 1685 MAP(XK_Select, 4); 1686 1687 MAP(XK_Prior, 216); 1688 MAP(XK_Next, 222); 1689 MAP(XK_Home, 214); 1690 MAP(XK_End, 220); 1691 MAP(XK_Begin, 218); /* kf41=kb2 */ 1692 1693 default: 1694 result = -1; 1695 break; 1696 } 1697 } 1698 if (result > 0) { 1699 reply->a_type = ANSI_CSI; 1700 reply->a_nparam = 1; 1701 reply->a_param[0] = result; 1702 reply->a_final = 'z'; 1703 } else if (IsCursorKey(kd->keysym)) { 1704 reply->a_type = ANSI_SS3; 1705 reply->a_final = (Char) curfinal[kd->keysym - XK_Home]; 1706 } 1707#else 1708 (void) reply; 1709 (void) kd; 1710#endif /* OPT_SUN_FUNC_KEYS */ 1711} 1712 1713#if OPT_NUM_LOCK 1714#define isName(c) ((c) == '_' || (c) == '-' || isalnum(CharOf(c))) 1715 1716static const char * 1717skipName(const char *s) 1718{ 1719 while (*s != '\0' && isName(CharOf(*s))) 1720 ++s; 1721 return s; 1722} 1723 1724/* 1725 * Found a ":" in a translation, check what is past it to see if it contains 1726 * any of the insert-text action names. 1727 */ 1728static Boolean 1729keyCanInsert(const char *parse) 1730{ 1731 Boolean result = False; 1732 Boolean escape = False; 1733 Boolean quoted = False; 1734 1735 static const char *const table[] = 1736 { 1737 "insert", 1738 "insert-seven-bit", 1739 "insert-eight-bit", 1740 "string", 1741 }; 1742 Cardinal n; 1743 1744 while (*parse != '\0' && *parse != '\n') { 1745 int ch = CharOf(*parse++); 1746 if (escape) { 1747 escape = False; 1748 } else if (ch == '\\') { 1749 escape = True; 1750 } else if (ch == '"') { 1751 quoted = (Boolean) !quoted; 1752 } else if (!quoted && isName(ch)) { 1753 const char *next = skipName(--parse); 1754 size_t need = (size_t) (next - parse); 1755 1756 for (n = 0; n < XtNumber(table); ++n) { 1757 if (need == strlen(table[n]) 1758 && !strncmp(parse, table[n], need)) { 1759 result = True; 1760 break; 1761 } 1762 } 1763 parse = next; 1764 } 1765 1766 } 1767 return result; 1768} 1769 1770/* 1771 * Strip the entire action, to avoid matching it. 1772 */ 1773static char * 1774stripAction(char *base, char *last) 1775{ 1776 while (last != base) { 1777 if (*--last == '\n') { 1778 break; 1779 } 1780 } 1781 return last; 1782} 1783 1784static char * 1785stripBlanks(char *base, char *last) 1786{ 1787 while (last != base) { 1788 int ch = CharOf(last[-1]); 1789 if (ch != ' ' && ch != '\t') 1790 break; 1791 --last; 1792 } 1793 return last; 1794} 1795 1796/* 1797 * Strip unneeded whitespace from a translations resource, mono-casing and 1798 * returning a malloc'd copy of the result. 1799 */ 1800static char * 1801stripTranslations(const char *s, Bool onlyInsert) 1802{ 1803 char *dst = 0; 1804 1805 if (s != 0) { 1806 dst = TypeMallocN(char, strlen(s) + 1); 1807 1808 if (dst != 0) { 1809 int state = 0; 1810 int prv = 0; 1811 char *d = dst; 1812 1813 TRACE(("stripping:\n%s\n", s)); 1814 while (*s != '\0') { 1815 int ch = *s++; 1816 if (ch == '\n') { 1817 if (d != dst) 1818 *d++ = (char) ch; 1819 state = 0; 1820 } else if (strchr(":!#", ch) != 0) { 1821 d = stripBlanks(dst, d); 1822 if (onlyInsert && (ch == ':') && !keyCanInsert(s)) { 1823 d = stripAction(dst, d); 1824 } 1825 state = -1; 1826 } else if (state >= 0) { 1827 if (isspace(CharOf(ch))) { 1828 if (state == 0 || strchr("<>~ \t", prv)) 1829 continue; 1830 } else if (strchr("<>~", ch)) { 1831 d = stripBlanks(dst, d); 1832 } 1833 *d++ = x_toupper(ch); 1834 ++state; 1835 } 1836 prv = ch; 1837 } 1838 *d = '\0'; 1839 TRACE(("...result:\n%s\n", dst)); 1840 } 1841 } 1842 return dst; 1843} 1844 1845/* 1846 * Make a simple check to see if a given translations keyword appears in 1847 * xterm's translations resource. It does not attempt to parse the strings, 1848 * just makes a case-independent check and ensures that the ends of the match 1849 * are on token-boundaries. 1850 * 1851 * That this can only retrieve translations that are given as resource values; 1852 * the default translations in charproc.c for example are not retrievable by 1853 * any interface to X. 1854 * 1855 * Also: We can retrieve only the most-specified translation resource. For 1856 * example, if the resource file specifies both "*translations" and 1857 * "XTerm*translations", we see only the latter. 1858 */ 1859static Bool 1860TranslationsUseKeyword(Widget w, char **cache, const char *keyword, Bool onlyInsert) 1861{ 1862 Bool result = False; 1863 char *copy; 1864 char *test; 1865 1866 if ((test = stripTranslations(keyword, onlyInsert)) != 0) { 1867 if (*cache == 0) { 1868 String data = 0; 1869 getKeymapResources(w, "vt100", "VT100", XtRString, &data, sizeof(data)); 1870 if (data != 0 && (copy = stripTranslations(data, onlyInsert)) != 0) { 1871 *cache = copy; 1872 } 1873 } 1874 1875 if (*cache != 0) { 1876 char *p = *cache; 1877 int state = 0; 1878 int now = ' '; 1879 1880 while (*p != 0) { 1881 int prv = now; 1882 now = *p++; 1883 if (now == ':' 1884 || now == '!') { 1885 state = -1; 1886 } else if (now == '\n') { 1887 state = 0; 1888 } else if (state >= 0) { 1889 if (now == test[state]) { 1890 if ((state != 0 1891 || !isName(prv)) 1892 && ((test[++state] == 0) 1893 && !isName(*p))) { 1894 result = True; 1895 break; 1896 } 1897 } else { 1898 state = 0; 1899 } 1900 } 1901 } 1902 } 1903 free(test); 1904 } 1905 TRACE(("TranslationsUseKeyword(%p, %s) = %d\n", 1906 (void *) w, keyword, result)); 1907 return result; 1908} 1909 1910static Bool 1911xtermHasTranslation(XtermWidget xw, const char *keyword, Bool onlyInsert) 1912{ 1913 return (TranslationsUseKeyword(SHELL_OF(xw), 1914 &(xw->keyboard.shell_translations), 1915 keyword, 1916 onlyInsert) 1917 || TranslationsUseKeyword((Widget) xw, 1918 &(xw->keyboard.xterm_translations), 1919 keyword, 1920 onlyInsert)); 1921} 1922 1923#if OPT_EXTRA_PASTE 1924static void 1925addTranslation(XtermWidget xw, const char *fromString, const char *toString) 1926{ 1927 size_t have = (xw->keyboard.extra_translations 1928 ? strlen(xw->keyboard.extra_translations) 1929 : 0); 1930 size_t need = (((have != 0) ? (have + 4) : 0) 1931 + strlen(fromString) 1932 + strlen(toString) 1933 + 6); 1934 1935 if (!xtermHasTranslation(xw, fromString, False)) { 1936 xw->keyboard.extra_translations 1937 = TypeRealloc(char, need, xw->keyboard.extra_translations); 1938 if ((xw->keyboard.extra_translations) != 0) { 1939 TRACE(("adding %s: %s\n", fromString, toString)); 1940 if (have) 1941 strcat(xw->keyboard.extra_translations, " \\n\\"); 1942 sprintf(xw->keyboard.extra_translations, "%s: %s", 1943 fromString, toString); 1944 TRACE(("...{%s}\n", xw->keyboard.extra_translations)); 1945 } 1946 } 1947} 1948#endif 1949 1950#define SaveMask(name) xw->work.name |= (unsigned) mask;\ 1951 TRACE(("SaveMask(%#x -> %s) %#x (%#x is%s modifier)\n", \ 1952 (unsigned) keysym, #name, \ 1953 xw->work.name, (unsigned) mask, \ 1954 ModifierName((unsigned) mask))); 1955/* 1956 * Determine which modifier mask (if any) applies to the Num_Lock keysym. 1957 * 1958 * Also, determine which modifiers are associated with the ALT keys, so we can 1959 * send that information as a parameter for special keys in Sun/PC keyboard 1960 * mode. However, if the ALT modifier is used in translations, we do not want 1961 * to confuse things by sending the parameter. 1962 */ 1963void 1964VTInitModifiers(XtermWidget xw) 1965{ 1966 Display *dpy = XtDisplay(xw); 1967 XModifierKeymap *keymap = XGetModifierMapping(dpy); 1968 KeySym keysym; 1969 int min_keycode, max_keycode, keysyms_per_keycode = 0; 1970 1971 if (keymap != 0) { 1972 KeySym *theMap; 1973 int keycode_count; 1974 1975 TRACE(("VTInitModifiers\n")); 1976 1977 XDisplayKeycodes(dpy, &min_keycode, &max_keycode); 1978 keycode_count = (max_keycode - min_keycode + 1); 1979 theMap = XGetKeyboardMapping(dpy, 1980 (KeyCode) min_keycode, 1981 keycode_count, 1982 &keysyms_per_keycode); 1983 1984 if (theMap != 0) { 1985 int i, j, k, l; 1986 unsigned long mask; 1987 1988#if OPT_EXTRA_PASTE 1989 /* 1990 * Assume that if we can find the paste keysym in the X keyboard 1991 * mapping that the server allows the corresponding translations 1992 * resource. 1993 */ 1994 int limit = (max_keycode - min_keycode) * keysyms_per_keycode; 1995 for (i = 0; i < limit; ++i) { 1996#ifdef XF86XK_Paste 1997 if (theMap[i] == XF86XK_Paste) { 1998 TRACE(("keyboard has XF86XK_Paste\n")); 1999 addTranslation(xw, 2000 ":<KeyPress> XF86Paste", 2001 "insert-selection(SELECT, CUT_BUFFER0)"); 2002 } 2003#endif 2004#ifdef SunXK_Paste 2005 if (theMap[i] == SunXK_Paste) { 2006 TRACE(("keyboard has SunXK_Paste\n")); 2007 addTranslation(xw, 2008 ":<KeyPress> SunPaste", 2009 "insert-selection(SELECT, CUT_BUFFER0)"); 2010 } 2011#endif 2012 } 2013#endif /* OPT_EXTRA_PASTE */ 2014 2015 for (i = k = 0, mask = 1; i < 8; i++, mask <<= 1) { 2016 for (j = 0; j < keymap->max_keypermod; j++) { 2017 KeyCode code = keymap->modifiermap[k++]; 2018 if (code == 0) 2019 continue; 2020 2021 for (l = 0; l < keysyms_per_keycode; ++l) { 2022#ifdef HAVE_XKBKEYCODETOKEYSYM 2023 keysym = XkbKeycodeToKeysym(dpy, code, 0, l); 2024#else 2025 keysym = XKeycodeToKeysym(dpy, code, l); 2026#endif 2027 if (keysym == NoSymbol) { 2028 /* EMPTY */ ; 2029 } else if (keysym == XK_Num_Lock) { 2030 SaveMask(num_lock); 2031 } else if (keysym == XK_Alt_L || keysym == XK_Alt_R) { 2032 SaveMask(alt_mods); 2033 } else if (keysym == XK_Meta_L || keysym == XK_Meta_R) { 2034 SaveMask(meta_mods); 2035 } 2036 } 2037 } 2038 } 2039 XFree(theMap); 2040 } 2041 2042 /* Don't disable any mods if "alwaysUseMods" is true. */ 2043 if (!xw->misc.alwaysUseMods) { 2044 2045 /* 2046 * Force TranslationsUseKeyword() to reload. 2047 */ 2048 if (xw->keyboard.shell_translations) { 2049 free(xw->keyboard.shell_translations); 2050 xw->keyboard.shell_translations = 0; 2051 } 2052 if (xw->keyboard.xterm_translations) { 2053 free(xw->keyboard.xterm_translations); 2054 xw->keyboard.xterm_translations = 0; 2055 } 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