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