#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
#if HAVE_X11_XF86KEYSYM_H
#include <X11/XF86keysym.h>
#endif
#include <X11/Xutil.h>
#include <stdio.h>
#include <ctype.h>
#include <xutf8.h>
#include <data.h>
#include <fontutils.h>
#include <xstrings.h>
#include <xtermcap.h>
#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 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 Masked(value,mask) ((value) & (unsigned) (~(mask)))
#define KEYSYM_FMT "0x%04lX"
#define TEK4014_GIN(tw) (tw != 0 && tw->screen.TekGIN)
typedef struct {
KeySym keysym;
Bool is_fkey;
int nbytes;
#define STRBUFSIZE 500
char strbuf[STRBUFSIZE];
} KEY_DATA;
static char *kypd_num = " XXXXXXXX\tXXX\rXXXxxxxXXXXXXXXXXXXXXXXXXXXX*+,-./0123456789XXX=";
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(XtermWidget xw)
{
TScreen *screen = &(xw->screen);
if (screen->scrollkey && screen->topline != 0)
WindowScroll(xw, 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;
}
}
static Bool
IsEditFunctionKey(KeySym keysym)
{
switch (keysym) {
case XK_Prior:
case XK_Next:
case XK_Insert:
case XK_Find:
case XK_Select:
#ifdef DXK_Remove
case DXK_Remove:
#endif
#ifdef XK_KP_Delete
case XK_KP_Delete:
case XK_KP_Insert:
#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) < ANSI_SPA || ((n) >= 0x7f && (n) <= 0x9f))
static Bool
IsControlInput(KEY_DATA * kd)
{
return ((kd->keysym) >= 0x40 && (kd->keysym) <= 0x7f);
}
static Bool
IsControlOutput(KEY_DATA * kd)
{
return IS_CTRL(kd->keysym);
}
static Bool
IsControlAlias(KEY_DATA * kd)
{
Bool result = False;
if (kd->nbytes == 1) {
result = IS_CTRL(CharOf(kd->strbuf[0]));
}
return result;
}
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 (!(IsKeypadKey(kd->keysym) && keypad_mode)
#if OPT_SUNPC_KBD
&& keyboard->type != keyboardIsVT220
#endif
#if OPT_VT52_MODE
&& screen->vtXX_level != 0
#endif
) {
result = True;
}
return result;
}
#undef CTRL
#define UNMOD 1
#define SHIFT 1
#define ALT 2
#define CTRL 4
#define META 8
#define MODIFIER_NAME(parm, name) \
(((parm > UNMOD) && ((parm - UNMOD) & name)) ? " "#name : "")
unsigned
xtermParamToState(XtermWidget xw, unsigned param)
{
unsigned result = 0;
#if OPT_NUM_LOCK
if (param > UNMOD
&& ((ShiftMask
| ControlMask
| xw->misc.alt_mods
| xw->misc.meta_mods) & xw->misc.other_mods) == 0) {
if ((param - UNMOD) & SHIFT)
result |= ShiftMask;
if ((param - UNMOD) & CTRL)
result |= ControlMask;
if ((param - UNMOD) & ALT)
result |= xw->misc.alt_mods;
if ((param - UNMOD) & META)
result |= xw->misc.meta_mods;
}
#else
(void) xw;
(void) param;
#endif
TRACE(("xtermParamToState(%d) %s%s%s%s -> %#x\n", param,
MODIFIER_NAME(param, SHIFT),
MODIFIER_NAME(param, ALT),
MODIFIER_NAME(param, CTRL),
MODIFIER_NAME(param, META),
result));
return result;
}
unsigned
xtermStateToParam(XtermWidget xw, unsigned state)
{
unsigned 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(("...xtermStateToParam %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;
}
#define computeMaskedModifier(xw, state, mask) \
xtermStateToParam(xw, Masked(state, mask))
#if OPT_NUM_LOCK
static unsigned
filterAltMeta(unsigned result, unsigned mask, Bool enable, KEY_DATA * kd)
{
if ((result & mask) != 0) {
if (enable) {
result &= ~mask;
}
if ((result & ~(mask)) == 0) {
result &= ~mask;
}
if ((IsControlInput(kd)
|| IsControlOutput(kd))
&& (result & ControlMask) != 0) {
result &= ~(mask | ControlMask);
}
if (kd->keysym == XK_Return || kd->keysym == XK_Tab) {
result &= ~(mask | ControlMask);
}
}
return result;
}
#endif
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
unsigned result = (state & (ControlMask
| ShiftMask
| a_or_m));
if (xw->keyboard.modify_now.other_keys <= 1) {
if (IsControlInput(kd)
&& Masked(result, ControlMask) == 0) {
if (xw->keyboard.modify_now.other_keys == 0) {
result &= ~ControlMask;
}
} else if (kd->keysym == XK_Tab || kd->keysym == XK_Return) {
;
} else if (IsControlAlias(kd)) {
if (Masked(result, (ControlMask | ShiftMask)) == 0) {
result = 0;
}
} else if (!IsControlOutput(kd) && !IsPredefinedKey(kd->keysym)) {
if (!(result & ControlMask)) {
result &= ~ShiftMask;
}
}
#if OPT_NUM_LOCK
result = filterAltMeta(result,
xw->misc.meta_mods,
xw->screen.meta_sends_esc, kd);
if (xw->screen.alt_is_not_meta) {
result = filterAltMeta(result,
xw->misc.alt_mods,
xw->screen.alt_sends_esc, kd);
}
#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;
}
static Bool
ModifyOtherKeys(XtermWidget xw,
unsigned state,
KEY_DATA * kd,
unsigned modify_parm)
{
TKeyboard *keyboard = &(xw->keyboard);
Bool result = False;
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 (computeMaskedModifier(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 (computeMaskedModifier(xw, state, ControlMask)
> 1) {
result = True;
}
} else {
result = True;
}
break;
}
break;
case 2:
switch (kd->keysym) {
case XK_BackSpace:
if (computeMaskedModifier(xw, state, ControlMask) > 1)
result = True;
break;
case XK_Delete:
result = (xtermStateToParam(xw, state) > 1);
break;
#ifdef XK_ISO_Left_Tab
case XK_ISO_Left_Tab:
if (computeMaskedModifier(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 (computeMaskedModifier(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[reply->a_nparam] = (ParmType) number; \
reply->a_nparam++
static Bool
modifyOtherKey(ANSI * reply, int input_char, unsigned modify_parm, int format_keys)
{
Bool result = False;
if (input_char >= 0) {
reply->a_type = ANSI_CSI;
if (format_keys) {
APPEND_PARM(input_char);
APPEND_PARM(modify_parm);
reply->a_final = 'u';
} else {
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, unsigned *modify_parm)
{
if (*modify_parm > 1) {
if (modify < 0) {
*modify_parm = 0;
}
if (modify > 0) {
reply->a_type = ANSI_CSI;
}
if (modify > 1 && reply->a_nparam == 0) {
APPEND_PARM(1);
}
if (modify > 2) {
reply->a_pintro = '>';
}
}
}
#else
#define modifyCursorKey(reply, modify, parm)
#endif
#if OPT_SUNPC_KBD
static KeySym
TranslateFromSUNPC(KeySym keysym)
{
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
};
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
#define VT52_KEYPAD \
if_OPT_VT52_MODE(screen,{ \
reply.a_type = ANSI_ESC; \
reply.a_pintro = '?'; \
})
#define VT52_CURSOR_KEYS \
if_OPT_VT52_MODE(screen,{ \
reply.a_type = ANSI_ESC; \
})
#undef APPEND_PARM
#define APPEND_PARM(number) \
reply.a_param[reply.a_nparam] = (ParmType) number, \
reply.a_nparam++
#if OPT_MOD_FKEYS
#define MODIFIER_PARM \
if (modify_parm > 1) APPEND_PARM(modify_parm)
#else
#define MODIFIER_PARM
#endif
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;
unsigned modify_parm = 0;
int keypad_mode = ((keyboard->flags & MODE_DECKPAM) != 0);
unsigned evt_state = event->state;
unsigned mod_state;
KEY_DATA kd;
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 = (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
if (status_return == XLookupBoth
&& kd.nbytes <= 1
&& !IsPredefinedKey(kd.keysym)
&& (keyboard->modify_now.other_keys > 1)
&& !IsControlInput(&kd)) {
kd.nbytes = 1;
kd.strbuf[0] = (char) kd.keysym;
}
#endif
} else
#endif
{
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 > 0)
? (unsigned) kd.nbytes
: 0)),
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
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
#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 = xtermStateToParam(xw, evt_state);
}
if (keyboard->modify_now.other_keys > 1) {
if (IsTabKey(kd.keysym) && kd.nbytes == 0) {
kd.nbytes = 1;
kd.strbuf[0] = '\t';
}
}
#endif
if ((kd.nbytes == 1)
&& IsBackarrowToggle(keyboard, kd.keysym, evt_state)) {
kd.strbuf[0] = ANSI_DEL;
TRACE(("...Input backarrow changed to %d\n", kd.strbuf[0]));
}
#if OPT_SUNPC_KBD
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 += (KeySym) (XK_Home - XK_KP_Home);
TRACE(("...Input keypad changed to " KEYSYM_FMT "\n", kd.keysym));
}
#endif
}
#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
if ((evt_state & (ControlMask | ShiftMask)) != 0
&& kd.is_fkey) {
if (keyboard->type == keyboardIsVT220
|| keyboard->type == keyboardIsLegacy) {
TRACE(("...map XK_F%ld", kd.keysym - XK_Fn(1) + 1));
if (evt_state & ControlMask) {
kd.keysym += (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 += (KeySym) (xw->misc.ctrl_fkeys * 1);
evt_state &= ~ShiftMask;
}
if (evt_state & ControlMask) {
kd.keysym += (KeySym) (xw->misc.ctrl_fkeys * 2);
evt_state &= ~ControlMask;
}
TRACE((" to XK_F%ld\n", kd.keysym - XK_Fn(1) + 1));
}
if (modify_parm)
modify_parm = xtermStateToParam(xw, evt_state);
#endif
}
switch (keyboard->type) {
case keyboardIsHP:
hpfuncvalue(&reply, &kd);
break;
case keyboardIsSCO:
scofuncvalue(&reply, &kd);
break;
case keyboardIsSun:
sunfuncvalue(&reply, &kd);
break;
case keyboardIsTermcap:
#if OPT_TCAP_FKEYS
if (xtermcapString(xw, (int) kd.keysym, evt_state))
return;
#endif
break;
case keyboardIsDefault:
case keyboardIsLegacy:
case keyboardIsVT220:
break;
}
if (reply.a_final) {
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
else if (keyboard->type != keyboardIsLegacy
&& (dec_code >= 11 && dec_code <= 14)) {
reply.a_type = ANSI_SS3;
VT52_CURSOR_KEYS;
reply.a_final = (Char) 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 = ANSI_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
&& computeMaskedModifier(xw, evt_state, ShiftMask) > 1)
modifyOtherKey(&reply, '\t', modify_parm, keyboard->format_keys);
#endif
} else
#endif
{
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] = (ParmType) 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 = ANSI_SS3;
reply.a_final = (Char) ((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 = ANSI_SS3;
reply.a_final = (Char) (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 = ANSI_SS3;
} else {
reply.a_type = ANSI_CSI;
}
modifyCursorKey(&reply, keyboard->modify_now.cursor_keys, &modify_parm);
reply.a_final = (Char) (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 (TEK4014_GIN(tekWidget)) {
TekEnqMouse(tekWidget, kd.strbuf[0]);
TekGINoff(tekWidget);
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 = xtermStateToParam(xw, evt_state);
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, keyboard->format_keys)) {
unparseseq(xw, &reply);
} else {
Bell(XkbBI_MinorError, 0);
}
} else
#endif
{
#if OPT_NUM_LOCK
if (kd.nbytes != 0) {
if (screen->meta_sends_esc
&& (evt_state & xw->misc.meta_mods) != 0) {
TRACE(("...input-char is modified by META\n"));
evt_state &= ~xw->misc.meta_mods;
eightbit = False;
prefix = ANSI_ESC;
} else if (eightbit) {
TRACE(("...input-char is shifted by META\n"));
}
if (screen->alt_is_not_meta
&& (evt_state & xw->misc.alt_mods) != 0) {
evt_state &= ~xw->misc.alt_mods;
if (screen->alt_sends_esc) {
TRACE(("...input-char is modified by ALT\n"));
eightbit = False;
prefix = ANSI_ESC;
} else if (!eightbit) {
TRACE(("...input-char is shifted by ALT\n"));
eightbit = True;
}
}
}
#endif
if (eightbit && (kd.nbytes == 1) && screen->input_eight_bits) {
IChar ch = CharOf(kd.strbuf[0]);
if (ch < 128) {
kd.strbuf[0] |= (char) 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) {
ch = CharOf(kd.strbuf[0]);
kd.nbytes = 2;
kd.strbuf[0] = (char) (0xc0 | ((ch >> 6) & 0x3));
kd.strbuf[1] = (char) (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)
#endif
{
if ((xw->flags & NATIONAL) != 0) {
unsigned 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] = (char) cmp;
} else if (eightbit) {
prefix = ANSI_ESC;
} else if (kd.strbuf[0] == '?'
&& (evt_state & ControlMask) != 0) {
kd.strbuf[0] = ANSI_DEL;
evt_state &= ~ControlMask;
}
}
if (prefix != 0)
unparseputc(xw, prefix);
for (j = 0; j < kd.nbytes; ++j)
unparseputc(xw, CharOf(kd.strbuf[j]));
}
key = True;
}
unparse_end(xw);
if (key && !TEK4014_ACTIVE(xw))
AdjustAfterInput(xw);
return;
}
void
StringInput(XtermWidget xw, Char * string, size_t nbytes)
{
TRACE(("InputString (%s,%d)\n",
visibleChars(PAIRED_CHARS(string, 0), nbytes),
nbytes));
#if OPT_TEK4014
if (nbytes && TEK4014_GIN(tekWidget)) {
TekEnqMouse(tekWidget, *string++);
TekGINoff(tekWidget);
nbytes--;
}
#endif
while (nbytes-- != 0)
unparseputc(xw, *string++);
if (!TEK4014_ACTIVE(xw))
AdjustAfterInput(xw);
unparse_end(xw);
}
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:
result = 42 + (int) (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 = ANSI_ESC;
reply->a_final = (Char) result;
}
#else
(void) reply;
(void) kd;
#endif
}
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), '{');
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 = ANSI_CSI;
reply->a_final = (Char) result;
}
#else
(void) reply;
(void) kd;
#endif
}
static void
sunfuncvalue(ANSI * reply, KEY_DATA * kd)
{
#if OPT_SUN_FUNC_KEYS
ParmType result;
if (kd->is_fkey) {
switch (kd->keysym) {
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);
MAP(XK_Fn(15), 196);
MAP(XK_Fn(16), 197);
MAP(XK_Fn(17), 198);
MAP(XK_Fn(18), 199);
MAP(XK_Fn(19), 200);
MAP(XK_Fn(20), 201);
MAP(XK_Fn(21), 208);
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);
MAP(XK_Fn(27), 214);
MAP(XK_Fn(28), 215);
MAP(XK_Fn(29), 216);
MAP(XK_Fn(30), 217);
MAP(XK_Fn(31), 218);
MAP(XK_Fn(32), 219);
MAP(XK_Fn(33), 220);
MAP(XK_Fn(34), 221);
MAP(XK_Fn(35), 222);
MAP(XK_Fn(36), 234);
MAP(XK_Fn(37), 235);
default:
result = -1;
break;
}
} else {
switch (kd->keysym) {
MAP(XK_Help, 196);
MAP(XK_Menu, 197);
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, 216);
MAP(XK_Next, 222);
MAP(XK_Home, 214);
MAP(XK_End, 220);
MAP(XK_Begin, 218);
default:
result = -1;
break;
}
}
if (result > 0) {
reply->a_type = ANSI_CSI;
reply->a_nparam = 1;
reply->a_param[0] = result;
reply->a_final = 'z';
} else if (IsCursorKey(kd->keysym)) {
reply->a_type = ANSI_SS3;
reply->a_final = (Char) curfinal[kd->keysym - XK_Home];
}
#else
(void) reply;
(void) kd;
#endif
}
#if OPT_NUM_LOCK
#define isName(c) ((c) == '_' || isalnum(CharOf(c)))
static char *
stripTranslations(const char *s)
{
char *dst = 0;
if (s != 0) {
dst = TypeMallocN(char, strlen(s) + 1);
if (dst != 0) {
int state = 0;
int ch = 0;
int prv = 0;
char *d = dst;
TRACE(("stripping:\n%s\n", s));
while (*s != '\0') {
ch = *s++;
if (ch == '\n') {
if (d != dst)
*d++ = (char) ch;
state = 0;
} else if (strchr(":!#", ch) != 0) {
while (d != dst && isspace(CharOf(d[-1])))
--d;
state = -1;
} else if (state >= 0) {
if (isspace(CharOf(ch))) {
if (state == 0 || strchr("<>~ \t", prv))
continue;
} else if (strchr("<>~", ch)) {
while (d != dst && isspace(CharOf(d[-1])))
--d;
}
*d++ = x_toupper(ch);
++state;
}
prv = ch;
}
*d = '\0';
TRACE(("...result:\n%s\n", dst));
}
}
return dst;
}
static Bool
TranslationsUseKeyword(Widget w, char **cache, const char *keyword)
{
static String data;
static XtResource key_resources[] =
{
{XtNtranslations, XtCTranslations, XtRString,
sizeof(data), 0, XtRString, (XtPointer) NULL}
};
Bool result = False;
char *copy;
char *test;
if ((test = stripTranslations(keyword)) != 0) {
if (*cache == 0) {
XtGetSubresources(w,
(XtPointer) &data,
"vt100",
"VT100",
key_resources,
XtNumber(key_resources),
NULL,
(Cardinal) 0);
if (data != 0 && (copy = stripTranslations(data)) != 0) {
*cache = copy;
}
}
if (*cache != 0) {
char *p = *cache;
int state = 0;
int now = ' ', prv;
while (*p != 0) {
prv = now;
now = *p++;
if (now == ':'
|| now == '!') {
state = -1;
} else if (now == '\n') {
state = 0;
} else if (state >= 0) {
if (now == test[state]) {
if ((state != 0
|| !isName(prv))
&& ((test[++state] == 0)
&& !isName(*p))) {
result = True;
break;
}
} else {
state = 0;
}
}
}
}
free(test);
}
TRACE(("TranslationsUseKeyword(%p, %s) = %d\n", w, keyword, result));
return result;
}
static Bool
xtermHasTranslation(XtermWidget xw, const char *keyword)
{
return (TranslationsUseKeyword(SHELL_OF(xw),
&(xw->keyboard.shell_translations),
keyword)
|| TranslationsUseKeyword((Widget) xw,
&(xw->keyboard.xterm_translations),
keyword));
}
#if OPT_EXTRA_PASTE
static void
addTranslation(XtermWidget xw, char *fromString, char *toString)
{
unsigned have = (xw->keyboard.extra_translations
? strlen(xw->keyboard.extra_translations)
: 0);
unsigned need = (((have != 0) ? (have + 4) : 0)
+ strlen(fromString)
+ strlen(toString)
+ 6);
if (!xtermHasTranslation(xw, fromString)) {
xw->keyboard.extra_translations
= TypeRealloc(char, need, xw->keyboard.extra_translations);
if ((xw->keyboard.extra_translations) != 0) {
TRACE(("adding %s: %s\n", fromString, toString));
if (have)
strcat(xw->keyboard.extra_translations, " \\n\\");
sprintf(xw->keyboard.extra_translations, "%s: %s",
fromString, toString);
TRACE(("...{%s}\n", xw->keyboard.extra_translations));
}
}
}
#endif
#define SaveMask(name) xw->misc.name |= mask;\
TRACE(("SaveMask(%s) %#lx (%#lx is%s modifier)\n", \
#name, \
xw->misc.name, mask, \
ModifierName(mask)));
void
VTInitModifiers(XtermWidget xw)
{
Display *dpy = XtDisplay(xw);
XModifierKeymap *keymap = XGetModifierMapping(dpy);
int i, j, k, l;
KeySym keysym;
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,
(KeyCode) min_keycode,
keycode_count,
&keysyms_per_keycode);
if (theMap != 0) {
#if OPT_EXTRA_PASTE
int limit = (max_keycode - min_keycode) * keysyms_per_keycode;
for (i = 0; i < limit; ++i) {
#ifdef XF86XK_Paste
if (theMap[i] == XF86XK_Paste) {
TRACE(("keyboard has XF86XK_Paste\n"));
addTranslation(xw,
"<KeyPress> XF86Paste",
"insert-selection(SELECT, CUT_BUFFER0)");
}
#endif
#ifdef SunXK_Paste
if (theMap[i] == SunXK_Paste) {
TRACE(("keyboard has SunXK_Paste\n"));
addTranslation(xw,
"<KeyPress> SunPaste",
"insert-selection(SELECT, CUT_BUFFER0)");
}
#endif
}
#endif
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)
continue;
for (l = 0; l < keysyms_per_keycode; ++l) {
keysym = XKeycodeToKeysym(dpy, code, l);
if (keysym == NoSymbol) {
;
} else 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)) {
;
} else if (mask == ControlMask
&& (keysym == XK_Control_L
|| keysym == XK_Control_R)) {
;
} else if (mask == LockMask
&& (keysym == XK_Caps_Lock)) {
;
} else if (keysym == XK_Mode_switch
#ifdef XK_ISO_Level3_Shift
|| keysym == XK_ISO_Level3_Shift
#endif
) {
SaveMask(other_mods);
}
}
}
}
XFree(theMap);
}
if (!xw->misc.alwaysUseMods) {
if ((xw->misc.alt_mods != 0)
&& xtermHasTranslation(xw, "alt")) {
TRACE(("ALT is used as a modifier in translations (ignore mask)\n"));
xw->misc.alt_mods = 0;
}
if ((xw->misc.meta_mods != 0)
&& xtermHasTranslation(xw, "meta")) {
TRACE(("META is used as a modifier in translations\n"));
xw->misc.meta_mods = 0;
}
}
XFreeModifiermap(keymap);
}
}
#endif