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