/* $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 #include #ifdef VMS #include #endif #if HAVE_X11_DECKEYSYM_H #include #endif #if HAVE_X11_SUNKEYSYM_H #include #endif #include #include #include #include #include /* * 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 */ 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