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