input.c revision f2e35a3a
1f2e35a3aSmrg/* $XTermId: input.c,v 1.365 2020/10/12 19:21:53 tom Exp $ */ 2d522f475Smrg 3d522f475Smrg/* 4f2e35a3aSmrg * Copyright 1999-2019,2020 by Thomas E. Dickey 5d522f475Smrg * 6d522f475Smrg * All Rights Reserved 7d522f475Smrg * 8d522f475Smrg * Permission is hereby granted, free of charge, to any person obtaining a 9d522f475Smrg * copy of this software and associated documentation files (the 10d522f475Smrg * "Software"), to deal in the Software without restriction, including 11d522f475Smrg * without limitation the rights to use, copy, modify, merge, publish, 12d522f475Smrg * distribute, sublicense, and/or sell copies of the Software, and to 13d522f475Smrg * permit persons to whom the Software is furnished to do so, subject to 14d522f475Smrg * the following conditions: 15d522f475Smrg * 16d522f475Smrg * The above copyright notice and this permission notice shall be included 17d522f475Smrg * in all copies or substantial portions of the Software. 18d522f475Smrg * 19d522f475Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 20d522f475Smrg * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 21d522f475Smrg * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 22d522f475Smrg * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 23d522f475Smrg * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 24d522f475Smrg * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 25d522f475Smrg * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 26d522f475Smrg * 27d522f475Smrg * Except as contained in this notice, the name(s) of the above copyright 28d522f475Smrg * holders shall not be used in advertising or otherwise to promote the 29d522f475Smrg * sale, use or other dealings in this Software without prior written 30d522f475Smrg * authorization. 31d522f475Smrg * 32d522f475Smrg * 33d522f475Smrg * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. 34d522f475Smrg * 35d522f475Smrg * All Rights Reserved 36d522f475Smrg * 37d522f475Smrg * Permission to use, copy, modify, and distribute this software and its 38d522f475Smrg * documentation for any purpose and without fee is hereby granted, 39d522f475Smrg * provided that the above copyright notice appear in all copies and that 40d522f475Smrg * both that copyright notice and this permission notice appear in 41d522f475Smrg * supporting documentation, and that the name of Digital Equipment 42d522f475Smrg * Corporation not be used in advertising or publicity pertaining to 43d522f475Smrg * distribution of the software without specific, written prior permission. 44d522f475Smrg * 45d522f475Smrg * 46d522f475Smrg * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING 47d522f475Smrg * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL 48d522f475Smrg * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR 49d522f475Smrg * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, 50d522f475Smrg * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, 51d522f475Smrg * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS 52d522f475Smrg * SOFTWARE. 53d522f475Smrg */ 54d522f475Smrg 55d522f475Smrg/* input.c */ 56d522f475Smrg 57d522f475Smrg#include <xterm.h> 58d522f475Smrg 59d522f475Smrg#include <X11/keysym.h> 60d522f475Smrg 61d522f475Smrg#ifdef VMS 62d522f475Smrg#include <X11/keysymdef.h> 63d522f475Smrg#endif 64d522f475Smrg 65d522f475Smrg#if HAVE_X11_DECKEYSYM_H 66d522f475Smrg#include <X11/DECkeysym.h> 67d522f475Smrg#endif 68d522f475Smrg 69d522f475Smrg#if HAVE_X11_SUNKEYSYM_H 70d522f475Smrg#include <X11/Sunkeysym.h> 71d522f475Smrg#endif 72d522f475Smrg 73d522f475Smrg#if HAVE_X11_XF86KEYSYM_H 74d522f475Smrg#include <X11/XF86keysym.h> 75d522f475Smrg#endif 76d522f475Smrg 77f2e35a3aSmrg#if !defined(HAVE_CONFIG_H) && defined(_X_DEPRECATED) 78f2e35a3aSmrg#define HAVE_XKBKEYCODETOKEYSYM 1 79f2e35a3aSmrg#endif 80f2e35a3aSmrg 810bd37d32Smrg#ifdef HAVE_XKBKEYCODETOKEYSYM 820bd37d32Smrg#include <X11/XKBlib.h> 830bd37d32Smrg#endif 840bd37d32Smrg 85d522f475Smrg#include <X11/Xutil.h> 86d522f475Smrg#include <stdio.h> 87d522f475Smrg#include <ctype.h> 88d522f475Smrg 89d522f475Smrg#include <xutf8.h> 90d522f475Smrg 91d522f475Smrg#include <data.h> 92d522f475Smrg#include <fontutils.h> 932eaa94a1Schristos#include <xstrings.h> 94d522f475Smrg#include <xtermcap.h> 95d522f475Smrg 96d522f475Smrg/* 97d522f475Smrg * Xutil.h has no macro to check for the complete set of function- and 98d522f475Smrg * modifier-keys that might be returned. Fake it. 99d522f475Smrg */ 100d522f475Smrg#ifdef XK_ISO_Lock 101d522f475Smrg#define IsPredefinedKey(n) ((n) >= XK_ISO_Lock && (n) <= XK_Delete) 102d522f475Smrg#else 103d522f475Smrg#define IsPredefinedKey(n) ((n) >= XK_BackSpace && (n) <= XK_Delete) 104d522f475Smrg#endif 105d522f475Smrg 106d522f475Smrg#ifdef XK_ISO_Left_Tab 107d522f475Smrg#define IsTabKey(n) ((n) == XK_Tab || (n) == XK_ISO_Left_Tab) 108d522f475Smrg#else 109d522f475Smrg#define IsTabKey(n) ((n) == XK_Tab) 110d522f475Smrg#endif 111d522f475Smrg 112d522f475Smrg#ifndef IsPrivateKeypadKey 113d522f475Smrg#define IsPrivateKeypadKey(k) (0) 114d522f475Smrg#endif 115d522f475Smrg 116d522f475Smrg#define IsBackarrowToggle(keyboard, keysym, state) \ 117d522f475Smrg ((((keyboard->flags & MODE_DECBKM) == 0) \ 118d522f475Smrg ^ ((state & ControlMask) != 0)) \ 119d522f475Smrg && (keysym == XK_BackSpace)) 120d522f475Smrg 121d522f475Smrg#define MAP(from, to) case from: result = to; break 122d522f475Smrg#define Masked(value,mask) ((value) & (unsigned) (~(mask))) 123d522f475Smrg 124d522f475Smrg#define KEYSYM_FMT "0x%04lX" /* simplify matching <X11/keysymdef.h> */ 125d522f475Smrg 12620d2c4d2Smrg#define TEK4014_GIN(tw) (tw != 0 && TekScreenOf(tw)->TekGIN) 127d522f475Smrg 128d522f475Smrgtypedef struct { 129d522f475Smrg KeySym keysym; 130d522f475Smrg Bool is_fkey; 131d522f475Smrg int nbytes; 132d522f475Smrg#define STRBUFSIZE 500 133d522f475Smrg char strbuf[STRBUFSIZE]; 134d522f475Smrg} KEY_DATA; 135d522f475Smrg 13620d2c4d2Smrgstatic 13701037d57Smrgconst char kypd_num[] = " XXXXXXXX\tXXX\rXXXxxxxXXXXXXXXXXXXXXXXXXXXX*+,-./0123456789XXX="; 13801037d57Smrg/* 0123456789 abc def0123456789abcdef0123456789abcdef0123456789abcd */ 13920d2c4d2Smrgstatic 14001037d57Smrgconst char kypd_apl[] = " ABCDEFGHIJKLMNOPQRSTUVWXYZ??????abcdefghijklmnopqrstuvwxyzXXX"; 14101037d57Smrg/* 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd */ 14220d2c4d2Smrgstatic 14301037d57Smrgconst char curfinal[] = "HDACB FE"; 144d522f475Smrg 145d522f475Smrgstatic int decfuncvalue(KEY_DATA *); 146d522f475Smrgstatic void sunfuncvalue(ANSI *, KEY_DATA *); 147d522f475Smrgstatic void hpfuncvalue(ANSI *, KEY_DATA *); 148d522f475Smrgstatic void scofuncvalue(ANSI *, KEY_DATA *); 149d522f475Smrg 150d522f475Smrgstatic void 151d522f475SmrgAdjustAfterInput(XtermWidget xw) 152d522f475Smrg{ 15320d2c4d2Smrg TScreen *screen = TScreenOf(xw); 154d522f475Smrg 155d522f475Smrg if (screen->scrollkey && screen->topline != 0) 15620d2c4d2Smrg WindowScroll(xw, 0, False); 157d522f475Smrg if (screen->marginbell) { 158d522f475Smrg int col = screen->max_col - screen->nmarginbell; 15920d2c4d2Smrg if (screen->bellArmed >= 0) { 16020d2c4d2Smrg if (screen->bellArmed == screen->cur_row) { 161d522f475Smrg if (screen->cur_col >= col) { 16220d2c4d2Smrg Bell(xw, XkbBI_MarginBell, 0); 16320d2c4d2Smrg screen->bellArmed = -1; 164d522f475Smrg } 16520d2c4d2Smrg } else { 16620d2c4d2Smrg screen->bellArmed = 167d522f475Smrg screen->cur_col < col ? screen->cur_row : -1; 16820d2c4d2Smrg } 169d522f475Smrg } else if (screen->cur_col < col) 17020d2c4d2Smrg screen->bellArmed = screen->cur_row; 171d522f475Smrg } 172d522f475Smrg} 173d522f475Smrg 174d522f475Smrg/* 175d522f475Smrg * Return true if the key is on the editing keypad. This overlaps with 1760bd37d32Smrg * IsCursorKey() and IsKeypadKey() and must be tested before those macros to 177d522f475Smrg * distinguish it from them. 1780bd37d32Smrg * 1790bd37d32Smrg * VT220 emulation uses the VT100 numeric keypad as well as a 6-key 1800bd37d32Smrg * editing keypad. Here's a picture of the VT220 editing keypad: 1810bd37d32Smrg * +--------+--------+--------+ 1820bd37d32Smrg * | Find | Insert | Remove | 1830bd37d32Smrg * +--------+--------+--------+ 1840bd37d32Smrg * | Select | Prev | Next | 1850bd37d32Smrg * +--------+--------+--------+ 1860bd37d32Smrg * 1870bd37d32Smrg * and the similar Sun and PC keypads: 1880bd37d32Smrg * +--------+--------+--------+ 1890bd37d32Smrg * | Insert | Home | PageUp | 1900bd37d32Smrg * +--------+--------+--------+ 1910bd37d32Smrg * | Delete | End | PageDn | 1920bd37d32Smrg * +--------+--------+--------+ 193d522f475Smrg */ 194d522f475Smrgstatic Bool 1950bd37d32SmrgIsEditKeypad(XtermWidget xw, KeySym keysym) 196d522f475Smrg{ 1970bd37d32Smrg Bool result; 1980bd37d32Smrg 199d522f475Smrg switch (keysym) { 2000bd37d32Smrg case XK_Delete: 2010bd37d32Smrg result = !xtermDeleteIsDEL(xw); 2020bd37d32Smrg break; 2030bd37d32Smrg case XK_Prior: 2040bd37d32Smrg case XK_Next: 2050bd37d32Smrg case XK_Insert: 2060bd37d32Smrg case XK_Find: 2070bd37d32Smrg case XK_Select: 208d522f475Smrg#ifdef DXK_Remove 2090bd37d32Smrg case DXK_Remove: 210d522f475Smrg#endif 2110bd37d32Smrg result = True; 2120bd37d32Smrg break; 2130bd37d32Smrg default: 2140bd37d32Smrg result = False; 2150bd37d32Smrg break; 2160bd37d32Smrg } 2170bd37d32Smrg return result; 2180bd37d32Smrg} 2190bd37d32Smrg 2200bd37d32Smrg/* 2210bd37d32Smrg * Editing-keypad, plus other editing keys which are not included in the 2220bd37d32Smrg * other macros. 2230bd37d32Smrg */ 2240bd37d32Smrgstatic Bool 2250bd37d32SmrgIsEditFunctionKey(XtermWidget xw, KeySym keysym) 2260bd37d32Smrg{ 2270bd37d32Smrg Bool result; 2280bd37d32Smrg 2290bd37d32Smrg switch (keysym) { 230d522f475Smrg#ifdef XK_KP_Delete 231d522f475Smrg case XK_KP_Delete: /* editing key on numeric keypad */ 232d522f475Smrg case XK_KP_Insert: /* editing key on numeric keypad */ 233d522f475Smrg#endif 234d522f475Smrg#ifdef XK_ISO_Left_Tab 235d522f475Smrg case XK_ISO_Left_Tab: 236d522f475Smrg#endif 2370bd37d32Smrg result = True; 2380bd37d32Smrg break; 239d522f475Smrg default: 2400bd37d32Smrg result = IsEditKeypad(xw, keysym); 2410bd37d32Smrg break; 242d522f475Smrg } 2430bd37d32Smrg return result; 244d522f475Smrg} 245d522f475Smrg 246d522f475Smrg#if OPT_MOD_FKEYS 247d522f475Smrg#define IS_CTRL(n) ((n) < ANSI_SPA || ((n) >= 0x7f && (n) <= 0x9f)) 248d522f475Smrg 249d522f475Smrg/* 250d522f475Smrg * Return true if the keysym corresponds to one of the control characters, 251d522f475Smrg * or one of the common ASCII characters that is combined with control to 252d522f475Smrg * make a control character. 253d522f475Smrg */ 254d522f475Smrgstatic Bool 255d522f475SmrgIsControlInput(KEY_DATA * kd) 256d522f475Smrg{ 257d522f475Smrg return ((kd->keysym) >= 0x40 && (kd->keysym) <= 0x7f); 258d522f475Smrg} 259d522f475Smrg 260d522f475Smrgstatic Bool 261d522f475SmrgIsControlOutput(KEY_DATA * kd) 262d522f475Smrg{ 263d522f475Smrg return IS_CTRL(kd->keysym); 264d522f475Smrg} 265d522f475Smrg 266d522f475Smrg/* 267d522f475Smrg * X "normally" has some built-in translations, which the user may want to 268d522f475Smrg * suppress when processing the modifyOtherKeys resource. In particular, the 269d522f475Smrg * control modifier applied to some of the keyboard digits gives results for 270d522f475Smrg * control characters. 271d522f475Smrg * 272d522f475Smrg * control 2 0 NUL 273d522f475Smrg * control SPC 0 NUL 274d522f475Smrg * control @ 0 NUL 275d522f475Smrg * control ` 0 NUL 276d522f475Smrg * control 3 0x1b ESC 277d522f475Smrg * control 4 0x1c FS 278d522f475Smrg * control \ 0x1c FS 279d522f475Smrg * control 5 0x1d GS 280d522f475Smrg * control 6 0x1e RS 281d522f475Smrg * control ^ 0x1e RS 282d522f475Smrg * control ~ 0x1e RS 283d522f475Smrg * control 7 0x1f US 284d522f475Smrg * control / 0x1f US 285d522f475Smrg * control _ 0x1f US 286d522f475Smrg * control 8 0x7f DEL 287d522f475Smrg * 288d522f475Smrg * It is possible that some other keyboards do not work for these combinations, 289d522f475Smrg * but they do work with modifyOtherKeys=2 for the US keyboard: 290d522f475Smrg * 291d522f475Smrg * control ` 0 NUL 292d522f475Smrg * control [ 0x1b ESC 293d522f475Smrg * control \ 0x1c FS 294d522f475Smrg * control ] 0x1d GS 295d522f475Smrg * control ? 0x7f DEL 296d522f475Smrg */ 297d522f475Smrgstatic Bool 298d522f475SmrgIsControlAlias(KEY_DATA * kd) 299d522f475Smrg{ 300d522f475Smrg Bool result = False; 301d522f475Smrg 302d522f475Smrg if (kd->nbytes == 1) { 303d522f475Smrg result = IS_CTRL(CharOf(kd->strbuf[0])); 304d522f475Smrg } 305d522f475Smrg return result; 306d522f475Smrg} 307d522f475Smrg 308d522f475Smrg/* 309d522f475Smrg * If we are in the non-VT220/VT52 keyboard state, allow modifiers to add a 310d522f475Smrg * parameter to the function-key control sequences. 311d522f475Smrg * 312d522f475Smrg * Note that we generally cannot capture the Shift-modifier for the numeric 313d522f475Smrg * keypad since this is commonly used to act as a type of NumLock, e.g., 314d522f475Smrg * making the keypad send "7" (actually XK_KP_7) where the unshifted code 315d522f475Smrg * would be Home (XK_KP_Home). The other modifiers work, subject to the 316d522f475Smrg * usual window-manager assignments. 317d522f475Smrg */ 3180bd37d32Smrg#if OPT_SUNPC_KBD 3190bd37d32Smrg#define LegacyAllows(code) (!is_legacy || (code & xw->keyboard.modify_now.allow_keys) != 0) 3200bd37d32Smrg#else 3210bd37d32Smrg#define LegacyAllows(code) True 3220bd37d32Smrg#endif 3230bd37d32Smrg 324d522f475Smrgstatic Bool 325d522f475SmrgallowModifierParm(XtermWidget xw, KEY_DATA * kd) 326d522f475Smrg{ 327d522f475Smrg TKeyboard *keyboard = &(xw->keyboard); 3280bd37d32Smrg int is_legacy = (keyboard->type == keyboardIsLegacy); 329d522f475Smrg Bool result = False; 330d522f475Smrg 331d522f475Smrg#if OPT_SUNPC_KBD 3320bd37d32Smrg if (keyboard->type == keyboardIsVT220) 3330bd37d32Smrg is_legacy = True; 334d522f475Smrg#endif 3350bd37d32Smrg 336d522f475Smrg#if OPT_VT52_MODE 337e0a2b6dfSmrg if (TScreenOf(xw)->vtXX_level != 0) 338d522f475Smrg#endif 3390bd37d32Smrg { 3400bd37d32Smrg if (IsCursorKey(kd->keysym) || IsEditFunctionKey(xw, kd->keysym)) { 3410bd37d32Smrg result = LegacyAllows(2); 3420bd37d32Smrg } else if (IsKeypadKey(kd->keysym)) { 343e0a2b6dfSmrg result = LegacyAllows(1); 3440bd37d32Smrg } else if (IsFunctionKey(kd->keysym)) { 3450bd37d32Smrg result = LegacyAllows(4); 3460bd37d32Smrg } else if (IsMiscFunctionKey(kd->keysym)) { 3470bd37d32Smrg result = LegacyAllows(8); 3480bd37d32Smrg } 3490bd37d32Smrg } 3500bd37d32Smrg if (xw->keyboard.modify_now.other_keys != 0) { 351d522f475Smrg result = True; 352d522f475Smrg } 353d522f475Smrg return result; 354d522f475Smrg} 355d522f475Smrg 356d522f475Smrg/* 357d522f475Smrg* Modifier codes: 358d522f475Smrg* None 1 359d522f475Smrg* Shift 2 = 1(None)+1(Shift) 360d522f475Smrg* Alt 3 = 1(None)+2(Alt) 361d522f475Smrg* Alt+Shift 4 = 1(None)+1(Shift)+2(Alt) 362d522f475Smrg* Ctrl 5 = 1(None)+4(Ctrl) 363d522f475Smrg* Ctrl+Shift 6 = 1(None)+1(Shift)+4(Ctrl) 364d522f475Smrg* Ctrl+Alt 7 = 1(None)+2(Alt)+4(Ctrl) 365d522f475Smrg* Ctrl+Alt+Shift 8 = 1(None)+1(Shift)+2(Alt)+4(Ctrl) 366d522f475Smrg* Meta 9 = 1(None)+8(Meta) 367d522f475Smrg* Meta+Shift 10 = 1(None)+8(Meta)+1(Shift) 368d522f475Smrg* Meta+Alt 11 = 1(None)+8(Meta)+2(Alt) 369d522f475Smrg* Meta+Alt+Shift 12 = 1(None)+8(Meta)+1(Shift)+2(Alt) 370d522f475Smrg* Meta+Ctrl 13 = 1(None)+8(Meta)+4(Ctrl) 371d522f475Smrg* Meta+Ctrl+Shift 14 = 1(None)+8(Meta)+1(Shift)+4(Ctrl) 372d522f475Smrg* Meta+Ctrl+Alt 15 = 1(None)+8(Meta)+2(Alt)+4(Ctrl) 373d522f475Smrg* Meta+Ctrl+Alt+Shift 16 = 1(None)+8(Meta)+1(Shift)+2(Alt)+4(Ctrl) 374d522f475Smrg*/ 375d522f475Smrg 376956cc18dSsnjunsigned 377d522f475SmrgxtermParamToState(XtermWidget xw, unsigned param) 378d522f475Smrg{ 379956cc18dSsnj unsigned result = 0; 380d522f475Smrg#if OPT_NUM_LOCK 3810bd37d32Smrg if (param > MOD_NONE) { 382956cc18dSsnj if ((param - MOD_NONE) & MOD_SHIFT) 38320d2c4d2Smrg UIntSet(result, ShiftMask); 384956cc18dSsnj if ((param - MOD_NONE) & MOD_CTRL) 38520d2c4d2Smrg UIntSet(result, ControlMask); 386956cc18dSsnj if ((param - MOD_NONE) & MOD_ALT) 3870bd37d32Smrg UIntSet(result, xw->work.alt_mods); 388956cc18dSsnj if ((param - MOD_NONE) & MOD_META) 3890bd37d32Smrg UIntSet(result, xw->work.meta_mods); 390d522f475Smrg } 391d522f475Smrg#else 392d522f475Smrg (void) xw; 393d522f475Smrg (void) param; 394d522f475Smrg#endif 395d522f475Smrg TRACE(("xtermParamToState(%d) %s%s%s%s -> %#x\n", param, 396956cc18dSsnj MODIFIER_NAME(param, MOD_SHIFT), 397956cc18dSsnj MODIFIER_NAME(param, MOD_ALT), 398956cc18dSsnj MODIFIER_NAME(param, MOD_CTRL), 399956cc18dSsnj MODIFIER_NAME(param, MOD_META), 400d522f475Smrg result)); 401d522f475Smrg return result; 402d522f475Smrg} 403d522f475Smrg 404956cc18dSsnjunsigned 405d522f475SmrgxtermStateToParam(XtermWidget xw, unsigned state) 406d522f475Smrg{ 407956cc18dSsnj unsigned modify_parm = MOD_NONE; 408d522f475Smrg 409956cc18dSsnj TRACE(("xtermStateToParam %#x\n", state)); 410d522f475Smrg#if OPT_NUM_LOCK 4110bd37d32Smrg if (state & ShiftMask) { 4120bd37d32Smrg modify_parm += MOD_SHIFT; 4130bd37d32Smrg UIntClr(state, ShiftMask); 4140bd37d32Smrg } 4150bd37d32Smrg if (state & ControlMask) { 4160bd37d32Smrg modify_parm += MOD_CTRL; 4170bd37d32Smrg UIntClr(state, ControlMask); 4180bd37d32Smrg } 4190bd37d32Smrg if ((state & xw->work.alt_mods) != 0) { 4200bd37d32Smrg modify_parm += MOD_ALT; 4210bd37d32Smrg UIntClr(state, xw->work.alt_mods); 4220bd37d32Smrg } 4230bd37d32Smrg if ((state & xw->work.meta_mods) != 0) { 4240bd37d32Smrg modify_parm += MOD_META; 4252e4f8982Smrg /* UIntClr(state, xw->work.meta_mods); */ 426d522f475Smrg } 427956cc18dSsnj if (modify_parm == MOD_NONE) 428956cc18dSsnj modify_parm = 0; 429d522f475Smrg#else 430d522f475Smrg (void) xw; 431d522f475Smrg (void) state; 432d522f475Smrg#endif 433d522f475Smrg TRACE(("...xtermStateToParam %d%s%s%s%s\n", modify_parm, 434956cc18dSsnj MODIFIER_NAME(modify_parm, MOD_SHIFT), 435956cc18dSsnj MODIFIER_NAME(modify_parm, MOD_ALT), 436956cc18dSsnj MODIFIER_NAME(modify_parm, MOD_CTRL), 437956cc18dSsnj MODIFIER_NAME(modify_parm, MOD_META))); 438d522f475Smrg return modify_parm; 439d522f475Smrg} 440d522f475Smrg 441d522f475Smrg#define computeMaskedModifier(xw, state, mask) \ 442d522f475Smrg xtermStateToParam(xw, Masked(state, mask)) 443d522f475Smrg 444d522f475Smrg#if OPT_NUM_LOCK 445d522f475Smrgstatic unsigned 446d522f475SmrgfilterAltMeta(unsigned result, unsigned mask, Bool enable, KEY_DATA * kd) 447d522f475Smrg{ 448d522f475Smrg if ((result & mask) != 0) { 449d522f475Smrg /* 450d522f475Smrg * metaSendsEscape makes the meta key independent of 451d522f475Smrg * modifyOtherKeys. 452d522f475Smrg */ 453d522f475Smrg if (enable) { 454d522f475Smrg result &= ~mask; 455d522f475Smrg } 456d522f475Smrg /* 457d522f475Smrg * A bare meta-modifier is independent of modifyOtherKeys. If it 458d522f475Smrg * is combined with other modifiers, make it depend. 459d522f475Smrg */ 460d522f475Smrg if ((result & ~(mask)) == 0) { 461d522f475Smrg result &= ~mask; 462d522f475Smrg } 463d522f475Smrg /* 464d522f475Smrg * Check for special cases of control+meta which are used by some 465d522f475Smrg * applications, e.g., emacs. 466d522f475Smrg */ 467d522f475Smrg if ((IsControlInput(kd) 468d522f475Smrg || IsControlOutput(kd)) 469d522f475Smrg && (result & ControlMask) != 0) { 470d522f475Smrg result &= ~(mask | ControlMask); 471d522f475Smrg } 472d522f475Smrg if (kd->keysym == XK_Return || kd->keysym == XK_Tab) { 473d522f475Smrg result &= ~(mask | ControlMask); 474d522f475Smrg } 475d522f475Smrg } 476d522f475Smrg return result; 477d522f475Smrg} 478d522f475Smrg#endif /* OPT_NUM_LOCK */ 479d522f475Smrg 480d522f475Smrg/* 481d522f475Smrg * Single characters (not function-keys) are allowed fewer modifiers when 482d522f475Smrg * interpreting modifyOtherKeys due to pre-existing associations with some 483d522f475Smrg * modifiers. 484d522f475Smrg */ 485d522f475Smrgstatic unsigned 486d522f475SmrgallowedCharModifiers(XtermWidget xw, unsigned state, KEY_DATA * kd) 487d522f475Smrg{ 488d522f475Smrg#if OPT_NUM_LOCK 4890bd37d32Smrg unsigned a_or_m = (state & (xw->work.meta_mods | xw->work.alt_mods)); 490d522f475Smrg#else 491d522f475Smrg unsigned a_or_m = 0; 492d522f475Smrg#endif 493d522f475Smrg /* 494d522f475Smrg * Start by limiting the result to the modifiers we might want to use. 495d522f475Smrg */ 496d522f475Smrg unsigned result = (state & (ControlMask 497d522f475Smrg | ShiftMask 498d522f475Smrg | a_or_m)); 499d522f475Smrg 500d522f475Smrg /* 501d522f475Smrg * If modifyOtherKeys is off or medium (0 or 1), moderate its effects by 502d522f475Smrg * excluding the common cases for modifiers. 503d522f475Smrg */ 504d522f475Smrg if (xw->keyboard.modify_now.other_keys <= 1) { 505d522f475Smrg if (IsControlInput(kd) 506d522f475Smrg && Masked(result, ControlMask) == 0) { 507d522f475Smrg /* These keys are already associated with the control-key */ 508d522f475Smrg if (xw->keyboard.modify_now.other_keys == 0) { 50920d2c4d2Smrg UIntClr(result, ControlMask); 510d522f475Smrg } 511d522f475Smrg } else if (kd->keysym == XK_Tab || kd->keysym == XK_Return) { 512a1f3da82Smrg /* EMPTY */ ; 513d522f475Smrg } else if (IsControlAlias(kd)) { 514d522f475Smrg /* Things like "^_" work here... */ 515d522f475Smrg if (Masked(result, (ControlMask | ShiftMask)) == 0) { 516d522f475Smrg result = 0; 517d522f475Smrg } 518d522f475Smrg } else if (!IsControlOutput(kd) && !IsPredefinedKey(kd->keysym)) { 519d522f475Smrg /* Printable keys are already associated with the shift-key */ 520d522f475Smrg if (!(result & ControlMask)) { 52120d2c4d2Smrg UIntClr(result, ShiftMask); 522d522f475Smrg } 523d522f475Smrg } 524d522f475Smrg#if OPT_NUM_LOCK 525d522f475Smrg result = filterAltMeta(result, 5260bd37d32Smrg xw->work.meta_mods, 52720d2c4d2Smrg TScreenOf(xw)->meta_sends_esc, kd); 52820d2c4d2Smrg if (TScreenOf(xw)->alt_is_not_meta) { 529d522f475Smrg result = filterAltMeta(result, 5300bd37d32Smrg xw->work.alt_mods, 53120d2c4d2Smrg TScreenOf(xw)->alt_sends_esc, kd); 532d522f475Smrg } 533d522f475Smrg#endif 534d522f475Smrg } 535d522f475Smrg TRACE(("...allowedCharModifiers(state=%u" FMT_MODIFIER_NAMES 536d522f475Smrg ", ch=" KEYSYM_FMT ") ->" 537d522f475Smrg "%u" FMT_MODIFIER_NAMES "\n", 538d522f475Smrg state, ARG_MODIFIER_NAMES(state), kd->keysym, 539d522f475Smrg result, ARG_MODIFIER_NAMES(result))); 540d522f475Smrg return result; 541d522f475Smrg} 542d522f475Smrg 543d522f475Smrg/* 544d522f475Smrg * Decide if we should generate a special escape sequence for "other" keys 545d522f475Smrg * than cursor-, function-keys, etc., as per the modifyOtherKeys resource. 546d522f475Smrg */ 547d522f475Smrgstatic Bool 548d522f475SmrgModifyOtherKeys(XtermWidget xw, 549d522f475Smrg unsigned state, 550d522f475Smrg KEY_DATA * kd, 551956cc18dSsnj unsigned modify_parm) 552d522f475Smrg{ 553d522f475Smrg TKeyboard *keyboard = &(xw->keyboard); 554d522f475Smrg Bool result = False; 555d522f475Smrg 556d522f475Smrg /* 557d522f475Smrg * Exclude the keys already covered by a modifier. 558d522f475Smrg */ 559d522f475Smrg if (kd->is_fkey 5600bd37d32Smrg || IsEditFunctionKey(xw, kd->keysym) 561d522f475Smrg || IsKeypadKey(kd->keysym) 562d522f475Smrg || IsCursorKey(kd->keysym) 563d522f475Smrg || IsPFKey(kd->keysym) 564d522f475Smrg || IsMiscFunctionKey(kd->keysym) 5650bd37d32Smrg || IsPrivateKeypadKey(kd->keysym)) { 566d522f475Smrg result = False; 567d522f475Smrg } else if (modify_parm != 0) { 568d522f475Smrg if (IsBackarrowToggle(keyboard, kd->keysym, state)) { 569d522f475Smrg kd->keysym = XK_Delete; 57020d2c4d2Smrg UIntClr(state, ControlMask); 571d522f475Smrg } 572d522f475Smrg if (!IsPredefinedKey(kd->keysym)) { 573d522f475Smrg state = allowedCharModifiers(xw, state, kd); 574d522f475Smrg } 575d522f475Smrg if (state != 0) { 576d522f475Smrg switch (keyboard->modify_now.other_keys) { 577d522f475Smrg default: 578d522f475Smrg break; 579d522f475Smrg case 1: 580d522f475Smrg switch (kd->keysym) { 581d522f475Smrg case XK_BackSpace: 582d522f475Smrg case XK_Delete: 583d522f475Smrg result = False; 584d522f475Smrg break; 585d522f475Smrg#ifdef XK_ISO_Left_Tab 586d522f475Smrg case XK_ISO_Left_Tab: 587956cc18dSsnj if (computeMaskedModifier(xw, state, ShiftMask)) 588d522f475Smrg result = True; 589d522f475Smrg break; 590d522f475Smrg#endif 591d522f475Smrg case XK_Return: 592d522f475Smrg case XK_Tab: 593956cc18dSsnj result = (modify_parm != 0); 594d522f475Smrg break; 595d522f475Smrg default: 596d522f475Smrg if (IsControlInput(kd)) { 597d522f475Smrg if (state == ControlMask || state == ShiftMask) { 598d522f475Smrg result = False; 599d522f475Smrg } else { 600956cc18dSsnj result = (modify_parm != 0); 601d522f475Smrg } 602d522f475Smrg } else if (IsControlAlias(kd)) { 603d522f475Smrg if (state == ShiftMask) 604d522f475Smrg result = False; 605956cc18dSsnj else if (computeMaskedModifier(xw, state, ControlMask)) { 606d522f475Smrg result = True; 607d522f475Smrg } 608d522f475Smrg } else { 609d522f475Smrg result = True; 610d522f475Smrg } 611d522f475Smrg break; 612d522f475Smrg } 613d522f475Smrg break; 614d522f475Smrg case 2: 615d522f475Smrg switch (kd->keysym) { 616d522f475Smrg case XK_BackSpace: 617d522f475Smrg /* strip ControlMask as per IsBackarrowToggle() */ 618956cc18dSsnj if (computeMaskedModifier(xw, state, ControlMask)) 619d522f475Smrg result = True; 620d522f475Smrg break; 621d522f475Smrg case XK_Delete: 622956cc18dSsnj result = (xtermStateToParam(xw, state) != 0); 623d522f475Smrg break; 624d522f475Smrg#ifdef XK_ISO_Left_Tab 625d522f475Smrg case XK_ISO_Left_Tab: 626956cc18dSsnj if (computeMaskedModifier(xw, state, ShiftMask)) 627d522f475Smrg result = True; 628d522f475Smrg break; 629d522f475Smrg#endif 630d522f475Smrg case XK_Return: 631d522f475Smrg case XK_Tab: 632956cc18dSsnj result = (modify_parm != 0); 633d522f475Smrg break; 634d522f475Smrg default: 635d522f475Smrg if (IsControlInput(kd)) { 636d522f475Smrg result = True; 637d522f475Smrg } else if (state == ShiftMask) { 638d522f475Smrg result = (kd->keysym == ' ' || kd->keysym == XK_Return); 639956cc18dSsnj } else if (computeMaskedModifier(xw, state, ShiftMask)) { 640d522f475Smrg result = True; 641d522f475Smrg } 642d522f475Smrg break; 643d522f475Smrg } 644d522f475Smrg break; 645d522f475Smrg } 646d522f475Smrg } 647d522f475Smrg } 648d522f475Smrg TRACE(("...ModifyOtherKeys(%d,%d) %s\n", 649d522f475Smrg keyboard->modify_now.other_keys, 650d522f475Smrg modify_parm, 651d522f475Smrg BtoS(result))); 652d522f475Smrg return result; 653d522f475Smrg} 654d522f475Smrg 655d522f475Smrg#define APPEND_PARM(number) \ 656956cc18dSsnj reply->a_param[reply->a_nparam] = (ParmType) number; \ 657956cc18dSsnj reply->a_nparam++ 658d522f475Smrg 659d522f475Smrg/* 660d522f475Smrg * Function-key code 27 happens to not be used in the vt220-style encoding. 661d522f475Smrg * xterm uses this to represent modified non-function-keys such as control/+ in 662d522f475Smrg * the Sun/PC keyboard layout. See the modifyOtherKeys resource in the manpage 663d522f475Smrg * for more information. 664d522f475Smrg */ 665d522f475Smrgstatic Bool 666e0a2b6dfSmrgmodifyOtherKey(ANSI *reply, int input_char, unsigned modify_parm, int format_keys) 667d522f475Smrg{ 668d522f475Smrg Bool result = False; 669d522f475Smrg 670d522f475Smrg if (input_char >= 0) { 671d522f475Smrg reply->a_type = ANSI_CSI; 672d522f475Smrg if (format_keys) { 673d522f475Smrg APPEND_PARM(input_char); 674d522f475Smrg APPEND_PARM(modify_parm); 675d522f475Smrg reply->a_final = 'u'; 676d522f475Smrg } else { 677d522f475Smrg APPEND_PARM(27); 678d522f475Smrg APPEND_PARM(modify_parm); 679d522f475Smrg APPEND_PARM(input_char); 680d522f475Smrg reply->a_final = '~'; 681d522f475Smrg } 682d522f475Smrg 683d522f475Smrg result = True; 684d522f475Smrg } 685d522f475Smrg return result; 686d522f475Smrg} 687d522f475Smrg 688d522f475Smrgstatic void 689e0a2b6dfSmrgmodifyCursorKey(ANSI *reply, int modify, unsigned *modify_parm) 690d522f475Smrg{ 691956cc18dSsnj if (*modify_parm != 0) { 692d522f475Smrg if (modify < 0) { 693d522f475Smrg *modify_parm = 0; 694d522f475Smrg } 695d522f475Smrg if (modify > 0) { 696d522f475Smrg reply->a_type = ANSI_CSI; /* SS3 should not have params */ 697d522f475Smrg } 698d522f475Smrg if (modify > 1 && reply->a_nparam == 0) { 699d522f475Smrg APPEND_PARM(1); /* force modifier to 2nd param */ 700d522f475Smrg } 701d522f475Smrg if (modify > 2) { 702d522f475Smrg reply->a_pintro = '>'; /* mark this as "private" */ 703d522f475Smrg } 704d522f475Smrg } 705d522f475Smrg} 706d522f475Smrg#else 707d522f475Smrg#define modifyCursorKey(reply, modify, parm) /* nothing */ 708d522f475Smrg#endif /* OPT_MOD_FKEYS */ 709d522f475Smrg 710d522f475Smrg#if OPT_SUNPC_KBD 711d522f475Smrg/* 712d522f475Smrg * If we have told xterm that our keyboard is really a Sun/PC keyboard, this is 713d522f475Smrg * enough to make a reasonable approximation to DEC vt220 numeric and editing 714d522f475Smrg * keypads. 715d522f475Smrg */ 716d522f475Smrgstatic KeySym 717d522f475SmrgTranslateFromSUNPC(KeySym keysym) 718d522f475Smrg{ 719d522f475Smrg /* *INDENT-OFF* */ 720d522f475Smrg static struct { 721d522f475Smrg KeySym before, after; 722d522f475Smrg } table[] = { 723d522f475Smrg#ifdef DXK_Remove 724d522f475Smrg { XK_Delete, DXK_Remove }, 725d522f475Smrg#endif 726d522f475Smrg { XK_Home, XK_Find }, 727d522f475Smrg { XK_End, XK_Select }, 728d522f475Smrg#ifdef XK_KP_Home 729d522f475Smrg { XK_Delete, XK_KP_Decimal }, 730d522f475Smrg { XK_KP_Delete, XK_KP_Decimal }, 731d522f475Smrg { XK_KP_Insert, XK_KP_0 }, 732d522f475Smrg { XK_KP_End, XK_KP_1 }, 733d522f475Smrg { XK_KP_Down, XK_KP_2 }, 734d522f475Smrg { XK_KP_Next, XK_KP_3 }, 735d522f475Smrg { XK_KP_Left, XK_KP_4 }, 736d522f475Smrg { XK_KP_Begin, XK_KP_5 }, 737d522f475Smrg { XK_KP_Right, XK_KP_6 }, 738d522f475Smrg { XK_KP_Home, XK_KP_7 }, 739d522f475Smrg { XK_KP_Up, XK_KP_8 }, 740d522f475Smrg { XK_KP_Prior, XK_KP_9 }, 741d522f475Smrg#endif 742d522f475Smrg }; 743d522f475Smrg /* *INDENT-ON* */ 744d522f475Smrg 745d522f475Smrg unsigned n; 746d522f475Smrg 747d522f475Smrg for (n = 0; n < sizeof(table) / sizeof(table[0]); n++) { 748d522f475Smrg if (table[n].before == keysym) { 749d522f475Smrg TRACE(("...Input keypad before was " KEYSYM_FMT "\n", keysym)); 750d522f475Smrg keysym = table[n].after; 751d522f475Smrg TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", keysym)); 752d522f475Smrg break; 753d522f475Smrg } 754d522f475Smrg } 755d522f475Smrg return keysym; 756d522f475Smrg} 757d522f475Smrg#endif /* OPT_SUNPC_KBD */ 758d522f475Smrg 759d522f475Smrg#define VT52_KEYPAD \ 760d522f475Smrg if_OPT_VT52_MODE(screen,{ \ 761d522f475Smrg reply.a_type = ANSI_ESC; \ 762d522f475Smrg reply.a_pintro = '?'; \ 763d522f475Smrg }) 764d522f475Smrg 765d522f475Smrg#define VT52_CURSOR_KEYS \ 766d522f475Smrg if_OPT_VT52_MODE(screen,{ \ 767d522f475Smrg reply.a_type = ANSI_ESC; \ 768d522f475Smrg }) 769d522f475Smrg 770d522f475Smrg#undef APPEND_PARM 771d522f475Smrg#define APPEND_PARM(number) \ 772956cc18dSsnj reply.a_param[reply.a_nparam] = (ParmType) number, \ 773956cc18dSsnj reply.a_nparam++ 774d522f475Smrg 775d522f475Smrg#if OPT_MOD_FKEYS 776d522f475Smrg#define MODIFIER_PARM \ 777956cc18dSsnj if (modify_parm != 0) APPEND_PARM(modify_parm) 778d522f475Smrg#else 779d522f475Smrg#define MODIFIER_PARM /*nothing */ 780d522f475Smrg#endif 781d522f475Smrg 782d522f475Smrg/* 783d522f475Smrg * Determine if we use the \E[3~ sequence for Delete, or the legacy ^?. We 784d522f475Smrg * maintain the delete_is_del value as 3 states: unspecified(2), true and 785d522f475Smrg * false. If unspecified, it is handled differently according to whether the 786d522f475Smrg * legacy keyboard support is enabled, or if xterm emulates a VT220. 787d522f475Smrg * 788d522f475Smrg * Once the user (or application) has specified delete_is_del via resource 789d522f475Smrg * setting, popup menu or escape sequence, it overrides the keyboard type 790d522f475Smrg * rather than the reverse. 791d522f475Smrg */ 792d522f475SmrgBool 793d522f475SmrgxtermDeleteIsDEL(XtermWidget xw) 794d522f475Smrg{ 795d522f475Smrg Bool result = True; 796d522f475Smrg 797d522f475Smrg if (xw->keyboard.type == keyboardIsDefault 798d522f475Smrg || xw->keyboard.type == keyboardIsVT220) 79920d2c4d2Smrg result = (TScreenOf(xw)->delete_is_del == True); 800d522f475Smrg 801d522f475Smrg if (xw->keyboard.type == keyboardIsLegacy) 80220d2c4d2Smrg result = (TScreenOf(xw)->delete_is_del != False); 803d522f475Smrg 804d522f475Smrg TRACE(("xtermDeleteIsDEL(%d/%d) = %d\n", 805d522f475Smrg xw->keyboard.type, 80620d2c4d2Smrg TScreenOf(xw)->delete_is_del, 807d522f475Smrg result)); 808d522f475Smrg 809d522f475Smrg return result; 810d522f475Smrg} 811d522f475Smrg 8120bd37d32Smrgstatic Boolean 81301037d57SmrglookupKeyData(KEY_DATA * kd, XtermWidget xw, XKeyEvent *event) 814d522f475Smrg{ 81520d2c4d2Smrg TScreen *screen = TScreenOf(xw); 8160bd37d32Smrg Boolean result = True; 817f2e35a3aSmrg#if OPT_INPUT_METHOD 8182e4f8982Smrg#if OPT_MOD_FKEYS 8192e4f8982Smrg TKeyboard *keyboard = &(xw->keyboard); 8202e4f8982Smrg#endif 8212e4f8982Smrg#endif 822d522f475Smrg 823913cc679Smrg (void) screen; 824913cc679Smrg 8250bd37d32Smrg TRACE(("%s %#x\n", visibleEventType(event->type), event->keycode)); 826d522f475Smrg 8270bd37d32Smrg kd->keysym = 0; 8280bd37d32Smrg kd->is_fkey = False; 829d522f475Smrg#if OPT_TCAP_QUERY 830d522f475Smrg if (screen->tc_query_code >= 0) { 8310bd37d32Smrg kd->keysym = (KeySym) screen->tc_query_code; 8320bd37d32Smrg kd->is_fkey = screen->tc_query_fkey; 8330bd37d32Smrg if (kd->keysym != XK_BackSpace) { 8340bd37d32Smrg kd->nbytes = 0; 8350bd37d32Smrg kd->strbuf[0] = 0; 836d522f475Smrg } else { 8370bd37d32Smrg kd->nbytes = 1; 8380bd37d32Smrg kd->strbuf[0] = 8; 839d522f475Smrg } 840d522f475Smrg } else 841d522f475Smrg#endif 842d522f475Smrg { 843f2e35a3aSmrg#if OPT_INPUT_METHOD 8440bd37d32Smrg TInput *input = lookupTInput(xw, (Widget) xw); 8450bd37d32Smrg if (input && input->xic) { 846d522f475Smrg Status status_return; 847d522f475Smrg#if OPT_WIDE_CHARS 848d522f475Smrg if (screen->utf8_mode) { 8490bd37d32Smrg kd->nbytes = Xutf8LookupString(input->xic, event, 8500bd37d32Smrg kd->strbuf, (int) sizeof(kd->strbuf), 8510bd37d32Smrg &(kd->keysym), &status_return); 852d522f475Smrg } else 853d522f475Smrg#endif 854d522f475Smrg { 8550bd37d32Smrg kd->nbytes = XmbLookupString(input->xic, event, 8560bd37d32Smrg kd->strbuf, (int) sizeof(kd->strbuf), 8570bd37d32Smrg &(kd->keysym), &status_return); 858d522f475Smrg } 859d522f475Smrg#if OPT_MOD_FKEYS 860d522f475Smrg /* 861d522f475Smrg * Fill-in some code useful with IsControlAlias(): 862d522f475Smrg */ 863d522f475Smrg if (status_return == XLookupBoth 8640bd37d32Smrg && kd->nbytes <= 1 8650bd37d32Smrg && !IsPredefinedKey(kd->keysym) 866d522f475Smrg && (keyboard->modify_now.other_keys > 1) 8670bd37d32Smrg && !IsControlInput(kd)) { 8680bd37d32Smrg kd->nbytes = 1; 8690bd37d32Smrg kd->strbuf[0] = (char) kd->keysym; 870d522f475Smrg } 871d522f475Smrg#endif /* OPT_MOD_FKEYS */ 872d522f475Smrg } else 873f2e35a3aSmrg#endif /* OPT_INPUT_METHOD */ 874d522f475Smrg { 875d522f475Smrg static XComposeStatus compose_status = 876d522f475Smrg {NULL, 0}; 8770bd37d32Smrg kd->nbytes = XLookupString(event, 8780bd37d32Smrg kd->strbuf, (int) sizeof(kd->strbuf), 8790bd37d32Smrg &(kd->keysym), &compose_status); 880d522f475Smrg } 8810bd37d32Smrg kd->is_fkey = IsFunctionKey(kd->keysym); 882d522f475Smrg } 8830bd37d32Smrg return result; 8840bd37d32Smrg} 8850bd37d32Smrg 8860bd37d32Smrgvoid 8870bd37d32SmrgInput(XtermWidget xw, 88801037d57Smrg XKeyEvent *event, 8890bd37d32Smrg Bool eightbit) 8900bd37d32Smrg{ 8910bd37d32Smrg Char *string; 8920bd37d32Smrg 8930bd37d32Smrg TKeyboard *keyboard = &(xw->keyboard); 8940bd37d32Smrg TScreen *screen = TScreenOf(xw); 8950bd37d32Smrg 8960bd37d32Smrg int j; 8970bd37d32Smrg int key = False; 8980bd37d32Smrg ANSI reply; 8990bd37d32Smrg int dec_code; 9000bd37d32Smrg unsigned modify_parm = 0; 9010bd37d32Smrg int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0); 9020bd37d32Smrg unsigned evt_state = event->state; 9030bd37d32Smrg unsigned mod_state; 9040bd37d32Smrg KEY_DATA kd; 9050bd37d32Smrg 9060bd37d32Smrg /* Ignore characters typed at the keyboard */ 9070bd37d32Smrg if (keyboard->flags & MODE_KAM) 9080bd37d32Smrg return; 9090bd37d32Smrg 9100bd37d32Smrg lookupKeyData(&kd, xw, event); 911d522f475Smrg 912d522f475Smrg memset(&reply, 0, sizeof(reply)); 913d522f475Smrg 914f2e35a3aSmrg TRACE(("Input(%d,%d) keysym " 915d522f475Smrg KEYSYM_FMT 916d522f475Smrg ", %d:'%s'%s" FMT_MODIFIER_NAMES "%s%s%s%s%s%s\n", 917f2e35a3aSmrg screen->cur_row, screen->cur_col, 918d522f475Smrg kd.keysym, 919d522f475Smrg kd.nbytes, 920956cc18dSsnj visibleChars((Char *) kd.strbuf, 921d522f475Smrg ((kd.nbytes > 0) 922d522f475Smrg ? (unsigned) kd.nbytes 923d522f475Smrg : 0)), 924d522f475Smrg ARG_MODIFIER_NAMES(evt_state), 925d522f475Smrg eightbit ? " 8bit" : " 7bit", 926d522f475Smrg IsKeypadKey(kd.keysym) ? " KeypadKey" : "", 927d522f475Smrg IsCursorKey(kd.keysym) ? " CursorKey" : "", 928d522f475Smrg IsPFKey(kd.keysym) ? " PFKey" : "", 929d522f475Smrg kd.is_fkey ? " FKey" : "", 930d522f475Smrg IsMiscFunctionKey(kd.keysym) ? " MiscFKey" : "", 9310bd37d32Smrg IsEditFunctionKey(xw, kd.keysym) ? " EditFkey" : "")); 932d522f475Smrg 933d522f475Smrg#if OPT_SUNPC_KBD 934d522f475Smrg /* 935d522f475Smrg * DEC keyboards don't have keypad(+), but do have keypad(,) instead. 936d522f475Smrg * Other (Sun, PC) keyboards commonly have keypad(+), but no keypad(,) 937d522f475Smrg * - it's a pain for users to work around. 938d522f475Smrg */ 939d522f475Smrg if (keyboard->type == keyboardIsVT220 940d522f475Smrg && (evt_state & ShiftMask) == 0) { 941d522f475Smrg if (kd.keysym == XK_KP_Add) { 942d522f475Smrg kd.keysym = XK_KP_Separator; 94320d2c4d2Smrg UIntClr(evt_state, ShiftMask); 944d522f475Smrg TRACE(("...Input keypad(+), change keysym to " 945d522f475Smrg KEYSYM_FMT 946d522f475Smrg "\n", 947d522f475Smrg kd.keysym)); 948d522f475Smrg } 949d522f475Smrg if ((evt_state & ControlMask) != 0 950d522f475Smrg && kd.keysym == XK_KP_Separator) { 951d522f475Smrg kd.keysym = XK_KP_Subtract; 95220d2c4d2Smrg UIntClr(evt_state, ControlMask); 953d522f475Smrg TRACE(("...Input control/keypad(,), change keysym to " 954d522f475Smrg KEYSYM_FMT 955d522f475Smrg "\n", 956d522f475Smrg kd.keysym)); 957d522f475Smrg } 958d522f475Smrg } 959d522f475Smrg#endif 960d522f475Smrg 961d522f475Smrg /* 962d522f475Smrg * The keyboard tables may give us different keypad codes according to 963d522f475Smrg * whether NumLock is pressed. Use this check to simplify the process 964d522f475Smrg * of determining whether we generate an escape sequence for a keypad 965d522f475Smrg * key, or force it to the value kypd_num[]. There is no fixed 966d522f475Smrg * modifier for this feature, so we assume that it is the one assigned 967d522f475Smrg * to the NumLock key. 968d522f475Smrg * 969d522f475Smrg * This check used to try to return the contents of strbuf, but that 970d522f475Smrg * does not work properly when a control modifier is given (trash is 971d522f475Smrg * returned in the buffer in some cases -- perhaps an X bug). 972d522f475Smrg */ 973d522f475Smrg#if OPT_NUM_LOCK 974d522f475Smrg if (kd.nbytes == 1 975d522f475Smrg && IsKeypadKey(kd.keysym) 976d522f475Smrg && xw->misc.real_NumLock 9770bd37d32Smrg && (xw->work.num_lock & evt_state) != 0) { 978d522f475Smrg keypad_mode = 0; 979d522f475Smrg TRACE(("...Input num_lock, force keypad_mode off\n")); 980d522f475Smrg } 981d522f475Smrg#endif 982d522f475Smrg 983d522f475Smrg#if OPT_MOD_FKEYS 984d522f475Smrg if (evt_state != 0 985d522f475Smrg && allowModifierParm(xw, &kd)) { 986d522f475Smrg modify_parm = xtermStateToParam(xw, evt_state); 987d522f475Smrg } 988d522f475Smrg 989d522f475Smrg /* 990d522f475Smrg * Shift-tab is often mapped to XK_ISO_Left_Tab which is classified as 991d522f475Smrg * IsEditFunctionKey(), and the conversion does not produce any bytes. 992d522f475Smrg * Check for this special case so we have data when handling the 993d522f475Smrg * modifyOtherKeys resource. 994d522f475Smrg */ 995d522f475Smrg if (keyboard->modify_now.other_keys > 1) { 996d522f475Smrg if (IsTabKey(kd.keysym) && kd.nbytes == 0) { 997d522f475Smrg kd.nbytes = 1; 998d522f475Smrg kd.strbuf[0] = '\t'; 999d522f475Smrg } 1000d522f475Smrg } 10010bd37d32Smrg#ifdef XK_ISO_Left_Tab 10020bd37d32Smrg else if (IsTabKey(kd.keysym) 10030bd37d32Smrg && kd.nbytes <= 1 10040bd37d32Smrg && modify_parm == (MOD_NONE + MOD_SHIFT)) { 10050bd37d32Smrg kd.keysym = XK_ISO_Left_Tab; 10060bd37d32Smrg } 10070bd37d32Smrg#endif 1008d522f475Smrg#endif /* OPT_MOD_FKEYS */ 1009d522f475Smrg 1010d522f475Smrg /* VT300 & up: backarrow toggle */ 1011d522f475Smrg if ((kd.nbytes == 1) 1012d522f475Smrg && IsBackarrowToggle(keyboard, kd.keysym, evt_state)) { 1013d522f475Smrg kd.strbuf[0] = ANSI_DEL; 1014d522f475Smrg TRACE(("...Input backarrow changed to %d\n", kd.strbuf[0])); 1015d522f475Smrg } 1016d522f475Smrg#if OPT_SUNPC_KBD 1017d522f475Smrg /* make an DEC editing-keypad from a Sun or PC editing-keypad */ 1018d522f475Smrg if (keyboard->type == keyboardIsVT220 1019d522f475Smrg && (kd.keysym != XK_Delete || !xtermDeleteIsDEL(xw))) 1020d522f475Smrg kd.keysym = TranslateFromSUNPC(kd.keysym); 1021d522f475Smrg else 1022d522f475Smrg#endif 1023d522f475Smrg { 1024d522f475Smrg#ifdef XK_KP_Home 1025d522f475Smrg if (kd.keysym >= XK_KP_Home && kd.keysym <= XK_KP_Begin) { 1026d522f475Smrg TRACE(("...Input keypad before was " KEYSYM_FMT "\n", kd.keysym)); 10274e40088cSchristos kd.keysym += (KeySym) (XK_Home - XK_KP_Home); 1028d522f475Smrg TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", kd.keysym)); 1029d522f475Smrg } 1030d522f475Smrg#endif 1031d522f475Smrg } 1032d522f475Smrg 1033d522f475Smrg /* 1034d522f475Smrg * Map the Sun afterthought-keys in as F36 and F37. 1035d522f475Smrg */ 1036d522f475Smrg#ifdef SunXK_F36 1037d522f475Smrg if (!kd.is_fkey) { 1038d522f475Smrg if (kd.keysym == SunXK_F36) { 1039d522f475Smrg kd.keysym = XK_Fn(36); 1040d522f475Smrg kd.is_fkey = True; 1041d522f475Smrg } 1042d522f475Smrg if (kd.keysym == SunXK_F37) { 1043d522f475Smrg kd.keysym = XK_Fn(37); 1044d522f475Smrg kd.is_fkey = True; 1045d522f475Smrg } 1046d522f475Smrg } 1047d522f475Smrg#endif 1048d522f475Smrg 1049d522f475Smrg /* 1050d522f475Smrg * Use the control- and shift-modifiers to obtain more function keys than 1051d522f475Smrg * the keyboard provides. We can do this if there is no conflicting use of 1052d522f475Smrg * those modifiers: 1053d522f475Smrg * 1054d522f475Smrg * a) for VT220 keyboard, we use only the control-modifier. The keyboard 1055d522f475Smrg * uses shift-modifier for UDK's. 1056d522f475Smrg * 1057d522f475Smrg * b) for non-VT220 keyboards, we only have to check if the 1058d522f475Smrg * modifyFunctionKeys resource is inactive. 1059d522f475Smrg * 1060d522f475Smrg * Thereafter, we note when we have a function-key and keep that 1061d522f475Smrg * distinction when testing for "function-key" values. 1062d522f475Smrg */ 1063d522f475Smrg if ((evt_state & (ControlMask | ShiftMask)) != 0 1064d522f475Smrg && kd.is_fkey) { 1065d522f475Smrg 1066d522f475Smrg /* VT220 keyboard uses shift for UDK */ 1067d522f475Smrg if (keyboard->type == keyboardIsVT220 1068d522f475Smrg || keyboard->type == keyboardIsLegacy) { 1069d522f475Smrg 1070d522f475Smrg TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1)); 1071d522f475Smrg if (evt_state & ControlMask) { 10722eaa94a1Schristos kd.keysym += (KeySym) xw->misc.ctrl_fkeys; 107320d2c4d2Smrg UIntClr(evt_state, ControlMask); 1074d522f475Smrg } 1075d522f475Smrg TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1)); 1076d522f475Smrg 1077d522f475Smrg } 1078d522f475Smrg#if OPT_MOD_FKEYS 1079d522f475Smrg else if (keyboard->modify_now.function_keys < 0) { 1080d522f475Smrg 1081d522f475Smrg TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1)); 1082d522f475Smrg if (evt_state & ShiftMask) { 10832eaa94a1Schristos kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 1); 108420d2c4d2Smrg UIntClr(evt_state, ShiftMask); 1085d522f475Smrg } 1086d522f475Smrg if (evt_state & ControlMask) { 10872eaa94a1Schristos kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 2); 108820d2c4d2Smrg UIntClr(evt_state, ControlMask); 1089d522f475Smrg } 1090d522f475Smrg TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1)); 1091d522f475Smrg 1092d522f475Smrg } 1093d522f475Smrg /* 1094d522f475Smrg * Reevaluate the modifier parameter, stripping off the modifiers 1095d522f475Smrg * that we just used. 1096d522f475Smrg */ 10970bd37d32Smrg if (modify_parm) { 1098d522f475Smrg modify_parm = xtermStateToParam(xw, evt_state); 10990bd37d32Smrg } 1100d522f475Smrg#endif /* OPT_MOD_FKEYS */ 1101d522f475Smrg } 1102d522f475Smrg 1103d522f475Smrg /* 1104d522f475Smrg * Test for one of the keyboard variants. 1105d522f475Smrg */ 1106d522f475Smrg switch (keyboard->type) { 1107d522f475Smrg case keyboardIsHP: 1108d522f475Smrg hpfuncvalue(&reply, &kd); 1109d522f475Smrg break; 1110d522f475Smrg case keyboardIsSCO: 1111d522f475Smrg scofuncvalue(&reply, &kd); 1112d522f475Smrg break; 1113d522f475Smrg case keyboardIsSun: 1114d522f475Smrg sunfuncvalue(&reply, &kd); 1115d522f475Smrg break; 1116d522f475Smrg case keyboardIsTermcap: 1117d522f475Smrg#if OPT_TCAP_FKEYS 1118d522f475Smrg if (xtermcapString(xw, (int) kd.keysym, evt_state)) 1119d522f475Smrg return; 1120d522f475Smrg#endif 1121d522f475Smrg break; 1122d522f475Smrg case keyboardIsDefault: 1123d522f475Smrg case keyboardIsLegacy: 1124d522f475Smrg case keyboardIsVT220: 1125d522f475Smrg break; 1126d522f475Smrg } 1127d522f475Smrg 1128d522f475Smrg if (reply.a_final) { 1129d522f475Smrg /* 1130d522f475Smrg * The key symbol matches one of the variants. Most of those are 1131d522f475Smrg * function-keys, though some cursor- and editing-keys are mixed in. 1132d522f475Smrg */ 1133d522f475Smrg modifyCursorKey(&reply, 1134d522f475Smrg ((kd.is_fkey 1135d522f475Smrg || IsMiscFunctionKey(kd.keysym) 11360bd37d32Smrg || IsEditFunctionKey(xw, kd.keysym)) 1137d522f475Smrg ? keyboard->modify_now.function_keys 1138d522f475Smrg : keyboard->modify_now.cursor_keys), 1139d522f475Smrg &modify_parm); 1140d522f475Smrg MODIFIER_PARM; 1141d522f475Smrg unparseseq(xw, &reply); 1142d522f475Smrg } else if (((kd.is_fkey 1143d522f475Smrg || IsMiscFunctionKey(kd.keysym) 11440bd37d32Smrg || IsEditFunctionKey(xw, kd.keysym)) 1145d522f475Smrg#if OPT_MOD_FKEYS 1146d522f475Smrg && !ModifyOtherKeys(xw, evt_state, &kd, modify_parm) 1147d522f475Smrg#endif 1148d522f475Smrg ) || (kd.keysym == XK_Delete 1149956cc18dSsnj && ((modify_parm != 0) 1150d522f475Smrg || !xtermDeleteIsDEL(xw)))) { 1151d522f475Smrg dec_code = decfuncvalue(&kd); 1152d522f475Smrg if ((evt_state & ShiftMask) 1153d522f475Smrg#if OPT_SUNPC_KBD 1154d522f475Smrg && keyboard->type == keyboardIsVT220 1155d522f475Smrg#endif 1156894e0ac8Smrg && ((string = (Char *) udk_lookup(xw, dec_code, &kd.nbytes)) != 0)) { 1157f2e35a3aSmrg /* UIntClr(evt_state, ShiftMask); */ 1158d522f475Smrg while (kd.nbytes-- > 0) 1159d522f475Smrg unparseputc(xw, CharOf(*string++)); 1160d522f475Smrg } 1161d522f475Smrg /* 1162d522f475Smrg * Interpret F1-F4 as PF1-PF4 for VT52, VT100 1163d522f475Smrg */ 1164d522f475Smrg else if (keyboard->type != keyboardIsLegacy 1165d522f475Smrg && (dec_code >= 11 && dec_code <= 14)) { 1166d522f475Smrg reply.a_type = ANSI_SS3; 1167d522f475Smrg VT52_CURSOR_KEYS; 11682eaa94a1Schristos reply.a_final = (Char) A2E(dec_code - 11 + E2A('P')); 1169d522f475Smrg modifyCursorKey(&reply, 1170d522f475Smrg keyboard->modify_now.function_keys, 1171d522f475Smrg &modify_parm); 1172d522f475Smrg MODIFIER_PARM; 1173d522f475Smrg unparseseq(xw, &reply); 1174956cc18dSsnj } else { 1175d522f475Smrg reply.a_type = ANSI_CSI; 1176d522f475Smrg reply.a_final = 0; 1177d522f475Smrg 1178d522f475Smrg#ifdef XK_ISO_Left_Tab 1179d522f475Smrg if (kd.keysym == XK_ISO_Left_Tab) { 1180d522f475Smrg reply.a_nparam = 0; 1181d522f475Smrg reply.a_final = 'Z'; 1182d522f475Smrg#if OPT_MOD_FKEYS 1183d522f475Smrg if (keyboard->modify_now.other_keys > 1 1184956cc18dSsnj && computeMaskedModifier(xw, evt_state, ShiftMask)) 1185d522f475Smrg modifyOtherKey(&reply, '\t', modify_parm, keyboard->format_keys); 1186d522f475Smrg#endif 1187d522f475Smrg } else 1188d522f475Smrg#endif /* XK_ISO_Left_Tab */ 1189d522f475Smrg { 1190d522f475Smrg reply.a_nparam = 1; 1191d522f475Smrg#if OPT_MOD_FKEYS 1192d522f475Smrg if (kd.is_fkey) { 1193d522f475Smrg modifyCursorKey(&reply, 1194d522f475Smrg keyboard->modify_now.function_keys, 1195d522f475Smrg &modify_parm); 1196d522f475Smrg } 1197d522f475Smrg MODIFIER_PARM; 1198d522f475Smrg#endif 1199956cc18dSsnj reply.a_param[0] = (ParmType) dec_code; 1200d522f475Smrg reply.a_final = '~'; 1201d522f475Smrg } 1202d522f475Smrg if (reply.a_final != 0 1203d522f475Smrg && (reply.a_nparam == 0 || reply.a_param[0] >= 0)) 1204d522f475Smrg unparseseq(xw, &reply); 1205d522f475Smrg } 1206d522f475Smrg key = True; 1207d522f475Smrg } else if (IsPFKey(kd.keysym)) { 1208d522f475Smrg reply.a_type = ANSI_SS3; 12092eaa94a1Schristos reply.a_final = (Char) ((kd.keysym - XK_KP_F1) + 'P'); 1210d522f475Smrg VT52_CURSOR_KEYS; 1211d522f475Smrg MODIFIER_PARM; 1212d522f475Smrg unparseseq(xw, &reply); 1213d522f475Smrg key = True; 1214d522f475Smrg } else if (IsKeypadKey(kd.keysym)) { 1215d522f475Smrg if (keypad_mode) { 1216d522f475Smrg reply.a_type = ANSI_SS3; 12172eaa94a1Schristos reply.a_final = (Char) (kypd_apl[kd.keysym - XK_KP_Space]); 1218d522f475Smrg VT52_KEYPAD; 1219d522f475Smrg MODIFIER_PARM; 1220d522f475Smrg unparseseq(xw, &reply); 1221d522f475Smrg } else { 1222d522f475Smrg unparseputc(xw, kypd_num[kd.keysym - XK_KP_Space]); 1223d522f475Smrg } 1224d522f475Smrg key = True; 1225d522f475Smrg } else if (IsCursorKey(kd.keysym)) { 1226d522f475Smrg if (keyboard->flags & MODE_DECCKM) { 1227d522f475Smrg reply.a_type = ANSI_SS3; 1228d522f475Smrg } else { 1229d522f475Smrg reply.a_type = ANSI_CSI; 1230d522f475Smrg } 1231d522f475Smrg modifyCursorKey(&reply, keyboard->modify_now.cursor_keys, &modify_parm); 12322eaa94a1Schristos reply.a_final = (Char) (curfinal[kd.keysym - XK_Home]); 1233d522f475Smrg VT52_CURSOR_KEYS; 1234d522f475Smrg MODIFIER_PARM; 1235d522f475Smrg unparseseq(xw, &reply); 1236d522f475Smrg key = True; 1237d522f475Smrg } else if (kd.nbytes > 0) { 1238d522f475Smrg 1239d522f475Smrg#if OPT_TEK4014 1240d522f475Smrg if (TEK4014_GIN(tekWidget)) { 1241d522f475Smrg TekEnqMouse(tekWidget, kd.strbuf[0]); 1242d522f475Smrg TekGINoff(tekWidget); 1243d522f475Smrg kd.nbytes--; 1244d522f475Smrg for (j = 0; j < kd.nbytes; ++j) { 1245d522f475Smrg kd.strbuf[j] = kd.strbuf[j + 1]; 1246d522f475Smrg } 1247d522f475Smrg } 1248d522f475Smrg#endif 1249d522f475Smrg#if OPT_MOD_FKEYS 1250d522f475Smrg if ((keyboard->modify_now.other_keys > 0) 1251d522f475Smrg && ModifyOtherKeys(xw, evt_state, &kd, modify_parm) 1252d522f475Smrg && (mod_state = allowedCharModifiers(xw, evt_state, &kd)) != 0) { 1253d522f475Smrg int input_char; 1254d522f475Smrg 1255d522f475Smrg evt_state = mod_state; 1256d522f475Smrg 1257d522f475Smrg modify_parm = xtermStateToParam(xw, evt_state); 1258d522f475Smrg 1259d522f475Smrg /* 1260d522f475Smrg * We want to show a keycode that corresponds to the 8-bit value 1261d522f475Smrg * of the key. If the keysym is less than 256, that is good 1262d522f475Smrg * enough. Special keys such as Tab may result in a value that 1263d522f475Smrg * is usable as well. For the latter (special cases), try to use 1264d522f475Smrg * the result from the X library lookup. 1265d522f475Smrg */ 1266d522f475Smrg input_char = ((kd.keysym < 256) 1267d522f475Smrg ? (int) kd.keysym 1268d522f475Smrg : ((kd.nbytes == 1) 1269d522f475Smrg ? CharOf(kd.strbuf[0]) 1270d522f475Smrg : -1)); 1271d522f475Smrg 1272d522f475Smrg TRACE(("...modifyOtherKeys %d;%d\n", modify_parm, input_char)); 1273d522f475Smrg if (modifyOtherKey(&reply, input_char, modify_parm, keyboard->format_keys)) { 1274d522f475Smrg unparseseq(xw, &reply); 1275d522f475Smrg } else { 127620d2c4d2Smrg Bell(xw, XkbBI_MinorError, 0); 1277d522f475Smrg } 1278d522f475Smrg } else 1279d522f475Smrg#endif /* OPT_MOD_FKEYS */ 1280d522f475Smrg { 12812e4f8982Smrg int prefix = 0; 12822e4f8982Smrg 1283d522f475Smrg#if OPT_NUM_LOCK 1284d522f475Smrg /* 1285d522f475Smrg * Send ESC if we have a META modifier and metaSendsEcape is true. 1286d522f475Smrg * Like eightBitInput, except that it is not associated with 1287d522f475Smrg * terminal settings. 1288d522f475Smrg */ 1289d522f475Smrg if (kd.nbytes != 0) { 1290d522f475Smrg if (screen->meta_sends_esc 12910bd37d32Smrg && (evt_state & xw->work.meta_mods) != 0) { 1292d522f475Smrg TRACE(("...input-char is modified by META\n")); 12930bd37d32Smrg UIntClr(evt_state, xw->work.meta_mods); 1294d522f475Smrg eightbit = False; 1295d522f475Smrg prefix = ANSI_ESC; 1296d522f475Smrg } else if (eightbit) { 1297d522f475Smrg /* it might be overridden, but this helps for debugging */ 1298d522f475Smrg TRACE(("...input-char is shifted by META\n")); 1299d522f475Smrg } 1300d522f475Smrg if (screen->alt_is_not_meta 13010bd37d32Smrg && (evt_state & xw->work.alt_mods) != 0) { 13020bd37d32Smrg UIntClr(evt_state, xw->work.alt_mods); 1303d522f475Smrg if (screen->alt_sends_esc) { 1304d522f475Smrg TRACE(("...input-char is modified by ALT\n")); 13052eaa94a1Schristos eightbit = False; 1306d522f475Smrg prefix = ANSI_ESC; 1307d522f475Smrg } else if (!eightbit) { 1308d522f475Smrg TRACE(("...input-char is shifted by ALT\n")); 1309d522f475Smrg eightbit = True; 1310d522f475Smrg } 1311d522f475Smrg } 1312d522f475Smrg } 1313d522f475Smrg#endif 1314d522f475Smrg /* 1315d522f475Smrg * If metaSendsEscape is false, fall through to this chunk, which 1316d522f475Smrg * implements the eightBitInput resource. 1317d522f475Smrg * 1318d522f475Smrg * It is normally executed when the user presses Meta plus a 1319d522f475Smrg * printable key, e.g., Meta+space. The presence of the Meta 1320d522f475Smrg * modifier is not guaranteed since what really happens is the 1321d522f475Smrg * "insert-eight-bit" or "insert-seven-bit" action, which we 1322d522f475Smrg * distinguish by the eightbit parameter to this function. So the 1323d522f475Smrg * eightBitInput resource really means that we use this shifting 1324d522f475Smrg * logic in the "insert-eight-bit" action. 1325d522f475Smrg */ 1326d522f475Smrg if (eightbit && (kd.nbytes == 1) && screen->input_eight_bits) { 1327d522f475Smrg IChar ch = CharOf(kd.strbuf[0]); 13280bd37d32Smrg if ((ch < 128) && (screen->eight_bit_meta == ebTrue)) { 13292eaa94a1Schristos kd.strbuf[0] |= (char) 0x80; 1330d522f475Smrg TRACE(("...input shift from %d to %d (%#x to %#x)\n", 1331d522f475Smrg ch, CharOf(kd.strbuf[0]), 1332d522f475Smrg ch, CharOf(kd.strbuf[0]))); 1333d522f475Smrg#if OPT_WIDE_CHARS 1334d522f475Smrg if (screen->utf8_mode) { 1335d522f475Smrg /* 1336d522f475Smrg * We could interpret the incoming code as "in the 1337d522f475Smrg * current locale", but it's simpler to treat it as 1338d522f475Smrg * a Unicode value to translate to UTF-8. 1339d522f475Smrg */ 1340d522f475Smrg ch = CharOf(kd.strbuf[0]); 1341d522f475Smrg kd.nbytes = 2; 13422eaa94a1Schristos kd.strbuf[0] = (char) (0xc0 | ((ch >> 6) & 0x3)); 13432eaa94a1Schristos kd.strbuf[1] = (char) (0x80 | (ch & 0x3f)); 1344d522f475Smrg TRACE(("...encoded %#x in UTF-8 as %#x,%#x\n", 1345d522f475Smrg ch, CharOf(kd.strbuf[0]), CharOf(kd.strbuf[1]))); 1346d522f475Smrg } 1347d522f475Smrg#endif 1348d522f475Smrg } 1349d522f475Smrg eightbit = False; 1350d522f475Smrg } 1351d522f475Smrg#if OPT_WIDE_CHARS 1352d522f475Smrg if (kd.nbytes == 1) /* cannot do NRC on UTF-8, for instance */ 1353d522f475Smrg#endif 1354d522f475Smrg { 1355d522f475Smrg /* VT220 & up: National Replacement Characters */ 1356d522f475Smrg if ((xw->flags & NATIONAL) != 0) { 1357f2e35a3aSmrg unsigned cmp = xtermCharSetIn(xw, 1358e0a2b6dfSmrg CharOf(kd.strbuf[0]), 1359f2e35a3aSmrg (DECNRCM_codes) 13602eaa94a1Schristos screen->keyboard_dialect[0]); 1361d522f475Smrg TRACE(("...input NRC %d, %s %d\n", 1362d522f475Smrg CharOf(kd.strbuf[0]), 1363d522f475Smrg (CharOf(kd.strbuf[0]) == cmp) 1364d522f475Smrg ? "unchanged" 1365d522f475Smrg : "changed to", 1366d522f475Smrg CharOf(cmp))); 13672eaa94a1Schristos kd.strbuf[0] = (char) cmp; 1368d522f475Smrg } else if (eightbit) { 1369d522f475Smrg prefix = ANSI_ESC; 1370d522f475Smrg } else if (kd.strbuf[0] == '?' 1371d522f475Smrg && (evt_state & ControlMask) != 0) { 1372d522f475Smrg kd.strbuf[0] = ANSI_DEL; 1373d522f475Smrg } 1374d522f475Smrg } 1375d522f475Smrg if (prefix != 0) 1376d522f475Smrg unparseputc(xw, prefix); /* escape */ 1377d522f475Smrg for (j = 0; j < kd.nbytes; ++j) 1378d522f475Smrg unparseputc(xw, CharOf(kd.strbuf[j])); 1379d522f475Smrg } 138020d2c4d2Smrg key = ((kd.keysym != ANSI_XOFF) && (kd.keysym != ANSI_XON)); 1381d522f475Smrg } 1382d522f475Smrg unparse_end(xw); 1383d522f475Smrg 1384d522f475Smrg if (key && !TEK4014_ACTIVE(xw)) 1385d522f475Smrg AdjustAfterInput(xw); 1386d522f475Smrg 1387d522f475Smrg xtermShowPointer(xw, False); 1388d522f475Smrg return; 1389d522f475Smrg} 1390d522f475Smrg 1391d522f475Smrgvoid 1392e0a2b6dfSmrgStringInput(XtermWidget xw, const Char *string, size_t nbytes) 1393d522f475Smrg{ 139420d2c4d2Smrg TRACE(("InputString (%s,%lu)\n", 139520d2c4d2Smrg visibleChars(string, (unsigned) nbytes), 139620d2c4d2Smrg (unsigned long) nbytes)); 1397d522f475Smrg#if OPT_TEK4014 1398d522f475Smrg if (nbytes && TEK4014_GIN(tekWidget)) { 1399d522f475Smrg TekEnqMouse(tekWidget, *string++); 1400d522f475Smrg TekGINoff(tekWidget); 1401d522f475Smrg nbytes--; 1402d522f475Smrg } 1403d522f475Smrg#endif 1404d522f475Smrg while (nbytes-- != 0) 1405d522f475Smrg unparseputc(xw, *string++); 1406d522f475Smrg if (!TEK4014_ACTIVE(xw)) 1407d522f475Smrg AdjustAfterInput(xw); 1408d522f475Smrg unparse_end(xw); 1409d522f475Smrg} 1410d522f475Smrg 1411d522f475Smrg/* These definitions are DEC-style (e.g., vt320) */ 1412d522f475Smrgstatic int 1413d522f475Smrgdecfuncvalue(KEY_DATA * kd) 1414d522f475Smrg{ 1415d522f475Smrg int result; 1416d522f475Smrg 1417d522f475Smrg if (kd->is_fkey) { 1418d522f475Smrg switch (kd->keysym) { 1419d522f475Smrg MAP(XK_Fn(1), 11); 1420d522f475Smrg MAP(XK_Fn(2), 12); 1421d522f475Smrg MAP(XK_Fn(3), 13); 1422d522f475Smrg MAP(XK_Fn(4), 14); 1423d522f475Smrg MAP(XK_Fn(5), 15); 1424d522f475Smrg MAP(XK_Fn(6), 17); 1425d522f475Smrg MAP(XK_Fn(7), 18); 1426d522f475Smrg MAP(XK_Fn(8), 19); 1427d522f475Smrg MAP(XK_Fn(9), 20); 1428d522f475Smrg MAP(XK_Fn(10), 21); 1429d522f475Smrg MAP(XK_Fn(11), 23); 1430d522f475Smrg MAP(XK_Fn(12), 24); 1431d522f475Smrg MAP(XK_Fn(13), 25); 1432d522f475Smrg MAP(XK_Fn(14), 26); 1433d522f475Smrg MAP(XK_Fn(15), 28); 1434d522f475Smrg MAP(XK_Fn(16), 29); 1435d522f475Smrg MAP(XK_Fn(17), 31); 1436d522f475Smrg MAP(XK_Fn(18), 32); 1437d522f475Smrg MAP(XK_Fn(19), 33); 1438d522f475Smrg MAP(XK_Fn(20), 34); 1439d522f475Smrg default: 1440d522f475Smrg /* after F20 the codes are made up and do not correspond to any 1441d522f475Smrg * real terminal. So they are simply numbered sequentially. 1442d522f475Smrg */ 14432eaa94a1Schristos result = 42 + (int) (kd->keysym - XK_Fn(21)); 1444d522f475Smrg break; 1445d522f475Smrg } 1446d522f475Smrg } else { 1447d522f475Smrg switch (kd->keysym) { 1448d522f475Smrg MAP(XK_Find, 1); 1449d522f475Smrg MAP(XK_Insert, 2); 1450d522f475Smrg MAP(XK_Delete, 3); 1451d522f475Smrg#ifdef XK_KP_Insert 1452d522f475Smrg MAP(XK_KP_Insert, 2); 1453d522f475Smrg MAP(XK_KP_Delete, 3); 1454d522f475Smrg#endif 1455d522f475Smrg#ifdef DXK_Remove 1456d522f475Smrg MAP(DXK_Remove, 3); 1457d522f475Smrg#endif 1458d522f475Smrg MAP(XK_Select, 4); 1459d522f475Smrg MAP(XK_Prior, 5); 1460d522f475Smrg MAP(XK_Next, 6); 1461d522f475Smrg#ifdef XK_ISO_Left_Tab 1462d522f475Smrg MAP(XK_ISO_Left_Tab, 'Z'); 1463d522f475Smrg#endif 1464d522f475Smrg MAP(XK_Help, 28); 1465d522f475Smrg MAP(XK_Menu, 29); 1466d522f475Smrg default: 1467d522f475Smrg result = -1; 1468d522f475Smrg break; 1469d522f475Smrg } 1470d522f475Smrg } 1471d522f475Smrg return result; 1472d522f475Smrg} 1473d522f475Smrg 1474d522f475Smrgstatic void 1475e0a2b6dfSmrghpfuncvalue(ANSI *reply, KEY_DATA * kd) 1476d522f475Smrg{ 1477d522f475Smrg#if OPT_HP_FUNC_KEYS 1478d522f475Smrg int result; 1479d522f475Smrg 1480d522f475Smrg if (kd->is_fkey) { 1481d522f475Smrg switch (kd->keysym) { 1482d522f475Smrg MAP(XK_Fn(1), 'p'); 1483d522f475Smrg MAP(XK_Fn(2), 'q'); 1484d522f475Smrg MAP(XK_Fn(3), 'r'); 1485d522f475Smrg MAP(XK_Fn(4), 's'); 1486d522f475Smrg MAP(XK_Fn(5), 't'); 1487d522f475Smrg MAP(XK_Fn(6), 'u'); 1488d522f475Smrg MAP(XK_Fn(7), 'v'); 1489d522f475Smrg MAP(XK_Fn(8), 'w'); 1490d522f475Smrg default: 1491d522f475Smrg result = -1; 1492d522f475Smrg break; 1493d522f475Smrg } 1494d522f475Smrg } else { 1495d522f475Smrg switch (kd->keysym) { 1496d522f475Smrg MAP(XK_Up, 'A'); 1497d522f475Smrg MAP(XK_Down, 'B'); 1498d522f475Smrg MAP(XK_Right, 'C'); 1499d522f475Smrg MAP(XK_Left, 'D'); 1500d522f475Smrg MAP(XK_End, 'F'); 1501d522f475Smrg MAP(XK_Clear, 'J'); 1502d522f475Smrg MAP(XK_Delete, 'P'); 1503d522f475Smrg MAP(XK_Insert, 'Q'); 1504d522f475Smrg MAP(XK_Next, 'S'); 1505d522f475Smrg MAP(XK_Prior, 'T'); 1506d522f475Smrg MAP(XK_Home, 'h'); 1507d522f475Smrg#ifdef XK_KP_Insert 1508d522f475Smrg MAP(XK_KP_Delete, 'P'); 1509d522f475Smrg MAP(XK_KP_Insert, 'Q'); 1510d522f475Smrg#endif 1511d522f475Smrg#ifdef DXK_Remove 1512d522f475Smrg MAP(DXK_Remove, 'P'); 1513d522f475Smrg#endif 1514d522f475Smrg MAP(XK_Select, 'F'); 1515d522f475Smrg MAP(XK_Find, 'h'); 1516d522f475Smrg default: 1517d522f475Smrg result = -1; 1518d522f475Smrg break; 1519d522f475Smrg } 1520d522f475Smrg } 1521d522f475Smrg if (result > 0) { 1522d522f475Smrg reply->a_type = ANSI_ESC; 15232eaa94a1Schristos reply->a_final = (Char) result; 1524d522f475Smrg } 1525d522f475Smrg#else 1526d522f475Smrg (void) reply; 1527d522f475Smrg (void) kd; 1528d522f475Smrg#endif /* OPT_HP_FUNC_KEYS */ 1529d522f475Smrg} 1530d522f475Smrg 1531d522f475Smrgstatic void 1532e0a2b6dfSmrgscofuncvalue(ANSI *reply, KEY_DATA * kd) 1533d522f475Smrg{ 1534d522f475Smrg#if OPT_SCO_FUNC_KEYS 1535d522f475Smrg int result; 1536d522f475Smrg 1537d522f475Smrg if (kd->is_fkey) { 1538d522f475Smrg switch (kd->keysym) { 1539d522f475Smrg MAP(XK_Fn(1), 'M'); 1540d522f475Smrg MAP(XK_Fn(2), 'N'); 1541d522f475Smrg MAP(XK_Fn(3), 'O'); 1542d522f475Smrg MAP(XK_Fn(4), 'P'); 1543d522f475Smrg MAP(XK_Fn(5), 'Q'); 1544d522f475Smrg MAP(XK_Fn(6), 'R'); 1545d522f475Smrg MAP(XK_Fn(7), 'S'); 1546d522f475Smrg MAP(XK_Fn(8), 'T'); 1547d522f475Smrg MAP(XK_Fn(9), 'U'); 1548d522f475Smrg MAP(XK_Fn(10), 'V'); 1549d522f475Smrg MAP(XK_Fn(11), 'W'); 1550d522f475Smrg MAP(XK_Fn(12), 'X'); 1551d522f475Smrg MAP(XK_Fn(13), 'Y'); 1552d522f475Smrg MAP(XK_Fn(14), 'Z'); 1553d522f475Smrg MAP(XK_Fn(15), 'a'); 1554d522f475Smrg MAP(XK_Fn(16), 'b'); 1555d522f475Smrg MAP(XK_Fn(17), 'c'); 1556d522f475Smrg MAP(XK_Fn(18), 'd'); 1557d522f475Smrg MAP(XK_Fn(19), 'e'); 1558d522f475Smrg MAP(XK_Fn(20), 'f'); 1559d522f475Smrg MAP(XK_Fn(21), 'g'); 1560d522f475Smrg MAP(XK_Fn(22), 'h'); 1561d522f475Smrg MAP(XK_Fn(23), 'i'); 1562d522f475Smrg MAP(XK_Fn(24), 'j'); 1563d522f475Smrg MAP(XK_Fn(25), 'k'); 1564d522f475Smrg MAP(XK_Fn(26), 'l'); 1565d522f475Smrg MAP(XK_Fn(27), 'm'); 1566d522f475Smrg MAP(XK_Fn(28), 'n'); 1567d522f475Smrg MAP(XK_Fn(29), 'o'); 1568d522f475Smrg MAP(XK_Fn(30), 'p'); 1569d522f475Smrg MAP(XK_Fn(31), 'q'); 1570d522f475Smrg MAP(XK_Fn(32), 'r'); 1571d522f475Smrg MAP(XK_Fn(33), 's'); 1572d522f475Smrg MAP(XK_Fn(34), 't'); 1573d522f475Smrg MAP(XK_Fn(35), 'u'); 1574d522f475Smrg MAP(XK_Fn(36), 'v'); 1575d522f475Smrg MAP(XK_Fn(37), 'w'); 1576d522f475Smrg MAP(XK_Fn(38), 'x'); 1577d522f475Smrg MAP(XK_Fn(39), 'y'); 1578d522f475Smrg MAP(XK_Fn(40), 'z'); 1579d522f475Smrg MAP(XK_Fn(41), '@'); 1580d522f475Smrg MAP(XK_Fn(42), '['); 1581d522f475Smrg MAP(XK_Fn(43), '\\'); 1582d522f475Smrg MAP(XK_Fn(44), ']'); 1583d522f475Smrg MAP(XK_Fn(45), '^'); 1584d522f475Smrg MAP(XK_Fn(46), '_'); 1585d522f475Smrg MAP(XK_Fn(47), '`'); 158601037d57Smrg MAP(XK_Fn(48), L_CURL); 1587d522f475Smrg default: 1588d522f475Smrg result = -1; 1589d522f475Smrg break; 1590d522f475Smrg } 1591d522f475Smrg } else { 1592d522f475Smrg switch (kd->keysym) { 1593d522f475Smrg MAP(XK_Up, 'A'); 1594d522f475Smrg MAP(XK_Down, 'B'); 1595d522f475Smrg MAP(XK_Right, 'C'); 1596d522f475Smrg MAP(XK_Left, 'D'); 1597d522f475Smrg MAP(XK_Begin, 'E'); 1598d522f475Smrg MAP(XK_End, 'F'); 1599d522f475Smrg MAP(XK_Insert, 'L'); 1600d522f475Smrg MAP(XK_Next, 'G'); 1601d522f475Smrg MAP(XK_Prior, 'I'); 1602d522f475Smrg MAP(XK_Home, 'H'); 1603d522f475Smrg#ifdef XK_KP_Insert 1604d522f475Smrg MAP(XK_KP_Insert, 'L'); 1605d522f475Smrg#endif 1606d522f475Smrg default: 1607d522f475Smrg result = -1; 1608d522f475Smrg break; 1609d522f475Smrg } 1610d522f475Smrg } 1611d522f475Smrg if (result > 0) { 1612d522f475Smrg reply->a_type = ANSI_CSI; 16132eaa94a1Schristos reply->a_final = (Char) result; 1614d522f475Smrg } 1615d522f475Smrg#else 1616d522f475Smrg (void) reply; 1617d522f475Smrg (void) kd; 1618d522f475Smrg#endif /* OPT_SCO_FUNC_KEYS */ 1619d522f475Smrg} 1620d522f475Smrg 1621d522f475Smrgstatic void 1622e0a2b6dfSmrgsunfuncvalue(ANSI *reply, KEY_DATA * kd) 1623d522f475Smrg{ 1624d522f475Smrg#if OPT_SUN_FUNC_KEYS 1625956cc18dSsnj ParmType result; 1626d522f475Smrg 1627d522f475Smrg if (kd->is_fkey) { 1628d522f475Smrg switch (kd->keysym) { 1629d522f475Smrg /* kf1-kf20 are numbered sequentially */ 1630d522f475Smrg MAP(XK_Fn(1), 224); 1631d522f475Smrg MAP(XK_Fn(2), 225); 1632d522f475Smrg MAP(XK_Fn(3), 226); 1633d522f475Smrg MAP(XK_Fn(4), 227); 1634d522f475Smrg MAP(XK_Fn(5), 228); 1635d522f475Smrg MAP(XK_Fn(6), 229); 1636d522f475Smrg MAP(XK_Fn(7), 230); 1637d522f475Smrg MAP(XK_Fn(8), 231); 1638d522f475Smrg MAP(XK_Fn(9), 232); 1639d522f475Smrg MAP(XK_Fn(10), 233); 1640d522f475Smrg MAP(XK_Fn(11), 192); 1641d522f475Smrg MAP(XK_Fn(12), 193); 1642d522f475Smrg MAP(XK_Fn(13), 194); 1643d522f475Smrg MAP(XK_Fn(14), 195); /* kund */ 1644d522f475Smrg MAP(XK_Fn(15), 196); 1645d522f475Smrg MAP(XK_Fn(16), 197); /* kcpy */ 1646d522f475Smrg MAP(XK_Fn(17), 198); 1647d522f475Smrg MAP(XK_Fn(18), 199); 1648d522f475Smrg MAP(XK_Fn(19), 200); /* kfnd */ 1649d522f475Smrg MAP(XK_Fn(20), 201); 1650d522f475Smrg 1651d522f475Smrg /* kf31-kf36 are numbered sequentially */ 1652d522f475Smrg MAP(XK_Fn(21), 208); /* kf31 */ 1653d522f475Smrg MAP(XK_Fn(22), 209); 1654d522f475Smrg MAP(XK_Fn(23), 210); 1655d522f475Smrg MAP(XK_Fn(24), 211); 1656d522f475Smrg MAP(XK_Fn(25), 212); 1657d522f475Smrg MAP(XK_Fn(26), 213); /* kf36 */ 1658d522f475Smrg 1659d522f475Smrg /* kf37-kf47 are interspersed with keypad keys */ 1660d522f475Smrg MAP(XK_Fn(27), 214); /* khome */ 1661d522f475Smrg MAP(XK_Fn(28), 215); /* kf38 */ 1662d522f475Smrg MAP(XK_Fn(29), 216); /* kpp */ 1663d522f475Smrg MAP(XK_Fn(30), 217); /* kf40 */ 1664d522f475Smrg MAP(XK_Fn(31), 218); /* kb2 */ 1665d522f475Smrg MAP(XK_Fn(32), 219); /* kf42 */ 1666d522f475Smrg MAP(XK_Fn(33), 220); /* kend */ 1667d522f475Smrg MAP(XK_Fn(34), 221); /* kf44 */ 1668d522f475Smrg MAP(XK_Fn(35), 222); /* knp */ 1669d522f475Smrg MAP(XK_Fn(36), 234); /* kf46 */ 1670d522f475Smrg MAP(XK_Fn(37), 235); /* kf47 */ 1671d522f475Smrg default: 1672d522f475Smrg result = -1; 1673d522f475Smrg break; 1674d522f475Smrg } 1675d522f475Smrg } else { 1676d522f475Smrg switch (kd->keysym) { 1677d522f475Smrg MAP(XK_Help, 196); /* khlp */ 1678d522f475Smrg MAP(XK_Menu, 197); 1679d522f475Smrg 1680d522f475Smrg MAP(XK_Find, 1); 1681d522f475Smrg MAP(XK_Insert, 2); /* kich1 */ 1682d522f475Smrg MAP(XK_Delete, 3); 1683d522f475Smrg#ifdef XK_KP_Insert 1684d522f475Smrg MAP(XK_KP_Insert, 2); 1685d522f475Smrg MAP(XK_KP_Delete, 3); 1686d522f475Smrg#endif 1687d522f475Smrg#ifdef DXK_Remove 1688d522f475Smrg MAP(DXK_Remove, 3); 1689d522f475Smrg#endif 1690d522f475Smrg MAP(XK_Select, 4); 1691d522f475Smrg 1692d522f475Smrg MAP(XK_Prior, 216); 1693d522f475Smrg MAP(XK_Next, 222); 1694d522f475Smrg MAP(XK_Home, 214); 1695d522f475Smrg MAP(XK_End, 220); 1696d522f475Smrg MAP(XK_Begin, 218); /* kf41=kb2 */ 1697d522f475Smrg 1698d522f475Smrg default: 1699d522f475Smrg result = -1; 1700d522f475Smrg break; 1701d522f475Smrg } 1702d522f475Smrg } 1703d522f475Smrg if (result > 0) { 1704d522f475Smrg reply->a_type = ANSI_CSI; 1705d522f475Smrg reply->a_nparam = 1; 1706d522f475Smrg reply->a_param[0] = result; 1707d522f475Smrg reply->a_final = 'z'; 1708d522f475Smrg } else if (IsCursorKey(kd->keysym)) { 1709d522f475Smrg reply->a_type = ANSI_SS3; 17102eaa94a1Schristos reply->a_final = (Char) curfinal[kd->keysym - XK_Home]; 1711d522f475Smrg } 1712d522f475Smrg#else 1713d522f475Smrg (void) reply; 1714d522f475Smrg (void) kd; 1715d522f475Smrg#endif /* OPT_SUN_FUNC_KEYS */ 1716d522f475Smrg} 1717d522f475Smrg 1718d522f475Smrg#if OPT_NUM_LOCK 171920d2c4d2Smrg#define isName(c) ((c) == '_' || (c) == '-' || isalnum(CharOf(c))) 172020d2c4d2Smrg 172120d2c4d2Smrgstatic const char * 172220d2c4d2SmrgskipName(const char *s) 172320d2c4d2Smrg{ 172420d2c4d2Smrg while (*s != '\0' && isName(CharOf(*s))) 172520d2c4d2Smrg ++s; 172620d2c4d2Smrg return s; 172720d2c4d2Smrg} 172820d2c4d2Smrg 172920d2c4d2Smrg/* 173020d2c4d2Smrg * Found a ":" in a translation, check what is past it to see if it contains 173120d2c4d2Smrg * any of the insert-text action names. 173220d2c4d2Smrg */ 173320d2c4d2Smrgstatic Boolean 173420d2c4d2SmrgkeyCanInsert(const char *parse) 173520d2c4d2Smrg{ 173620d2c4d2Smrg Boolean result = False; 173720d2c4d2Smrg Boolean escape = False; 173820d2c4d2Smrg Boolean quoted = False; 173920d2c4d2Smrg 174001037d57Smrg static const char *const table[] = 174120d2c4d2Smrg { 174220d2c4d2Smrg "insert", 174320d2c4d2Smrg "insert-seven-bit", 174420d2c4d2Smrg "insert-eight-bit", 174520d2c4d2Smrg "string", 174620d2c4d2Smrg }; 174720d2c4d2Smrg Cardinal n; 174820d2c4d2Smrg 174920d2c4d2Smrg while (*parse != '\0' && *parse != '\n') { 17502e4f8982Smrg int ch = CharOf(*parse++); 175120d2c4d2Smrg if (escape) { 175220d2c4d2Smrg escape = False; 175320d2c4d2Smrg } else if (ch == '\\') { 175420d2c4d2Smrg escape = True; 175520d2c4d2Smrg } else if (ch == '"') { 1756e0a2b6dfSmrg quoted = (Boolean) !quoted; 175720d2c4d2Smrg } else if (!quoted && isName(ch)) { 175820d2c4d2Smrg const char *next = skipName(--parse); 175920d2c4d2Smrg size_t need = (size_t) (next - parse); 176020d2c4d2Smrg 176120d2c4d2Smrg for (n = 0; n < XtNumber(table); ++n) { 176220d2c4d2Smrg if (need == strlen(table[n]) 176320d2c4d2Smrg && !strncmp(parse, table[n], need)) { 176420d2c4d2Smrg result = True; 176520d2c4d2Smrg break; 176620d2c4d2Smrg } 176720d2c4d2Smrg } 176820d2c4d2Smrg parse = next; 176920d2c4d2Smrg } 177020d2c4d2Smrg 177120d2c4d2Smrg } 177220d2c4d2Smrg return result; 177320d2c4d2Smrg} 177420d2c4d2Smrg 177520d2c4d2Smrg/* 177620d2c4d2Smrg * Strip the entire action, to avoid matching it. 177720d2c4d2Smrg */ 177820d2c4d2Smrgstatic char * 177920d2c4d2SmrgstripAction(char *base, char *last) 178020d2c4d2Smrg{ 178120d2c4d2Smrg while (last != base) { 178220d2c4d2Smrg if (*--last == '\n') { 178320d2c4d2Smrg break; 178420d2c4d2Smrg } 178520d2c4d2Smrg } 178620d2c4d2Smrg return last; 178720d2c4d2Smrg} 178820d2c4d2Smrg 178920d2c4d2Smrgstatic char * 179020d2c4d2SmrgstripBlanks(char *base, char *last) 179120d2c4d2Smrg{ 179220d2c4d2Smrg while (last != base) { 179320d2c4d2Smrg int ch = CharOf(last[-1]); 179420d2c4d2Smrg if (ch != ' ' && ch != '\t') 179520d2c4d2Smrg break; 179620d2c4d2Smrg --last; 179720d2c4d2Smrg } 179820d2c4d2Smrg return last; 179920d2c4d2Smrg} 1800d522f475Smrg 1801d522f475Smrg/* 18022eaa94a1Schristos * Strip unneeded whitespace from a translations resource, mono-casing and 1803d522f475Smrg * returning a malloc'd copy of the result. 1804d522f475Smrg */ 1805d522f475Smrgstatic char * 180620d2c4d2SmrgstripTranslations(const char *s, Bool onlyInsert) 1807d522f475Smrg{ 1808d522f475Smrg char *dst = 0; 1809d522f475Smrg 1810d522f475Smrg if (s != 0) { 1811d522f475Smrg dst = TypeMallocN(char, strlen(s) + 1); 1812d522f475Smrg 1813d522f475Smrg if (dst != 0) { 1814d522f475Smrg int state = 0; 1815d522f475Smrg int prv = 0; 1816d522f475Smrg char *d = dst; 1817d522f475Smrg 1818d522f475Smrg TRACE(("stripping:\n%s\n", s)); 1819d522f475Smrg while (*s != '\0') { 18202e4f8982Smrg int ch = *s++; 1821d522f475Smrg if (ch == '\n') { 1822d522f475Smrg if (d != dst) 18232eaa94a1Schristos *d++ = (char) ch; 1824d522f475Smrg state = 0; 1825d522f475Smrg } else if (strchr(":!#", ch) != 0) { 182620d2c4d2Smrg d = stripBlanks(dst, d); 182720d2c4d2Smrg if (onlyInsert && (ch == ':') && !keyCanInsert(s)) { 182820d2c4d2Smrg d = stripAction(dst, d); 182920d2c4d2Smrg } 1830d522f475Smrg state = -1; 1831d522f475Smrg } else if (state >= 0) { 1832d522f475Smrg if (isspace(CharOf(ch))) { 1833d522f475Smrg if (state == 0 || strchr("<>~ \t", prv)) 1834d522f475Smrg continue; 1835d522f475Smrg } else if (strchr("<>~", ch)) { 183620d2c4d2Smrg d = stripBlanks(dst, d); 1837d522f475Smrg } 18382eaa94a1Schristos *d++ = x_toupper(ch); 1839d522f475Smrg ++state; 1840d522f475Smrg } 1841d522f475Smrg prv = ch; 1842d522f475Smrg } 1843d522f475Smrg *d = '\0'; 1844d522f475Smrg TRACE(("...result:\n%s\n", dst)); 1845d522f475Smrg } 1846d522f475Smrg } 1847d522f475Smrg return dst; 1848d522f475Smrg} 1849d522f475Smrg 1850d522f475Smrg/* 1851d522f475Smrg * Make a simple check to see if a given translations keyword appears in 1852d522f475Smrg * xterm's translations resource. It does not attempt to parse the strings, 1853d522f475Smrg * just makes a case-independent check and ensures that the ends of the match 1854d522f475Smrg * are on token-boundaries. 1855d522f475Smrg * 1856d522f475Smrg * That this can only retrieve translations that are given as resource values; 1857d522f475Smrg * the default translations in charproc.c for example are not retrievable by 1858d522f475Smrg * any interface to X. 1859d522f475Smrg * 1860d522f475Smrg * Also: We can retrieve only the most-specified translation resource. For 1861d522f475Smrg * example, if the resource file specifies both "*translations" and 1862d522f475Smrg * "XTerm*translations", we see only the latter. 1863d522f475Smrg */ 1864d522f475Smrgstatic Bool 186520d2c4d2SmrgTranslationsUseKeyword(Widget w, char **cache, const char *keyword, Bool onlyInsert) 1866d522f475Smrg{ 1867d522f475Smrg Bool result = False; 1868d522f475Smrg char *copy; 1869d522f475Smrg char *test; 1870d522f475Smrg 187120d2c4d2Smrg if ((test = stripTranslations(keyword, onlyInsert)) != 0) { 1872d522f475Smrg if (*cache == 0) { 187301037d57Smrg String data = 0; 187401037d57Smrg getKeymapResources(w, "vt100", "VT100", XtRString, &data, sizeof(data)); 187520d2c4d2Smrg if (data != 0 && (copy = stripTranslations(data, onlyInsert)) != 0) { 1876d522f475Smrg *cache = copy; 1877d522f475Smrg } 1878d522f475Smrg } 1879d522f475Smrg 1880d522f475Smrg if (*cache != 0) { 1881d522f475Smrg char *p = *cache; 1882d522f475Smrg int state = 0; 18832e4f8982Smrg int now = ' '; 1884d522f475Smrg 1885d522f475Smrg while (*p != 0) { 18862e4f8982Smrg int prv = now; 1887d522f475Smrg now = *p++; 1888d522f475Smrg if (now == ':' 1889d522f475Smrg || now == '!') { 1890d522f475Smrg state = -1; 1891d522f475Smrg } else if (now == '\n') { 1892d522f475Smrg state = 0; 1893d522f475Smrg } else if (state >= 0) { 1894d522f475Smrg if (now == test[state]) { 1895d522f475Smrg if ((state != 0 1896d522f475Smrg || !isName(prv)) 1897d522f475Smrg && ((test[++state] == 0) 1898d522f475Smrg && !isName(*p))) { 1899d522f475Smrg result = True; 1900d522f475Smrg break; 1901d522f475Smrg } 1902d522f475Smrg } else { 1903d522f475Smrg state = 0; 1904d522f475Smrg } 1905d522f475Smrg } 1906d522f475Smrg } 1907d522f475Smrg } 1908d522f475Smrg free(test); 1909d522f475Smrg } 191020d2c4d2Smrg TRACE(("TranslationsUseKeyword(%p, %s) = %d\n", 191120d2c4d2Smrg (void *) w, keyword, result)); 1912d522f475Smrg return result; 1913d522f475Smrg} 1914d522f475Smrg 1915d522f475Smrgstatic Bool 191620d2c4d2SmrgxtermHasTranslation(XtermWidget xw, const char *keyword, Bool onlyInsert) 1917d522f475Smrg{ 1918d522f475Smrg return (TranslationsUseKeyword(SHELL_OF(xw), 1919d522f475Smrg &(xw->keyboard.shell_translations), 192020d2c4d2Smrg keyword, 192120d2c4d2Smrg onlyInsert) 1922d522f475Smrg || TranslationsUseKeyword((Widget) xw, 1923d522f475Smrg &(xw->keyboard.xterm_translations), 192420d2c4d2Smrg keyword, 192520d2c4d2Smrg onlyInsert)); 1926d522f475Smrg} 1927d522f475Smrg 1928d522f475Smrg#if OPT_EXTRA_PASTE 1929d522f475Smrgstatic void 193020d2c4d2SmrgaddTranslation(XtermWidget xw, const char *fromString, const char *toString) 1931d522f475Smrg{ 193220d2c4d2Smrg size_t have = (xw->keyboard.extra_translations 193320d2c4d2Smrg ? strlen(xw->keyboard.extra_translations) 193420d2c4d2Smrg : 0); 193520d2c4d2Smrg size_t need = (((have != 0) ? (have + 4) : 0) 193620d2c4d2Smrg + strlen(fromString) 193720d2c4d2Smrg + strlen(toString) 193820d2c4d2Smrg + 6); 193920d2c4d2Smrg 194020d2c4d2Smrg if (!xtermHasTranslation(xw, fromString, False)) { 1941d522f475Smrg xw->keyboard.extra_translations 1942d522f475Smrg = TypeRealloc(char, need, xw->keyboard.extra_translations); 1943d522f475Smrg if ((xw->keyboard.extra_translations) != 0) { 1944d522f475Smrg TRACE(("adding %s: %s\n", fromString, toString)); 1945d522f475Smrg if (have) 1946d522f475Smrg strcat(xw->keyboard.extra_translations, " \\n\\"); 1947d522f475Smrg sprintf(xw->keyboard.extra_translations, "%s: %s", 1948d522f475Smrg fromString, toString); 1949d522f475Smrg TRACE(("...{%s}\n", xw->keyboard.extra_translations)); 1950d522f475Smrg } 1951d522f475Smrg } 1952d522f475Smrg} 1953d522f475Smrg#endif 1954d522f475Smrg 19550bd37d32Smrg#define SaveMask(name) xw->work.name |= (unsigned) mask;\ 19560bd37d32Smrg TRACE(("SaveMask(%#x -> %s) %#x (%#x is%s modifier)\n", \ 19570bd37d32Smrg (unsigned) keysym, #name, \ 19580bd37d32Smrg xw->work.name, (unsigned) mask, \ 195920d2c4d2Smrg ModifierName((unsigned) mask))); 1960d522f475Smrg/* 1961d522f475Smrg * Determine which modifier mask (if any) applies to the Num_Lock keysym. 1962d522f475Smrg * 1963d522f475Smrg * Also, determine which modifiers are associated with the ALT keys, so we can 1964d522f475Smrg * send that information as a parameter for special keys in Sun/PC keyboard 1965d522f475Smrg * mode. However, if the ALT modifier is used in translations, we do not want 1966d522f475Smrg * to confuse things by sending the parameter. 1967d522f475Smrg */ 1968d522f475Smrgvoid 1969d522f475SmrgVTInitModifiers(XtermWidget xw) 1970d522f475Smrg{ 1971d522f475Smrg Display *dpy = XtDisplay(xw); 1972d522f475Smrg XModifierKeymap *keymap = XGetModifierMapping(dpy); 1973d522f475Smrg KeySym keysym; 1974d522f475Smrg int min_keycode, max_keycode, keysyms_per_keycode = 0; 1975d522f475Smrg 1976d522f475Smrg if (keymap != 0) { 1977d522f475Smrg KeySym *theMap; 1978d522f475Smrg int keycode_count; 1979d522f475Smrg 1980d522f475Smrg TRACE(("VTInitModifiers\n")); 1981d522f475Smrg 1982d522f475Smrg XDisplayKeycodes(dpy, &min_keycode, &max_keycode); 1983d522f475Smrg keycode_count = (max_keycode - min_keycode + 1); 1984d522f475Smrg theMap = XGetKeyboardMapping(dpy, 1985956cc18dSsnj (KeyCode) min_keycode, 1986d522f475Smrg keycode_count, 1987d522f475Smrg &keysyms_per_keycode); 1988d522f475Smrg 1989d522f475Smrg if (theMap != 0) { 19902e4f8982Smrg int i, j, k, l; 19912e4f8982Smrg unsigned long mask; 1992d522f475Smrg 1993d522f475Smrg#if OPT_EXTRA_PASTE 1994d522f475Smrg /* 1995d522f475Smrg * Assume that if we can find the paste keysym in the X keyboard 1996d522f475Smrg * mapping that the server allows the corresponding translations 1997d522f475Smrg * resource. 1998d522f475Smrg */ 1999d522f475Smrg int limit = (max_keycode - min_keycode) * keysyms_per_keycode; 2000d522f475Smrg for (i = 0; i < limit; ++i) { 2001d522f475Smrg#ifdef XF86XK_Paste 2002d522f475Smrg if (theMap[i] == XF86XK_Paste) { 2003d522f475Smrg TRACE(("keyboard has XF86XK_Paste\n")); 2004d522f475Smrg addTranslation(xw, 2005894e0ac8Smrg ":<KeyPress> XF86Paste", 2006d522f475Smrg "insert-selection(SELECT, CUT_BUFFER0)"); 2007d522f475Smrg } 2008d522f475Smrg#endif 2009d522f475Smrg#ifdef SunXK_Paste 2010d522f475Smrg if (theMap[i] == SunXK_Paste) { 2011d522f475Smrg TRACE(("keyboard has SunXK_Paste\n")); 2012d522f475Smrg addTranslation(xw, 2013894e0ac8Smrg ":<KeyPress> SunPaste", 2014d522f475Smrg "insert-selection(SELECT, CUT_BUFFER0)"); 2015d522f475Smrg } 2016d522f475Smrg#endif 2017d522f475Smrg } 2018d522f475Smrg#endif /* OPT_EXTRA_PASTE */ 2019d522f475Smrg 2020d522f475Smrg for (i = k = 0, mask = 1; i < 8; i++, mask <<= 1) { 2021d522f475Smrg for (j = 0; j < keymap->max_keypermod; j++) { 2022d522f475Smrg KeyCode code = keymap->modifiermap[k++]; 2023d522f475Smrg if (code == 0) 2024d522f475Smrg continue; 2025d522f475Smrg 2026d522f475Smrg for (l = 0; l < keysyms_per_keycode; ++l) { 20270bd37d32Smrg#ifdef HAVE_XKBKEYCODETOKEYSYM 20280bd37d32Smrg keysym = XkbKeycodeToKeysym(dpy, code, 0, l); 20290bd37d32Smrg#else 2030d522f475Smrg keysym = XKeycodeToKeysym(dpy, code, l); 20310bd37d32Smrg#endif 2032d522f475Smrg if (keysym == NoSymbol) { 2033a1f3da82Smrg /* EMPTY */ ; 2034d522f475Smrg } else if (keysym == XK_Num_Lock) { 2035d522f475Smrg SaveMask(num_lock); 2036d522f475Smrg } else if (keysym == XK_Alt_L || keysym == XK_Alt_R) { 2037d522f475Smrg SaveMask(alt_mods); 2038d522f475Smrg } else if (keysym == XK_Meta_L || keysym == XK_Meta_R) { 2039d522f475Smrg SaveMask(meta_mods); 2040d522f475Smrg } 2041d522f475Smrg } 2042d522f475Smrg } 2043d522f475Smrg } 2044d522f475Smrg XFree(theMap); 2045d522f475Smrg } 2046d522f475Smrg 2047d522f475Smrg /* Don't disable any mods if "alwaysUseMods" is true. */ 2048d522f475Smrg if (!xw->misc.alwaysUseMods) { 204920d2c4d2Smrg 205020d2c4d2Smrg /* 205120d2c4d2Smrg * Force TranslationsUseKeyword() to reload. 205220d2c4d2Smrg */ 2053f2e35a3aSmrg FreeAndNull(xw->keyboard.shell_translations); 2054f2e35a3aSmrg FreeAndNull(xw->keyboard.xterm_translations); 205520d2c4d2Smrg 2056d522f475Smrg /* 2057d522f475Smrg * If the Alt modifier is used in translations, we would rather not 2058d522f475Smrg * use it to modify function-keys when NumLock is active. 2059d522f475Smrg */ 20600bd37d32Smrg if ((xw->work.alt_mods != 0) 206120d2c4d2Smrg && xtermHasTranslation(xw, "alt", True)) { 2062d522f475Smrg TRACE(("ALT is used as a modifier in translations (ignore mask)\n")); 20630bd37d32Smrg xw->work.alt_mods = 0; 2064d522f475Smrg } 2065d522f475Smrg 2066d522f475Smrg /* 2067d522f475Smrg * If the Meta modifier is used in translations, we would rather not 2068d522f475Smrg * use it to modify function-keys. 2069d522f475Smrg */ 20700bd37d32Smrg if ((xw->work.meta_mods != 0) 207120d2c4d2Smrg && xtermHasTranslation(xw, "meta", True)) { 2072d522f475Smrg TRACE(("META is used as a modifier in translations\n")); 20730bd37d32Smrg xw->work.meta_mods = 0; 2074d522f475Smrg } 2075d522f475Smrg } 2076d522f475Smrg 2077d522f475Smrg XFreeModifiermap(keymap); 2078d522f475Smrg } 2079d522f475Smrg} 2080d522f475Smrg#endif /* OPT_NUM_LOCK */ 2081