1
0
mirror of https://git.tartarus.org/simon/putty.git synced 2025-06-30 19:12:48 -05:00

First attempt at a platform-independent keyboard handler. This isn't complete

yet -- there's no Alt+keypad support, and no way for the front-end to find
out what it should do with the Num Lock light.  It's also not fully tested.
Nonetheless, it's at least as good as the previous Mac keyboard handler.
Other platforms probably shouldn't adopt it just yet.

[originally from svn r2728]
This commit is contained in:
Ben Harris
2003-01-27 00:39:01 +00:00
parent b415d9e225
commit de34bdac6d
3 changed files with 550 additions and 181 deletions

View File

@ -4009,6 +4009,429 @@ void term_mouse(Terminal *term, Mouse_Button braw, Mouse_Button bcooked,
term_update(term);
}
void term_key(Terminal *term, Key_Sym keysym, wchar_t *text, size_t tlen,
unsigned int modifiers, unsigned int flags)
{
char output[10];
char *p = output;
int prependesc = FALSE;
int i;
fprintf(stderr, "keysym = %d, %d chars:", keysym, tlen);
for (i = 0; i < tlen; i++)
fprintf(stderr, " %04x", text[i]);
fprintf(stderr, "\n");
/* XXX Num Lock */
if ((flags & PKF_REPEAT) && term->repeat_off)
return;
/* Currently, Meta always just prefixes everything with ESC. */
if (modifiers & PKM_META)
prependesc = TRUE;
modifiers &= ~PKM_META;
/*
* Alt is only used for Alt+keypad, which isn't supported yet, so
* ignore it.
*/
modifiers &= ~PKM_ALT;
/* Standard local function keys */
switch (modifiers & (PKM_SHIFT | PKM_CONTROL)) {
case PKM_SHIFT:
if (keysym == PK_PAGEUP)
/* scroll up one page */;
if (keysym == PK_PAGEDOWN)
/* scroll down on page */;
if (keysym == PK_INSERT)
term_do_paste(term);
break;
case PKM_CONTROL:
if (keysym == PK_PAGEUP)
/* scroll up one line */;
if (keysym == PK_PAGEDOWN)
/* scroll down one line */;
/* Control-Numlock for app-keypad mode switch */
if (keysym == PK_PF1)
term->app_keypad_keys ^= 1;
break;
}
if (modifiers & PKM_ALT) {
/* Alt+F4 (close) */
/* Alt+Return (full screen) */
/* Alt+Space (system menu) */
}
if (keysym == PK_NULL && (modifiers & PKM_CONTROL) && tlen == 1 &&
text[0] >= 0x20 && text[0] <= 0x7e) {
/* ASCII chars + Control */
if (text[0] >= 0x40 && text[0] <= 0x5f ||
text[0] >= 0x61 && text[0] <= 0x7a)
text[0] &= 0x1f;
else {
/*
* Control-2 should return ^@ (0x00), Control-6 should return
* ^^ (0x1E), and Control-Minus should return ^_ (0x1F). Since
* the DOS keyboard handling did it, and we have nothing better
* to do with the key combo in question, we'll also map
* Control-Backquote to ^\ (0x1C).
*/
switch (text[0]) {
case ' ': text[0] = 0x00; break;
case '-': text[0] = 0x1f; break;
case '/': text[0] = 0x1f; break;
case '2': text[0] = 0x00; break;
case '3': text[0] = 0x1b; break;
case '4': text[0] = 0x1c; break;
case '5': text[0] = 0x1d; break;
case '6': text[0] = 0x1e; break;
case '7': text[0] = 0x1f; break;
case '8': text[0] = 0x7f; break;
case '`': text[0] = 0x1c; break;
}
}
}
/* Nethack keypad */
if (term->cfg.nethack_keypad) {
char c = 0;
switch (keysym) {
case PK_KP1: c = 'b'; break;
case PK_KP2: c = 'j'; break;
case PK_KP3: c = 'n'; break;
case PK_KP4: c = 'h'; break;
case PK_KP5: c = '.'; break;
case PK_KP6: c = 'l'; break;
case PK_KP7: c = 'y'; break;
case PK_KP8: c = 'k'; break;
case PK_KP9: c = 'u'; break;
}
if (c != 0) {
if (c != '.') {
if (modifiers & PKM_CONTROL)
c &= 0x1f;
else if (modifiers & PKM_SHIFT)
c = toupper(c);
}
*p++ = c;
goto done;
}
}
/* Numeric Keypad */
if (PK_ISKEYPAD(keysym)) {
int xkey = 0;
/*
* In VT400 mode, PFn always emits an escape sequence. In
* Linux and tilde modes, this only happens in app keypad mode.
*/
if (term->cfg.funky_type == FUNKY_VT400 ||
((term->cfg.funky_type == FUNKY_LINUX ||
term->cfg.funky_type == FUNKY_TILDE) &&
term->app_keypad_keys && !term->cfg.no_applic_k)) {
switch (keysym) {
case PK_PF1: xkey = 'P'; break;
case PK_PF2: xkey = 'Q'; break;
case PK_PF3: xkey = 'R'; break;
case PK_PF4: xkey = 'S'; break;
}
}
if (term->app_keypad_keys && !term->cfg.no_applic_k) {
switch (keysym) {
case PK_KP0: xkey = 'p'; break;
case PK_KP1: xkey = 'q'; break;
case PK_KP2: xkey = 'r'; break;
case PK_KP3: xkey = 's'; break;
case PK_KP4: xkey = 't'; break;
case PK_KP5: xkey = 'u'; break;
case PK_KP6: xkey = 'v'; break;
case PK_KP7: xkey = 'w'; break;
case PK_KP8: xkey = 'x'; break;
case PK_KP9: xkey = 'y'; break;
case PK_KPDECIMAL: xkey = 'n'; break;
case PK_KPENTER: xkey = 'M'; break;
}
if (term->cfg.funky_type == FUNKY_XTERM && tlen > 0) {
/*
* xterm can't see the layout of the keypad, so it has
* to rely on the X keysyms returned by the keys.
* Hence, we look at the strings here, not the PuTTY
* keysyms (which describe the layout).
*/
switch (text[0]) {
case '+':
if (modifiers & PKM_SHIFT)
xkey = 'l';
else
xkey = 'k';
break;
case '/': xkey = 'o'; break;
case '*': xkey = 'j'; break;
case '-': xkey = 'm'; break;
}
} else {
/*
* In all other modes, we try to retain the layout of
* the DEC keypad in application mode.
*/
switch (keysym) {
case PK_KPBIGPLUS:
/* This key covers the '-' and ',' keys on a VT220 */
if (modifiers & PKM_SHIFT)
xkey = 'm'; /* VT220 '-' */
else
xkey = 'l'; /* VT220 ',' */
break;
case PK_KPMINUS: xkey = 'm'; break;
case PK_KPCOMMA: xkey = 'l'; break;
}
}
}
if (xkey) {
if (term->vt52_mode) {
if (xkey >= 'P' && xkey <= 'S')
p += sprintf((char *) p, "\x1B%c", xkey);
else
p += sprintf((char *) p, "\x1B?%c", xkey);
} else
p += sprintf((char *) p, "\x1BO%c", xkey);
goto done;
}
/* Not in application mode -- treat the number pad as arrow keys? */
if ((flags & PKF_NUMLOCK) == 0) {
switch (keysym) {
case PK_KP0: keysym = PK_INSERT; break;
case PK_KP1: keysym = PK_END; break;
case PK_KP2: keysym = PK_DOWN; break;
case PK_KP3: keysym = PK_PAGEDOWN; break;
case PK_KP4: keysym = PK_LEFT; break;
case PK_KP5: keysym = PK_REST; break;
case PK_KP6: keysym = PK_RIGHT; break;
case PK_KP7: keysym = PK_HOME; break;
case PK_KP8: keysym = PK_UP; break;
case PK_KP9: keysym = PK_PAGEUP; break;
}
}
}
/* Miscellaneous keys */
switch (keysym) {
case PK_ESCAPE:
*p++ = 0x1b;
goto done;
case PK_BACKSPACE:
if (modifiers == 0)
*p++ = (term->cfg.bksp_is_delete ? 0x7F : 0x08);
else if (modifiers == PKM_SHIFT)
/* We do the opposite of what is configured */
*p++ = (term->cfg.bksp_is_delete ? 0x08 : 0x7F);
else break;
goto done;
case PK_TAB:
if (modifiers == 0)
*p++ = 0x09;
else if (modifiers == PKM_SHIFT)
*p++ = 0x1B, *p++ = '[', *p++ = 'Z';
else break;
goto done;
/* XXX window.c has ctrl+shift+space sending 0xa0 */
case PK_PAUSE:
if (modifiers == PKM_CONTROL)
*p++ = 26;
else break;
goto done;
case PK_RETURN:
case PK_KPENTER: /* Odd keypad modes handled above */
if (modifiers == 0) {
*p++ = 0x0d;
if (term->cr_lf_return)
*p++ = 0x0a;
goto done;
}
}
/* SCO function keys and editing keys */
if (term->cfg.funky_type == FUNKY_SCO) {
if (PK_ISFKEY(keysym) && keysym <= PK_F12) {
static char const codes[] =
"MNOPQRSTUVWX" "YZabcdefghij" "klmnopqrstuv" "wxyz@[\\]^_`{";
int index = keysym - PK_F1;
if (modifiers & PKM_SHIFT) index += 12;
if (modifiers & PKM_CONTROL) index += 24;
p += sprintf((char *) p, "\x1B[%c", codes[index]);
goto done;
}
if (PK_ISEDITING(keysym)) {
int xkey = 0;
switch (keysym) {
case PK_DELETE: *p++ = 0x7f; goto done;
case PK_HOME: xkey = 'H'; break;
case PK_INSERT: xkey = 'L'; break;
case PK_END: xkey = 'F'; break;
case PK_PAGEUP: xkey = 'I'; break;
case PK_PAGEDOWN: xkey = 'G'; break;
}
p += sprintf((char *) p, "\x1B[%c", xkey);
}
}
if (PK_ISEDITING(keysym) && (modifiers & PKM_SHIFT) == 0) {
int code;
if (term->cfg.funky_type == FUNKY_XTERM) {
/* Xterm shuffles these keys, apparently. */
switch (keysym) {
case PK_HOME: keysym = PK_INSERT; break;
case PK_INSERT: keysym = PK_HOME; break;
case PK_DELETE: keysym = PK_END; break;
case PK_END: keysym = PK_PAGEUP; break;
case PK_PAGEUP: keysym = PK_DELETE; break;
case PK_PAGEDOWN: keysym = PK_PAGEDOWN; break;
}
}
/* RXVT Home/End */
if (term->cfg.rxvt_homeend &&
(keysym == PK_HOME || keysym == PK_END)) {
p += sprintf((char *) p, keysym == PK_HOME ? "\x1B[H" : "\x1BOw");
goto done;
}
if (term->vt52_mode) {
int xkey;
/*
* A real VT52 doesn't have these, and a VT220 doesn't
* send anything for them in VT52 mode.
*/
switch (keysym) {
case PK_HOME: xkey = 'H'; break;
case PK_INSERT: xkey = 'L'; break;
case PK_DELETE: xkey = 'M'; break;
case PK_END: xkey = 'E'; break;
case PK_PAGEUP: xkey = 'I'; break;
case PK_PAGEDOWN: xkey = 'G'; break;
}
p += sprintf((char *) p, "\x1B%c", xkey);
goto done;
}
switch (keysym) {
case PK_HOME: code = 1; break;
case PK_INSERT: code = 2; break;
case PK_DELETE: code = 3; break;
case PK_END: code = 4; break;
case PK_PAGEUP: code = 5; break;
case PK_PAGEDOWN: code = 6; break;
}
p += sprintf((char *) p, "\x1B[%d~", code);
goto done;
}
if (PK_ISFKEY(keysym)) {
/* Map Shift+F1-F10 to F11-F20 */
if (keysym >= PK_F1 && keysym <= PK_F10 && (modifiers & PKM_SHIFT))
keysym += 10;
if ((term->vt52_mode || term->cfg.funky_type == FUNKY_VT100P) &&
keysym <= PK_F14) {
/* XXX This overrides the XTERM/VT52 mode below */
int offt = 0;
if (keysym >= PK_F6) offt++;
if (keysym >= PK_F12) offt++;
p += sprintf((char *) p, term->vt52_mode ? "\x1B%c" : "\x1BO%c",
'P' + keysym - PK_F1 - offt);
goto done;
}
if (term->cfg.funky_type == FUNKY_LINUX && keysym <= PK_F5) {
p += sprintf((char *) p, "\x1B[[%c", 'A' + keysym - PK_F1);
goto done;
}
if (term->cfg.funky_type == FUNKY_XTERM && keysym <= PK_F4) {
if (term->vt52_mode)
p += sprintf((char *) p, "\x1B%c", 'P' + keysym - PK_F1);
else
p += sprintf((char *) p, "\x1BO%c", 'P' + keysym - PK_F1);
goto done;
}
p += sprintf((char *) p, "\x1B[%d~", 11 + keysym - PK_F1);
goto done;
}
if (PK_ISCURSOR(keysym)) {
int xkey;
switch (keysym) {
case PK_UP: xkey = 'A'; break;
case PK_DOWN: xkey = 'B'; break;
case PK_RIGHT: xkey = 'C'; break;
case PK_LEFT: xkey = 'D'; break;
case PK_REST: xkey = 'G'; break; /* centre key on number pad */
}
if (term->vt52_mode)
p += sprintf((char *) p, "\x1B%c", xkey);
else {
int app_flg = (term->app_cursor_keys && !term->cfg.no_applic_c);
/* Useful mapping of Ctrl-arrows */
if (modifiers == PKM_CONTROL)
app_flg = !app_flg;
if (app_flg)
p += sprintf((char *) p, "\x1BO%c", xkey);
else
p += sprintf((char *) p, "\x1B[%c", xkey);
}
goto done;
}
done:
if (p > output || tlen > 0) {
/*
* Interrupt an ongoing paste. I'm not sure
* this is sensible, but for the moment it's
* preferable to having to faff about buffering
* things.
*/
term_nopaste(term);
/*
* We need not bother about stdin backlogs
* here, because in GUI PuTTY we can't do
* anything about it anyway; there's no means
* of asking Windows to hold off on KEYDOWN
* messages. We _have_ to buffer everything
* we're sent.
*/
term_seen_key_event(term);
if (prependesc) {
fprintf(stderr, "sending ESC\n");
ldisc_send(term->ldisc, "\x1b", 1, 1);
}
if (p > output) {
fprintf(stderr, "sending %d bytes:", p - output);
for (i = 0; i < p - output; i++)
fprintf(stderr, " %02x", output[i]);
fprintf(stderr, "\n");
ldisc_send(term->ldisc, output, p - output, 1);
} else if (tlen > 0) {
fprintf(stderr, "sending %d unichars:", tlen);
for (i = 0; i < tlen; i++)
fprintf(stderr, " %04x", text[i]);
fprintf(stderr, "\n");
luni_send(term->ldisc, text, tlen, 1);
}
}
}
void term_nopaste(Terminal *term)
{
if (term->paste_len == 0)