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