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