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