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