2014-10-14 00:08:15 +02:00
|
|
|
#include "termo.h"
|
|
|
|
#include "termo-internal.h"
|
2008-10-07 00:27:19 +02:00
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
// There are 64 basic codes 0x40 - 0x7F that end a key sequence,
|
|
|
|
// plus 0x24 ($) for shifted keys in rxvt-based terminals.
|
|
|
|
|
|
|
|
// The CSI/SS3 naming isn't completely appropriate, as that only really applies
|
|
|
|
// to the other direction of communication, that is from the application
|
|
|
|
// to the terminal. What the terminal sends back doesn't have to conform to
|
|
|
|
// ECMA-48 (and indeed doesn't, as rxvt's 0x24 ($) is out of the range).
|
|
|
|
|
2012-01-22 19:54:17 +01:00
|
|
|
static int keyinfo_initialised = 0;
|
2015-05-26 21:59:44 +02:00
|
|
|
static struct keyinfo ss3s[96];
|
|
|
|
static char ss3_kpalts[96];
|
2012-01-20 19:01:19 +01:00
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
typedef struct
|
|
|
|
{
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_t *tk;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_csi_t;
|
2012-01-20 19:01:19 +01:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
typedef termo_result_t (*csi_handler_fn)
|
|
|
|
(termo_t *tk, termo_key_t *key, int cmd, long *arg, int args);
|
2015-05-26 21:59:44 +02:00
|
|
|
static csi_handler_fn csi_handlers[96];
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
|
|
|
// Handler for CSI/SS3 cmd keys
|
|
|
|
//
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
static struct keyinfo csi_ss3s[96];
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
static termo_result_t
|
|
|
|
handle_csi_ss3_full (termo_t *tk,
|
|
|
|
termo_key_t *key, int cmd, long *arg, int args)
|
2012-04-24 17:33:13 +02:00
|
|
|
{
|
2014-09-23 02:33:06 +02:00
|
|
|
(void) tk;
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
if (args > 1 && arg[1] != -1)
|
|
|
|
key->modifiers = arg[1] - 1;
|
|
|
|
else
|
|
|
|
key->modifiers = 0;
|
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
key->type = csi_ss3s[cmd - 0x20].type;
|
|
|
|
key->code.sym = csi_ss3s[cmd - 0x20].sym;
|
|
|
|
key->modifiers &= ~(csi_ss3s[cmd - 0x20].modifier_mask);
|
|
|
|
key->modifiers |= csi_ss3s[cmd - 0x20].modifier_set;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
if (key->code.sym == TERMO_SYM_UNKNOWN)
|
|
|
|
return TERMO_RES_NONE;
|
|
|
|
return TERMO_RES_KEY;
|
2012-04-24 17:33:13 +02:00
|
|
|
}
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
static void
|
2014-10-14 00:08:15 +02:00
|
|
|
register_csi_ss3_full (termo_type_t type, termo_sym_t sym,
|
2014-09-23 01:38:08 +02:00
|
|
|
int modifier_set, int modifier_mask, unsigned char cmd)
|
2012-01-20 19:01:19 +01:00
|
|
|
{
|
2015-05-26 21:59:44 +02:00
|
|
|
if (cmd < 0x20 || cmd >= 0x80)
|
2014-09-23 01:38:08 +02:00
|
|
|
return;
|
2008-10-07 00:53:25 +02:00
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
csi_ss3s[cmd - 0x20].type = type;
|
|
|
|
csi_ss3s[cmd - 0x20].sym = sym;
|
|
|
|
csi_ss3s[cmd - 0x20].modifier_set = modifier_set;
|
|
|
|
csi_ss3s[cmd - 0x20].modifier_mask = modifier_mask;
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
csi_handlers[cmd - 0x20] = &handle_csi_ss3_full;
|
2012-01-20 19:01:19 +01:00
|
|
|
}
|
2008-10-07 00:27:19 +02:00
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
static void
|
2014-10-14 00:08:15 +02:00
|
|
|
register_csi_ss3 (termo_type_t type, termo_sym_t sym, unsigned char cmd)
|
2012-01-20 19:01:19 +01:00
|
|
|
{
|
2014-09-23 01:38:08 +02:00
|
|
|
register_csi_ss3_full (type, sym, 0, 0, cmd);
|
2012-01-20 19:01:19 +01:00
|
|
|
}
|
|
|
|
|
2014-11-19 00:42:59 +01:00
|
|
|
//
|
2015-07-25 19:34:56 +02:00
|
|
|
// Handler for regular cursor key codes
|
2014-11-19 00:42:59 +01:00
|
|
|
//
|
|
|
|
|
|
|
|
static termo_result_t
|
|
|
|
handle_csi_cursor (termo_t *tk,
|
|
|
|
termo_key_t *key, int cmd, long *arg, int args)
|
|
|
|
{
|
|
|
|
(void) tk;
|
2015-07-25 19:34:56 +02:00
|
|
|
|
|
|
|
// CSI arrow keys without arguments are usually Ctrl-modified,
|
|
|
|
// and if not, as is the case with urxvt, they're specified in terminfo.
|
|
|
|
// In addition to that, xterm can specify modifiers in an argument.
|
|
|
|
key->type = TERMO_TYPE_KEYSYM;
|
|
|
|
if (args > 1 && arg[1] != -1)
|
|
|
|
key->modifiers = arg[1] - 1;
|
|
|
|
else
|
|
|
|
key->modifiers = TERMO_KEYMOD_CTRL;
|
|
|
|
|
|
|
|
if (cmd == 'A') key->code.sym = TERMO_SYM_UP;
|
|
|
|
if (cmd == 'B') key->code.sym = TERMO_SYM_DOWN;
|
|
|
|
if (cmd == 'C') key->code.sym = TERMO_SYM_RIGHT;
|
|
|
|
if (cmd == 'D') key->code.sym = TERMO_SYM_LEFT;
|
|
|
|
return TERMO_RES_KEY;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Handler for rxvt special cursor key codes
|
|
|
|
//
|
|
|
|
|
|
|
|
static termo_result_t
|
|
|
|
handle_csi_cursor_rxvt (termo_t *tk,
|
|
|
|
termo_key_t *key, int cmd, long *arg, int args)
|
|
|
|
{
|
|
|
|
(void) tk;
|
2014-11-19 00:42:59 +01:00
|
|
|
(void) arg;
|
|
|
|
(void) args;
|
|
|
|
|
2015-07-25 19:34:56 +02:00
|
|
|
// CSI with small letter stands for Shift
|
|
|
|
// SS3 with small letter stands for Ctrl but we don't handle that here
|
|
|
|
key->type = TERMO_TYPE_KEYSYM;
|
|
|
|
key->modifiers = TERMO_KEYMOD_SHIFT;
|
2014-11-19 00:42:59 +01:00
|
|
|
|
|
|
|
if (cmd == 'a') key->code.sym = TERMO_SYM_UP;
|
|
|
|
if (cmd == 'b') key->code.sym = TERMO_SYM_DOWN;
|
|
|
|
if (cmd == 'c') key->code.sym = TERMO_SYM_RIGHT;
|
|
|
|
if (cmd == 'd') key->code.sym = TERMO_SYM_LEFT;
|
|
|
|
return TERMO_RES_KEY;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Handler for rxvt SS3-only key combinations
|
|
|
|
//
|
|
|
|
|
|
|
|
static void
|
|
|
|
register_ss3 (termo_type_t type, termo_sym_t sym,
|
|
|
|
int modifier_set, unsigned char cmd)
|
|
|
|
{
|
2015-05-26 21:59:44 +02:00
|
|
|
if (cmd < 0x20 || cmd >= 0x80)
|
2014-11-19 00:42:59 +01:00
|
|
|
return;
|
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
ss3s[cmd - 0x20].type = type;
|
|
|
|
ss3s[cmd - 0x20].sym = sym;
|
|
|
|
ss3s[cmd - 0x20].modifier_set = modifier_set;
|
|
|
|
ss3s[cmd - 0x20].modifier_mask = 0;
|
2014-11-19 00:42:59 +01:00
|
|
|
}
|
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
|
|
|
// Handler for SS3 keys with kpad alternate representations
|
|
|
|
//
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
static void
|
2014-10-14 00:08:15 +02:00
|
|
|
register_ss3kpalt (termo_type_t type, termo_sym_t sym,
|
2014-09-23 01:38:08 +02:00
|
|
|
unsigned char cmd, char kpalt)
|
2012-01-20 19:01:19 +01:00
|
|
|
{
|
2015-05-26 21:59:44 +02:00
|
|
|
if (cmd < 0x20 || cmd >= 0x80)
|
2014-09-23 01:38:08 +02:00
|
|
|
return;
|
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
ss3s[cmd - 0x20].type = type;
|
|
|
|
ss3s[cmd - 0x20].sym = sym;
|
|
|
|
ss3s[cmd - 0x20].modifier_set = 0;
|
|
|
|
ss3s[cmd - 0x20].modifier_mask = 0;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
ss3_kpalts[cmd - 0x20] = kpalt;
|
2012-01-20 19:01:19 +01:00
|
|
|
}
|
2008-10-07 00:53:25 +02:00
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
|
|
|
// Handler for CSI number ~ function keys
|
|
|
|
//
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
// This value must be increased if more CSI function keys are added
|
2014-09-23 01:38:08 +02:00
|
|
|
static struct keyinfo csifuncs[35];
|
2014-09-23 02:33:06 +02:00
|
|
|
#define NCSIFUNCS ((long) (sizeof csifuncs / sizeof csifuncs[0]))
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
static termo_result_t
|
|
|
|
handle_csifunc (termo_t *tk, termo_key_t *key, int cmd, long *arg, int args)
|
2012-04-24 17:33:13 +02:00
|
|
|
{
|
2014-09-23 02:33:06 +02:00
|
|
|
(void) cmd;
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
if (args > 1 && arg[1] != -1)
|
|
|
|
key->modifiers = arg[1] - 1;
|
|
|
|
else
|
|
|
|
key->modifiers = 0;
|
2014-10-14 00:08:15 +02:00
|
|
|
key->type = TERMO_TYPE_KEYSYM;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
|
|
|
if (arg[0] == 27)
|
|
|
|
{
|
|
|
|
int mod = key->modifiers;
|
|
|
|
(*tk->method.emit_codepoint) (tk, arg[2], key);
|
|
|
|
key->modifiers |= mod;
|
|
|
|
}
|
|
|
|
else if (arg[0] >= 0 && arg[0] < NCSIFUNCS)
|
|
|
|
{
|
|
|
|
key->type = csifuncs[arg[0]].type;
|
|
|
|
key->code.sym = csifuncs[arg[0]].sym;
|
|
|
|
key->modifiers &= ~(csifuncs[arg[0]].modifier_mask);
|
|
|
|
key->modifiers |= csifuncs[arg[0]].modifier_set;
|
|
|
|
}
|
|
|
|
else
|
2014-10-14 00:08:15 +02:00
|
|
|
key->code.sym = TERMO_SYM_UNKNOWN;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
if (key->code.sym == TERMO_SYM_UNKNOWN)
|
2014-09-23 01:38:08 +02:00
|
|
|
{
|
2012-04-24 17:33:13 +02:00
|
|
|
#ifdef DEBUG
|
2014-09-23 01:38:08 +02:00
|
|
|
fprintf (stderr, "CSI: Unknown function key %ld\n", arg[0]);
|
2012-04-24 17:33:13 +02:00
|
|
|
#endif
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_KEY;
|
2012-04-24 17:33:13 +02:00
|
|
|
}
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
static void
|
2014-10-14 00:08:15 +02:00
|
|
|
register_csifunc (termo_type_t type, termo_sym_t sym, int number)
|
2012-01-20 19:01:19 +01:00
|
|
|
{
|
2014-09-23 01:38:08 +02:00
|
|
|
if (number >= NCSIFUNCS)
|
|
|
|
return;
|
2012-01-20 19:01:19 +01:00
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
csifuncs[number].type = type;
|
|
|
|
csifuncs[number].sym = sym;
|
|
|
|
csifuncs[number].modifier_set = 0;
|
|
|
|
csifuncs[number].modifier_mask = 0;
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2015-05-26 21:59:44 +02:00
|
|
|
csi_handlers['~' - 0x20] = &handle_csifunc;
|
2012-04-24 17:33:13 +02:00
|
|
|
}
|
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
2014-11-19 00:42:59 +01:00
|
|
|
// rxvt seems to emit these instead of ~ when holding various modifiers
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
2014-09-28 03:51:45 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
static termo_result_t
|
2014-11-19 00:42:59 +01:00
|
|
|
handle_csi_rxvt (termo_t *tk,
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_key_t *key, int cmd, long *arg, int args)
|
2014-09-28 03:51:45 +02:00
|
|
|
{
|
2014-11-19 00:42:59 +01:00
|
|
|
termo_result_t res;
|
2014-09-28 03:51:45 +02:00
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case '^':
|
2014-11-19 00:42:59 +01:00
|
|
|
res = handle_csifunc (tk, key, cmd, arg, args);
|
2014-10-14 00:08:15 +02:00
|
|
|
if (res == TERMO_RES_KEY)
|
|
|
|
key->modifiers |= TERMO_KEYMOD_CTRL;
|
2014-09-28 03:51:45 +02:00
|
|
|
return res;
|
2014-11-19 00:42:59 +01:00
|
|
|
case '$':
|
|
|
|
res = handle_csifunc (tk, key, cmd, arg, args);
|
|
|
|
if (res == TERMO_RES_KEY)
|
|
|
|
key->modifiers |= TERMO_KEYMOD_SHIFT;
|
|
|
|
return res;
|
|
|
|
case '@':
|
|
|
|
res = handle_csifunc (tk, key, cmd, arg, args);
|
|
|
|
if (res == TERMO_RES_KEY)
|
|
|
|
key->modifiers |= TERMO_KEYMOD_CTRL | TERMO_KEYMOD_SHIFT;
|
|
|
|
return res;
|
2014-09-28 03:51:45 +02:00
|
|
|
default:
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
2014-09-28 03:51:45 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
|
|
|
// Handler for CSI u extended Unicode keys
|
|
|
|
//
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
static termo_result_t
|
|
|
|
handle_csi_u (termo_t *tk, termo_key_t *key, int cmd, long *arg, int args)
|
2012-04-24 17:33:13 +02:00
|
|
|
{
|
2014-09-23 01:38:08 +02:00
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case 'u':
|
|
|
|
{
|
|
|
|
if (args > 1 && arg[1] != -1)
|
|
|
|
key->modifiers = arg[1] - 1;
|
|
|
|
else
|
|
|
|
key->modifiers = 0;
|
|
|
|
|
|
|
|
int mod = key->modifiers;
|
2014-10-14 00:08:15 +02:00
|
|
|
key->type = TERMO_TYPE_KEYSYM;
|
2014-09-23 01:38:08 +02:00
|
|
|
(*tk->method.emit_codepoint) (tk, arg[0], key);
|
|
|
|
key->modifiers |= mod;
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_KEY;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
|
|
|
default:
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
2012-04-24 17:33:13 +02:00
|
|
|
}
|
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
|
|
|
// Handler for CSI M / CSI m mouse events in SGR and rxvt encodings
|
|
|
|
// Note: This does not handle X10 encoding
|
|
|
|
//
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
static termo_result_t
|
|
|
|
handle_csi_m (termo_t *tk, termo_key_t *key, int cmd, long *arg, int args)
|
2012-04-24 17:33:13 +02:00
|
|
|
{
|
2014-09-23 02:33:06 +02:00
|
|
|
(void) tk;
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
int initial = cmd >> 8;
|
|
|
|
cmd &= 0xff;
|
|
|
|
|
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case 'M':
|
|
|
|
case 'm':
|
|
|
|
break;
|
|
|
|
default:
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!initial && args >= 3)
|
|
|
|
{
|
|
|
|
// rxvt protocol
|
2014-10-14 00:08:15 +02:00
|
|
|
key->type = TERMO_TYPE_MOUSE;
|
2014-10-13 23:36:14 +02:00
|
|
|
key->code.mouse.info = arg[0] - 0x20;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2014-10-13 23:36:14 +02:00
|
|
|
key->modifiers = (key->code.mouse.info & 0x1c) >> 2;
|
|
|
|
key->code.mouse.info &= ~0x1c;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_key_set_linecol (key, arg[2] - 1, arg[1] - 1);
|
|
|
|
return TERMO_RES_KEY;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
if (initial == '<' && args >= 3)
|
|
|
|
{
|
|
|
|
// SGR protocol
|
2014-10-14 00:08:15 +02:00
|
|
|
key->type = TERMO_TYPE_MOUSE;
|
2014-10-13 23:36:14 +02:00
|
|
|
key->code.mouse.info = arg[0];
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2014-10-13 23:36:14 +02:00
|
|
|
key->modifiers = (key->code.mouse.info & 0x1c) >> 2;
|
|
|
|
key->code.mouse.info &= ~0x1c;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_key_set_linecol (key, arg[2] - 1, arg[1] - 1);
|
2014-09-23 01:38:08 +02:00
|
|
|
|
|
|
|
if (cmd == 'm') // release
|
2014-10-13 23:36:14 +02:00
|
|
|
key->code.mouse.info |= 0x8000;
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_KEY;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
2012-01-20 19:01:19 +01:00
|
|
|
}
|
|
|
|
|
2020-09-14 15:38:49 +02:00
|
|
|
//
|
|
|
|
// Handler for CSI I / CSI O focus events
|
|
|
|
//
|
|
|
|
|
|
|
|
static termo_result_t
|
|
|
|
handle_csi_IO (termo_t *tk, termo_key_t *key, int cmd, long *arg, int args)
|
|
|
|
{
|
|
|
|
(void) tk;
|
|
|
|
(void) arg;
|
|
|
|
(void) args;
|
|
|
|
|
|
|
|
switch (cmd &= 0xff)
|
|
|
|
{
|
|
|
|
case 'I':
|
|
|
|
key->type = TERMO_TYPE_FOCUS;
|
|
|
|
key->code.focused = true;
|
|
|
|
return TERMO_RES_KEY;
|
|
|
|
case 'O':
|
|
|
|
key->type = TERMO_TYPE_FOCUS;
|
|
|
|
key->code.focused = false;
|
|
|
|
return TERMO_RES_KEY;
|
|
|
|
default:
|
|
|
|
return TERMO_RES_NONE;
|
|
|
|
}
|
|
|
|
return TERMO_RES_NONE;
|
|
|
|
}
|
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_result_t
|
|
|
|
termo_interpret_mouse (termo_t *tk, const termo_key_t *key,
|
|
|
|
termo_mouse_event_t *event, int *button, int *line, int *col)
|
2012-11-30 16:01:20 +01:00
|
|
|
{
|
2014-09-23 02:33:06 +02:00
|
|
|
(void) tk;
|
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
if (key->type != TERMO_TYPE_MOUSE)
|
|
|
|
return TERMO_RES_NONE;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
|
|
|
int btn = 0;
|
2014-10-13 23:36:14 +02:00
|
|
|
int code = key->code.mouse.info;
|
2014-09-23 01:38:08 +02:00
|
|
|
int drag = code & 0x20;
|
|
|
|
code &= ~0x3c;
|
|
|
|
|
2014-10-18 20:32:45 +02:00
|
|
|
termo_mouse_event_t ev;
|
2014-09-23 01:38:08 +02:00
|
|
|
switch (code)
|
|
|
|
{
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
2014-10-18 20:32:45 +02:00
|
|
|
ev = drag ? TERMO_MOUSE_DRAG : TERMO_MOUSE_PRESS;
|
2014-09-23 01:38:08 +02:00
|
|
|
btn = code + 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
2014-10-18 20:32:45 +02:00
|
|
|
ev = TERMO_MOUSE_RELEASE;
|
2014-09-23 01:38:08 +02:00
|
|
|
// no button hint
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 64:
|
|
|
|
case 65:
|
2014-10-18 20:32:45 +02:00
|
|
|
ev = drag ? TERMO_MOUSE_DRAG : TERMO_MOUSE_PRESS;
|
2014-09-23 01:38:08 +02:00
|
|
|
btn = code + 4 - 64;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2014-10-18 20:32:45 +02:00
|
|
|
ev = TERMO_MOUSE_UNKNOWN;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
|
|
|
|
2014-10-18 20:32:45 +02:00
|
|
|
if (key->code.mouse.info & 0x8000)
|
|
|
|
ev = TERMO_MOUSE_RELEASE;
|
|
|
|
|
|
|
|
if (event)
|
|
|
|
*event = ev;
|
2014-09-23 01:38:08 +02:00
|
|
|
if (button)
|
|
|
|
*button = btn;
|
2014-10-18 20:32:45 +02:00
|
|
|
|
|
|
|
termo_key_get_linecol (key, line, col);
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_KEY;
|
2012-11-30 16:01:20 +01:00
|
|
|
}
|
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
|
|
|
// Handler for CSI ? R position reports
|
|
|
|
// A plain CSI R with no arguments is probably actually <F3>
|
|
|
|
//
|
2012-04-24 18:27:48 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
static termo_result_t
|
|
|
|
handle_csi_R (termo_t *tk, termo_key_t *key, int cmd, long *arg, int args)
|
2012-04-24 18:27:48 +02:00
|
|
|
{
|
2014-09-23 01:38:08 +02:00
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case 'R' | '?' << 8:
|
|
|
|
if (args < 2)
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
key->type = TERMO_TYPE_POSITION;
|
2015-05-27 21:36:50 +02:00
|
|
|
termo_key_set_linecol (key, arg[0] - 1, arg[1] - 1);
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_KEY;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
|
|
|
default:
|
|
|
|
return handle_csi_ss3_full (tk, key, cmd, arg, args);
|
|
|
|
}
|
2012-04-24 18:27:48 +02:00
|
|
|
}
|
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_result_t
|
|
|
|
termo_interpret_position (termo_t *tk,
|
|
|
|
const termo_key_t *key, int *line, int *col)
|
2012-11-30 16:01:20 +01:00
|
|
|
{
|
2014-09-23 02:33:06 +02:00
|
|
|
(void) tk;
|
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
if (key->type != TERMO_TYPE_POSITION)
|
|
|
|
return TERMO_RES_NONE;
|
2012-11-30 16:01:20 +01:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_key_get_linecol (key, line, col);
|
|
|
|
return TERMO_RES_KEY;
|
2012-11-30 16:01:20 +01:00
|
|
|
}
|
|
|
|
|
2014-10-14 21:19:11 +02:00
|
|
|
//
|
|
|
|
// Handler for CSI $y mode status reports
|
|
|
|
//
|
2012-11-30 17:34:47 +01:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
static termo_result_t
|
|
|
|
handle_csi_y (termo_t *tk, termo_key_t *key, int cmd, long *arg, int args)
|
2012-11-30 17:34:47 +01:00
|
|
|
{
|
2014-09-23 02:33:06 +02:00
|
|
|
(void) tk;
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
switch (cmd)
|
|
|
|
{
|
|
|
|
case 'y' | '$' << 16:
|
|
|
|
case 'y' | '$' << 16 | '?' << 8:
|
|
|
|
if (args < 2)
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
key->type = TERMO_TYPE_MODEREPORT;
|
2014-10-13 23:36:14 +02:00
|
|
|
key->code.mode.initial = (cmd >> 8);
|
|
|
|
key->code.mode.mode = arg[0];
|
|
|
|
key->code.mode.value = arg[1];
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_KEY;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
|
|
|
default:
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
2014-09-23 01:38:08 +02:00
|
|
|
}
|
2012-11-30 17:34:47 +01:00
|
|
|
}
|
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_result_t
|
|
|
|
termo_interpret_modereport (termo_t *tk,
|
|
|
|
const termo_key_t *key, int *initial, int *mode, int *value)
|
2012-11-30 17:34:47 +01:00
|
|
|
{
|
2014-09-23 02:33:06 +02:00
|
|
|
(void) tk;
|
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
if (key->type != TERMO_TYPE_MODEREPORT)
|
|
|
|
return TERMO_RES_NONE;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
|
|
|
if (initial)
|
2014-10-13 23:36:14 +02:00
|
|
|
*initial = key->code.mode.initial;
|
2014-09-23 01:38:08 +02:00
|
|
|
if (mode)
|
2014-10-13 23:36:14 +02:00
|
|
|
*mode = key->code.mode.mode;
|
2014-09-23 01:38:08 +02:00
|
|
|
if (value)
|
2014-10-13 23:36:14 +02:00
|
|
|
*value = key->code.mode.value;
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_KEY;
|
2012-11-30 17:34:47 +01:00
|
|
|
}
|
|
|
|
|
2012-11-30 14:52:56 +01:00
|
|
|
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
|
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
static termo_result_t
|
|
|
|
parse_csi (termo_t *tk, size_t introlen, size_t *csi_len,
|
2014-09-23 01:38:08 +02:00
|
|
|
long args[], size_t *nargs, unsigned long *commandp)
|
2012-11-30 14:52:56 +01:00
|
|
|
{
|
2015-05-28 20:02:14 +02:00
|
|
|
// Specifically allowing the rxvt special character for shifted function
|
|
|
|
// keys to end a CSI-like sequence, otherwise expecting ECMA-48-like input
|
|
|
|
bool allow_dollar = true;
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
size_t csi_end = introlen;
|
|
|
|
while (csi_end < tk->buffcount)
|
|
|
|
{
|
2015-05-26 21:59:44 +02:00
|
|
|
unsigned char c = CHARAT (csi_end);
|
2015-05-28 20:02:14 +02:00
|
|
|
if ((c >= 0x40 && c < 0x80) || (allow_dollar && c == '$'))
|
2014-09-23 01:38:08 +02:00
|
|
|
break;
|
2015-05-28 20:02:14 +02:00
|
|
|
|
|
|
|
// However just accepting the dollar as an end character would break
|
|
|
|
// parsing DECRPM responses (mode reports). We can work around this
|
|
|
|
// ambiguity by making use of the fact that rxvt key sequences have
|
|
|
|
// exactly one numeric argument and no initial byte.
|
2015-05-28 20:16:55 +02:00
|
|
|
if (c < '0' || c > '9')
|
2015-05-28 20:02:14 +02:00
|
|
|
allow_dollar = false;
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
csi_end++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (csi_end >= tk->buffcount)
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_AGAIN;
|
2014-09-23 01:38:08 +02:00
|
|
|
|
|
|
|
unsigned char cmd = CHARAT (csi_end);
|
|
|
|
*commandp = cmd;
|
|
|
|
|
|
|
|
char present = 0;
|
|
|
|
int argi = 0;
|
|
|
|
|
|
|
|
size_t p = introlen;
|
|
|
|
|
|
|
|
// See if there is an initial byte
|
|
|
|
if (CHARAT (p) >= '<' && CHARAT (p) <= '?')
|
|
|
|
{
|
|
|
|
*commandp |= (CHARAT (p) << 8);
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now attempt to parse out up number;number;... separated values
|
|
|
|
for (; p < csi_end; p++)
|
|
|
|
{
|
|
|
|
unsigned char c = CHARAT (p);
|
|
|
|
if (c >= '0' && c <= '9')
|
|
|
|
{
|
|
|
|
if (!present)
|
|
|
|
{
|
|
|
|
args[argi] = c - '0';
|
|
|
|
present = 1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
args[argi] = (args[argi] * 10) + c - '0';
|
|
|
|
}
|
|
|
|
else if (c == ';')
|
|
|
|
{
|
|
|
|
if (!present)
|
|
|
|
args[argi] = -1;
|
|
|
|
present = 0;
|
|
|
|
argi++;
|
|
|
|
|
|
|
|
if (argi > 16)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
else if (c >= 0x20 && c <= 0x2f)
|
|
|
|
{
|
|
|
|
*commandp |= c << 16;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (present)
|
|
|
|
argi++;
|
|
|
|
|
|
|
|
*nargs = argi;
|
|
|
|
*csi_len = csi_end + 1;
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_KEY;
|
2012-11-30 14:52:56 +01:00
|
|
|
}
|
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
termo_result_t
|
|
|
|
termo_interpret_csi (termo_t *tk, const termo_key_t *key,
|
2014-09-23 01:38:08 +02:00
|
|
|
long args[], size_t *nargs, unsigned long *cmd)
|
2012-11-30 16:01:20 +01:00
|
|
|
{
|
2014-09-23 01:38:08 +02:00
|
|
|
if (tk->hightide == 0)
|
2014-10-14 00:08:15 +02:00
|
|
|
return TERMO_RES_NONE;
|
|
|
|
if (key->type != TERMO_TYPE_UNKNOWN_CSI)
|
|
|
|
return TERMO_RES_NONE;
|
2012-11-30 16:01:20 +01:00
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
size_t dummy;
|
|
|
|
return parse_csi (tk, 0, &dummy, args, nargs, cmd);
|
2012-11-30 16:01:20 +01:00
|
|
|
}
|
|
|
|
|
2014-09-23 01:38:08 +02:00
|
|
|
static int
|
|
|
|
register_keys (void)
|
2012-01-20 19:01:19 +01:00
|
|
|
{
|
2014-09-23 01:38:08 +02:00
|
|
|
int i;
|
2015-07-25 19:02:57 +02:00
|
|
|
for (i = 0; i < 96; i++)
|
2014-09-23 01:38:08 +02:00
|
|
|
{
|
2014-10-14 00:08:15 +02:00
|
|
|
csi_ss3s[i].sym = TERMO_SYM_UNKNOWN;
|
|
|
|
ss3s[i].sym = TERMO_SYM_UNKNOWN;
|
2014-09-23 01:38:08 +02:00
|
|
|
ss3_kpalts[i] = 0;
|
|
|
|
}
|
|
|
|
for (i = 0; i < NCSIFUNCS; i++)
|
2014-10-14 00:08:15 +02:00
|
|
|
csifuncs[i].sym = TERMO_SYM_UNKNOWN;
|
|
|
|
|
2015-07-25 19:05:00 +02:00
|
|
|
// Cursor keys handling; there's some weird, weird stuff going on here:
|
|
|
|
//
|
|
|
|
// rxvt-based terminals should output SS3 A/B/C/D for C-S-arrow keys;
|
|
|
|
// rxvt-unicode however only seems to output Shift codes.
|
|
|
|
//
|
|
|
|
// xterm, PuTTY, tmux output SS3 A/B/C/D for normal arrow keys when
|
|
|
|
// terminfo start string has been written -- it gets eaten by the terminfo
|
|
|
|
// driver then, usually. To the contrary, CSI A/B/C/D is used for Ctrl.
|
|
|
|
|
|
|
|
register_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_UP, 0, 'A');
|
|
|
|
register_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_DOWN, 0, 'B');
|
|
|
|
register_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_RIGHT, 0, 'C');
|
|
|
|
register_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_LEFT, 0, 'D');
|
|
|
|
|
2015-07-25 19:34:56 +02:00
|
|
|
csi_handlers['A' - 0x20] = &handle_csi_cursor;
|
|
|
|
csi_handlers['B' - 0x20] = &handle_csi_cursor;
|
|
|
|
csi_handlers['C' - 0x20] = &handle_csi_cursor;
|
|
|
|
csi_handlers['D' - 0x20] = &handle_csi_cursor;
|
2014-10-14 00:08:15 +02:00
|
|
|
|
2014-11-19 00:42:59 +01:00
|
|
|
// Handle Shift-modified rxvt cursor keys (CSI a, CSI b, CSI c, CSI d)
|
2015-07-25 19:34:56 +02:00
|
|
|
csi_handlers['a' - 0x20] = &handle_csi_cursor_rxvt;
|
|
|
|
csi_handlers['b' - 0x20] = &handle_csi_cursor_rxvt;
|
|
|
|
csi_handlers['c' - 0x20] = &handle_csi_cursor_rxvt;
|
|
|
|
csi_handlers['d' - 0x20] = &handle_csi_cursor_rxvt;
|
2014-11-19 00:42:59 +01:00
|
|
|
|
|
|
|
// Handle Ctrl-modified rxvt cursor keys (SS3 a, SS3 b, SS3 c, SS3 d)
|
|
|
|
register_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_UP, TERMO_KEYMOD_CTRL, 'a');
|
|
|
|
register_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_DOWN, TERMO_KEYMOD_CTRL, 'b');
|
|
|
|
register_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_RIGHT, TERMO_KEYMOD_CTRL, 'c');
|
|
|
|
register_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_LEFT, TERMO_KEYMOD_CTRL, 'd');
|
|
|
|
|
2015-07-25 19:05:00 +02:00
|
|
|
// End of cursor keys handling
|
2014-11-19 00:42:59 +01:00
|
|
|
|
2015-07-25 19:05:00 +02:00
|
|
|
register_csi_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_BEGIN, 'E');
|
|
|
|
register_csi_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_END, 'F');
|
|
|
|
register_csi_ss3 (TERMO_TYPE_KEYSYM, TERMO_SYM_HOME, 'H');
|
|
|
|
register_csi_ss3 (TERMO_TYPE_FUNCTION, 1, 'P');
|
|
|
|
register_csi_ss3 (TERMO_TYPE_FUNCTION, 2, 'Q');
|
|
|
|
register_csi_ss3 (TERMO_TYPE_FUNCTION, 3, 'R');
|
|
|
|
register_csi_ss3 (TERMO_TYPE_FUNCTION, 4, 'S');
|
2014-11-30 00:36:18 +01:00
|
|
|
|
2014-10-14 00:08:15 +02:00
|
|
|
register_csi_ss3_full (TERMO_TYPE_KEYSYM, TERMO_SYM_TAB,
|
|
|
|
TERMO_KEYMOD_SHIFT, TERMO_KEYMOD_SHIFT, 'Z');
|
|
|
|
|
|
|
|
register_ss3kpalt (TERMO_TYPE_KEYSYM, TERMO_SYM_KPENTER, 'M', 0);
|
|
|
|
register_ss3kpalt (TERMO_TYPE_KEYSYM, TERMO_SYM_KPEQUALS, 'X', '=');
|
|
|
|
register_ss3kpalt (TERMO_TYPE_KEYSYM, TERMO_SYM_KPMULT, 'j', '*');
|
|
|
|
register_ss3kpalt (TERMO_TYPE_KEYSYM, TERMO_SYM_KPPLUS, 'k', '+');
|
|
|
|
register_ss3kpalt (TERMO_TYPE_KEYSYM, TERMO_SYM_KPCOMMA, 'l', ',');
|
|
|
|
register_ss3kpalt |