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