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