diff options
author | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 11:11:55 +0000 |
---|---|---|
committer | Matthieu Herrb <matthieu@cvs.openbsd.org> | 2006-11-26 11:11:55 +0000 |
commit | 145a665014b2aa230b81b582689c8ec17ef9968e (patch) | |
tree | 5ea1019527fe16cc21b9702371c72cc7f8c8090c /app/xterm/input.c | |
parent | 95c2d1cbda23a41cdf6e63520c7f0b825e63dd5b (diff) |
Importing xterm 216
Diffstat (limited to 'app/xterm/input.c')
-rw-r--r-- | app/xterm/input.c | 1963 |
1 files changed, 1963 insertions, 0 deletions
diff --git a/app/xterm/input.c b/app/xterm/input.c new file mode 100644 index 000000000..a9f687bda --- /dev/null +++ b/app/xterm/input.c @@ -0,0 +1,1963 @@ +/* $XTermId: input.c,v 1.262 2006/08/03 00:08:35 tom Exp $ */ + +/* $XFree86: xc/programs/xterm/input.c,v 3.76 2006/06/19 00:36:51 dickey Exp $ */ + +/* + * Copyright 1999-2005,2006 by Thomas E. Dickey + * + * All Rights Reserved + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sublicense, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice shall be included + * in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. + * IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY + * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + * Except as contained in this notice, the name(s) of the above copyright + * holders shall not be used in advertising or otherwise to promote the + * sale, use or other dealings in this Software without prior written + * authorization. + * + * + * Copyright 1987 by Digital Equipment Corporation, Maynard, Massachusetts. + * + * All Rights Reserved + * + * Permission to use, copy, modify, and distribute this software and its + * documentation for any purpose and without fee is hereby granted, + * provided that the above copyright notice appear in all copies and that + * both that copyright notice and this permission notice appear in + * supporting documentation, and that the name of Digital Equipment + * Corporation not be used in advertising or publicity pertaining to + * distribution of the software without specific, written prior permission. + * + * + * DIGITAL DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING + * ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT SHALL + * DIGITAL BE LIABLE FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR + * ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, + * WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, + * ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS + * SOFTWARE. + */ + +/* input.c */ + +#include <xterm.h> + +#include <X11/keysym.h> + +#ifdef VMS +#include <X11/keysymdef.h> +#endif + +#if HAVE_X11_DECKEYSYM_H +#include <X11/DECkeysym.h> +#endif + +#if HAVE_X11_SUNKEYSYM_H +#include <X11/Sunkeysym.h> +#endif + +#include <X11/Xutil.h> +#include <ctype.h> + +#include <xutf8.h> + +#include <data.h> +#include <fontutils.h> + +/* + * Xutil.h has no macro to check for the complete set of function- and + * modifier-keys that might be returned. Fake it. + */ +#ifdef XK_ISO_Lock +#define IsPredefinedKey(n) ((n) >= XK_ISO_Lock && (n) <= XK_Delete) +#else +#define IsPredefinedKey(n) ((n) >= XK_BackSpace && (n) <= XK_Delete) +#endif + +#ifdef XK_ISO_Left_Tab +#define IsTabKey(n) ((n) == XK_Tab || (n) == XK_ISO_Left_Tab) +#else +#define IsTabKey(n) ((n) == XK_Tab) +#endif + +#ifndef IsPrivateKeypadKey +#define IsPrivateKeypadKey(k) (0) +#endif + +#define XK_Fn(n) (XK_F1 + (n) - 1) + +#define IsBackarrowToggle(keyboard, keysym, state) \ + ((((keyboard->flags & MODE_DECBKM) == 0) \ + ^ ((state & ControlMask) != 0)) \ + && (keysym == XK_BackSpace)) + +#define MAP(from, to) case from: result = to; break + +#define KEYSYM_FMT "0x%04lX" /* simplify matching <X11/keysymdef.h> */ + +typedef struct { + KeySym keysym; + Bool is_fkey; + int nbytes; +#define STRBUFSIZE 500 + char strbuf[STRBUFSIZE]; +} KEY_DATA; + +/* 0123456789 abc def0123456789abcdef0123456789abcdef0123456789abcd */ +static char *kypd_num = " XXXXXXXX\tXXX\rXXXxxxxXXXXXXXXXXXXXXXXXXXXX*+,-./0123456789XXX="; + +/* 0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcd */ +static char *kypd_apl = " ABCDEFGHIJKLMNOPQRSTUVWXYZ??????abcdefghijklmnopqrstuvwxyzXXX"; + +static char *curfinal = "HDACB FE"; + +static int decfuncvalue(KEY_DATA *); +static void sunfuncvalue(ANSI *, KEY_DATA *); +static void hpfuncvalue(ANSI *, KEY_DATA *); +static void scofuncvalue(ANSI *, KEY_DATA *); + +#if OPT_TRACE +static char * +ModifierName(unsigned modifier) +{ + char *s = ""; + if (modifier & ShiftMask) + s = " Shift"; + else if (modifier & LockMask) + s = " Lock"; + else if (modifier & ControlMask) + s = " Control"; + else if (modifier & Mod1Mask) + s = " Mod1"; + else if (modifier & Mod2Mask) + s = " Mod2"; + else if (modifier & Mod3Mask) + s = " Mod3"; + else if (modifier & Mod4Mask) + s = " Mod4"; + else if (modifier & Mod5Mask) + s = " Mod5"; + return s; +} + +#define FMT_MODIFIER_NAMES "%s%s%s%s%s%s%s%s" +#define ARG_MODIFIER_NAMES(state) \ + ModifierName(state & ShiftMask), \ + ModifierName(state & LockMask), \ + ModifierName(state & ControlMask), \ + ModifierName(state & Mod1Mask), \ + ModifierName(state & Mod2Mask), \ + ModifierName(state & Mod3Mask), \ + ModifierName(state & Mod4Mask), \ + ModifierName(state & Mod5Mask) +#endif + +static void +AdjustAfterInput(TScreen * screen) +{ + if (screen->scrollkey && screen->topline != 0) + WindowScroll(screen, 0); + if (screen->marginbell) { + int col = screen->max_col - screen->nmarginbell; + if (screen->bellarmed >= 0) { + if (screen->bellarmed == screen->cur_row) { + if (screen->cur_col >= col) { + Bell(XkbBI_MarginBell, 0); + screen->bellarmed = -1; + } + } else + screen->bellarmed = + screen->cur_col < col ? screen->cur_row : -1; + } else if (screen->cur_col < col) + screen->bellarmed = screen->cur_row; + } +} + +/* + * Return true if the key is on the editing keypad. This overlaps with + * IsCursorKey() and IsKeypadKey() and must be tested before those macro to + * distinguish it from them. + */ +static Bool +IsEditFunctionKey(KeySym keysym) +{ + switch (keysym) { + case XK_Prior: /* editing keypad */ + case XK_Next: /* editing keypad */ + case XK_Insert: /* editing keypad */ + case XK_Find: /* editing keypad */ + case XK_Select: /* editing keypad */ +#ifdef DXK_Remove + case DXK_Remove: /* editing keypad */ +#endif +#ifdef XK_KP_Delete + case XK_KP_Delete: /* editing key on numeric keypad */ + case XK_KP_Insert: /* editing key on numeric keypad */ +#endif +#ifdef XK_ISO_Left_Tab + case XK_ISO_Left_Tab: +#endif + return True; + default: + return False; + } +} + +#if OPT_MOD_FKEYS +#define IS_CTRL(n) ((n) < 0x20 || ((n) >= 0x7f && (n) <= 0x9f)) + +/* + * Return true if the keysym corresponds to one of the control characters, + * or one of the common ASCII characters that is combined with control to + * make a control character. + */ +static Bool +IsControlInput(KEY_DATA * kd) +{ + return ((kd->keysym) >= 0x40 && (kd->keysym) <= 0x7f); +} + +static Bool +IsControlOutput(KEY_DATA * kd) +{ + return IS_CTRL(kd->keysym); +} + +/* + * X "normally" has some built-in translations, which the user may want to + * suppress when processing the modifyOtherKeys resource. In particular, the + * control modifier applied to some of the keyboard digits gives results for + * control characters. + * + * control 2 0 NUL + * control SPC 0 NUL + * control @ 0 NUL + * control ` 0 NUL + * control 3 0x1b ESC + * control 4 0x1c FS + * control \ 0x1c FS + * control 5 0x1d GS + * control 6 0x1e RS + * control ^ 0x1e RS + * control ~ 0x1e RS + * control 7 0x1f US + * control / 0x1f US + * control _ 0x1f US + * control 8 0x7f DEL + * + * It is possible that some other keyboards do not work for these combinations, + * but they do work with modifyOtherKeys=2 for the US keyboard: + * + * control ` 0 NUL + * control [ 0x1b ESC + * control \ 0x1c FS + * control ] 0x1d GS + * control ? 0x7f DEL + */ +static Bool +IsControlAlias(KEY_DATA * kd) +{ + Bool result = False; + + if (kd->nbytes == 1) { + result = IS_CTRL(CharOf(kd->strbuf[0])); + } + return result; +} + +/* + * If we are in the non-VT220/VT52 keyboard state, allow modifiers to add a + * parameter to the function-key control sequences. + * + * Note that we generally cannot capture the Shift-modifier for the numeric + * keypad since this is commonly used to act as a type of NumLock, e.g., + * making the keypad send "7" (actually XK_KP_7) where the unshifted code + * would be Home (XK_KP_Home). The other modifiers work, subject to the + * usual window-manager assignments. + */ +static Bool +allowModifierParm(XtermWidget xw, KEY_DATA * kd) +{ + TKeyboard *keyboard = &(xw->keyboard); + TScreen *screen = &(xw->screen); + int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0); + + Bool result = False; + + (void) screen; + if (1 +#if OPT_SUNPC_KBD || OPT_VT52 + && !(((IsKeypadKey(kd->keysym) && keypad_mode) + || kd->is_fkey) + && (0 +#if OPT_SUNPC_KBD + || (keyboard->type == keyboardIsVT220) +#endif +#if OPT_VT52_MODE + || (screen->vtXX_level == 0) +#endif + )) +#endif /* OPT_SUNPC_KBD || OPT_VT52 */ + ) { + result = True; + } + return result; +} + +/* +* Modifier codes: +* None 1 +* Shift 2 = 1(None)+1(Shift) +* Alt 3 = 1(None)+2(Alt) +* Alt+Shift 4 = 1(None)+1(Shift)+2(Alt) +* Ctrl 5 = 1(None)+4(Ctrl) +* Ctrl+Shift 6 = 1(None)+1(Shift)+4(Ctrl) +* Ctrl+Alt 7 = 1(None)+2(Alt)+4(Ctrl) +* Ctrl+Alt+Shift 8 = 1(None)+1(Shift)+2(Alt)+4(Ctrl) +* Meta 9 = 1(None)+8(Meta) +* Meta+Shift 10 = 1(None)+8(Meta)+1(Shift) +* Meta+Alt 11 = 1(None)+8(Meta)+2(Alt) +* Meta+Alt+Shift 12 = 1(None)+8(Meta)+1(Shift)+2(Alt) +* Meta+Ctrl 13 = 1(None)+8(Meta)+4(Ctrl) +* Meta+Ctrl+Shift 14 = 1(None)+8(Meta)+1(Shift)+4(Ctrl) +* Meta+Ctrl+Alt 15 = 1(None)+8(Meta)+2(Alt)+4(Ctrl) +* Meta+Ctrl+Alt+Shift 16 = 1(None)+8(Meta)+1(Shift)+2(Alt)+4(Ctrl) +*/ +#define UNMOD 1 +#define SHIFT 1 +#define ALT 2 +#define CTRL 4 +#define META 8 +#define MODIFIER_NAME(parm, name) (((parm - UNMOD) & name) ? " "#name : "") +static short +computeModifierParm(XtermWidget xw, int state) +{ + short modify_parm = UNMOD; + +#if OPT_NUM_LOCK + if ((state & xw->misc.other_mods) == 0) { + if (state & ShiftMask) { + modify_parm += SHIFT; + state &= ~ShiftMask; + } + if (state & ControlMask) { + modify_parm += CTRL; + state &= ~ControlMask; + } + if ((state & xw->misc.alt_mods) != 0) { + modify_parm += ALT; + state &= ~xw->misc.alt_mods; + } + if ((state & xw->misc.meta_mods) != 0) { + modify_parm += META; + state &= ~xw->misc.meta_mods; + } + } +#else + (void) xw; + (void) state; +#endif + TRACE(("...computeModifierParm %d%s%s%s%s\n", modify_parm, + MODIFIER_NAME(modify_parm, SHIFT), + MODIFIER_NAME(modify_parm, ALT), + MODIFIER_NAME(modify_parm, CTRL), + MODIFIER_NAME(modify_parm, META))); + return modify_parm; +} + +/* + * Single characters (not function-keys) are allowed fewer modifiers when + * interpreting modifyOtherKeys due to pre-existing associations with some + * modifiers. + */ +static unsigned +allowedCharModifiers(XtermWidget xw, unsigned state, KEY_DATA * kd) +{ +#if OPT_NUM_LOCK + unsigned a_or_m = (state & (xw->misc.meta_mods | xw->misc.alt_mods)); +#else + unsigned a_or_m = 0; +#endif + /* + * Start by limiting the result to the modifiers we might want to use. + */ + unsigned result = (state & (ControlMask + | ShiftMask + | a_or_m)); + + /* + * If modifyOtherKeys is off or medium (0 or 1), moderate its effects by + * excluding the common cases for modifiers. + */ + if (xw->keyboard.modify_now.other_keys <= 1) { + if (IsControlInput(kd) + && (result & ~ControlMask) == 0) { + /* These keys are already associated with the control-key */ + if (xw->keyboard.modify_now.other_keys == 0) { + result &= ~ControlMask; + } + } else if (kd->keysym == XK_Tab || kd->keysym == XK_Return) { + ; + } else if (IsControlAlias(kd)) { + /* Things like "^_" work here... */ + if ((result & ~(ControlMask | ShiftMask)) == 0) { + result = 0; + } + } else if (!IsControlOutput(kd) && !IsPredefinedKey(kd->keysym)) { + /* Printable keys are already associated with the shift-key */ + if (!(result & ControlMask)) { + result &= ~ShiftMask; + } + } +#if OPT_NUM_LOCK + if ((result & xw->misc.meta_mods) != 0) { + /* + * metaSendsEscape makes the meta key independent of + * modifyOtherKeys. + */ + if (xw->screen.meta_sends_esc) { + result &= ~xw->misc.meta_mods; + } + /* + * A bare meta-modifier is independent of modifyOtherKeys. If it + * is combined with other modifiers, make it depend. + */ + if ((result & ~(xw->misc.meta_mods)) == 0) { + result &= ~xw->misc.meta_mods; + } + /* + * Check for special cases of control+meta which are used by some + * applications, e.g., emacs. + */ + if ((IsControlInput(kd) + || IsControlOutput(kd)) + && (result & ControlMask) != 0) { + result &= ~(xw->misc.meta_mods | ControlMask); + } + if (kd->keysym == XK_Return || kd->keysym == XK_Tab) { + result &= ~(xw->misc.meta_mods | ControlMask); + } + } +#endif + } + TRACE(("...allowedCharModifiers(state=%u" FMT_MODIFIER_NAMES + ", ch=" KEYSYM_FMT ") ->" + "%u" FMT_MODIFIER_NAMES "\n", + state, ARG_MODIFIER_NAMES(state), kd->keysym, + result, ARG_MODIFIER_NAMES(result))); + return result; +} + +/* + * Decide if we should generate a special escape sequence for "other" keys + * than cursor-, function-keys, etc., as per the modifyOtherKeys resource. + */ +static Bool +ModifyOtherKeys(XtermWidget xw, + unsigned state, + KEY_DATA * kd, + int modify_parm) +{ + TKeyboard *keyboard = &(xw->keyboard); + Bool result = False; + + /* + * Exclude the keys already covered by a modifier. + */ + if (kd->is_fkey + || IsEditFunctionKey(kd->keysym) + || IsKeypadKey(kd->keysym) + || IsCursorKey(kd->keysym) + || IsPFKey(kd->keysym) + || IsMiscFunctionKey(kd->keysym) + || IsPrivateKeypadKey(kd->keysym) +#if OPT_NUM_LOCK + || (state & xw->misc.other_mods) != 0 +#endif + ) { + result = False; + } else if (modify_parm != 0) { + if (IsBackarrowToggle(keyboard, kd->keysym, state)) { + kd->keysym = XK_Delete; + state &= ~ControlMask; + } + if (!IsPredefinedKey(kd->keysym)) { + state = allowedCharModifiers(xw, state, kd); + } + if (state != 0) { + switch (keyboard->modify_now.other_keys) { + default: + break; + case 1: + switch (kd->keysym) { + case XK_BackSpace: + case XK_Delete: + result = False; + break; +#ifdef XK_ISO_Left_Tab + case XK_ISO_Left_Tab: + if (computeModifierParm(xw, state & ~ShiftMask) > 1) + result = True; + break; +#endif + case XK_Return: + case XK_Tab: + result = (modify_parm > 1); + break; + default: + if (IsControlInput(kd)) { + if (state == ControlMask || state == ShiftMask) { + result = False; + } else { + result = (modify_parm > 1); + } + } else if (IsControlAlias(kd)) { + if (state == ShiftMask) + result = False; + else if (computeModifierParm(xw, + (state & ~ControlMask)) + > 1) { + result = True; + } + } else { + result = True; + } + break; + } + break; + case 2: + switch (kd->keysym) { + case XK_BackSpace: + /* strip ControlMask as per IsBackarrowToggle() */ + if (computeModifierParm(xw, state & ~ControlMask) > 1) + result = True; + break; + case XK_Delete: + result = (computeModifierParm(xw, state) > 1); + break; +#ifdef XK_ISO_Left_Tab + case XK_ISO_Left_Tab: + if (computeModifierParm(xw, state & ~ShiftMask) > 1) + result = True; + break; +#endif + case XK_Return: + case XK_Tab: + result = (modify_parm > 1); + break; + default: + if (IsControlInput(kd)) { + result = True; + } else if (state == ShiftMask) { + result = (kd->keysym == ' ' || kd->keysym == XK_Return); + } else if (computeModifierParm(xw, state & ~ShiftMask) > 1) { + result = True; + } + break; + } + break; + } + } + } + TRACE(("...ModifyOtherKeys(%d,%d) %s\n", + keyboard->modify_now.other_keys, + modify_parm, + BtoS(result))); + return result; +} + +#define APPEND_PARM(number) \ + reply->a_param[(int) reply->a_nparam] = number, \ + reply->a_nparam += 1 + +/* + * Function-key code 27 happens to not be used in the vt220-style encoding. + * xterm uses this to represent modified non-function-keys such as control/+ in + * the Sun/PC keyboard layout. See the modifyOtherKeys resource in the manpage + * for more information. + */ +static Bool +modifyOtherKey(ANSI * reply, int input_char, int modify_parm) +{ + Bool result = False; + + if (input_char >= 0) { + reply->a_type = CSI; + APPEND_PARM(27); + APPEND_PARM(modify_parm); + APPEND_PARM(input_char); + reply->a_final = '~'; + + result = True; + } + return result; +} + +static void +modifyCursorKey(ANSI * reply, int modify, int modify_parm) +{ + if (modify_parm > 1) { + if (modify) { + reply->a_type = CSI; /* SS3 should not have params */ + } + if (modify > 1 && reply->a_nparam == 0) { + APPEND_PARM(1); /* force modifier to 2nd param */ + } + if (modify > 2) { + reply->a_pintro = '>'; /* mark this as "private" */ + } + } +} +#else +#define modifyCursorKey(reply, modify, parm) /* nothing */ +#endif /* OPT_MOD_FKEYS */ + +#if OPT_SUNPC_KBD +/* + * If we have told xterm that our keyboard is really a Sun/PC keyboard, this is + * enough to make a reasonable approximation to DEC vt220 numeric and editing + * keypads. + */ +static KeySym +TranslateFromSUNPC(KeySym keysym) +{ + /* *INDENT-OFF* */ + static struct { + KeySym before, after; + } table[] = { +#ifdef DXK_Remove + { XK_Delete, DXK_Remove }, +#endif + { XK_Home, XK_Find }, + { XK_End, XK_Select }, +#ifdef XK_KP_Home + { XK_Delete, XK_KP_Decimal }, + { XK_KP_Delete, XK_KP_Decimal }, + { XK_KP_Insert, XK_KP_0 }, + { XK_KP_End, XK_KP_1 }, + { XK_KP_Down, XK_KP_2 }, + { XK_KP_Next, XK_KP_3 }, + { XK_KP_Left, XK_KP_4 }, + { XK_KP_Begin, XK_KP_5 }, + { XK_KP_Right, XK_KP_6 }, + { XK_KP_Home, XK_KP_7 }, + { XK_KP_Up, XK_KP_8 }, + { XK_KP_Prior, XK_KP_9 }, +#endif + }; + /* *INDENT-ON* */ + + unsigned n; + + for (n = 0; n < sizeof(table) / sizeof(table[0]); n++) { + if (table[n].before == keysym) { + TRACE(("...Input keypad before was " KEYSYM_FMT "\n", keysym)); + keysym = table[n].after; + TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", keysym)); + break; + } + } + return keysym; +} +#endif /* OPT_SUNPC_KBD */ + +#define VT52_KEYPAD \ + if_OPT_VT52_MODE(screen,{ \ + reply.a_type = ESC; \ + reply.a_pintro = '?'; \ + }) + +#define VT52_CURSOR_KEYS \ + if_OPT_VT52_MODE(screen,{ \ + reply.a_type = ESC; \ + }) + +#undef APPEND_PARM +#define APPEND_PARM(number) \ + reply.a_param[(int) reply.a_nparam] = number, \ + reply.a_nparam += 1 + +#if OPT_MOD_FKEYS +#define MODIFIER_PARM \ + if (modify_parm > 1) APPEND_PARM(modify_parm) +#else +#define MODIFIER_PARM /*nothing */ +#endif + +/* + * Determine if we use the \E[3~ sequence for Delete, or the legacy ^?. We + * maintain the delete_is_del value as 3 states: unspecified(2), true and + * false. If unspecified, it is handled differently according to whether the + * legacy keyboard support is enabled, or if xterm emulates a VT220. + * + * Once the user (or application) has specified delete_is_del via resource + * setting, popup menu or escape sequence, it overrides the keyboard type + * rather than the reverse. + */ +Bool +xtermDeleteIsDEL(XtermWidget xw) +{ + Bool result = True; + + if (xw->keyboard.type == keyboardIsDefault + || xw->keyboard.type == keyboardIsVT220) + result = (xw->screen.delete_is_del == True); + + if (xw->keyboard.type == keyboardIsLegacy) + result = (xw->screen.delete_is_del != False); + + TRACE(("xtermDeleteIsDEL(%d/%d) = %d\n", + xw->keyboard.type, + xw->screen.delete_is_del, + result)); + + return result; +} + +void +Input(XtermWidget xw, + XKeyEvent * event, + Bool eightbit) +{ + Char *string; + + TKeyboard *keyboard = &(xw->keyboard); + TScreen *screen = &(xw->screen); + + int j; + int key = False; + ANSI reply; + int dec_code; + short modify_parm = 0; + int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0); + unsigned evt_state = event->state; + unsigned mod_state; + KEY_DATA kd; + + /* Ignore characters typed at the keyboard */ + if (keyboard->flags & MODE_KAM) + return; + + kd.keysym = 0; + kd.is_fkey = False; +#if OPT_TCAP_QUERY + if (screen->tc_query_code >= 0) { + kd.keysym = screen->tc_query_code; + kd.is_fkey = screen->tc_query_fkey; + if (kd.keysym != XK_BackSpace) { + kd.nbytes = 0; + kd.strbuf[0] = 0; + } else { + kd.nbytes = 1; + kd.strbuf[0] = 8; + } + } else +#endif + { +#if OPT_I18N_SUPPORT + if (screen->xic) { + Status status_return; +#if OPT_WIDE_CHARS + if (screen->utf8_mode) { + kd.nbytes = Xutf8LookupString(screen->xic, event, + kd.strbuf, sizeof(kd.strbuf), + &kd.keysym, &status_return); + } else +#endif + { + kd.nbytes = XmbLookupString(screen->xic, event, + kd.strbuf, sizeof(kd.strbuf), + &kd.keysym, &status_return); + } +#if OPT_MOD_FKEYS + /* + * Fill-in some code useful with IsControlAlias(): + */ + if (status_return == XLookupBoth + && kd.nbytes <= 1 + && !IsPredefinedKey(kd.keysym) + && (keyboard->modify_now.other_keys > 1) + && !IsControlInput(&kd)) { + kd.nbytes = 1; + kd.strbuf[0] = kd.keysym; + } +#endif /* OPT_MOD_FKEYS */ + } else +#endif /* OPT_I18N_SUPPORT */ + { + static XComposeStatus compose_status = + {NULL, 0}; + kd.nbytes = XLookupString(event, kd.strbuf, sizeof(kd.strbuf), + &kd.keysym, &compose_status); + } + kd.is_fkey = IsFunctionKey(kd.keysym); + } + + memset(&reply, 0, sizeof(reply)); + + TRACE(("Input keysym " + KEYSYM_FMT + ", %d:'%s'%s" FMT_MODIFIER_NAMES "%s%s%s%s%s%s\n", + kd.keysym, + kd.nbytes, + visibleChars(PAIRED_CHARS((Char *) kd.strbuf, 0), kd.nbytes), + ARG_MODIFIER_NAMES(evt_state), + eightbit ? " 8bit" : " 7bit", + IsKeypadKey(kd.keysym) ? " KeypadKey" : "", + IsCursorKey(kd.keysym) ? " CursorKey" : "", + IsPFKey(kd.keysym) ? " PFKey" : "", + kd.is_fkey ? " FKey" : "", + IsMiscFunctionKey(kd.keysym) ? " MiscFKey" : "", + IsEditFunctionKey(kd.keysym) ? " EditFkey" : "")); + +#if OPT_SUNPC_KBD + /* + * DEC keyboards don't have keypad(+), but do have keypad(,) instead. + * Other (Sun, PC) keyboards commonly have keypad(+), but no keypad(,) + * - it's a pain for users to work around. + */ + if (keyboard->type == keyboardIsVT220 + && (evt_state & ShiftMask) == 0) { + if (kd.keysym == XK_KP_Add) { + kd.keysym = XK_KP_Separator; + evt_state &= ~ShiftMask; + TRACE(("...Input keypad(+), change keysym to " + KEYSYM_FMT + "\n", + kd.keysym)); + } + if ((evt_state & ControlMask) != 0 + && kd.keysym == XK_KP_Separator) { + kd.keysym = XK_KP_Subtract; + evt_state &= ~ControlMask; + TRACE(("...Input control/keypad(,), change keysym to " + KEYSYM_FMT + "\n", + kd.keysym)); + } + } +#endif + + /* + * The keyboard tables may give us different keypad codes according to + * whether NumLock is pressed. Use this check to simplify the process + * of determining whether we generate an escape sequence for a keypad + * key, or force it to the value kypd_num[]. There is no fixed + * modifier for this feature, so we assume that it is the one assigned + * to the NumLock key. + * + * This check used to try to return the contents of strbuf, but that + * does not work properly when a control modifier is given (trash is + * returned in the buffer in some cases -- perhaps an X bug). + */ +#if OPT_NUM_LOCK + if (kd.nbytes == 1 + && IsKeypadKey(kd.keysym) + && xw->misc.real_NumLock + && (xw->misc.num_lock & evt_state) != 0) { + keypad_mode = 0; + TRACE(("...Input num_lock, force keypad_mode off\n")); + } +#endif + +#if OPT_MOD_FKEYS + if (evt_state != 0 + && allowModifierParm(xw, &kd)) { + modify_parm = computeModifierParm(xw, evt_state); + } + + /* + * Shift-tab is often mapped to XK_ISO_Left_Tab which is classified as + * IsEditFunctionKey(), and the conversion does not produce any bytes. + * Check for this special case so we have data when handling the + * modifyOtherKeys resource. + */ + if (keyboard->modify_now.other_keys > 1) { + if (IsTabKey(kd.keysym) && kd.nbytes == 0) { + kd.nbytes = 1; + kd.strbuf[0] = '\t'; + } + } +#endif /* OPT_MOD_FKEYS */ + + /* VT300 & up: backarrow toggle */ + if ((kd.nbytes == 1) + && IsBackarrowToggle(keyboard, kd.keysym, evt_state)) { + kd.strbuf[0] = DEL; + TRACE(("...Input backarrow changed to %d\n", kd.strbuf[0])); + } +#if OPT_SUNPC_KBD + /* make an DEC editing-keypad from a Sun or PC editing-keypad */ + if (keyboard->type == keyboardIsVT220 + && (kd.keysym != XK_Delete || !xtermDeleteIsDEL(xw))) + kd.keysym = TranslateFromSUNPC(kd.keysym); + else +#endif + { +#ifdef XK_KP_Home + if (kd.keysym >= XK_KP_Home && kd.keysym <= XK_KP_Begin) { + TRACE(("...Input keypad before was " KEYSYM_FMT "\n", kd.keysym)); + kd.keysym += XK_Home - XK_KP_Home; + TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", kd.keysym)); + } +#endif + } + + /* + * Map the Sun afterthought-keys in as F36 and F37. + */ +#ifdef SunXK_F36 + if (!kd.is_fkey) { + if (kd.keysym == SunXK_F36) { + kd.keysym = XK_Fn(36); + kd.is_fkey = True; + } + if (kd.keysym == SunXK_F37) { + kd.keysym = XK_Fn(37); + kd.is_fkey = True; + } + } +#endif + + /* + * Use the control- and shift-modifiers to obtain more function keys than + * the keyboard provides. We can do this if there is no conflicting use of + * those modifiers: + * + * a) for VT220 keyboard, we use only the control-modifier. The keyboard + * uses shift-modifier for UDK's. + * + * b) for non-VT220 keyboards, we only have to check if the + * modifyFunctionKeys resource is inactive. + * + * Thereafter, we note when we have a function-key and keep that + * distinction when testing for "function-key" values. + */ + if ((evt_state & (ControlMask | ShiftMask)) != 0 + && kd.is_fkey) { + + /* VT220 keyboard uses shift for UDK */ + if (keyboard->type == keyboardIsVT220 + || keyboard->type == keyboardIsLegacy) { + + TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1)); + if (evt_state & ControlMask) { + kd.keysym += xw->misc.ctrl_fkeys; + evt_state &= ~ControlMask; + } + TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1)); + + } +#if OPT_MOD_FKEYS + else if (keyboard->modify_now.function_keys < 0) { + + TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1)); + if (evt_state & ShiftMask) { + kd.keysym += xw->misc.ctrl_fkeys * 1; + evt_state &= ~ShiftMask; + } + if (evt_state & ControlMask) { + kd.keysym += xw->misc.ctrl_fkeys * 2; + evt_state &= ~ControlMask; + } + TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1)); + + } + /* + * Reevaluate the modifier parameter, stripping off the modifiers + * that we just used. + */ + if (modify_parm) + modify_parm = computeModifierParm(xw, evt_state); +#endif /* OPT_MOD_FKEYS */ + } + + /* + * Test for one of the keyboard variants. + */ + switch (keyboard->type) { + case keyboardIsHP: + hpfuncvalue(&reply, &kd); + break; + case keyboardIsSCO: + scofuncvalue(&reply, &kd); + break; + case keyboardIsSun: + sunfuncvalue(&reply, &kd); + break; + case keyboardIsDefault: + case keyboardIsLegacy: + case keyboardIsVT220: + break; + } + + if (reply.a_final) { + /* + * The key symbol matches one of the variants. Most of those are + * function-keys, though some cursor- and editing-keys are mixed in. + */ + modifyCursorKey(&reply, + ((kd.is_fkey + || IsMiscFunctionKey(kd.keysym) + || IsEditFunctionKey(kd.keysym)) + ? keyboard->modify_now.function_keys + : keyboard->modify_now.cursor_keys), + modify_parm); + MODIFIER_PARM; + unparseseq(xw, &reply); + } else if (((kd.is_fkey + || IsMiscFunctionKey(kd.keysym) + || IsEditFunctionKey(kd.keysym)) +#if OPT_MOD_FKEYS + && !ModifyOtherKeys(xw, evt_state, &kd, modify_parm) +#endif + ) || (kd.keysym == XK_Delete + && ((modify_parm > 1) + || !xtermDeleteIsDEL(xw)))) { + dec_code = decfuncvalue(&kd); + if ((evt_state & ShiftMask) +#if OPT_SUNPC_KBD + && keyboard->type == keyboardIsVT220 +#endif + && ((string = (Char *) udk_lookup(dec_code, &kd.nbytes)) != 0)) { + evt_state &= ~ShiftMask; + while (kd.nbytes-- > 0) + unparseputc(xw, CharOf(*string++)); + } +#if OPT_VT52_MODE + /* + * Interpret F1-F4 as PF1-PF4 for VT52, VT100 + */ + else if (keyboard->type != keyboardIsLegacy + && (dec_code >= 11 && dec_code <= 14)) { + reply.a_type = SS3; + VT52_CURSOR_KEYS; + reply.a_final = A2E(dec_code - 11 + E2A('P')); + modifyCursorKey(&reply, + keyboard->modify_now.function_keys, + modify_parm); + MODIFIER_PARM; + unparseseq(xw, &reply); + } +#endif + else { + reply.a_type = CSI; + reply.a_final = 0; + +#ifdef XK_ISO_Left_Tab + if (kd.keysym == XK_ISO_Left_Tab) { + reply.a_nparam = 0; + reply.a_final = 'Z'; +#if OPT_MOD_FKEYS + if (keyboard->modify_now.other_keys > 1 + && computeModifierParm(xw, evt_state & ~ShiftMask) > 1) + modifyOtherKey(&reply, '\t', modify_parm); +#endif + } else +#endif /* XK_ISO_Left_Tab */ + { + reply.a_nparam = 1; +#if OPT_MOD_FKEYS + if (kd.is_fkey) { + modifyCursorKey(&reply, + keyboard->modify_now.function_keys, + modify_parm); + } + MODIFIER_PARM; +#endif + reply.a_param[0] = dec_code; + reply.a_final = '~'; + } + if (reply.a_final != 0 + && (reply.a_nparam == 0 || reply.a_param[0] >= 0)) + unparseseq(xw, &reply); + } + key = True; + } else if (IsPFKey(kd.keysym)) { + reply.a_type = SS3; + reply.a_final = kd.keysym - XK_KP_F1 + 'P'; + VT52_CURSOR_KEYS; + MODIFIER_PARM; + unparseseq(xw, &reply); + key = True; + } else if (IsKeypadKey(kd.keysym)) { + if (keypad_mode) { + reply.a_type = SS3; + reply.a_final = kypd_apl[kd.keysym - XK_KP_Space]; + VT52_KEYPAD; + MODIFIER_PARM; + unparseseq(xw, &reply); + } else { + unparseputc(xw, kypd_num[kd.keysym - XK_KP_Space]); + } + key = True; + } else if (IsCursorKey(kd.keysym)) { + if (keyboard->flags & MODE_DECCKM) { + reply.a_type = SS3; + } else { + reply.a_type = CSI; + } + modifyCursorKey(&reply, keyboard->modify_now.cursor_keys, modify_parm); + reply.a_final = curfinal[kd.keysym - XK_Home]; + VT52_CURSOR_KEYS; + MODIFIER_PARM; + unparseseq(xw, &reply); + key = True; + } else if (kd.nbytes > 0) { + int prefix = 0; + +#if OPT_TEK4014 + if (screen->TekGIN) { + TekEnqMouse(kd.strbuf[0]); + TekGINoff(); + kd.nbytes--; + for (j = 0; j < kd.nbytes; ++j) { + kd.strbuf[j] = kd.strbuf[j + 1]; + } + } +#endif +#if OPT_MOD_FKEYS + if ((keyboard->modify_now.other_keys > 0) + && ModifyOtherKeys(xw, evt_state, &kd, modify_parm) + && (mod_state = allowedCharModifiers(xw, evt_state, &kd)) != 0) { + int input_char; + + evt_state = mod_state; + + modify_parm = computeModifierParm(xw, evt_state); + + /* + * We want to show a keycode that corresponds to the 8-bit value + * of the key. If the keysym is less than 256, that is good + * enough. Special keys such as Tab may result in a value that + * is usable as well. For the latter (special cases), try to use + * the result from the X library lookup. + */ + input_char = ((kd.keysym < 256) + ? (int) kd.keysym + : ((kd.nbytes == 1) + ? CharOf(kd.strbuf[0]) + : -1)); + + TRACE(("...modifyOtherKeys %d;%d\n", modify_parm, input_char)); + if (modifyOtherKey(&reply, input_char, modify_parm)) { + unparseseq(xw, &reply); + } else { + Bell(XkbBI_MinorError, 0); + } + } else +#endif /* OPT_MOD_FKEYS */ + { +#if OPT_NUM_LOCK + /* + * Send ESC if we have a META modifier and metaSendsEcape is true. + * Like eightBitInput, except that it is not associated with + * terminal settings. + */ + if (kd.nbytes != 0 + && screen->meta_sends_esc + && (evt_state & xw->misc.meta_mods) != 0) { + TRACE(("...input-char is modified by META\n")); + /* + * If we cannot distinguish between the Alt/Meta keys, disallow + * the corresponding shift for eightBitInput that would happen + * in the next chunk of code. + */ + if ((evt_state & xw->misc.alt_mods & xw->misc.meta_mods) != 0) + eightbit = False; + prefix = ESC; + evt_state &= ~xw->misc.meta_mods; + } +#endif + /* + * If metaSendsEscape is false, fall through to this chunk, which + * implements the eightBitInput resource. + * + * It is normally executed when the user presses Meta plus a + * printable key, e.g., Meta+space. The presence of the Meta + * modifier is not guaranteed since what really happens is the + * "insert-eight-bit" or "insert-seven-bit" action, which we + * distinguish by the eightbit parameter to this function. So the + * eightBitInput resource really means that we use this shifting + * logic in the "insert-eight-bit" action. + */ + if (eightbit && (kd.nbytes == 1) && screen->input_eight_bits) { + IChar ch = CharOf(kd.strbuf[0]); + if (ch < 128) { + kd.strbuf[0] |= 0x80; + TRACE(("...input shift from %d to %d (%#x to %#x)\n", + ch, CharOf(kd.strbuf[0]), + ch, CharOf(kd.strbuf[0]))); +#if OPT_WIDE_CHARS + if (screen->utf8_mode) { + /* + * We could interpret the incoming code as "in the + * current locale", but it's simpler to treat it as + * a Unicode value to translate to UTF-8. + */ + ch = CharOf(kd.strbuf[0]); + kd.nbytes = 2; + kd.strbuf[0] = 0xc0 | ((ch >> 6) & 0x3); + kd.strbuf[1] = 0x80 | (ch & 0x3f); + TRACE(("...encoded %#x in UTF-8 as %#x,%#x\n", + ch, CharOf(kd.strbuf[0]), CharOf(kd.strbuf[1]))); + } +#endif + } + eightbit = False; + } +#if OPT_WIDE_CHARS + if (kd.nbytes == 1) /* cannot do NRC on UTF-8, for instance */ +#endif + { + /* VT220 & up: National Replacement Characters */ + if ((xw->flags & NATIONAL) != 0) { + int cmp = xtermCharSetIn(CharOf(kd.strbuf[0]), + screen->keyboard_dialect[0]); + TRACE(("...input NRC %d, %s %d\n", + CharOf(kd.strbuf[0]), + (CharOf(kd.strbuf[0]) == cmp) + ? "unchanged" + : "changed to", + CharOf(cmp))); + kd.strbuf[0] = cmp; + } else if (eightbit) { + prefix = ESC; + } else if (kd.strbuf[0] == '?' + && (evt_state & ControlMask) != 0) { + kd.strbuf[0] = DEL; + evt_state &= ~ControlMask; + } + } + if (prefix != 0) + unparseputc(xw, prefix); /* escape */ + for (j = 0; j < kd.nbytes; ++j) + unparseputc(xw, CharOf(kd.strbuf[j])); + } + key = True; + } + unparse_end(xw); + + if (key && !TEK4014_ACTIVE(screen)) + AdjustAfterInput(screen); + + return; +} + +void +StringInput(XtermWidget xw, Char * string, size_t nbytes) +{ + TScreen *screen = &(xw->screen); + + TRACE(("InputString (%s,%d)\n", + visibleChars(PAIRED_CHARS(string, 0), nbytes), + nbytes)); +#if OPT_TEK4014 + if (nbytes && screen->TekGIN) { + TekEnqMouse(*string++); + TekGINoff(); + nbytes--; + } +#endif + while (nbytes-- != 0) + unparseputc(xw, *string++); + if (!TEK4014_ACTIVE(screen)) + AdjustAfterInput(screen); + unparse_end(xw); +} + +/* These definitions are DEC-style (e.g., vt320) */ +static int +decfuncvalue(KEY_DATA * kd) +{ + int result; + + if (kd->is_fkey) { + switch (kd->keysym) { + MAP(XK_Fn(1), 11); + MAP(XK_Fn(2), 12); + MAP(XK_Fn(3), 13); + MAP(XK_Fn(4), 14); + MAP(XK_Fn(5), 15); + MAP(XK_Fn(6), 17); + MAP(XK_Fn(7), 18); + MAP(XK_Fn(8), 19); + MAP(XK_Fn(9), 20); + MAP(XK_Fn(10), 21); + MAP(XK_Fn(11), 23); + MAP(XK_Fn(12), 24); + MAP(XK_Fn(13), 25); + MAP(XK_Fn(14), 26); + MAP(XK_Fn(15), 28); + MAP(XK_Fn(16), 29); + MAP(XK_Fn(17), 31); + MAP(XK_Fn(18), 32); + MAP(XK_Fn(19), 33); + MAP(XK_Fn(20), 34); + default: + /* after F20 the codes are made up and do not correspond to any + * real terminal. So they are simply numbered sequentially. + */ + result = 42 + (kd->keysym - XK_Fn(21)); + break; + } + } else { + switch (kd->keysym) { + MAP(XK_Find, 1); + MAP(XK_Insert, 2); + MAP(XK_Delete, 3); +#ifdef XK_KP_Insert + MAP(XK_KP_Insert, 2); + MAP(XK_KP_Delete, 3); +#endif +#ifdef DXK_Remove + MAP(DXK_Remove, 3); +#endif + MAP(XK_Select, 4); + MAP(XK_Prior, 5); + MAP(XK_Next, 6); +#ifdef XK_ISO_Left_Tab + MAP(XK_ISO_Left_Tab, 'Z'); +#endif + MAP(XK_Help, 28); + MAP(XK_Menu, 29); + default: + result = -1; + break; + } + } + return result; +} + +static void +hpfuncvalue(ANSI * reply, KEY_DATA * kd) +{ +#if OPT_HP_FUNC_KEYS + int result; + + if (kd->is_fkey) { + switch (kd->keysym) { + MAP(XK_Fn(1), 'p'); + MAP(XK_Fn(2), 'q'); + MAP(XK_Fn(3), 'r'); + MAP(XK_Fn(4), 's'); + MAP(XK_Fn(5), 't'); + MAP(XK_Fn(6), 'u'); + MAP(XK_Fn(7), 'v'); + MAP(XK_Fn(8), 'w'); + default: + result = -1; + break; + } + } else { + switch (kd->keysym) { + MAP(XK_Up, 'A'); + MAP(XK_Down, 'B'); + MAP(XK_Right, 'C'); + MAP(XK_Left, 'D'); + MAP(XK_End, 'F'); + MAP(XK_Clear, 'J'); + MAP(XK_Delete, 'P'); + MAP(XK_Insert, 'Q'); + MAP(XK_Next, 'S'); + MAP(XK_Prior, 'T'); + MAP(XK_Home, 'h'); +#ifdef XK_KP_Insert + MAP(XK_KP_Delete, 'P'); + MAP(XK_KP_Insert, 'Q'); +#endif +#ifdef DXK_Remove + MAP(DXK_Remove, 'P'); +#endif + MAP(XK_Select, 'F'); + MAP(XK_Find, 'h'); + default: + result = -1; + break; + } + } + if (result > 0) { + reply->a_type = ESC; + reply->a_final = result; + } +#else + (void) reply; + (void) kd; +#endif /* OPT_HP_FUNC_KEYS */ +} + +static void +scofuncvalue(ANSI * reply, KEY_DATA * kd) +{ +#if OPT_SCO_FUNC_KEYS + int result; + + if (kd->is_fkey) { + switch (kd->keysym) { + MAP(XK_Fn(1), 'M'); + MAP(XK_Fn(2), 'N'); + MAP(XK_Fn(3), 'O'); + MAP(XK_Fn(4), 'P'); + MAP(XK_Fn(5), 'Q'); + MAP(XK_Fn(6), 'R'); + MAP(XK_Fn(7), 'S'); + MAP(XK_Fn(8), 'T'); + MAP(XK_Fn(9), 'U'); + MAP(XK_Fn(10), 'V'); + MAP(XK_Fn(11), 'W'); + MAP(XK_Fn(12), 'X'); + MAP(XK_Fn(13), 'Y'); + MAP(XK_Fn(14), 'Z'); + MAP(XK_Fn(15), 'a'); + MAP(XK_Fn(16), 'b'); + MAP(XK_Fn(17), 'c'); + MAP(XK_Fn(18), 'd'); + MAP(XK_Fn(19), 'e'); + MAP(XK_Fn(20), 'f'); + MAP(XK_Fn(21), 'g'); + MAP(XK_Fn(22), 'h'); + MAP(XK_Fn(23), 'i'); + MAP(XK_Fn(24), 'j'); + MAP(XK_Fn(25), 'k'); + MAP(XK_Fn(26), 'l'); + MAP(XK_Fn(27), 'm'); + MAP(XK_Fn(28), 'n'); + MAP(XK_Fn(29), 'o'); + MAP(XK_Fn(30), 'p'); + MAP(XK_Fn(31), 'q'); + MAP(XK_Fn(32), 'r'); + MAP(XK_Fn(33), 's'); + MAP(XK_Fn(34), 't'); + MAP(XK_Fn(35), 'u'); + MAP(XK_Fn(36), 'v'); + MAP(XK_Fn(37), 'w'); + MAP(XK_Fn(38), 'x'); + MAP(XK_Fn(39), 'y'); + MAP(XK_Fn(40), 'z'); + MAP(XK_Fn(41), '@'); + MAP(XK_Fn(42), '['); + MAP(XK_Fn(43), '\\'); + MAP(XK_Fn(44), ']'); + MAP(XK_Fn(45), '^'); + MAP(XK_Fn(46), '_'); + MAP(XK_Fn(47), '`'); + MAP(XK_Fn(48), '{'); /* no matching '}' */ + default: + result = -1; + break; + } + } else { + switch (kd->keysym) { + MAP(XK_Up, 'A'); + MAP(XK_Down, 'B'); + MAP(XK_Right, 'C'); + MAP(XK_Left, 'D'); + MAP(XK_Begin, 'E'); + MAP(XK_End, 'F'); + MAP(XK_Insert, 'L'); + MAP(XK_Next, 'G'); + MAP(XK_Prior, 'I'); + MAP(XK_Home, 'H'); +#ifdef XK_KP_Insert + MAP(XK_KP_Insert, 'L'); +#endif + default: + result = -1; + break; + } + } + if (result > 0) { + reply->a_type = CSI; + reply->a_final = result; + } +#else + (void) reply; + (void) kd; +#endif /* OPT_SCO_FUNC_KEYS */ +} + +static void +sunfuncvalue(ANSI * reply, KEY_DATA * kd) +{ +#ifdef OPT_SUN_FUNC_KEYS + int result; + + if (kd->is_fkey) { + switch (kd->keysym) { + /* kf1-kf20 are numbered sequentially */ + MAP(XK_Fn(1), 224); + MAP(XK_Fn(2), 225); + MAP(XK_Fn(3), 226); + MAP(XK_Fn(4), 227); + MAP(XK_Fn(5), 228); + MAP(XK_Fn(6), 229); + MAP(XK_Fn(7), 230); + MAP(XK_Fn(8), 231); + MAP(XK_Fn(9), 232); + MAP(XK_Fn(10), 233); + MAP(XK_Fn(11), 192); + MAP(XK_Fn(12), 193); + MAP(XK_Fn(13), 194); + MAP(XK_Fn(14), 195); /* kund */ + MAP(XK_Fn(15), 196); + MAP(XK_Fn(16), 197); /* kcpy */ + MAP(XK_Fn(17), 198); + MAP(XK_Fn(18), 199); + MAP(XK_Fn(19), 200); /* kfnd */ + MAP(XK_Fn(20), 201); + + /* kf31-kf36 are numbered sequentially */ + MAP(XK_Fn(21), 208); /* kf31 */ + MAP(XK_Fn(22), 209); + MAP(XK_Fn(23), 210); + MAP(XK_Fn(24), 211); + MAP(XK_Fn(25), 212); + MAP(XK_Fn(26), 213); /* kf36 */ + + /* kf37-kf47 are interspersed with keypad keys */ + MAP(XK_Fn(27), 214); /* khome */ + MAP(XK_Fn(28), 215); /* kf38 */ + MAP(XK_Fn(29), 216); /* kpp */ + MAP(XK_Fn(30), 217); /* kf40 */ + MAP(XK_Fn(31), 218); /* kb2 */ + MAP(XK_Fn(32), 219); /* kf42 */ + MAP(XK_Fn(33), 220); /* kend */ + MAP(XK_Fn(34), 221); /* kf44 */ + MAP(XK_Fn(35), 222); /* knp */ + MAP(XK_Fn(36), 234); /* kf46 */ + MAP(XK_Fn(37), 235); /* kf47 */ + default: + result = -1; + break; + } + } else { + switch (kd->keysym) { + MAP(XK_Help, 196); /* khlp */ + MAP(XK_Menu, 197); + + MAP(XK_Find, 1); + MAP(XK_Insert, 2); /* kich1 */ + MAP(XK_Delete, 3); +#ifdef XK_KP_Insert + MAP(XK_KP_Insert, 2); + MAP(XK_KP_Delete, 3); +#endif +#ifdef DXK_Remove + MAP(DXK_Remove, 3); +#endif + MAP(XK_Select, 4); + + MAP(XK_Prior, 216); + MAP(XK_Next, 222); + MAP(XK_Home, 214); + MAP(XK_End, 220); + MAP(XK_Begin, 218); /* kf41=kb2 */ + + default: + result = -1; + break; + } + } + if (result > 0) { + reply->a_type = CSI; + reply->a_nparam = 1; + reply->a_param[0] = result; + reply->a_final = 'z'; + } else if (IsCursorKey(kd->keysym)) { + reply->a_type = SS3; + reply->a_final = curfinal[kd->keysym - XK_Home]; + } +#else + (void) reply; + (void) kd; +#endif /* OPT_SUN_FUNC_KEYS */ +} + +#if OPT_NUM_LOCK +/* + * Note that this can only retrieve translations that are given as resource + * values; the default translations in charproc.c for example are not + * retrievable by any interface to X. + * + * Also: We can retrieve only the most-specified translation resource. For + * example, if the resource file specifies both "*translations" and + * "XTerm*translations", we see only the latter. + */ +static Bool +TranslationsUseKeyword(Widget w, const char *keyword) +{ + static String data; + static XtResource key_resources[] = + { + {XtNtranslations, XtCTranslations, XtRString, + sizeof(data), 0, XtRString, (XtPointer) NULL} + }; + Bool result = False; + + XtGetSubresources(w, + (XtPointer) &data, + "vt100", + "VT100", + key_resources, + XtNumber(key_resources), + NULL, + (Cardinal) 0); + + if (data != 0) { + char *p = data; + int state = 0; + int now = ' ', prv; + TRACE(("TranslationsUseKeyword(%p):%s\n", w, p)); + while (*p != 0) { + prv = now; + now = char2lower(*p++); + if (now == ':' + || now == '!') { + state = -1; + } else if (now == '\n') { + state = 0; + } else if (state >= 0) { + if (isgraph(now) + && now == keyword[state]) { + if ((state != 0 + || !isalnum(prv)) + && ((keyword[++state] == 0) + && !isalnum(CharOf(*p)))) { + result = True; + break; + } + } else { + state = 0; + } + } + } + } + TRACE(("TranslationsUseKeyword(%p, %s) = %d\n", w, keyword, result)); + return result; +} + +#define SaveMask(name) xw->misc.name |= mask;\ + TRACE(("SaveMask(%s) %#lx (%#lx is%s modifier)\n", \ + #name, \ + xw->misc.name, mask, \ + ModifierName(mask))); +/* + * Determine which modifier mask (if any) applies to the Num_Lock keysym. + * + * Also, determine which modifiers are associated with the ALT keys, so we can + * send that information as a parameter for special keys in Sun/PC keyboard + * mode. However, if the ALT modifier is used in translations, we do not want + * to confuse things by sending the parameter. + */ +void +VTInitModifiers(XtermWidget xw) +{ + int i, j, k; + Display *dpy = XtDisplay(xw); + XModifierKeymap *keymap = XGetModifierMapping(dpy); + unsigned long mask; + int min_keycode, max_keycode, keysyms_per_keycode = 0; + + if (keymap != 0) { + KeySym *theMap; + int keycode_count; + + TRACE(("VTInitModifiers\n")); + + XDisplayKeycodes(dpy, &min_keycode, &max_keycode); + keycode_count = (max_keycode - min_keycode + 1); + theMap = XGetKeyboardMapping(dpy, + min_keycode, + keycode_count, + &keysyms_per_keycode); + + if (theMap != 0) { + for (i = k = 0, mask = 1; i < 8; i++, mask <<= 1) { + for (j = 0; j < keymap->max_keypermod; j++) { + KeyCode code = keymap->modifiermap[k]; + if (code != 0) { + KeySym keysym; + int l = 0; + do { + keysym = XKeycodeToKeysym(dpy, code, l); + l++; + } while (!keysym && l < keysyms_per_keycode); + if (keysym == XK_Num_Lock) { + SaveMask(num_lock); + } else if (keysym == XK_Alt_L || keysym == XK_Alt_R) { + SaveMask(alt_mods); + } else if (keysym == XK_Meta_L || keysym == XK_Meta_R) { + SaveMask(meta_mods); + } else if (mask == ShiftMask + && (keysym == XK_Shift_L + || keysym == XK_Shift_R)) { + ; /* ignore */ + } else if (mask == ControlMask + && (keysym == XK_Control_L + || keysym == XK_Control_R)) { + ; /* ignore */ + } else if (mask == LockMask + && (keysym == XK_Caps_Lock)) { + ; /* ignore */ + } else { + SaveMask(other_mods); + } + } + k++; + } + } + XFree(theMap); + } + + /* Don't disable any mods if "alwaysUseMods" is true. */ + if (!xw->misc.alwaysUseMods) { + /* + * If the Alt modifier is used in translations, we would rather not + * use it to modify function-keys when NumLock is active. + */ + if ((xw->misc.alt_mods != 0) + && (TranslationsUseKeyword(toplevel, "alt") + || TranslationsUseKeyword((Widget) xw, "alt"))) { + TRACE(("ALT is used as a modifier in translations (ignore mask)\n")); + xw->misc.alt_mods = 0; + } + + /* + * If the Meta modifier is used in translations, we would rather not + * use it to modify function-keys. + */ + if ((xw->misc.meta_mods != 0) + && (TranslationsUseKeyword(toplevel, "meta") + || TranslationsUseKeyword((Widget) xw, "meta"))) { + TRACE(("META is used as a modifier in translations\n")); + xw->misc.meta_mods = 0; + } + } + + XFreeModifiermap(keymap); + } +} +#endif /* OPT_NUM_LOCK */ + +#if OPT_TCAP_QUERY +static int +hex2int(int c) +{ + if (c >= '0' && c <= '9') + return c - '0'; + if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + return -1; +} + +/* + * Parse the termcap/terminfo name from the string, returning a positive number + * (the keysym) if found, otherwise -1. Update the string pointer. + * Returns the (shift, control) state in *state. + * + * This does not attempt to construct control/shift modifiers to construct + * function-key values. Instead, it sets the *fkey flag to pass to Input() + * and bypass the lookup of keysym altogether. + */ +int +xtermcapKeycode(XtermWidget xw, char **params, unsigned *state, Bool * fkey) +{ + /* *INDENT-OFF* */ +#define DATA(tc,ti,x,y) { tc, ti, x, y } + static struct { + char *tc; + char *ti; + int code; + unsigned state; + } table[] = { + /* tcap terminfo keycode masks */ + DATA( "%1", "khlp", XK_Help, 0 ), + DATA( "#1", "kHLP", XK_Help, ShiftMask ), + DATA( "@0", "kfnd", XK_Find, 0 ), + DATA( "*0", "kFND", XK_Find, ShiftMask ), + DATA( "*6", "kslt", XK_Select, 0 ), + DATA( "#6", "kSLT", XK_Select, ShiftMask ), + + DATA( "kh", "khome", XK_Home, 0 ), + DATA( "#2", "kHOM", XK_Home, ShiftMask ), + DATA( "@7", "kend", XK_End, 0 ), + DATA( "*7", "kEND", XK_End, ShiftMask ), + + DATA( "kl", "kcub1", XK_Left, 0 ), + DATA( "kr", "kcuf1", XK_Right, 0 ), + DATA( "ku", "kcuu1", XK_Up, 0 ), + DATA( "kd", "kcud1", XK_Down, 0 ), + + DATA( "#4", "kLFT", XK_Left, ShiftMask ), + DATA( "%i", "kRIT", XK_Right, ShiftMask ), + DATA( "%e", "kPRV", XK_Up, ShiftMask ), + DATA( "%c", "kNXT", XK_Down, ShiftMask ), + + DATA( "k1", "kf1", XK_Fn(1), 0 ), + DATA( "k2", "kf2", XK_Fn(2), 0 ), + DATA( "k3", "kf3", XK_Fn(3), 0 ), + DATA( "k4", "kf4", XK_Fn(4), 0 ), + DATA( "k5", "kf5", XK_Fn(5), 0 ), + DATA( "k6", "kf6", XK_Fn(6), 0 ), + DATA( "k7", "kf7", XK_Fn(7), 0 ), + DATA( "k8", "kf8", XK_Fn(8), 0 ), + DATA( "k9", "kf9", XK_Fn(9), 0 ), + DATA( "k;", "kf10", XK_Fn(10), 0 ), + + DATA( "F1", "kf11", XK_Fn(11), 0 ), + DATA( "F2", "kf12", XK_Fn(12), 0 ), + DATA( "F3", "kf13", XK_Fn(13), 0 ), + DATA( "F4", "kf14", XK_Fn(14), 0 ), + DATA( "F5", "kf15", XK_Fn(15), 0 ), + DATA( "F6", "kf16", XK_Fn(16), 0 ), + DATA( "F7", "kf17", XK_Fn(17), 0 ), + DATA( "F8", "kf18", XK_Fn(18), 0 ), + DATA( "F9", "kf19", XK_Fn(19), 0 ), + DATA( "FA", "kf20", XK_Fn(20), 0 ), + DATA( "FB", "kf21", XK_Fn(21), 0 ), + DATA( "FC", "kf22", XK_Fn(22), 0 ), + DATA( "FD", "kf23", XK_Fn(23), 0 ), + DATA( "FE", "kf24", XK_Fn(24), 0 ), + DATA( "FF", "kf25", XK_Fn(25), 0 ), + DATA( "FG", "kf26", XK_Fn(26), 0 ), + DATA( "FH", "kf27", XK_Fn(27), 0 ), + DATA( "FI", "kf28", XK_Fn(28), 0 ), + DATA( "FJ", "kf29", XK_Fn(29), 0 ), + DATA( "FK", "kf30", XK_Fn(30), 0 ), + DATA( "FL", "kf31", XK_Fn(31), 0 ), + DATA( "FM", "kf32", XK_Fn(32), 0 ), + DATA( "FN", "kf33", XK_Fn(33), 0 ), + DATA( "FO", "kf34", XK_Fn(34), 0 ), + DATA( "FP", "kf35", XK_Fn(35), 0 ), + + DATA( "FQ", "kf36", -36, 0 ), + DATA( "FR", "kf37", -37, 0 ), + DATA( "FS", "kf38", -38, 0 ), + DATA( "FT", "kf39", -39, 0 ), + DATA( "FU", "kf40", -40, 0 ), + DATA( "FV", "kf41", -41, 0 ), + DATA( "FW", "kf42", -42, 0 ), + DATA( "FX", "kf43", -43, 0 ), + DATA( "FY", "kf44", -44, 0 ), + DATA( "FZ", "kf45", -45, 0 ), + DATA( "Fa", "kf46", -46, 0 ), + DATA( "Fb", "kf47", -47, 0 ), + DATA( "Fc", "kf48", -48, 0 ), + DATA( "Fd", "kf49", -49, 0 ), + DATA( "Fe", "kf50", -50, 0 ), + DATA( "Ff", "kf51", -51, 0 ), + DATA( "Fg", "kf52", -52, 0 ), + DATA( "Fh", "kf53", -53, 0 ), + DATA( "Fi", "kf54", -54, 0 ), + DATA( "Fj", "kf55", -55, 0 ), + DATA( "Fk", "kf56", -56, 0 ), + DATA( "Fl", "kf57", -57, 0 ), + DATA( "Fm", "kf58", -58, 0 ), + DATA( "Fn", "kf59", -59, 0 ), + DATA( "Fo", "kf60", -60, 0 ), + DATA( "Fp", "kf61", -61, 0 ), + DATA( "Fq", "kf62", -62, 0 ), + DATA( "Fr", "kf63", -63, 0 ), + + DATA( "K1", "ka1", XK_KP_Home, 0 ), + DATA( "K4", "kc1", XK_KP_End, 0 ), + +#ifdef XK_ISO_Left_Tab + DATA( "kB", "kcbt", XK_ISO_Left_Tab, 0 ), +#endif + DATA( "kC", "kclr", XK_Clear, 0 ), + DATA( "kD", "kdch1", XK_Delete, 0 ), + DATA( "kI", "kich1", XK_Insert, 0 ), + DATA( "kN", "knp", XK_Next, 0 ), + DATA( "kP", "kpp", XK_Prior, 0 ), + DATA( "kb", "kbs", XK_BackSpace, 0 ), +# if OPT_ISO_COLORS + /* XK_COLORS is a fake code. */ + DATA( "Co", "colors", XK_COLORS, 0 ), +# endif + }; + /* *INDENT-ON* */ + + Cardinal n; + unsigned len = 0; + int code = -1; +#define MAX_TNAME_LEN 6 + char name[MAX_TNAME_LEN + 1]; + char *p; + + TRACE(("xtermcapKeycode(%s)\n", *params)); + + /* Convert hex encoded name to ascii */ + for (p = *params; hex2int(p[0]) >= 0 && hex2int(p[1]) >= 0; p += 2) { + if (len >= MAX_TNAME_LEN) + break; + name[len++] = (hex2int(p[0]) << 4) + hex2int(p[1]); + } + name[len] = 0; + *params = p; + + *state = 0; + *fkey = False; + + if (*p == 0 || *p == ';') { + for (n = 0; n < XtNumber(table); n++) { + if (!strcmp(table[n].ti, name) || !strcmp(table[n].tc, name)) { + code = table[n].code; + *state = table[n].state; + if (IsFunctionKey(code)) { + *fkey = True; + } else if (code < 0) { + *fkey = True; + code = XK_Fn((-code)); + } +#ifdef OPT_SUN_FUNC_KEYS + if (*fkey && xw->keyboard.type == keyboardIsSun) { + int num = code - XK_Fn(0); + + /* match function-key case in sunfuncvalue() */ + if (num > 20) { + if (num <= 30 || num > 47) { + code = -1; + } else { + code -= 10; + switch (num) { + case 37: /* khome */ + case 39: /* kpp */ + case 41: /* kb2 */ + case 43: /* kend */ + case 45: /* knp */ + code = -1; + break; + } + } + } + } +#endif + break; + } + } + } + + TRACE(("... xtermcapKeycode(%s, %u, %d) -> %#06x\n", + name, *state, *fkey, code)); + return code; +} +#endif |