"Fossies" - the Fresh Open Source Software Archive

Member "xterm-379/input.c" (24 Nov 2022, 54892 Bytes) of package /linux/misc/xterm-379.tgz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "input.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 376_vs_377.

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