input.c revision 0bd37d32
10bd37d32Smrg/* $XTermId: input.c,v 1.345 2013/02/06 09:51:33 tom Exp $ */
2d522f475Smrg
3d522f475Smrg/*
40bd37d32Smrg * Copyright 1999-2011,2012 by Thomas E. Dickey
5d522f475Smrg *
6d522f475Smrg *                         All Rights Reserved
7d522f475Smrg *
8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a
9d522f475Smrg * copy of this software and associated documentation files (the
10d522f475Smrg * "Software"), to deal in the Software without restriction, including
11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish,
12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to
13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to
14d522f475Smrg * the following conditions:
15d522f475Smrg *
16d522f475Smrg * The above copyright notice and this permission notice shall be included
17d522f475Smrg * in all copies or substantial portions of the Software.
18d522f475Smrg *
19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26d522f475Smrg *
27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright
28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the
29d522f475Smrg * sale, use or other dealings in this Software without prior written
30d522f475Smrg * authorization.
31d522f475Smrg *
32d522f475Smrg *
33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts.
34d522f475Smrg *
35d522f475Smrg *                         All Rights Reserved
36d522f475Smrg *
37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its
38d522f475Smrg * documentation for any purpose and without fee is hereby granted,
39d522f475Smrg * provided that the above copyright notice appear in all copies and that
40d522f475Smrg * both that copyright notice and this permission notice appear in
41d522f475Smrg * supporting documentation, and that the name of Digital Equipment
42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to
43d522f475Smrg * distribution of the software without specific, written prior permission.
44d522f475Smrg *
45d522f475Smrg *
46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING
47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL
48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR
49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS,
50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,
51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS
52d522f475Smrg * SOFTWARE.
53d522f475Smrg */
54d522f475Smrg
55d522f475Smrg/* input.c */
56d522f475Smrg
57d522f475Smrg#include <xterm.h>
58d522f475Smrg
59d522f475Smrg#include <X11/keysym.h>
60d522f475Smrg
61d522f475Smrg#ifdef VMS
62d522f475Smrg#include <X11/keysymdef.h>
63d522f475Smrg#endif
64d522f475Smrg
65d522f475Smrg#if HAVE_X11_DECKEYSYM_H
66d522f475Smrg#include <X11/DECkeysym.h>
67d522f475Smrg#endif
68d522f475Smrg
69d522f475Smrg#if HAVE_X11_SUNKEYSYM_H
70d522f475Smrg#include <X11/Sunkeysym.h>
71d522f475Smrg#endif
72d522f475Smrg
73d522f475Smrg#if HAVE_X11_XF86KEYSYM_H
74d522f475Smrg#include <X11/XF86keysym.h>
75d522f475Smrg#endif
76d522f475Smrg
770bd37d32Smrg#ifdef HAVE_XKBKEYCODETOKEYSYM
780bd37d32Smrg#include <X11/XKBlib.h>
790bd37d32Smrg#endif
800bd37d32Smrg
81d522f475Smrg#include <X11/Xutil.h>
82d522f475Smrg#include <stdio.h>
83d522f475Smrg#include <ctype.h>
84d522f475Smrg
85d522f475Smrg#include <xutf8.h>
86d522f475Smrg
87d522f475Smrg#include <data.h>
88d522f475Smrg#include <fontutils.h>
892eaa94a1Schristos#include <xstrings.h>
90d522f475Smrg#include <xtermcap.h>
91d522f475Smrg
92d522f475Smrg/*
93d522f475Smrg * Xutil.h has no macro to check for the complete set of function- and
94d522f475Smrg * modifier-keys that might be returned.  Fake it.
95d522f475Smrg */
96d522f475Smrg#ifdef XK_ISO_Lock
97d522f475Smrg#define IsPredefinedKey(n) ((n) >= XK_ISO_Lock && (n) <= XK_Delete)
98d522f475Smrg#else
99d522f475Smrg#define IsPredefinedKey(n) ((n) >= XK_BackSpace && (n) <= XK_Delete)
100d522f475Smrg#endif
101d522f475Smrg
102d522f475Smrg#ifdef XK_ISO_Left_Tab
103d522f475Smrg#define IsTabKey(n) ((n) == XK_Tab || (n) == XK_ISO_Left_Tab)
104d522f475Smrg#else
105d522f475Smrg#define IsTabKey(n) ((n) == XK_Tab)
106d522f475Smrg#endif
107d522f475Smrg
108d522f475Smrg#ifndef IsPrivateKeypadKey
109d522f475Smrg#define IsPrivateKeypadKey(k) (0)
110d522f475Smrg#endif
111d522f475Smrg
112d522f475Smrg#define IsBackarrowToggle(keyboard, keysym, state) \
113d522f475Smrg	((((keyboard->flags & MODE_DECBKM) == 0) \
114d522f475Smrg	    ^ ((state & ControlMask) != 0)) \
115d522f475Smrg	&& (keysym == XK_BackSpace))
116d522f475Smrg
117d522f475Smrg#define MAP(from, to) case from: result = to; break
118d522f475Smrg#define Masked(value,mask) ((value) & (unsigned) (~(mask)))
119d522f475Smrg
120d522f475Smrg#define KEYSYM_FMT "0x%04lX"	/* simplify matching <X11/keysymdef.h> */
121d522f475Smrg
12220d2c4d2Smrg#define TEK4014_GIN(tw) (tw != 0 && TekScreenOf(tw)->TekGIN)
123d522f475Smrg
124d522f475Smrgtypedef struct {
125d522f475Smrg    KeySym keysym;
126d522f475Smrg    Bool is_fkey;
127d522f475Smrg    int nbytes;
128d522f475Smrg#define STRBUFSIZE 500
129d522f475Smrg    char strbuf[STRBUFSIZE];
130d522f475Smrg} KEY_DATA;
131d522f475Smrg
13220d2c4d2Smrgstatic
13320d2c4d2Smrgconst char *kypd_num = " XXXXXXXX\tXXX\rXXXxxxxXXXXXXXXXXXXXXXXXXXXX*+,-./0123456789XXX=";
13420d2c4d2Smrg/*                      0123456789 abc def0123456789abcdef0123456789abcdef0123456789abcd */
13520d2c4d2Smrgstatic
13620d2c4d2Smrgconst char *kypd_apl = " ABCDEFGHIJKLMNOPQRSTUVWXYZ??????abcdefghijklmnopqrstuvwxyzXXX";
13720d2c4d2Smrg/*                      0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd */
13820d2c4d2Smrgstatic
13920d2c4d2Smrgconst char *curfinal = "HDACB  FE";
140d522f475Smrg
141d522f475Smrgstatic int decfuncvalue(KEY_DATA *);
142d522f475Smrgstatic void sunfuncvalue(ANSI *, KEY_DATA *);
143d522f475Smrgstatic void hpfuncvalue(ANSI *, KEY_DATA *);
144d522f475Smrgstatic void scofuncvalue(ANSI *, KEY_DATA *);
145d522f475Smrg
146d522f475Smrgstatic void
147d522f475SmrgAdjustAfterInput(XtermWidget xw)
148d522f475Smrg{
14920d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
150d522f475Smrg
151d522f475Smrg    if (screen->scrollkey && screen->topline != 0)
15220d2c4d2Smrg	WindowScroll(xw, 0, False);
153d522f475Smrg    if (screen->marginbell) {
154d522f475Smrg	int col = screen->max_col - screen->nmarginbell;
15520d2c4d2Smrg	if (screen->bellArmed >= 0) {
15620d2c4d2Smrg	    if (screen->bellArmed == screen->cur_row) {
157d522f475Smrg		if (screen->cur_col >= col) {
15820d2c4d2Smrg		    Bell(xw, XkbBI_MarginBell, 0);
15920d2c4d2Smrg		    screen->bellArmed = -1;
160d522f475Smrg		}
16120d2c4d2Smrg	    } else {
16220d2c4d2Smrg		screen->bellArmed =
163d522f475Smrg		    screen->cur_col < col ? screen->cur_row : -1;
16420d2c4d2Smrg	    }
165d522f475Smrg	} else if (screen->cur_col < col)
16620d2c4d2Smrg	    screen->bellArmed = screen->cur_row;
167d522f475Smrg    }
168d522f475Smrg}
169d522f475Smrg
170d522f475Smrg/*
171d522f475Smrg * Return true if the key is on the editing keypad.  This overlaps with
1720bd37d32Smrg * IsCursorKey() and IsKeypadKey() and must be tested before those macros to
173d522f475Smrg * distinguish it from them.
1740bd37d32Smrg *
1750bd37d32Smrg * VT220  emulation  uses  the  VT100  numeric  keypad as well as a 6-key
1760bd37d32Smrg * editing keypad. Here's a picture of the VT220 editing keypad:
1770bd37d32Smrg *      +--------+--------+--------+
1780bd37d32Smrg *      | Find   | Insert | Remove |
1790bd37d32Smrg *      +--------+--------+--------+
1800bd37d32Smrg *      | Select | Prev   | Next   |
1810bd37d32Smrg *      +--------+--------+--------+
1820bd37d32Smrg *
1830bd37d32Smrg * and the similar Sun and PC keypads:
1840bd37d32Smrg *      +--------+--------+--------+
1850bd37d32Smrg *      | Insert | Home   | PageUp |
1860bd37d32Smrg *      +--------+--------+--------+
1870bd37d32Smrg *      | Delete | End    | PageDn |
1880bd37d32Smrg *      +--------+--------+--------+
189d522f475Smrg */
190d522f475Smrgstatic Bool
1910bd37d32SmrgIsEditKeypad(XtermWidget xw, KeySym keysym)
192d522f475Smrg{
1930bd37d32Smrg    Bool result;
1940bd37d32Smrg
195d522f475Smrg    switch (keysym) {
1960bd37d32Smrg    case XK_Delete:
1970bd37d32Smrg	result = !xtermDeleteIsDEL(xw);
1980bd37d32Smrg	break;
1990bd37d32Smrg    case XK_Prior:
2000bd37d32Smrg    case XK_Next:
2010bd37d32Smrg    case XK_Insert:
2020bd37d32Smrg    case XK_Find:
2030bd37d32Smrg    case XK_Select:
204d522f475Smrg#ifdef DXK_Remove
2050bd37d32Smrg    case DXK_Remove:
206d522f475Smrg#endif
2070bd37d32Smrg	result = True;
2080bd37d32Smrg	break;
2090bd37d32Smrg    default:
2100bd37d32Smrg	result = False;
2110bd37d32Smrg	break;
2120bd37d32Smrg    }
2130bd37d32Smrg    return result;
2140bd37d32Smrg}
2150bd37d32Smrg
2160bd37d32Smrg/*
2170bd37d32Smrg * Editing-keypad, plus other editing keys which are not included in the
2180bd37d32Smrg * other macros.
2190bd37d32Smrg */
2200bd37d32Smrgstatic Bool
2210bd37d32SmrgIsEditFunctionKey(XtermWidget xw, KeySym keysym)
2220bd37d32Smrg{
2230bd37d32Smrg    Bool result;
2240bd37d32Smrg
2250bd37d32Smrg    switch (keysym) {
226d522f475Smrg#ifdef XK_KP_Delete
227d522f475Smrg    case XK_KP_Delete:		/* editing key on numeric keypad */
228d522f475Smrg    case XK_KP_Insert:		/* editing key on numeric keypad */
229d522f475Smrg#endif
230d522f475Smrg#ifdef XK_ISO_Left_Tab
231d522f475Smrg    case XK_ISO_Left_Tab:
232d522f475Smrg#endif
2330bd37d32Smrg	result = True;
2340bd37d32Smrg	break;
235d522f475Smrg    default:
2360bd37d32Smrg	result = IsEditKeypad(xw, keysym);
2370bd37d32Smrg	break;
238d522f475Smrg    }
2390bd37d32Smrg    return result;
240d522f475Smrg}
241d522f475Smrg
242d522f475Smrg#if OPT_MOD_FKEYS
243d522f475Smrg#define IS_CTRL(n) ((n) < ANSI_SPA || ((n) >= 0x7f && (n) <= 0x9f))
244d522f475Smrg
245d522f475Smrg/*
246d522f475Smrg * Return true if the keysym corresponds to one of the control characters,
247d522f475Smrg * or one of the common ASCII characters that is combined with control to
248d522f475Smrg * make a control character.
249d522f475Smrg */
250d522f475Smrgstatic Bool
251d522f475SmrgIsControlInput(KEY_DATA * kd)
252d522f475Smrg{
253d522f475Smrg    return ((kd->keysym) >= 0x40 && (kd->keysym) <= 0x7f);
254d522f475Smrg}
255d522f475Smrg
256d522f475Smrgstatic Bool
257d522f475SmrgIsControlOutput(KEY_DATA * kd)
258d522f475Smrg{
259d522f475Smrg    return IS_CTRL(kd->keysym);
260d522f475Smrg}
261d522f475Smrg
262d522f475Smrg/*
263d522f475Smrg * X "normally" has some built-in translations, which the user may want to
264d522f475Smrg * suppress when processing the modifyOtherKeys resource.  In particular, the
265d522f475Smrg * control modifier applied to some of the keyboard digits gives results for
266d522f475Smrg * control characters.
267d522f475Smrg *
268d522f475Smrg * control 2   0    NUL
269d522f475Smrg * control SPC 0    NUL
270d522f475Smrg * control @   0    NUL
271d522f475Smrg * control `   0    NUL
272d522f475Smrg * control 3   0x1b ESC
273d522f475Smrg * control 4   0x1c FS
274d522f475Smrg * control \   0x1c FS
275d522f475Smrg * control 5   0x1d GS
276d522f475Smrg * control 6   0x1e RS
277d522f475Smrg * control ^   0x1e RS
278d522f475Smrg * control ~   0x1e RS
279d522f475Smrg * control 7   0x1f US
280d522f475Smrg * control /   0x1f US
281d522f475Smrg * control _   0x1f US
282d522f475Smrg * control 8   0x7f DEL
283d522f475Smrg *
284d522f475Smrg * It is possible that some other keyboards do not work for these combinations,
285d522f475Smrg * but they do work with modifyOtherKeys=2 for the US keyboard:
286d522f475Smrg *
287d522f475Smrg * control `   0    NUL
288d522f475Smrg * control [   0x1b ESC
289d522f475Smrg * control \   0x1c FS
290d522f475Smrg * control ]   0x1d GS
291d522f475Smrg * control ?   0x7f DEL
292d522f475Smrg */
293d522f475Smrgstatic Bool
294d522f475SmrgIsControlAlias(KEY_DATA * kd)
295d522f475Smrg{
296d522f475Smrg    Bool result = False;
297d522f475Smrg
298d522f475Smrg    if (kd->nbytes == 1) {
299d522f475Smrg	result = IS_CTRL(CharOf(kd->strbuf[0]));
300d522f475Smrg    }
301d522f475Smrg    return result;
302d522f475Smrg}
303d522f475Smrg
304d522f475Smrg/*
305d522f475Smrg * If we are in the non-VT220/VT52 keyboard state, allow modifiers to add a
306d522f475Smrg * parameter to the function-key control sequences.
307d522f475Smrg *
308d522f475Smrg * Note that we generally cannot capture the Shift-modifier for the numeric
309d522f475Smrg * keypad since this is commonly used to act as a type of NumLock, e.g.,
310d522f475Smrg * making the keypad send "7" (actually XK_KP_7) where the unshifted code
311d522f475Smrg * would be Home (XK_KP_Home).  The other modifiers work, subject to the
312d522f475Smrg * usual window-manager assignments.
313d522f475Smrg */
3140bd37d32Smrg#if OPT_SUNPC_KBD
3150bd37d32Smrg#define LegacyAllows(code) (!is_legacy || (code & xw->keyboard.modify_now.allow_keys) != 0)
3160bd37d32Smrg#else
3170bd37d32Smrg#define LegacyAllows(code) True
3180bd37d32Smrg#endif
3190bd37d32Smrg
320d522f475Smrgstatic Bool
321d522f475SmrgallowModifierParm(XtermWidget xw, KEY_DATA * kd)
322d522f475Smrg{
323d522f475Smrg    TKeyboard *keyboard = &(xw->keyboard);
32420d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
325d522f475Smrg    int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0);
3260bd37d32Smrg    int is_legacy = (keyboard->type == keyboardIsLegacy);
327d522f475Smrg    Bool result = False;
328d522f475Smrg
329d522f475Smrg#if OPT_SUNPC_KBD
3300bd37d32Smrg    if (keyboard->type == keyboardIsVT220)
3310bd37d32Smrg	is_legacy = True;
332d522f475Smrg#endif
3330bd37d32Smrg
3340bd37d32Smrg    (void) screen;
335d522f475Smrg#if OPT_VT52_MODE
3360bd37d32Smrg    if (screen->vtXX_level != 0)
337d522f475Smrg#endif
3380bd37d32Smrg    {
3390bd37d32Smrg	if (IsCursorKey(kd->keysym) || IsEditFunctionKey(xw, kd->keysym)) {
3400bd37d32Smrg	    result = LegacyAllows(2);
3410bd37d32Smrg	} else if (IsKeypadKey(kd->keysym)) {
3420bd37d32Smrg	    if (keypad_mode) {
3430bd37d32Smrg		result = LegacyAllows(1);
3440bd37d32Smrg	    }
3450bd37d32Smrg	} else if (IsFunctionKey(kd->keysym)) {
3460bd37d32Smrg	    result = LegacyAllows(4);
3470bd37d32Smrg	} else if (IsMiscFunctionKey(kd->keysym)) {
3480bd37d32Smrg	    result = LegacyAllows(8);
3490bd37d32Smrg	}
3500bd37d32Smrg    }
3510bd37d32Smrg    if (xw->keyboard.modify_now.other_keys != 0) {
352d522f475Smrg	result = True;
353d522f475Smrg    }
354d522f475Smrg    return result;
355d522f475Smrg}
356d522f475Smrg
357d522f475Smrg/*
358d522f475Smrg* Modifier codes:
359d522f475Smrg*       None                  1
360d522f475Smrg*       Shift                 2 = 1(None)+1(Shift)
361d522f475Smrg*       Alt                   3 = 1(None)+2(Alt)
362d522f475Smrg*       Alt+Shift             4 = 1(None)+1(Shift)+2(Alt)
363d522f475Smrg*       Ctrl                  5 = 1(None)+4(Ctrl)
364d522f475Smrg*       Ctrl+Shift            6 = 1(None)+1(Shift)+4(Ctrl)
365d522f475Smrg*       Ctrl+Alt              7 = 1(None)+2(Alt)+4(Ctrl)
366d522f475Smrg*       Ctrl+Alt+Shift        8 = 1(None)+1(Shift)+2(Alt)+4(Ctrl)
367d522f475Smrg*       Meta                  9 = 1(None)+8(Meta)
368d522f475Smrg*       Meta+Shift           10 = 1(None)+8(Meta)+1(Shift)
369d522f475Smrg*       Meta+Alt             11 = 1(None)+8(Meta)+2(Alt)
370d522f475Smrg*       Meta+Alt+Shift       12 = 1(None)+8(Meta)+1(Shift)+2(Alt)
371d522f475Smrg*       Meta+Ctrl            13 = 1(None)+8(Meta)+4(Ctrl)
372d522f475Smrg*       Meta+Ctrl+Shift      14 = 1(None)+8(Meta)+1(Shift)+4(Ctrl)
373d522f475Smrg*       Meta+Ctrl+Alt        15 = 1(None)+8(Meta)+2(Alt)+4(Ctrl)
374d522f475Smrg*       Meta+Ctrl+Alt+Shift  16 = 1(None)+8(Meta)+1(Shift)+2(Alt)+4(Ctrl)
375d522f475Smrg*/
376d522f475Smrg
377956cc18dSsnjunsigned
378d522f475SmrgxtermParamToState(XtermWidget xw, unsigned param)
379d522f475Smrg{
380956cc18dSsnj    unsigned result = 0;
381d522f475Smrg#if OPT_NUM_LOCK
3820bd37d32Smrg    if (param > MOD_NONE) {
383956cc18dSsnj	if ((param - MOD_NONE) & MOD_SHIFT)
38420d2c4d2Smrg	    UIntSet(result, ShiftMask);
385956cc18dSsnj	if ((param - MOD_NONE) & MOD_CTRL)
38620d2c4d2Smrg	    UIntSet(result, ControlMask);
387956cc18dSsnj	if ((param - MOD_NONE) & MOD_ALT)
3880bd37d32Smrg	    UIntSet(result, xw->work.alt_mods);
389956cc18dSsnj	if ((param - MOD_NONE) & MOD_META)
3900bd37d32Smrg	    UIntSet(result, xw->work.meta_mods);
391d522f475Smrg    }
392d522f475Smrg#else
393d522f475Smrg    (void) xw;
394d522f475Smrg    (void) param;
395d522f475Smrg#endif
396d522f475Smrg    TRACE(("xtermParamToState(%d) %s%s%s%s -> %#x\n", param,
397956cc18dSsnj	   MODIFIER_NAME(param, MOD_SHIFT),
398956cc18dSsnj	   MODIFIER_NAME(param, MOD_ALT),
399956cc18dSsnj	   MODIFIER_NAME(param, MOD_CTRL),
400956cc18dSsnj	   MODIFIER_NAME(param, MOD_META),
401d522f475Smrg	   result));
402d522f475Smrg    return result;
403d522f475Smrg}
404d522f475Smrg
405956cc18dSsnjunsigned
406d522f475SmrgxtermStateToParam(XtermWidget xw, unsigned state)
407d522f475Smrg{
408956cc18dSsnj    unsigned modify_parm = MOD_NONE;
409d522f475Smrg
410956cc18dSsnj    TRACE(("xtermStateToParam %#x\n", state));
411d522f475Smrg#if OPT_NUM_LOCK
4120bd37d32Smrg    if (state & ShiftMask) {
4130bd37d32Smrg	modify_parm += MOD_SHIFT;
4140bd37d32Smrg	UIntClr(state, ShiftMask);
4150bd37d32Smrg    }
4160bd37d32Smrg    if (state & ControlMask) {
4170bd37d32Smrg	modify_parm += MOD_CTRL;
4180bd37d32Smrg	UIntClr(state, ControlMask);
4190bd37d32Smrg    }
4200bd37d32Smrg    if ((state & xw->work.alt_mods) != 0) {
4210bd37d32Smrg	modify_parm += MOD_ALT;
4220bd37d32Smrg	UIntClr(state, xw->work.alt_mods);
4230bd37d32Smrg    }
4240bd37d32Smrg    if ((state & xw->work.meta_mods) != 0) {
4250bd37d32Smrg	modify_parm += MOD_META;
4260bd37d32Smrg	UIntClr(state, xw->work.meta_mods);
427d522f475Smrg    }
428956cc18dSsnj    if (modify_parm == MOD_NONE)
429956cc18dSsnj	modify_parm = 0;
430d522f475Smrg#else
431d522f475Smrg    (void) xw;
432d522f475Smrg    (void) state;
433d522f475Smrg#endif
434d522f475Smrg    TRACE(("...xtermStateToParam %d%s%s%s%s\n", modify_parm,
435956cc18dSsnj	   MODIFIER_NAME(modify_parm, MOD_SHIFT),
436956cc18dSsnj	   MODIFIER_NAME(modify_parm, MOD_ALT),
437956cc18dSsnj	   MODIFIER_NAME(modify_parm, MOD_CTRL),
438956cc18dSsnj	   MODIFIER_NAME(modify_parm, MOD_META)));
439d522f475Smrg    return modify_parm;
440d522f475Smrg}
441d522f475Smrg
442d522f475Smrg#define computeMaskedModifier(xw, state, mask) \
443d522f475Smrg	xtermStateToParam(xw, Masked(state, mask))
444d522f475Smrg
445d522f475Smrg#if OPT_NUM_LOCK
446d522f475Smrgstatic unsigned
447d522f475SmrgfilterAltMeta(unsigned result, unsigned mask, Bool enable, KEY_DATA * kd)
448d522f475Smrg{
449d522f475Smrg    if ((result & mask) != 0) {
450d522f475Smrg	/*
451d522f475Smrg	 * metaSendsEscape makes the meta key independent of
452d522f475Smrg	 * modifyOtherKeys.
453d522f475Smrg	 */
454d522f475Smrg	if (enable) {
455d522f475Smrg	    result &= ~mask;
456d522f475Smrg	}
457d522f475Smrg	/*
458d522f475Smrg	 * A bare meta-modifier is independent of modifyOtherKeys.  If it
459d522f475Smrg	 * is combined with other modifiers, make it depend.
460d522f475Smrg	 */
461d522f475Smrg	if ((result & ~(mask)) == 0) {
462d522f475Smrg	    result &= ~mask;
463d522f475Smrg	}
464d522f475Smrg	/*
465d522f475Smrg	 * Check for special cases of control+meta which are used by some
466d522f475Smrg	 * applications, e.g., emacs.
467d522f475Smrg	 */
468d522f475Smrg	if ((IsControlInput(kd)
469d522f475Smrg	     || IsControlOutput(kd))
470d522f475Smrg	    && (result & ControlMask) != 0) {
471d522f475Smrg	    result &= ~(mask | ControlMask);
472d522f475Smrg	}
473d522f475Smrg	if (kd->keysym == XK_Return || kd->keysym == XK_Tab) {
474d522f475Smrg	    result &= ~(mask | ControlMask);
475d522f475Smrg	}
476d522f475Smrg    }
477d522f475Smrg    return result;
478d522f475Smrg}
479d522f475Smrg#endif /* OPT_NUM_LOCK */
480d522f475Smrg
481d522f475Smrg/*
482d522f475Smrg * Single characters (not function-keys) are allowed fewer modifiers when
483d522f475Smrg * interpreting modifyOtherKeys due to pre-existing associations with some
484d522f475Smrg * modifiers.
485d522f475Smrg */
486d522f475Smrgstatic unsigned
487d522f475SmrgallowedCharModifiers(XtermWidget xw, unsigned state, KEY_DATA * kd)
488d522f475Smrg{
489d522f475Smrg#if OPT_NUM_LOCK
4900bd37d32Smrg    unsigned a_or_m = (state & (xw->work.meta_mods | xw->work.alt_mods));
491d522f475Smrg#else
492d522f475Smrg    unsigned a_or_m = 0;
493d522f475Smrg#endif
494d522f475Smrg    /*
495d522f475Smrg     * Start by limiting the result to the modifiers we might want to use.
496d522f475Smrg     */
497d522f475Smrg    unsigned result = (state & (ControlMask
498d522f475Smrg				| ShiftMask
499d522f475Smrg				| a_or_m));
500d522f475Smrg
501d522f475Smrg    /*
502d522f475Smrg     * If modifyOtherKeys is off or medium (0 or 1), moderate its effects by
503d522f475Smrg     * excluding the common cases for modifiers.
504d522f475Smrg     */
505d522f475Smrg    if (xw->keyboard.modify_now.other_keys <= 1) {
506d522f475Smrg	if (IsControlInput(kd)
507d522f475Smrg	    && Masked(result, ControlMask) == 0) {
508d522f475Smrg	    /* These keys are already associated with the control-key */
509d522f475Smrg	    if (xw->keyboard.modify_now.other_keys == 0) {
51020d2c4d2Smrg		UIntClr(result, ControlMask);
511d522f475Smrg	    }
512d522f475Smrg	} else if (kd->keysym == XK_Tab || kd->keysym == XK_Return) {
513a1f3da82Smrg	    /* EMPTY */ ;
514d522f475Smrg	} else if (IsControlAlias(kd)) {
515d522f475Smrg	    /* Things like "^_" work here... */
516d522f475Smrg	    if (Masked(result, (ControlMask | ShiftMask)) == 0) {
517d522f475Smrg		result = 0;
518d522f475Smrg	    }
519d522f475Smrg	} else if (!IsControlOutput(kd) && !IsPredefinedKey(kd->keysym)) {
520d522f475Smrg	    /* Printable keys are already associated with the shift-key */
521d522f475Smrg	    if (!(result & ControlMask)) {
52220d2c4d2Smrg		UIntClr(result, ShiftMask);
523d522f475Smrg	    }
524d522f475Smrg	}
525d522f475Smrg#if OPT_NUM_LOCK
526d522f475Smrg	result = filterAltMeta(result,
5270bd37d32Smrg			       xw->work.meta_mods,
52820d2c4d2Smrg			       TScreenOf(xw)->meta_sends_esc, kd);
52920d2c4d2Smrg	if (TScreenOf(xw)->alt_is_not_meta) {
530d522f475Smrg	    result = filterAltMeta(result,
5310bd37d32Smrg				   xw->work.alt_mods,
53220d2c4d2Smrg				   TScreenOf(xw)->alt_sends_esc, kd);
533d522f475Smrg	}
534d522f475Smrg#endif
535d522f475Smrg    }
536d522f475Smrg    TRACE(("...allowedCharModifiers(state=%u" FMT_MODIFIER_NAMES
537d522f475Smrg	   ", ch=" KEYSYM_FMT ") ->"
538d522f475Smrg	   "%u" FMT_MODIFIER_NAMES "\n",
539d522f475Smrg	   state, ARG_MODIFIER_NAMES(state), kd->keysym,
540d522f475Smrg	   result, ARG_MODIFIER_NAMES(result)));
541d522f475Smrg    return result;
542d522f475Smrg}
543d522f475Smrg
544d522f475Smrg/*
545d522f475Smrg * Decide if we should generate a special escape sequence for "other" keys
546d522f475Smrg * than cursor-, function-keys, etc., as per the modifyOtherKeys resource.
547d522f475Smrg */
548d522f475Smrgstatic Bool
549d522f475SmrgModifyOtherKeys(XtermWidget xw,
550d522f475Smrg		unsigned state,
551d522f475Smrg		KEY_DATA * kd,
552956cc18dSsnj		unsigned modify_parm)
553d522f475Smrg{
554d522f475Smrg    TKeyboard *keyboard = &(xw->keyboard);
555d522f475Smrg    Bool result = False;
556d522f475Smrg
557d522f475Smrg    /*
558d522f475Smrg     * Exclude the keys already covered by a modifier.
559d522f475Smrg     */
560d522f475Smrg    if (kd->is_fkey
5610bd37d32Smrg	|| IsEditFunctionKey(xw, kd->keysym)
562d522f475Smrg	|| IsKeypadKey(kd->keysym)
563d522f475Smrg	|| IsCursorKey(kd->keysym)
564d522f475Smrg	|| IsPFKey(kd->keysym)
565d522f475Smrg	|| IsMiscFunctionKey(kd->keysym)
5660bd37d32Smrg	|| IsPrivateKeypadKey(kd->keysym)) {
567d522f475Smrg	result = False;
568d522f475Smrg    } else if (modify_parm != 0) {
569d522f475Smrg	if (IsBackarrowToggle(keyboard, kd->keysym, state)) {
570d522f475Smrg	    kd->keysym = XK_Delete;
57120d2c4d2Smrg	    UIntClr(state, ControlMask);
572d522f475Smrg	}
573d522f475Smrg	if (!IsPredefinedKey(kd->keysym)) {
574d522f475Smrg	    state = allowedCharModifiers(xw, state, kd);
575d522f475Smrg	}
576d522f475Smrg	if (state != 0) {
577d522f475Smrg	    switch (keyboard->modify_now.other_keys) {
578d522f475Smrg	    default:
579d522f475Smrg		break;
580d522f475Smrg	    case 1:
581d522f475Smrg		switch (kd->keysym) {
582d522f475Smrg		case XK_BackSpace:
583d522f475Smrg		case XK_Delete:
584d522f475Smrg		    result = False;
585d522f475Smrg		    break;
586d522f475Smrg#ifdef XK_ISO_Left_Tab
587d522f475Smrg		case XK_ISO_Left_Tab:
588956cc18dSsnj		    if (computeMaskedModifier(xw, state, ShiftMask))
589d522f475Smrg			result = True;
590d522f475Smrg		    break;
591d522f475Smrg#endif
592d522f475Smrg		case XK_Return:
593d522f475Smrg		case XK_Tab:
594956cc18dSsnj		    result = (modify_parm != 0);
595d522f475Smrg		    break;
596d522f475Smrg		default:
597d522f475Smrg		    if (IsControlInput(kd)) {
598d522f475Smrg			if (state == ControlMask || state == ShiftMask) {
599d522f475Smrg			    result = False;
600d522f475Smrg			} else {
601956cc18dSsnj			    result = (modify_parm != 0);
602d522f475Smrg			}
603d522f475Smrg		    } else if (IsControlAlias(kd)) {
604d522f475Smrg			if (state == ShiftMask)
605d522f475Smrg			    result = False;
606956cc18dSsnj			else if (computeMaskedModifier(xw, state, ControlMask)) {
607d522f475Smrg			    result = True;
608d522f475Smrg			}
609d522f475Smrg		    } else {
610d522f475Smrg			result = True;
611d522f475Smrg		    }
612d522f475Smrg		    break;
613d522f475Smrg		}
614d522f475Smrg		break;
615d522f475Smrg	    case 2:
616d522f475Smrg		switch (kd->keysym) {
617d522f475Smrg		case XK_BackSpace:
618d522f475Smrg		    /* strip ControlMask as per IsBackarrowToggle() */
619956cc18dSsnj		    if (computeMaskedModifier(xw, state, ControlMask))
620d522f475Smrg			result = True;
621d522f475Smrg		    break;
622d522f475Smrg		case XK_Delete:
623956cc18dSsnj		    result = (xtermStateToParam(xw, state) != 0);
624d522f475Smrg		    break;
625d522f475Smrg#ifdef XK_ISO_Left_Tab
626d522f475Smrg		case XK_ISO_Left_Tab:
627956cc18dSsnj		    if (computeMaskedModifier(xw, state, ShiftMask))
628d522f475Smrg			result = True;
629d522f475Smrg		    break;
630d522f475Smrg#endif
631d522f475Smrg		case XK_Return:
632d522f475Smrg		case XK_Tab:
633956cc18dSsnj		    result = (modify_parm != 0);
634d522f475Smrg		    break;
635d522f475Smrg		default:
636d522f475Smrg		    if (IsControlInput(kd)) {
637d522f475Smrg			result = True;
638d522f475Smrg		    } else if (state == ShiftMask) {
639d522f475Smrg			result = (kd->keysym == ' ' || kd->keysym == XK_Return);
640956cc18dSsnj		    } else if (computeMaskedModifier(xw, state, ShiftMask)) {
641d522f475Smrg			result = True;
642d522f475Smrg		    }
643d522f475Smrg		    break;
644d522f475Smrg		}
645d522f475Smrg		break;
646d522f475Smrg	    }
647d522f475Smrg	}
648d522f475Smrg    }
649d522f475Smrg    TRACE(("...ModifyOtherKeys(%d,%d) %s\n",
650d522f475Smrg	   keyboard->modify_now.other_keys,
651d522f475Smrg	   modify_parm,
652d522f475Smrg	   BtoS(result)));
653d522f475Smrg    return result;
654d522f475Smrg}
655d522f475Smrg
656d522f475Smrg#define APPEND_PARM(number) \
657956cc18dSsnj	    reply->a_param[reply->a_nparam] = (ParmType) number; \
658956cc18dSsnj	    reply->a_nparam++
659d522f475Smrg
660d522f475Smrg/*
661d522f475Smrg * Function-key code 27 happens to not be used in the vt220-style encoding.
662d522f475Smrg * xterm uses this to represent modified non-function-keys such as control/+ in
663d522f475Smrg * the Sun/PC keyboard layout.  See the modifyOtherKeys resource in the manpage
664d522f475Smrg * for more information.
665d522f475Smrg */
666d522f475Smrgstatic Bool
667956cc18dSsnjmodifyOtherKey(ANSI * reply, int input_char, unsigned modify_parm, int format_keys)
668d522f475Smrg{
669d522f475Smrg    Bool result = False;
670d522f475Smrg
671d522f475Smrg    if (input_char >= 0) {
672d522f475Smrg	reply->a_type = ANSI_CSI;
673d522f475Smrg	if (format_keys) {
674d522f475Smrg	    APPEND_PARM(input_char);
675d522f475Smrg	    APPEND_PARM(modify_parm);
676d522f475Smrg	    reply->a_final = 'u';
677d522f475Smrg	} else {
678d522f475Smrg	    APPEND_PARM(27);
679d522f475Smrg	    APPEND_PARM(modify_parm);
680d522f475Smrg	    APPEND_PARM(input_char);
681d522f475Smrg	    reply->a_final = '~';
682d522f475Smrg	}
683d522f475Smrg
684d522f475Smrg	result = True;
685d522f475Smrg    }
686d522f475Smrg    return result;
687d522f475Smrg}
688d522f475Smrg
689d522f475Smrgstatic void
690956cc18dSsnjmodifyCursorKey(ANSI * reply, int modify, unsigned *modify_parm)
691d522f475Smrg{
692956cc18dSsnj    if (*modify_parm != 0) {
693d522f475Smrg	if (modify < 0) {
694d522f475Smrg	    *modify_parm = 0;
695d522f475Smrg	}
696d522f475Smrg	if (modify > 0) {
697d522f475Smrg	    reply->a_type = ANSI_CSI;	/* SS3 should not have params */
698d522f475Smrg	}
699d522f475Smrg	if (modify > 1 && reply->a_nparam == 0) {
700d522f475Smrg	    APPEND_PARM(1);	/* force modifier to 2nd param */
701d522f475Smrg	}
702d522f475Smrg	if (modify > 2) {
703d522f475Smrg	    reply->a_pintro = '>';	/* mark this as "private" */
704d522f475Smrg	}
705d522f475Smrg    }
706d522f475Smrg}
707d522f475Smrg#else
708d522f475Smrg#define modifyCursorKey(reply, modify, parm)	/* nothing */
709d522f475Smrg#endif /* OPT_MOD_FKEYS */
710d522f475Smrg
711d522f475Smrg#if OPT_SUNPC_KBD
712d522f475Smrg/*
713d522f475Smrg * If we have told xterm that our keyboard is really a Sun/PC keyboard, this is
714d522f475Smrg * enough to make a reasonable approximation to DEC vt220 numeric and editing
715d522f475Smrg * keypads.
716d522f475Smrg */
717d522f475Smrgstatic KeySym
718d522f475SmrgTranslateFromSUNPC(KeySym keysym)
719d522f475Smrg{
720d522f475Smrg    /* *INDENT-OFF* */
721d522f475Smrg    static struct {
722d522f475Smrg	    KeySym before, after;
723d522f475Smrg    } table[] = {
724d522f475Smrg#ifdef DXK_Remove
725d522f475Smrg	{ XK_Delete,       DXK_Remove },
726d522f475Smrg#endif
727d522f475Smrg	{ XK_Home,         XK_Find },
728d522f475Smrg	{ XK_End,          XK_Select },
729d522f475Smrg#ifdef XK_KP_Home
730d522f475Smrg	{ XK_Delete,       XK_KP_Decimal },
731d522f475Smrg	{ XK_KP_Delete,    XK_KP_Decimal },
732d522f475Smrg	{ XK_KP_Insert,    XK_KP_0 },
733d522f475Smrg	{ XK_KP_End,       XK_KP_1 },
734d522f475Smrg	{ XK_KP_Down,      XK_KP_2 },
735d522f475Smrg	{ XK_KP_Next,      XK_KP_3 },
736d522f475Smrg	{ XK_KP_Left,      XK_KP_4 },
737d522f475Smrg	{ XK_KP_Begin,     XK_KP_5 },
738d522f475Smrg	{ XK_KP_Right,     XK_KP_6 },
739d522f475Smrg	{ XK_KP_Home,      XK_KP_7 },
740d522f475Smrg	{ XK_KP_Up,        XK_KP_8 },
741d522f475Smrg	{ XK_KP_Prior,     XK_KP_9 },
742d522f475Smrg#endif
743d522f475Smrg    };
744d522f475Smrg    /* *INDENT-ON* */
745d522f475Smrg
746d522f475Smrg    unsigned n;
747d522f475Smrg
748d522f475Smrg    for (n = 0; n < sizeof(table) / sizeof(table[0]); n++) {
749d522f475Smrg	if (table[n].before == keysym) {
750d522f475Smrg	    TRACE(("...Input keypad before was " KEYSYM_FMT "\n", keysym));
751d522f475Smrg	    keysym = table[n].after;
752d522f475Smrg	    TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", keysym));
753d522f475Smrg	    break;
754d522f475Smrg	}
755d522f475Smrg    }
756d522f475Smrg    return keysym;
757d522f475Smrg}
758d522f475Smrg#endif /* OPT_SUNPC_KBD */
759d522f475Smrg
760d522f475Smrg#define VT52_KEYPAD \
761d522f475Smrg	if_OPT_VT52_MODE(screen,{ \
762d522f475Smrg		reply.a_type = ANSI_ESC; \
763d522f475Smrg		reply.a_pintro = '?'; \
764d522f475Smrg		})
765d522f475Smrg
766d522f475Smrg#define VT52_CURSOR_KEYS \
767d522f475Smrg	if_OPT_VT52_MODE(screen,{ \
768d522f475Smrg		reply.a_type = ANSI_ESC; \
769d522f475Smrg		})
770d522f475Smrg
771d522f475Smrg#undef  APPEND_PARM
772d522f475Smrg#define APPEND_PARM(number) \
773956cc18dSsnj	    reply.a_param[reply.a_nparam] = (ParmType) number, \
774956cc18dSsnj	    reply.a_nparam++
775d522f475Smrg
776d522f475Smrg#if OPT_MOD_FKEYS
777d522f475Smrg#define MODIFIER_PARM \
778956cc18dSsnj	if (modify_parm != 0) APPEND_PARM(modify_parm)
779d522f475Smrg#else
780d522f475Smrg#define MODIFIER_PARM		/*nothing */
781d522f475Smrg#endif
782d522f475Smrg
783d522f475Smrg/*
784d522f475Smrg * Determine if we use the \E[3~ sequence for Delete, or the legacy ^?.  We
785d522f475Smrg * maintain the delete_is_del value as 3 states:  unspecified(2), true and
786d522f475Smrg * false.  If unspecified, it is handled differently according to whether the
787d522f475Smrg * legacy keyboard support is enabled, or if xterm emulates a VT220.
788d522f475Smrg *
789d522f475Smrg * Once the user (or application) has specified delete_is_del via resource
790d522f475Smrg * setting, popup menu or escape sequence, it overrides the keyboard type
791d522f475Smrg * rather than the reverse.
792d522f475Smrg */
793d522f475SmrgBool
794d522f475SmrgxtermDeleteIsDEL(XtermWidget xw)
795d522f475Smrg{
796d522f475Smrg    Bool result = True;
797d522f475Smrg
798d522f475Smrg    if (xw->keyboard.type == keyboardIsDefault
799d522f475Smrg	|| xw->keyboard.type == keyboardIsVT220)
80020d2c4d2Smrg	result = (TScreenOf(xw)->delete_is_del == True);
801d522f475Smrg
802d522f475Smrg    if (xw->keyboard.type == keyboardIsLegacy)
80320d2c4d2Smrg	result = (TScreenOf(xw)->delete_is_del != False);
804d522f475Smrg
805d522f475Smrg    TRACE(("xtermDeleteIsDEL(%d/%d) = %d\n",
806d522f475Smrg	   xw->keyboard.type,
80720d2c4d2Smrg	   TScreenOf(xw)->delete_is_del,
808d522f475Smrg	   result));
809d522f475Smrg
810d522f475Smrg    return result;
811d522f475Smrg}
812d522f475Smrg
8130bd37d32Smrgstatic Boolean
8140bd37d32SmrglookupKeyData(KEY_DATA * kd, XtermWidget xw, XKeyEvent * event)
815d522f475Smrg{
81620d2c4d2Smrg    TScreen *screen = TScreenOf(xw);
8170bd37d32Smrg    TKeyboard *keyboard = &(xw->keyboard);
8180bd37d32Smrg    Boolean result = True;
819d522f475Smrg
8200bd37d32Smrg    TRACE(("%s %#x\n", visibleEventType(event->type), event->keycode));
821d522f475Smrg
8220bd37d32Smrg    kd->keysym = 0;
8230bd37d32Smrg    kd->is_fkey = False;
824d522f475Smrg#if OPT_TCAP_QUERY
825d522f475Smrg    if (screen->tc_query_code >= 0) {
8260bd37d32Smrg	kd->keysym = (KeySym) screen->tc_query_code;
8270bd37d32Smrg	kd->is_fkey = screen->tc_query_fkey;
8280bd37d32Smrg	if (kd->keysym != XK_BackSpace) {
8290bd37d32Smrg	    kd->nbytes = 0;
8300bd37d32Smrg	    kd->strbuf[0] = 0;
831d522f475Smrg	} else {
8320bd37d32Smrg	    kd->nbytes = 1;
8330bd37d32Smrg	    kd->strbuf[0] = 8;
834d522f475Smrg	}
835d522f475Smrg    } else
836d522f475Smrg#endif
837d522f475Smrg    {
8380bd37d32Smrg#if OPT_I18N_SUPPORT && OPT_INPUT_METHOD
8390bd37d32Smrg	TInput *input = lookupTInput(xw, (Widget) xw);
8400bd37d32Smrg	if (input && input->xic) {
841d522f475Smrg	    Status status_return;
842d522f475Smrg#if OPT_WIDE_CHARS
843d522f475Smrg	    if (screen->utf8_mode) {
8440bd37d32Smrg		kd->nbytes = Xutf8LookupString(input->xic, event,
8450bd37d32Smrg					       kd->strbuf, (int) sizeof(kd->strbuf),
8460bd37d32Smrg					       &(kd->keysym), &status_return);
847d522f475Smrg	    } else
848d522f475Smrg#endif
849d522f475Smrg	    {
8500bd37d32Smrg		kd->nbytes = XmbLookupString(input->xic, event,
8510bd37d32Smrg					     kd->strbuf, (int) sizeof(kd->strbuf),
8520bd37d32Smrg					     &(kd->keysym), &status_return);
853d522f475Smrg	    }
854d522f475Smrg#if OPT_MOD_FKEYS
855d522f475Smrg	    /*
856d522f475Smrg	     * Fill-in some code useful with IsControlAlias():
857d522f475Smrg	     */
858d522f475Smrg	    if (status_return == XLookupBoth
8590bd37d32Smrg		&& kd->nbytes <= 1
8600bd37d32Smrg		&& !IsPredefinedKey(kd->keysym)
861d522f475Smrg		&& (keyboard->modify_now.other_keys > 1)
8620bd37d32Smrg		&& !IsControlInput(kd)) {
8630bd37d32Smrg		kd->nbytes = 1;
8640bd37d32Smrg		kd->strbuf[0] = (char) kd->keysym;
865d522f475Smrg	    }
866d522f475Smrg#endif /* OPT_MOD_FKEYS */
867d522f475Smrg	} else
868d522f475Smrg#endif /* OPT_I18N_SUPPORT */
869d522f475Smrg	{
870d522f475Smrg	    static XComposeStatus compose_status =
871d522f475Smrg	    {NULL, 0};
8720bd37d32Smrg	    kd->nbytes = XLookupString(event,
8730bd37d32Smrg				       kd->strbuf, (int) sizeof(kd->strbuf),
8740bd37d32Smrg				       &(kd->keysym), &compose_status);
875d522f475Smrg	}
8760bd37d32Smrg	kd->is_fkey = IsFunctionKey(kd->keysym);
877d522f475Smrg    }
8780bd37d32Smrg    return result;
8790bd37d32Smrg}
8800bd37d32Smrg
8810bd37d32Smrgvoid
8820bd37d32SmrgInput(XtermWidget xw,
8830bd37d32Smrg      XKeyEvent * event,
8840bd37d32Smrg      Bool eightbit)
8850bd37d32Smrg{
8860bd37d32Smrg    Char *string;
8870bd37d32Smrg
8880bd37d32Smrg    TKeyboard *keyboard = &(xw->keyboard);
8890bd37d32Smrg    TScreen *screen = TScreenOf(xw);
8900bd37d32Smrg
8910bd37d32Smrg    int j;
8920bd37d32Smrg    int key = False;
8930bd37d32Smrg    ANSI reply;
8940bd37d32Smrg    int dec_code;
8950bd37d32Smrg    unsigned modify_parm = 0;
8960bd37d32Smrg    int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0);
8970bd37d32Smrg    unsigned evt_state = event->state;
8980bd37d32Smrg    unsigned mod_state;
8990bd37d32Smrg    KEY_DATA kd;
9000bd37d32Smrg
9010bd37d32Smrg    /* Ignore characters typed at the keyboard */
9020bd37d32Smrg    if (keyboard->flags & MODE_KAM)
9030bd37d32Smrg	return;
9040bd37d32Smrg
9050bd37d32Smrg    lookupKeyData(&kd, xw, event);
906d522f475Smrg
907d522f475Smrg    memset(&reply, 0, sizeof(reply));
908d522f475Smrg
909d522f475Smrg    TRACE(("Input keysym "
910d522f475Smrg	   KEYSYM_FMT
911d522f475Smrg	   ", %d:'%s'%s" FMT_MODIFIER_NAMES "%s%s%s%s%s%s\n",
912d522f475Smrg	   kd.keysym,
913d522f475Smrg	   kd.nbytes,
914956cc18dSsnj	   visibleChars((Char *) kd.strbuf,
915d522f475Smrg			((kd.nbytes > 0)
916d522f475Smrg			 ? (unsigned) kd.nbytes
917d522f475Smrg			 : 0)),
918d522f475Smrg	   ARG_MODIFIER_NAMES(evt_state),
919d522f475Smrg	   eightbit ? " 8bit" : " 7bit",
920d522f475Smrg	   IsKeypadKey(kd.keysym) ? " KeypadKey" : "",
921d522f475Smrg	   IsCursorKey(kd.keysym) ? " CursorKey" : "",
922d522f475Smrg	   IsPFKey(kd.keysym) ? " PFKey" : "",
923d522f475Smrg	   kd.is_fkey ? " FKey" : "",
924d522f475Smrg	   IsMiscFunctionKey(kd.keysym) ? " MiscFKey" : "",
9250bd37d32Smrg	   IsEditFunctionKey(xw, kd.keysym) ? " EditFkey" : ""));
926d522f475Smrg
927d522f475Smrg#if OPT_SUNPC_KBD
928d522f475Smrg    /*
929d522f475Smrg     * DEC keyboards don't have keypad(+), but do have keypad(,) instead.
930d522f475Smrg     * Other (Sun, PC) keyboards commonly have keypad(+), but no keypad(,)
931d522f475Smrg     * - it's a pain for users to work around.
932d522f475Smrg     */
933d522f475Smrg    if (keyboard->type == keyboardIsVT220
934d522f475Smrg	&& (evt_state & ShiftMask) == 0) {
935d522f475Smrg	if (kd.keysym == XK_KP_Add) {
936d522f475Smrg	    kd.keysym = XK_KP_Separator;
93720d2c4d2Smrg	    UIntClr(evt_state, ShiftMask);
938d522f475Smrg	    TRACE(("...Input keypad(+), change keysym to "
939d522f475Smrg		   KEYSYM_FMT
940d522f475Smrg		   "\n",
941d522f475Smrg		   kd.keysym));
942d522f475Smrg	}
943d522f475Smrg	if ((evt_state & ControlMask) != 0
944d522f475Smrg	    && kd.keysym == XK_KP_Separator) {
945d522f475Smrg	    kd.keysym = XK_KP_Subtract;
94620d2c4d2Smrg	    UIntClr(evt_state, ControlMask);
947d522f475Smrg	    TRACE(("...Input control/keypad(,), change keysym to "
948d522f475Smrg		   KEYSYM_FMT
949d522f475Smrg		   "\n",
950d522f475Smrg		   kd.keysym));
951d522f475Smrg	}
952d522f475Smrg    }
953d522f475Smrg#endif
954d522f475Smrg
955d522f475Smrg    /*
956d522f475Smrg     * The keyboard tables may give us different keypad codes according to
957d522f475Smrg     * whether NumLock is pressed.  Use this check to simplify the process
958d522f475Smrg     * of determining whether we generate an escape sequence for a keypad
959d522f475Smrg     * key, or force it to the value kypd_num[].  There is no fixed
960d522f475Smrg     * modifier for this feature, so we assume that it is the one assigned
961d522f475Smrg     * to the NumLock key.
962d522f475Smrg     *
963d522f475Smrg     * This check used to try to return the contents of strbuf, but that
964d522f475Smrg     * does not work properly when a control modifier is given (trash is
965d522f475Smrg     * returned in the buffer in some cases -- perhaps an X bug).
966d522f475Smrg     */
967d522f475Smrg#if OPT_NUM_LOCK
968d522f475Smrg    if (kd.nbytes == 1
969d522f475Smrg	&& IsKeypadKey(kd.keysym)
970d522f475Smrg	&& xw->misc.real_NumLock
9710bd37d32Smrg	&& (xw->work.num_lock & evt_state) != 0) {
972d522f475Smrg	keypad_mode = 0;
973d522f475Smrg	TRACE(("...Input num_lock, force keypad_mode off\n"));
974d522f475Smrg    }
975d522f475Smrg#endif
976d522f475Smrg
977d522f475Smrg#if OPT_MOD_FKEYS
978d522f475Smrg    if (evt_state != 0
979d522f475Smrg	&& allowModifierParm(xw, &kd)) {
980d522f475Smrg	modify_parm = xtermStateToParam(xw, evt_state);
981d522f475Smrg    }
982d522f475Smrg
983d522f475Smrg    /*
984d522f475Smrg     * Shift-tab is often mapped to XK_ISO_Left_Tab which is classified as
985d522f475Smrg     * IsEditFunctionKey(), and the conversion does not produce any bytes.
986d522f475Smrg     * Check for this special case so we have data when handling the
987d522f475Smrg     * modifyOtherKeys resource.
988d522f475Smrg     */
989d522f475Smrg    if (keyboard->modify_now.other_keys > 1) {
990d522f475Smrg	if (IsTabKey(kd.keysym) && kd.nbytes == 0) {
991d522f475Smrg	    kd.nbytes = 1;
992d522f475Smrg	    kd.strbuf[0] = '\t';
993d522f475Smrg	}
994d522f475Smrg    }
9950bd37d32Smrg#ifdef XK_ISO_Left_Tab
9960bd37d32Smrg    else if (IsTabKey(kd.keysym)
9970bd37d32Smrg	     && kd.nbytes <= 1
9980bd37d32Smrg	     && modify_parm == (MOD_NONE + MOD_SHIFT)) {
9990bd37d32Smrg	kd.keysym = XK_ISO_Left_Tab;
10000bd37d32Smrg    }
10010bd37d32Smrg#endif
1002d522f475Smrg#endif /* OPT_MOD_FKEYS */
1003d522f475Smrg
1004d522f475Smrg    /* VT300 & up: backarrow toggle */
1005d522f475Smrg    if ((kd.nbytes == 1)
1006d522f475Smrg	&& IsBackarrowToggle(keyboard, kd.keysym, evt_state)) {
1007d522f475Smrg	kd.strbuf[0] = ANSI_DEL;
1008d522f475Smrg	TRACE(("...Input backarrow changed to %d\n", kd.strbuf[0]));
1009d522f475Smrg    }
1010d522f475Smrg#if OPT_SUNPC_KBD
1011d522f475Smrg    /* make an DEC editing-keypad from a Sun or PC editing-keypad */
1012d522f475Smrg    if (keyboard->type == keyboardIsVT220
1013d522f475Smrg	&& (kd.keysym != XK_Delete || !xtermDeleteIsDEL(xw)))
1014d522f475Smrg	kd.keysym = TranslateFromSUNPC(kd.keysym);
1015d522f475Smrg    else
1016d522f475Smrg#endif
1017d522f475Smrg    {
1018d522f475Smrg#ifdef XK_KP_Home
1019d522f475Smrg	if (kd.keysym >= XK_KP_Home && kd.keysym <= XK_KP_Begin) {
1020d522f475Smrg	    TRACE(("...Input keypad before was " KEYSYM_FMT "\n", kd.keysym));
10214e40088cSchristos	    kd.keysym += (KeySym) (XK_Home - XK_KP_Home);
1022d522f475Smrg	    TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", kd.keysym));
1023d522f475Smrg	}
1024d522f475Smrg#endif
1025d522f475Smrg    }
1026d522f475Smrg
1027d522f475Smrg    /*
1028d522f475Smrg     * Map the Sun afterthought-keys in as F36 and F37.
1029d522f475Smrg     */
1030d522f475Smrg#ifdef SunXK_F36
1031d522f475Smrg    if (!kd.is_fkey) {
1032d522f475Smrg	if (kd.keysym == SunXK_F36) {
1033d522f475Smrg	    kd.keysym = XK_Fn(36);
1034d522f475Smrg	    kd.is_fkey = True;
1035d522f475Smrg	}
1036d522f475Smrg	if (kd.keysym == SunXK_F37) {
1037d522f475Smrg	    kd.keysym = XK_Fn(37);
1038d522f475Smrg	    kd.is_fkey = True;
1039d522f475Smrg	}
1040d522f475Smrg    }
1041d522f475Smrg#endif
1042d522f475Smrg
1043d522f475Smrg    /*
1044d522f475Smrg     * Use the control- and shift-modifiers to obtain more function keys than
1045d522f475Smrg     * the keyboard provides.  We can do this if there is no conflicting use of
1046d522f475Smrg     * those modifiers:
1047d522f475Smrg     *
1048d522f475Smrg     * a) for VT220 keyboard, we use only the control-modifier.  The keyboard
1049d522f475Smrg     * uses shift-modifier for UDK's.
1050d522f475Smrg     *
1051d522f475Smrg     * b) for non-VT220 keyboards, we only have to check if the
1052d522f475Smrg     * modifyFunctionKeys resource is inactive.
1053d522f475Smrg     *
1054d522f475Smrg     * Thereafter, we note when we have a function-key and keep that
1055d522f475Smrg     * distinction when testing for "function-key" values.
1056d522f475Smrg     */
1057d522f475Smrg    if ((evt_state & (ControlMask | ShiftMask)) != 0
1058d522f475Smrg	&& kd.is_fkey) {
1059d522f475Smrg
1060d522f475Smrg	/* VT220 keyboard uses shift for UDK */
1061d522f475Smrg	if (keyboard->type == keyboardIsVT220
1062d522f475Smrg	    || keyboard->type == keyboardIsLegacy) {
1063d522f475Smrg
1064d522f475Smrg	    TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1));
1065d522f475Smrg	    if (evt_state & ControlMask) {
10662eaa94a1Schristos		kd.keysym += (KeySym) xw->misc.ctrl_fkeys;
106720d2c4d2Smrg		UIntClr(evt_state, ControlMask);
1068d522f475Smrg	    }
1069d522f475Smrg	    TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1));
1070d522f475Smrg
1071d522f475Smrg	}
1072d522f475Smrg#if OPT_MOD_FKEYS
1073d522f475Smrg	else if (keyboard->modify_now.function_keys < 0) {
1074d522f475Smrg
1075d522f475Smrg	    TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1));
1076d522f475Smrg	    if (evt_state & ShiftMask) {
10772eaa94a1Schristos		kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 1);
107820d2c4d2Smrg		UIntClr(evt_state, ShiftMask);
1079d522f475Smrg	    }
1080d522f475Smrg	    if (evt_state & ControlMask) {
10812eaa94a1Schristos		kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 2);
108220d2c4d2Smrg		UIntClr(evt_state, ControlMask);
1083d522f475Smrg	    }
1084d522f475Smrg	    TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1));
1085d522f475Smrg
1086d522f475Smrg	}
1087d522f475Smrg	/*
1088d522f475Smrg	 * Reevaluate the modifier parameter, stripping off the modifiers
1089d522f475Smrg	 * that we just used.
1090d522f475Smrg	 */
10910bd37d32Smrg	if (modify_parm) {
1092d522f475Smrg	    modify_parm = xtermStateToParam(xw, evt_state);
10930bd37d32Smrg	}
1094d522f475Smrg#endif /* OPT_MOD_FKEYS */
1095d522f475Smrg    }
1096d522f475Smrg
1097d522f475Smrg    /*
1098d522f475Smrg     * Test for one of the keyboard variants.
1099d522f475Smrg     */
1100d522f475Smrg    switch (keyboard->type) {
1101d522f475Smrg    case keyboardIsHP:
1102d522f475Smrg	hpfuncvalue(&reply, &kd);
1103d522f475Smrg	break;
1104d522f475Smrg    case keyboardIsSCO:
1105d522f475Smrg	scofuncvalue(&reply, &kd);
1106d522f475Smrg	break;
1107d522f475Smrg    case keyboardIsSun:
1108d522f475Smrg	sunfuncvalue(&reply, &kd);
1109d522f475Smrg	break;
1110d522f475Smrg    case keyboardIsTermcap:
1111d522f475Smrg#if OPT_TCAP_FKEYS
1112d522f475Smrg	if (xtermcapString(xw, (int) kd.keysym, evt_state))
1113d522f475Smrg	    return;
1114d522f475Smrg#endif
1115d522f475Smrg	break;
1116d522f475Smrg    case keyboardIsDefault:
1117d522f475Smrg    case keyboardIsLegacy:
1118d522f475Smrg    case keyboardIsVT220:
1119d522f475Smrg	break;
1120d522f475Smrg    }
1121d522f475Smrg
1122d522f475Smrg    if (reply.a_final) {
1123d522f475Smrg	/*
1124d522f475Smrg	 * The key symbol matches one of the variants.  Most of those are
1125d522f475Smrg	 * function-keys, though some cursor- and editing-keys are mixed in.
1126d522f475Smrg	 */
1127d522f475Smrg	modifyCursorKey(&reply,
1128d522f475Smrg			((kd.is_fkey
1129d522f475Smrg			  || IsMiscFunctionKey(kd.keysym)
11300bd37d32Smrg			  || IsEditFunctionKey(xw, kd.keysym))
1131d522f475Smrg			 ? keyboard->modify_now.function_keys
1132d522f475Smrg			 : keyboard->modify_now.cursor_keys),
1133d522f475Smrg			&modify_parm);
1134d522f475Smrg	MODIFIER_PARM;
1135d522f475Smrg	unparseseq(xw, &reply);
1136d522f475Smrg    } else if (((kd.is_fkey
1137d522f475Smrg		 || IsMiscFunctionKey(kd.keysym)
11380bd37d32Smrg		 || IsEditFunctionKey(xw, kd.keysym))
1139d522f475Smrg#if OPT_MOD_FKEYS
1140d522f475Smrg		&& !ModifyOtherKeys(xw, evt_state, &kd, modify_parm)
1141d522f475Smrg#endif
1142d522f475Smrg	       ) || (kd.keysym == XK_Delete
1143956cc18dSsnj		     && ((modify_parm != 0)
1144d522f475Smrg			 || !xtermDeleteIsDEL(xw)))) {
1145d522f475Smrg	dec_code = decfuncvalue(&kd);
1146d522f475Smrg	if ((evt_state & ShiftMask)
1147d522f475Smrg#if OPT_SUNPC_KBD
1148d522f475Smrg	    && keyboard->type == keyboardIsVT220
1149d522f475Smrg#endif
1150d522f475Smrg	    && ((string = (Char *) udk_lookup(dec_code, &kd.nbytes)) != 0)) {
115120d2c4d2Smrg	    UIntClr(evt_state, ShiftMask);
1152d522f475Smrg	    while (kd.nbytes-- > 0)
1153d522f475Smrg		unparseputc(xw, CharOf(*string++));
1154d522f475Smrg	}
1155d522f475Smrg	/*
1156d522f475Smrg	 * Interpret F1-F4 as PF1-PF4 for VT52, VT100
1157d522f475Smrg	 */
1158d522f475Smrg	else if (keyboard->type != keyboardIsLegacy
1159d522f475Smrg		 && (dec_code >= 11 && dec_code <= 14)) {
1160d522f475Smrg	    reply.a_type = ANSI_SS3;
1161d522f475Smrg	    VT52_CURSOR_KEYS;
11622eaa94a1Schristos	    reply.a_final = (Char) A2E(dec_code - 11 + E2A('P'));
1163d522f475Smrg	    modifyCursorKey(&reply,
1164d522f475Smrg			    keyboard->modify_now.function_keys,
1165d522f475Smrg			    &modify_parm);
1166d522f475Smrg	    MODIFIER_PARM;
1167d522f475Smrg	    unparseseq(xw, &reply);
1168956cc18dSsnj	} else {
1169d522f475Smrg	    reply.a_type = ANSI_CSI;
1170d522f475Smrg	    reply.a_final = 0;
1171d522f475Smrg
1172d522f475Smrg#ifdef XK_ISO_Left_Tab
1173d522f475Smrg	    if (kd.keysym == XK_ISO_Left_Tab) {
1174d522f475Smrg		reply.a_nparam = 0;
1175d522f475Smrg		reply.a_final = 'Z';
1176d522f475Smrg#if OPT_MOD_FKEYS
1177d522f475Smrg		if (keyboard->modify_now.other_keys > 1
1178956cc18dSsnj		    && computeMaskedModifier(xw, evt_state, ShiftMask))
1179d522f475Smrg		    modifyOtherKey(&reply, '\t', modify_parm, keyboard->format_keys);
1180d522f475Smrg#endif
1181d522f475Smrg	    } else
1182d522f475Smrg#endif /* XK_ISO_Left_Tab */
1183d522f475Smrg	    {
1184d522f475Smrg		reply.a_nparam = 1;
1185d522f475Smrg#if OPT_MOD_FKEYS
1186d522f475Smrg		if (kd.is_fkey) {
1187d522f475Smrg		    modifyCursorKey(&reply,
1188d522f475Smrg				    keyboard->modify_now.function_keys,
1189d522f475Smrg				    &modify_parm);
1190d522f475Smrg		}
1191d522f475Smrg		MODIFIER_PARM;
1192d522f475Smrg#endif
1193956cc18dSsnj		reply.a_param[0] = (ParmType) dec_code;
1194d522f475Smrg		reply.a_final = '~';
1195d522f475Smrg	    }
1196d522f475Smrg	    if (reply.a_final != 0
1197d522f475Smrg		&& (reply.a_nparam == 0 || reply.a_param[0] >= 0))
1198d522f475Smrg		unparseseq(xw, &reply);
1199d522f475Smrg	}
1200d522f475Smrg	key = True;
1201d522f475Smrg    } else if (IsPFKey(kd.keysym)) {
1202d522f475Smrg	reply.a_type = ANSI_SS3;
12032eaa94a1Schristos	reply.a_final = (Char) ((kd.keysym - XK_KP_F1) + 'P');
1204d522f475Smrg	VT52_CURSOR_KEYS;
1205d522f475Smrg	MODIFIER_PARM;
1206d522f475Smrg	unparseseq(xw, &reply);
1207d522f475Smrg	key = True;
1208d522f475Smrg    } else if (IsKeypadKey(kd.keysym)) {
1209d522f475Smrg	if (keypad_mode) {
1210d522f475Smrg	    reply.a_type = ANSI_SS3;
12112eaa94a1Schristos	    reply.a_final = (Char) (kypd_apl[kd.keysym - XK_KP_Space]);
1212d522f475Smrg	    VT52_KEYPAD;
1213d522f475Smrg	    MODIFIER_PARM;
1214d522f475Smrg	    unparseseq(xw, &reply);
1215d522f475Smrg	} else {
1216d522f475Smrg	    unparseputc(xw, kypd_num[kd.keysym - XK_KP_Space]);
1217d522f475Smrg	}
1218d522f475Smrg	key = True;
1219d522f475Smrg    } else if (IsCursorKey(kd.keysym)) {
1220d522f475Smrg	if (keyboard->flags & MODE_DECCKM) {
1221d522f475Smrg	    reply.a_type = ANSI_SS3;
1222d522f475Smrg	} else {
1223d522f475Smrg	    reply.a_type = ANSI_CSI;
1224d522f475Smrg	}
1225d522f475Smrg	modifyCursorKey(&reply, keyboard->modify_now.cursor_keys, &modify_parm);
12262eaa94a1Schristos	reply.a_final = (Char) (curfinal[kd.keysym - XK_Home]);
1227d522f475Smrg	VT52_CURSOR_KEYS;
1228d522f475Smrg	MODIFIER_PARM;
1229d522f475Smrg	unparseseq(xw, &reply);
1230d522f475Smrg	key = True;
1231d522f475Smrg    } else if (kd.nbytes > 0) {
1232d522f475Smrg	int prefix = 0;
1233d522f475Smrg
1234d522f475Smrg#if OPT_TEK4014
1235d522f475Smrg	if (TEK4014_GIN(tekWidget)) {
1236d522f475Smrg	    TekEnqMouse(tekWidget, kd.strbuf[0]);
1237d522f475Smrg	    TekGINoff(tekWidget);
1238d522f475Smrg	    kd.nbytes--;
1239d522f475Smrg	    for (j = 0; j < kd.nbytes; ++j) {
1240d522f475Smrg		kd.strbuf[j] = kd.strbuf[j + 1];
1241d522f475Smrg	    }
1242d522f475Smrg	}
1243d522f475Smrg#endif
1244d522f475Smrg#if OPT_MOD_FKEYS
1245d522f475Smrg	if ((keyboard->modify_now.other_keys > 0)
1246d522f475Smrg	    && ModifyOtherKeys(xw, evt_state, &kd, modify_parm)
1247d522f475Smrg	    && (mod_state = allowedCharModifiers(xw, evt_state, &kd)) != 0) {
1248d522f475Smrg	    int input_char;
1249d522f475Smrg
1250d522f475Smrg	    evt_state = mod_state;
1251d522f475Smrg
1252d522f475Smrg	    modify_parm = xtermStateToParam(xw, evt_state);
1253d522f475Smrg
1254d522f475Smrg	    /*
1255d522f475Smrg	     * We want to show a keycode that corresponds to the 8-bit value
1256d522f475Smrg	     * of the key.  If the keysym is less than 256, that is good
1257d522f475Smrg	     * enough.  Special keys such as Tab may result in a value that
1258d522f475Smrg	     * is usable as well.  For the latter (special cases), try to use
1259d522f475Smrg	     * the result from the X library lookup.
1260d522f475Smrg	     */
1261d522f475Smrg	    input_char = ((kd.keysym < 256)
1262d522f475Smrg			  ? (int) kd.keysym
1263d522f475Smrg			  : ((kd.nbytes == 1)
1264d522f475Smrg			     ? CharOf(kd.strbuf[0])
1265d522f475Smrg			     : -1));
1266d522f475Smrg
1267d522f475Smrg	    TRACE(("...modifyOtherKeys %d;%d\n", modify_parm, input_char));
1268d522f475Smrg	    if (modifyOtherKey(&reply, input_char, modify_parm, keyboard->format_keys)) {
1269d522f475Smrg		unparseseq(xw, &reply);
1270d522f475Smrg	    } else {
127120d2c4d2Smrg		Bell(xw, XkbBI_MinorError, 0);
1272d522f475Smrg	    }
1273d522f475Smrg	} else
1274d522f475Smrg#endif /* OPT_MOD_FKEYS */
1275d522f475Smrg	{
1276d522f475Smrg#if OPT_NUM_LOCK
1277d522f475Smrg	    /*
1278d522f475Smrg	     * Send ESC if we have a META modifier and metaSendsEcape is true.
1279d522f475Smrg	     * Like eightBitInput, except that it is not associated with
1280d522f475Smrg	     * terminal settings.
1281d522f475Smrg	     */
1282d522f475Smrg	    if (kd.nbytes != 0) {
1283d522f475Smrg		if (screen->meta_sends_esc
12840bd37d32Smrg		    && (evt_state & xw->work.meta_mods) != 0) {
1285d522f475Smrg		    TRACE(("...input-char is modified by META\n"));
12860bd37d32Smrg		    UIntClr(evt_state, xw->work.meta_mods);
1287d522f475Smrg		    eightbit = False;
1288d522f475Smrg		    prefix = ANSI_ESC;
1289d522f475Smrg		} else if (eightbit) {
1290d522f475Smrg		    /* it might be overridden, but this helps for debugging */
1291d522f475Smrg		    TRACE(("...input-char is shifted by META\n"));
1292d522f475Smrg		}
1293d522f475Smrg		if (screen->alt_is_not_meta
12940bd37d32Smrg		    && (evt_state & xw->work.alt_mods) != 0) {
12950bd37d32Smrg		    UIntClr(evt_state, xw->work.alt_mods);
1296d522f475Smrg		    if (screen->alt_sends_esc) {
1297d522f475Smrg			TRACE(("...input-char is modified by ALT\n"));
12982eaa94a1Schristos			eightbit = False;
1299d522f475Smrg			prefix = ANSI_ESC;
1300d522f475Smrg		    } else if (!eightbit) {
1301d522f475Smrg			TRACE(("...input-char is shifted by ALT\n"));
1302d522f475Smrg			eightbit = True;
1303d522f475Smrg		    }
1304d522f475Smrg		}
1305d522f475Smrg	    }
1306d522f475Smrg#endif
1307d522f475Smrg	    /*
1308d522f475Smrg	     * If metaSendsEscape is false, fall through to this chunk, which
1309d522f475Smrg	     * implements the eightBitInput resource.
1310d522f475Smrg	     *
1311d522f475Smrg	     * It is normally executed when the user presses Meta plus a
1312d522f475Smrg	     * printable key, e.g., Meta+space.  The presence of the Meta
1313d522f475Smrg	     * modifier is not guaranteed since what really happens is the
1314d522f475Smrg	     * "insert-eight-bit" or "insert-seven-bit" action, which we
1315d522f475Smrg	     * distinguish by the eightbit parameter to this function.  So the
1316d522f475Smrg	     * eightBitInput resource really means that we use this shifting
1317d522f475Smrg	     * logic in the "insert-eight-bit" action.
1318d522f475Smrg	     */
1319d522f475Smrg	    if (eightbit && (kd.nbytes == 1) && screen->input_eight_bits) {
1320d522f475Smrg		IChar ch = CharOf(kd.strbuf[0]);
13210bd37d32Smrg		if ((ch < 128) && (screen->eight_bit_meta == ebTrue)) {
13222eaa94a1Schristos		    kd.strbuf[0] |= (char) 0x80;
1323d522f475Smrg		    TRACE(("...input shift from %d to %d (%#x to %#x)\n",
1324d522f475Smrg			   ch, CharOf(kd.strbuf[0]),
1325d522f475Smrg			   ch, CharOf(kd.strbuf[0])));
1326d522f475Smrg#if OPT_WIDE_CHARS
1327d522f475Smrg		    if (screen->utf8_mode) {
1328d522f475Smrg			/*
1329d522f475Smrg			 * We could interpret the incoming code as "in the
1330d522f475Smrg			 * current locale", but it's simpler to treat it as
1331d522f475Smrg			 * a Unicode value to translate to UTF-8.
1332d522f475Smrg			 */
1333d522f475Smrg			ch = CharOf(kd.strbuf[0]);
1334d522f475Smrg			kd.nbytes = 2;
13352eaa94a1Schristos			kd.strbuf[0] = (char) (0xc0 | ((ch >> 6) & 0x3));
13362eaa94a1Schristos			kd.strbuf[1] = (char) (0x80 | (ch & 0x3f));
1337d522f475Smrg			TRACE(("...encoded %#x in UTF-8 as %#x,%#x\n",
1338d522f475Smrg			       ch, CharOf(kd.strbuf[0]), CharOf(kd.strbuf[1])));
1339d522f475Smrg		    }
1340d522f475Smrg#endif
1341d522f475Smrg		}
1342d522f475Smrg		eightbit = False;
1343d522f475Smrg	    }
1344d522f475Smrg#if OPT_WIDE_CHARS
1345d522f475Smrg	    if (kd.nbytes == 1)	/* cannot do NRC on UTF-8, for instance */
1346d522f475Smrg#endif
1347d522f475Smrg	    {
1348d522f475Smrg		/* VT220 & up: National Replacement Characters */
1349d522f475Smrg		if ((xw->flags & NATIONAL) != 0) {
13502eaa94a1Schristos		    unsigned cmp = xtermCharSetIn(CharOf(kd.strbuf[0]),
13512eaa94a1Schristos						  screen->keyboard_dialect[0]);
1352d522f475Smrg		    TRACE(("...input NRC %d, %s %d\n",
1353d522f475Smrg			   CharOf(kd.strbuf[0]),
1354d522f475Smrg			   (CharOf(kd.strbuf[0]) == cmp)
1355d522f475Smrg			   ? "unchanged"
1356d522f475Smrg			   : "changed to",
1357d522f475Smrg			   CharOf(cmp)));
13582eaa94a1Schristos		    kd.strbuf[0] = (char) cmp;
1359d522f475Smrg		} else if (eightbit) {
1360d522f475Smrg		    prefix = ANSI_ESC;
1361d522f475Smrg		} else if (kd.strbuf[0] == '?'
1362d522f475Smrg			   && (evt_state & ControlMask) != 0) {
1363d522f475Smrg		    kd.strbuf[0] = ANSI_DEL;
136420d2c4d2Smrg		    UIntClr(evt_state, ControlMask);
1365d522f475Smrg		}
1366d522f475Smrg	    }
1367d522f475Smrg	    if (prefix != 0)
1368d522f475Smrg		unparseputc(xw, prefix);	/* escape */
1369d522f475Smrg	    for (j = 0; j < kd.nbytes; ++j)
1370d522f475Smrg		unparseputc(xw, CharOf(kd.strbuf[j]));
1371d522f475Smrg	}
137220d2c4d2Smrg	key = ((kd.keysym != ANSI_XOFF) && (kd.keysym != ANSI_XON));
1373d522f475Smrg    }
1374d522f475Smrg    unparse_end(xw);
1375d522f475Smrg
1376d522f475Smrg    if (key && !TEK4014_ACTIVE(xw))
1377d522f475Smrg	AdjustAfterInput(xw);
1378d522f475Smrg
1379d522f475Smrg    xtermShowPointer(xw, False);
1380d522f475Smrg    return;
1381d522f475Smrg}
1382d522f475Smrg
1383d522f475Smrgvoid
138420d2c4d2SmrgStringInput(XtermWidget xw, const Char * string, size_t nbytes)
1385d522f475Smrg{
138620d2c4d2Smrg    TRACE(("InputString (%s,%lu)\n",
138720d2c4d2Smrg	   visibleChars(string, (unsigned) nbytes),
138820d2c4d2Smrg	   (unsigned long) nbytes));
1389d522f475Smrg#if OPT_TEK4014
1390d522f475Smrg    if (nbytes && TEK4014_GIN(tekWidget)) {
1391d522f475Smrg	TekEnqMouse(tekWidget, *string++);
1392d522f475Smrg	TekGINoff(tekWidget);
1393d522f475Smrg	nbytes--;
1394d522f475Smrg    }
1395d522f475Smrg#endif
1396d522f475Smrg    while (nbytes-- != 0)
1397d522f475Smrg	unparseputc(xw, *string++);
1398d522f475Smrg    if (!TEK4014_ACTIVE(xw))
1399d522f475Smrg	AdjustAfterInput(xw);
1400d522f475Smrg    unparse_end(xw);
1401d522f475Smrg}
1402d522f475Smrg
1403d522f475Smrg/* These definitions are DEC-style (e.g., vt320) */
1404d522f475Smrgstatic int
1405d522f475Smrgdecfuncvalue(KEY_DATA * kd)
1406d522f475Smrg{
1407d522f475Smrg    int result;
1408d522f475Smrg
1409d522f475Smrg    if (kd->is_fkey) {
1410d522f475Smrg	switch (kd->keysym) {
1411d522f475Smrg	    MAP(XK_Fn(1), 11);
1412d522f475Smrg	    MAP(XK_Fn(2), 12);
1413d522f475Smrg	    MAP(XK_Fn(3), 13);
1414d522f475Smrg	    MAP(XK_Fn(4), 14);
1415d522f475Smrg	    MAP(XK_Fn(5), 15);
1416d522f475Smrg	    MAP(XK_Fn(6), 17);
1417d522f475Smrg	    MAP(XK_Fn(7), 18);
1418d522f475Smrg	    MAP(XK_Fn(8), 19);
1419d522f475Smrg	    MAP(XK_Fn(9), 20);
1420d522f475Smrg	    MAP(XK_Fn(10), 21);
1421d522f475Smrg	    MAP(XK_Fn(11), 23);
1422d522f475Smrg	    MAP(XK_Fn(12), 24);
1423d522f475Smrg	    MAP(XK_Fn(13), 25);
1424d522f475Smrg	    MAP(XK_Fn(14), 26);
1425d522f475Smrg	    MAP(XK_Fn(15), 28);
1426d522f475Smrg	    MAP(XK_Fn(16), 29);
1427d522f475Smrg	    MAP(XK_Fn(17), 31);
1428d522f475Smrg	    MAP(XK_Fn(18), 32);
1429d522f475Smrg	    MAP(XK_Fn(19), 33);
1430d522f475Smrg	    MAP(XK_Fn(20), 34);
1431d522f475Smrg	default:
1432d522f475Smrg	    /* after F20 the codes are made up and do not correspond to any
1433d522f475Smrg	     * real terminal.  So they are simply numbered sequentially.
1434d522f475Smrg	     */
14352eaa94a1Schristos	    result = 42 + (int) (kd->keysym - XK_Fn(21));
1436d522f475Smrg	    break;
1437d522f475Smrg	}
1438d522f475Smrg    } else {
1439d522f475Smrg	switch (kd->keysym) {
1440d522f475Smrg	    MAP(XK_Find, 1);
1441d522f475Smrg	    MAP(XK_Insert, 2);
1442d522f475Smrg	    MAP(XK_Delete, 3);
1443d522f475Smrg#ifdef XK_KP_Insert
1444d522f475Smrg	    MAP(XK_KP_Insert, 2);
1445d522f475Smrg	    MAP(XK_KP_Delete, 3);
1446d522f475Smrg#endif
1447d522f475Smrg#ifdef DXK_Remove
1448d522f475Smrg	    MAP(DXK_Remove, 3);
1449d522f475Smrg#endif
1450d522f475Smrg	    MAP(XK_Select, 4);
1451d522f475Smrg	    MAP(XK_Prior, 5);
1452d522f475Smrg	    MAP(XK_Next, 6);
1453d522f475Smrg#ifdef XK_ISO_Left_Tab
1454d522f475Smrg	    MAP(XK_ISO_Left_Tab, 'Z');
1455d522f475Smrg#endif
1456d522f475Smrg	    MAP(XK_Help, 28);
1457d522f475Smrg	    MAP(XK_Menu, 29);
1458d522f475Smrg	default:
1459d522f475Smrg	    result = -1;
1460d522f475Smrg	    break;
1461d522f475Smrg	}
1462d522f475Smrg    }
1463d522f475Smrg    return result;
1464d522f475Smrg}
1465d522f475Smrg
1466d522f475Smrgstatic void
1467d522f475Smrghpfuncvalue(ANSI * reply, KEY_DATA * kd)
1468d522f475Smrg{
1469d522f475Smrg#if OPT_HP_FUNC_KEYS
1470d522f475Smrg    int result;
1471d522f475Smrg
1472d522f475Smrg    if (kd->is_fkey) {
1473d522f475Smrg	switch (kd->keysym) {
1474d522f475Smrg	    MAP(XK_Fn(1), 'p');
1475d522f475Smrg	    MAP(XK_Fn(2), 'q');
1476d522f475Smrg	    MAP(XK_Fn(3), 'r');
1477d522f475Smrg	    MAP(XK_Fn(4), 's');
1478d522f475Smrg	    MAP(XK_Fn(5), 't');
1479d522f475Smrg	    MAP(XK_Fn(6), 'u');
1480d522f475Smrg	    MAP(XK_Fn(7), 'v');
1481d522f475Smrg	    MAP(XK_Fn(8), 'w');
1482d522f475Smrg	default:
1483d522f475Smrg	    result = -1;
1484d522f475Smrg	    break;
1485d522f475Smrg	}
1486d522f475Smrg    } else {
1487d522f475Smrg	switch (kd->keysym) {
1488d522f475Smrg	    MAP(XK_Up, 'A');
1489d522f475Smrg	    MAP(XK_Down, 'B');
1490d522f475Smrg	    MAP(XK_Right, 'C');
1491d522f475Smrg	    MAP(XK_Left, 'D');
1492d522f475Smrg	    MAP(XK_End, 'F');
1493d522f475Smrg	    MAP(XK_Clear, 'J');
1494d522f475Smrg	    MAP(XK_Delete, 'P');
1495d522f475Smrg	    MAP(XK_Insert, 'Q');
1496d522f475Smrg	    MAP(XK_Next, 'S');
1497d522f475Smrg	    MAP(XK_Prior, 'T');
1498d522f475Smrg	    MAP(XK_Home, 'h');
1499d522f475Smrg#ifdef XK_KP_Insert
1500d522f475Smrg	    MAP(XK_KP_Delete, 'P');
1501d522f475Smrg	    MAP(XK_KP_Insert, 'Q');
1502d522f475Smrg#endif
1503d522f475Smrg#ifdef DXK_Remove
1504d522f475Smrg	    MAP(DXK_Remove, 'P');
1505d522f475Smrg#endif
1506d522f475Smrg	    MAP(XK_Select, 'F');
1507d522f475Smrg	    MAP(XK_Find, 'h');
1508d522f475Smrg	default:
1509d522f475Smrg	    result = -1;
1510d522f475Smrg	    break;
1511d522f475Smrg	}
1512d522f475Smrg    }
1513d522f475Smrg    if (result > 0) {
1514d522f475Smrg	reply->a_type = ANSI_ESC;
15152eaa94a1Schristos	reply->a_final = (Char) result;
1516d522f475Smrg    }
1517d522f475Smrg#else
1518d522f475Smrg    (void) reply;
1519d522f475Smrg    (void) kd;
1520d522f475Smrg#endif /* OPT_HP_FUNC_KEYS */
1521d522f475Smrg}
1522d522f475Smrg
1523d522f475Smrgstatic void
1524d522f475Smrgscofuncvalue(ANSI * reply, KEY_DATA * kd)
1525d522f475Smrg{
1526d522f475Smrg#if OPT_SCO_FUNC_KEYS
1527d522f475Smrg    int result;
1528d522f475Smrg
1529d522f475Smrg    if (kd->is_fkey) {
1530d522f475Smrg	switch (kd->keysym) {
1531d522f475Smrg	    MAP(XK_Fn(1), 'M');
1532d522f475Smrg	    MAP(XK_Fn(2), 'N');
1533d522f475Smrg	    MAP(XK_Fn(3), 'O');
1534d522f475Smrg	    MAP(XK_Fn(4), 'P');
1535d522f475Smrg	    MAP(XK_Fn(5), 'Q');
1536d522f475Smrg	    MAP(XK_Fn(6), 'R');
1537d522f475Smrg	    MAP(XK_Fn(7), 'S');
1538d522f475Smrg	    MAP(XK_Fn(8), 'T');
1539d522f475Smrg	    MAP(XK_Fn(9), 'U');
1540d522f475Smrg	    MAP(XK_Fn(10), 'V');
1541d522f475Smrg	    MAP(XK_Fn(11), 'W');
1542d522f475Smrg	    MAP(XK_Fn(12), 'X');
1543d522f475Smrg	    MAP(XK_Fn(13), 'Y');
1544d522f475Smrg	    MAP(XK_Fn(14), 'Z');
1545d522f475Smrg	    MAP(XK_Fn(15), 'a');
1546d522f475Smrg	    MAP(XK_Fn(16), 'b');
1547d522f475Smrg	    MAP(XK_Fn(17), 'c');
1548d522f475Smrg	    MAP(XK_Fn(18), 'd');
1549d522f475Smrg	    MAP(XK_Fn(19), 'e');
1550d522f475Smrg	    MAP(XK_Fn(20), 'f');
1551d522f475Smrg	    MAP(XK_Fn(21), 'g');
1552d522f475Smrg	    MAP(XK_Fn(22), 'h');
1553d522f475Smrg	    MAP(XK_Fn(23), 'i');
1554d522f475Smrg	    MAP(XK_Fn(24), 'j');
1555d522f475Smrg	    MAP(XK_Fn(25), 'k');
1556d522f475Smrg	    MAP(XK_Fn(26), 'l');
1557d522f475Smrg	    MAP(XK_Fn(27), 'm');
1558d522f475Smrg	    MAP(XK_Fn(28), 'n');
1559d522f475Smrg	    MAP(XK_Fn(29), 'o');
1560d522f475Smrg	    MAP(XK_Fn(30), 'p');
1561d522f475Smrg	    MAP(XK_Fn(31), 'q');
1562d522f475Smrg	    MAP(XK_Fn(32), 'r');
1563d522f475Smrg	    MAP(XK_Fn(33), 's');
1564d522f475Smrg	    MAP(XK_Fn(34), 't');
1565d522f475Smrg	    MAP(XK_Fn(35), 'u');
1566d522f475Smrg	    MAP(XK_Fn(36), 'v');
1567d522f475Smrg	    MAP(XK_Fn(37), 'w');
1568d522f475Smrg	    MAP(XK_Fn(38), 'x');
1569d522f475Smrg	    MAP(XK_Fn(39), 'y');
1570d522f475Smrg	    MAP(XK_Fn(40), 'z');
1571d522f475Smrg	    MAP(XK_Fn(41), '@');
1572d522f475Smrg	    MAP(XK_Fn(42), '[');
1573d522f475Smrg	    MAP(XK_Fn(43), '\\');
1574d522f475Smrg	    MAP(XK_Fn(44), ']');
1575d522f475Smrg	    MAP(XK_Fn(45), '^');
1576d522f475Smrg	    MAP(XK_Fn(46), '_');
1577d522f475Smrg	    MAP(XK_Fn(47), '`');
1578d522f475Smrg	    MAP(XK_Fn(48), '{');	/* no matching '}' */
1579d522f475Smrg	default:
1580d522f475Smrg	    result = -1;
1581d522f475Smrg	    break;
1582d522f475Smrg	}
1583d522f475Smrg    } else {
1584d522f475Smrg	switch (kd->keysym) {
1585d522f475Smrg	    MAP(XK_Up, 'A');
1586d522f475Smrg	    MAP(XK_Down, 'B');
1587d522f475Smrg	    MAP(XK_Right, 'C');
1588d522f475Smrg	    MAP(XK_Left, 'D');
1589d522f475Smrg	    MAP(XK_Begin, 'E');
1590d522f475Smrg	    MAP(XK_End, 'F');
1591d522f475Smrg	    MAP(XK_Insert, 'L');
1592d522f475Smrg	    MAP(XK_Next, 'G');
1593d522f475Smrg	    MAP(XK_Prior, 'I');
1594d522f475Smrg	    MAP(XK_Home, 'H');
1595d522f475Smrg#ifdef XK_KP_Insert
1596d522f475Smrg	    MAP(XK_KP_Insert, 'L');
1597d522f475Smrg#endif
1598d522f475Smrg	default:
1599d522f475Smrg	    result = -1;
1600d522f475Smrg	    break;
1601d522f475Smrg	}
1602d522f475Smrg    }
1603d522f475Smrg    if (result > 0) {
1604d522f475Smrg	reply->a_type = ANSI_CSI;
16052eaa94a1Schristos	reply->a_final = (Char) result;
1606d522f475Smrg    }
1607d522f475Smrg#else
1608d522f475Smrg    (void) reply;
1609d522f475Smrg    (void) kd;
1610d522f475Smrg#endif /* OPT_SCO_FUNC_KEYS */
1611d522f475Smrg}
1612d522f475Smrg
1613d522f475Smrgstatic void
1614d522f475Smrgsunfuncvalue(ANSI * reply, KEY_DATA * kd)
1615d522f475Smrg{
1616d522f475Smrg#if OPT_SUN_FUNC_KEYS
1617956cc18dSsnj    ParmType result;
1618d522f475Smrg
1619d522f475Smrg    if (kd->is_fkey) {
1620d522f475Smrg	switch (kd->keysym) {
1621d522f475Smrg	    /* kf1-kf20 are numbered sequentially */
1622d522f475Smrg	    MAP(XK_Fn(1), 224);
1623d522f475Smrg	    MAP(XK_Fn(2), 225);
1624d522f475Smrg	    MAP(XK_Fn(3), 226);
1625d522f475Smrg	    MAP(XK_Fn(4), 227);
1626d522f475Smrg	    MAP(XK_Fn(5), 228);
1627d522f475Smrg	    MAP(XK_Fn(6), 229);
1628d522f475Smrg	    MAP(XK_Fn(7), 230);
1629d522f475Smrg	    MAP(XK_Fn(8), 231);
1630d522f475Smrg	    MAP(XK_Fn(9), 232);
1631d522f475Smrg	    MAP(XK_Fn(10), 233);
1632d522f475Smrg	    MAP(XK_Fn(11), 192);
1633d522f475Smrg	    MAP(XK_Fn(12), 193);
1634d522f475Smrg	    MAP(XK_Fn(13), 194);
1635d522f475Smrg	    MAP(XK_Fn(14), 195);	/* kund */
1636d522f475Smrg	    MAP(XK_Fn(15), 196);
1637d522f475Smrg	    MAP(XK_Fn(16), 197);	/* kcpy */
1638d522f475Smrg	    MAP(XK_Fn(17), 198);
1639d522f475Smrg	    MAP(XK_Fn(18), 199);
1640d522f475Smrg	    MAP(XK_Fn(19), 200);	/* kfnd */
1641d522f475Smrg	    MAP(XK_Fn(20), 201);
1642d522f475Smrg
1643d522f475Smrg	    /* kf31-kf36 are numbered sequentially */
1644d522f475Smrg	    MAP(XK_Fn(21), 208);	/* kf31 */
1645d522f475Smrg	    MAP(XK_Fn(22), 209);
1646d522f475Smrg	    MAP(XK_Fn(23), 210);
1647d522f475Smrg	    MAP(XK_Fn(24), 211);
1648d522f475Smrg	    MAP(XK_Fn(25), 212);
1649d522f475Smrg	    MAP(XK_Fn(26), 213);	/* kf36 */
1650d522f475Smrg
1651d522f475Smrg	    /* kf37-kf47 are interspersed with keypad keys */
1652d522f475Smrg	    MAP(XK_Fn(27), 214);	/* khome */
1653d522f475Smrg	    MAP(XK_Fn(28), 215);	/* kf38 */
1654d522f475Smrg	    MAP(XK_Fn(29), 216);	/* kpp */
1655d522f475Smrg	    MAP(XK_Fn(30), 217);	/* kf40 */
1656d522f475Smrg	    MAP(XK_Fn(31), 218);	/* kb2 */
1657d522f475Smrg	    MAP(XK_Fn(32), 219);	/* kf42 */
1658d522f475Smrg	    MAP(XK_Fn(33), 220);	/* kend */
1659d522f475Smrg	    MAP(XK_Fn(34), 221);	/* kf44 */
1660d522f475Smrg	    MAP(XK_Fn(35), 222);	/* knp */
1661d522f475Smrg	    MAP(XK_Fn(36), 234);	/* kf46 */
1662d522f475Smrg	    MAP(XK_Fn(37), 235);	/* kf47 */
1663d522f475Smrg	default:
1664d522f475Smrg	    result = -1;
1665d522f475Smrg	    break;
1666d522f475Smrg	}
1667d522f475Smrg    } else {
1668d522f475Smrg	switch (kd->keysym) {
1669d522f475Smrg	    MAP(XK_Help, 196);	/* khlp */
1670d522f475Smrg	    MAP(XK_Menu, 197);
1671d522f475Smrg
1672d522f475Smrg	    MAP(XK_Find, 1);
1673d522f475Smrg	    MAP(XK_Insert, 2);	/* kich1 */
1674d522f475Smrg	    MAP(XK_Delete, 3);
1675d522f475Smrg#ifdef XK_KP_Insert
1676d522f475Smrg	    MAP(XK_KP_Insert, 2);
1677d522f475Smrg	    MAP(XK_KP_Delete, 3);
1678d522f475Smrg#endif
1679d522f475Smrg#ifdef DXK_Remove
1680d522f475Smrg	    MAP(DXK_Remove, 3);
1681d522f475Smrg#endif
1682d522f475Smrg	    MAP(XK_Select, 4);
1683d522f475Smrg
1684d522f475Smrg	    MAP(XK_Prior, 216);
1685d522f475Smrg	    MAP(XK_Next, 222);
1686d522f475Smrg	    MAP(XK_Home, 214);
1687d522f475Smrg	    MAP(XK_End, 220);
1688d522f475Smrg	    MAP(XK_Begin, 218);	/* kf41=kb2 */
1689d522f475Smrg
1690d522f475Smrg	default:
1691d522f475Smrg	    result = -1;
1692d522f475Smrg	    break;
1693d522f475Smrg	}
1694d522f475Smrg    }
1695d522f475Smrg    if (result > 0) {
1696d522f475Smrg	reply->a_type = ANSI_CSI;
1697d522f475Smrg	reply->a_nparam = 1;
1698d522f475Smrg	reply->a_param[0] = result;
1699d522f475Smrg	reply->a_final = 'z';
1700d522f475Smrg    } else if (IsCursorKey(kd->keysym)) {
1701d522f475Smrg	reply->a_type = ANSI_SS3;
17022eaa94a1Schristos	reply->a_final = (Char) curfinal[kd->keysym - XK_Home];
1703d522f475Smrg    }
1704d522f475Smrg#else
1705d522f475Smrg    (void) reply;
1706d522f475Smrg    (void) kd;
1707d522f475Smrg#endif /* OPT_SUN_FUNC_KEYS */
1708d522f475Smrg}
1709d522f475Smrg
1710d522f475Smrg#if OPT_NUM_LOCK
171120d2c4d2Smrg#define isName(c) ((c) == '_' || (c) == '-' || isalnum(CharOf(c)))
171220d2c4d2Smrg
171320d2c4d2Smrgstatic const char *
171420d2c4d2SmrgskipName(const char *s)
171520d2c4d2Smrg{
171620d2c4d2Smrg    while (*s != '\0' && isName(CharOf(*s)))
171720d2c4d2Smrg	++s;
171820d2c4d2Smrg    return s;
171920d2c4d2Smrg}
172020d2c4d2Smrg
172120d2c4d2Smrg/*
172220d2c4d2Smrg * Found a ":" in a translation, check what is past it to see if it contains
172320d2c4d2Smrg * any of the insert-text action names.
172420d2c4d2Smrg */
172520d2c4d2Smrgstatic Boolean
172620d2c4d2SmrgkeyCanInsert(const char *parse)
172720d2c4d2Smrg{
172820d2c4d2Smrg    Boolean result = False;
172920d2c4d2Smrg    int ch;
173020d2c4d2Smrg    Boolean escape = False;
173120d2c4d2Smrg    Boolean quoted = False;
173220d2c4d2Smrg
173320d2c4d2Smrg    static const char *table[] =
173420d2c4d2Smrg    {
173520d2c4d2Smrg	"insert",
173620d2c4d2Smrg	"insert-seven-bit",
173720d2c4d2Smrg	"insert-eight-bit",
173820d2c4d2Smrg	"string",
173920d2c4d2Smrg    };
174020d2c4d2Smrg    Cardinal n;
174120d2c4d2Smrg
174220d2c4d2Smrg    while (*parse != '\0' && *parse != '\n') {
174320d2c4d2Smrg	ch = CharOf(*parse++);
174420d2c4d2Smrg	if (escape) {
174520d2c4d2Smrg	    escape = False;
174620d2c4d2Smrg	} else if (ch == '\\') {
174720d2c4d2Smrg	    escape = True;
174820d2c4d2Smrg	} else if (ch == '"') {
174920d2c4d2Smrg	    quoted = (Boolean) ! quoted;
175020d2c4d2Smrg	} else if (!quoted && isName(ch)) {
175120d2c4d2Smrg	    const char *next = skipName(--parse);
175220d2c4d2Smrg	    size_t need = (size_t) (next - parse);
175320d2c4d2Smrg
175420d2c4d2Smrg	    for (n = 0; n < XtNumber(table); ++n) {
175520d2c4d2Smrg		if (need == strlen(table[n])
175620d2c4d2Smrg		    && !strncmp(parse, table[n], need)) {
175720d2c4d2Smrg		    result = True;
175820d2c4d2Smrg		    break;
175920d2c4d2Smrg		}
176020d2c4d2Smrg	    }
176120d2c4d2Smrg	    parse = next;
176220d2c4d2Smrg	}
176320d2c4d2Smrg
176420d2c4d2Smrg    }
176520d2c4d2Smrg    return result;
176620d2c4d2Smrg}
176720d2c4d2Smrg
176820d2c4d2Smrg/*
176920d2c4d2Smrg * Strip the entire action, to avoid matching it.
177020d2c4d2Smrg */
177120d2c4d2Smrgstatic char *
177220d2c4d2SmrgstripAction(char *base, char *last)
177320d2c4d2Smrg{
177420d2c4d2Smrg    while (last != base) {
177520d2c4d2Smrg	if (*--last == '\n') {
177620d2c4d2Smrg	    break;
177720d2c4d2Smrg	}
177820d2c4d2Smrg    }
177920d2c4d2Smrg    return last;
178020d2c4d2Smrg}
178120d2c4d2Smrg
178220d2c4d2Smrgstatic char *
178320d2c4d2SmrgstripBlanks(char *base, char *last)
178420d2c4d2Smrg{
178520d2c4d2Smrg    while (last != base) {
178620d2c4d2Smrg	int ch = CharOf(last[-1]);
178720d2c4d2Smrg	if (ch != ' ' && ch != '\t')
178820d2c4d2Smrg	    break;
178920d2c4d2Smrg	--last;
179020d2c4d2Smrg    }
179120d2c4d2Smrg    return last;
179220d2c4d2Smrg}
1793d522f475Smrg
1794d522f475Smrg/*
17952eaa94a1Schristos * Strip unneeded whitespace from a translations resource, mono-casing and
1796d522f475Smrg * returning a malloc'd copy of the result.
1797d522f475Smrg */
1798d522f475Smrgstatic char *
179920d2c4d2SmrgstripTranslations(const char *s, Bool onlyInsert)
1800d522f475Smrg{
1801d522f475Smrg    char *dst = 0;
1802d522f475Smrg
1803d522f475Smrg    if (s != 0) {
1804d522f475Smrg	dst = TypeMallocN(char, strlen(s) + 1);
1805d522f475Smrg
1806d522f475Smrg	if (dst != 0) {
1807d522f475Smrg	    int state = 0;
1808d522f475Smrg	    int ch = 0;
1809d522f475Smrg	    int prv = 0;
1810d522f475Smrg	    char *d = dst;
1811d522f475Smrg
1812d522f475Smrg	    TRACE(("stripping:\n%s\n", s));
1813d522f475Smrg	    while (*s != '\0') {
1814d522f475Smrg		ch = *s++;
1815d522f475Smrg		if (ch == '\n') {
1816d522f475Smrg		    if (d != dst)
18172eaa94a1Schristos			*d++ = (char) ch;
1818d522f475Smrg		    state = 0;
1819d522f475Smrg		} else if (strchr(":!#", ch) != 0) {
182020d2c4d2Smrg		    d = stripBlanks(dst, d);
182120d2c4d2Smrg		    if (onlyInsert && (ch == ':') && !keyCanInsert(s)) {
182220d2c4d2Smrg			d = stripAction(dst, d);
182320d2c4d2Smrg		    }
1824d522f475Smrg		    state = -1;
1825d522f475Smrg		} else if (state >= 0) {
1826d522f475Smrg		    if (isspace(CharOf(ch))) {
1827d522f475Smrg			if (state == 0 || strchr("<>~ \t", prv))
1828d522f475Smrg			    continue;
1829d522f475Smrg		    } else if (strchr("<>~", ch)) {
183020d2c4d2Smrg			d = stripBlanks(dst, d);
1831d522f475Smrg		    }
18322eaa94a1Schristos		    *d++ = x_toupper(ch);
1833d522f475Smrg		    ++state;
1834d522f475Smrg		}
1835d522f475Smrg		prv = ch;
1836d522f475Smrg	    }
1837d522f475Smrg	    *d = '\0';
1838d522f475Smrg	    TRACE(("...result:\n%s\n", dst));
1839d522f475Smrg	}
1840d522f475Smrg    }
1841d522f475Smrg    return dst;
1842d522f475Smrg}
1843d522f475Smrg
1844d522f475Smrg/*
1845d522f475Smrg * Make a simple check to see if a given translations keyword appears in
1846d522f475Smrg * xterm's translations resource.  It does not attempt to parse the strings,
1847d522f475Smrg * just makes a case-independent check and ensures that the ends of the match
1848d522f475Smrg * are on token-boundaries.
1849d522f475Smrg *
1850d522f475Smrg * That this can only retrieve translations that are given as resource values;
1851d522f475Smrg * the default translations in charproc.c for example are not retrievable by
1852d522f475Smrg * any interface to X.
1853d522f475Smrg *
1854d522f475Smrg * Also:  We can retrieve only the most-specified translation resource.  For
1855d522f475Smrg * example, if the resource file specifies both "*translations" and
1856d522f475Smrg * "XTerm*translations", we see only the latter.
1857d522f475Smrg */
1858d522f475Smrgstatic Bool
185920d2c4d2SmrgTranslationsUseKeyword(Widget w, char **cache, const char *keyword, Bool onlyInsert)
1860d522f475Smrg{
1861d522f475Smrg    static String data;
1862d522f475Smrg    static XtResource key_resources[] =
1863d522f475Smrg    {
1864d522f475Smrg	{XtNtranslations, XtCTranslations, XtRString,
1865d522f475Smrg	 sizeof(data), 0, XtRString, (XtPointer) NULL}
1866d522f475Smrg    };
1867d522f475Smrg    Bool result = False;
1868d522f475Smrg    char *copy;
1869d522f475Smrg    char *test;
1870d522f475Smrg
187120d2c4d2Smrg    if ((test = stripTranslations(keyword, onlyInsert)) != 0) {
1872d522f475Smrg	if (*cache == 0) {
1873d522f475Smrg	    XtGetSubresources(w,
1874d522f475Smrg			      (XtPointer) &data,
1875d522f475Smrg			      "vt100",
1876d522f475Smrg			      "VT100",
1877d522f475Smrg			      key_resources,
1878d522f475Smrg			      XtNumber(key_resources),
1879d522f475Smrg			      NULL,
1880d522f475Smrg			      (Cardinal) 0);
188120d2c4d2Smrg	    if (data != 0 && (copy = stripTranslations(data, onlyInsert)) != 0) {
1882d522f475Smrg		*cache = copy;
1883d522f475Smrg	    }
1884d522f475Smrg	}
1885d522f475Smrg
1886d522f475Smrg	if (*cache != 0) {
1887d522f475Smrg	    char *p = *cache;
1888d522f475Smrg	    int state = 0;
1889d522f475Smrg	    int now = ' ', prv;
1890d522f475Smrg
1891d522f475Smrg	    while (*p != 0) {
1892d522f475Smrg		prv = now;
1893d522f475Smrg		now = *p++;
1894d522f475Smrg		if (now == ':'
1895d522f475Smrg		    || now == '!') {
1896d522f475Smrg		    state = -1;
1897d522f475Smrg		} else if (now == '\n') {
1898d522f475Smrg		    state = 0;
1899d522f475Smrg		} else if (state >= 0) {
1900d522f475Smrg		    if (now == test[state]) {
1901d522f475Smrg			if ((state != 0
1902d522f475Smrg			     || !isName(prv))
1903d522f475Smrg			    && ((test[++state] == 0)
1904d522f475Smrg				&& !isName(*p))) {
1905d522f475Smrg			    result = True;
1906d522f475Smrg			    break;
1907d522f475Smrg			}
1908d522f475Smrg		    } else {
1909d522f475Smrg			state = 0;
1910d522f475Smrg		    }
1911d522f475Smrg		}
1912d522f475Smrg	    }
1913d522f475Smrg	}
1914d522f475Smrg	free(test);
1915d522f475Smrg    }
191620d2c4d2Smrg    TRACE(("TranslationsUseKeyword(%p, %s) = %d\n",
191720d2c4d2Smrg	   (void *) w, keyword, result));
1918d522f475Smrg    return result;
1919d522f475Smrg}
1920d522f475Smrg
1921d522f475Smrgstatic Bool
192220d2c4d2SmrgxtermHasTranslation(XtermWidget xw, const char *keyword, Bool onlyInsert)
1923d522f475Smrg{
1924d522f475Smrg    return (TranslationsUseKeyword(SHELL_OF(xw),
1925d522f475Smrg				   &(xw->keyboard.shell_translations),
192620d2c4d2Smrg				   keyword,
192720d2c4d2Smrg				   onlyInsert)
1928d522f475Smrg	    || TranslationsUseKeyword((Widget) xw,
1929d522f475Smrg				      &(xw->keyboard.xterm_translations),
193020d2c4d2Smrg				      keyword,
193120d2c4d2Smrg				      onlyInsert));
1932d522f475Smrg}
1933d522f475Smrg
1934d522f475Smrg#if OPT_EXTRA_PASTE
1935d522f475Smrgstatic void
193620d2c4d2SmrgaddTranslation(XtermWidget xw, const char *fromString, const char *toString)
1937d522f475Smrg{
193820d2c4d2Smrg    size_t have = (xw->keyboard.extra_translations
193920d2c4d2Smrg		   ? strlen(xw->keyboard.extra_translations)
194020d2c4d2Smrg		   : 0);
194120d2c4d2Smrg    size_t need = (((have != 0) ? (have + 4) : 0)
194220d2c4d2Smrg		   + strlen(fromString)
194320d2c4d2Smrg		   + strlen(toString)
194420d2c4d2Smrg		   + 6);
194520d2c4d2Smrg
194620d2c4d2Smrg    if (!xtermHasTranslation(xw, fromString, False)) {
1947d522f475Smrg	xw->keyboard.extra_translations
1948d522f475Smrg	    = TypeRealloc(char, need, xw->keyboard.extra_translations);
1949d522f475Smrg	if ((xw->keyboard.extra_translations) != 0) {
1950d522f475Smrg	    TRACE(("adding %s: %s\n", fromString, toString));
1951d522f475Smrg	    if (have)
1952d522f475Smrg		strcat(xw->keyboard.extra_translations, " \\n\\");
1953d522f475Smrg	    sprintf(xw->keyboard.extra_translations, "%s: %s",
1954d522f475Smrg		    fromString, toString);
1955d522f475Smrg	    TRACE(("...{%s}\n", xw->keyboard.extra_translations));
1956d522f475Smrg	}
1957d522f475Smrg    }
1958d522f475Smrg}
1959d522f475Smrg#endif
1960d522f475Smrg
19610bd37d32Smrg#define SaveMask(name)	xw->work.name |= (unsigned) mask;\
19620bd37d32Smrg			TRACE(("SaveMask(%#x -> %s) %#x (%#x is%s modifier)\n", \
19630bd37d32Smrg				(unsigned) keysym, #name, \
19640bd37d32Smrg				xw->work.name, (unsigned) mask, \
196520d2c4d2Smrg				ModifierName((unsigned) mask)));
1966d522f475Smrg/*
1967d522f475Smrg * Determine which modifier mask (if any) applies to the Num_Lock keysym.
1968d522f475Smrg *
1969d522f475Smrg * Also, determine which modifiers are associated with the ALT keys, so we can
1970d522f475Smrg * send that information as a parameter for special keys in Sun/PC keyboard
1971d522f475Smrg * mode.  However, if the ALT modifier is used in translations, we do not want
1972d522f475Smrg * to confuse things by sending the parameter.
1973d522f475Smrg */
1974d522f475Smrgvoid
1975d522f475SmrgVTInitModifiers(XtermWidget xw)
1976d522f475Smrg{
1977d522f475Smrg    Display *dpy = XtDisplay(xw);
1978d522f475Smrg    XModifierKeymap *keymap = XGetModifierMapping(dpy);
1979d522f475Smrg    int i, j, k, l;
1980d522f475Smrg    KeySym keysym;
1981d522f475Smrg    unsigned long mask;
1982d522f475Smrg    int min_keycode, max_keycode, keysyms_per_keycode = 0;
1983d522f475Smrg
1984d522f475Smrg    if (keymap != 0) {
1985d522f475Smrg	KeySym *theMap;
1986d522f475Smrg	int keycode_count;
1987d522f475Smrg
1988d522f475Smrg	TRACE(("VTInitModifiers\n"));
1989d522f475Smrg
1990d522f475Smrg	XDisplayKeycodes(dpy, &min_keycode, &max_keycode);
1991d522f475Smrg	keycode_count = (max_keycode - min_keycode + 1);
1992d522f475Smrg	theMap = XGetKeyboardMapping(dpy,
1993956cc18dSsnj				     (KeyCode) min_keycode,
1994d522f475Smrg				     keycode_count,
1995d522f475Smrg				     &keysyms_per_keycode);
1996d522f475Smrg
1997d522f475Smrg	if (theMap != 0) {
1998d522f475Smrg
1999d522f475Smrg#if OPT_EXTRA_PASTE
2000d522f475Smrg	    /*
2001d522f475Smrg	     * Assume that if we can find the paste keysym in the X keyboard
2002d522f475Smrg	     * mapping that the server allows the corresponding translations
2003d522f475Smrg	     * resource.
2004d522f475Smrg	     */
2005d522f475Smrg	    int limit = (max_keycode - min_keycode) * keysyms_per_keycode;
2006d522f475Smrg	    for (i = 0; i < limit; ++i) {
2007d522f475Smrg#ifdef XF86XK_Paste
2008d522f475Smrg		if (theMap[i] == XF86XK_Paste) {
2009d522f475Smrg		    TRACE(("keyboard has XF86XK_Paste\n"));
2010d522f475Smrg		    addTranslation(xw,
2011d522f475Smrg				   "<KeyPress> XF86Paste",
2012d522f475Smrg				   "insert-selection(SELECT, CUT_BUFFER0)");
2013d522f475Smrg		}
2014d522f475Smrg#endif
2015d522f475Smrg#ifdef SunXK_Paste
2016d522f475Smrg		if (theMap[i] == SunXK_Paste) {
2017d522f475Smrg		    TRACE(("keyboard has SunXK_Paste\n"));
2018d522f475Smrg		    addTranslation(xw,
2019d522f475Smrg				   "<KeyPress> SunPaste",
2020d522f475Smrg				   "insert-selection(SELECT, CUT_BUFFER0)");
2021d522f475Smrg		}
2022d522f475Smrg#endif
2023d522f475Smrg	    }
2024d522f475Smrg#endif /* OPT_EXTRA_PASTE */
2025d522f475Smrg
2026d522f475Smrg	    for (i = k = 0, mask = 1; i < 8; i++, mask <<= 1) {
2027d522f475Smrg		for (j = 0; j < keymap->max_keypermod; j++) {
2028d522f475Smrg		    KeyCode code = keymap->modifiermap[k++];
2029d522f475Smrg		    if (code == 0)
2030d522f475Smrg			continue;
2031d522f475Smrg
2032d522f475Smrg		    for (l = 0; l < keysyms_per_keycode; ++l) {
20330bd37d32Smrg#ifdef HAVE_XKBKEYCODETOKEYSYM
20340bd37d32Smrg			keysym = XkbKeycodeToKeysym(dpy, code, 0, l);
20350bd37d32Smrg#else
2036d522f475Smrg			keysym = XKeycodeToKeysym(dpy, code, l);
20370bd37d32Smrg#endif
2038d522f475Smrg			if (keysym == NoSymbol) {
2039a1f3da82Smrg			    /* EMPTY */ ;
2040d522f475Smrg			} else if (keysym == XK_Num_Lock) {
2041d522f475Smrg			    SaveMask(num_lock);
2042d522f475Smrg			} else if (keysym == XK_Alt_L || keysym == XK_Alt_R) {
2043d522f475Smrg			    SaveMask(alt_mods);
2044d522f475Smrg			} else if (keysym == XK_Meta_L || keysym == XK_Meta_R) {
2045d522f475Smrg			    SaveMask(meta_mods);
2046d522f475Smrg			}
2047d522f475Smrg		    }
2048d522f475Smrg		}
2049d522f475Smrg	    }
2050d522f475Smrg	    XFree(theMap);
2051d522f475Smrg	}
2052d522f475Smrg
2053d522f475Smrg	/* Don't disable any mods if "alwaysUseMods" is true. */
2054d522f475Smrg	if (!xw->misc.alwaysUseMods) {
205520d2c4d2Smrg
205620d2c4d2Smrg	    /*
205720d2c4d2Smrg	     * Force TranslationsUseKeyword() to reload.
205820d2c4d2Smrg	     */
205920d2c4d2Smrg	    if (xw->keyboard.shell_translations) {
206020d2c4d2Smrg		free(xw->keyboard.shell_translations);
206120d2c4d2Smrg		xw->keyboard.shell_translations = 0;
206220d2c4d2Smrg	    }
206320d2c4d2Smrg	    if (xw->keyboard.xterm_translations) {
206420d2c4d2Smrg		free(xw->keyboard.xterm_translations);
206520d2c4d2Smrg		xw->keyboard.xterm_translations = 0;
206620d2c4d2Smrg	    }
206720d2c4d2Smrg
2068d522f475Smrg	    /*
2069d522f475Smrg	     * If the Alt modifier is used in translations, we would rather not
2070d522f475Smrg	     * use it to modify function-keys when NumLock is active.
2071d522f475Smrg	     */
20720bd37d32Smrg	    if ((xw->work.alt_mods != 0)
207320d2c4d2Smrg		&& xtermHasTranslation(xw, "alt", True)) {
2074d522f475Smrg		TRACE(("ALT is used as a modifier in translations (ignore mask)\n"));
20750bd37d32Smrg		xw->work.alt_mods = 0;
2076d522f475Smrg	    }
2077d522f475Smrg
2078d522f475Smrg	    /*
2079d522f475Smrg	     * If the Meta modifier is used in translations, we would rather not
2080d522f475Smrg	     * use it to modify function-keys.
2081d522f475Smrg	     */
20820bd37d32Smrg	    if ((xw->work.meta_mods != 0)
208320d2c4d2Smrg		&& xtermHasTranslation(xw, "meta", True)) {
2084d522f475Smrg		TRACE(("META is used as a modifier in translations\n"));
20850bd37d32Smrg		xw->work.meta_mods = 0;
2086d522f475Smrg	    }
2087d522f475Smrg	}
2088d522f475Smrg
2089d522f475Smrg	XFreeModifiermap(keymap);
2090d522f475Smrg    }
2091d522f475Smrg}
2092d522f475Smrg#endif /* OPT_NUM_LOCK */
2093