2008-10-07 00:27:19 +02:00
|
|
|
#include "termkey.h"
|
|
|
|
#include "termkey-internal.h"
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
// There are 64 codes 0x40 - 0x7F
|
2012-01-22 19:54:17 +01:00
|
|
|
static int keyinfo_initialised = 0;
|
|
|
|
static struct keyinfo ss3s[64];
|
|
|
|
static char ss3_kpalts[64];
|
2012-01-20 19:01:19 +01:00
|
|
|
|
2008-10-07 00:27:19 +02:00
|
|
|
typedef struct {
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKey *tk;
|
2012-01-20 19:01:19 +01:00
|
|
|
} TermKeyCsi;
|
|
|
|
|
2012-04-24 17:33:13 +02:00
|
|
|
typedef TermKeyResult CsiHandler(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args);
|
|
|
|
static CsiHandler *csi_handlers[64];
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handler for CSI/SS3 cmd keys
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct keyinfo csi_ss3s[64];
|
|
|
|
|
|
|
|
static TermKeyResult handle_csi_ss3_full(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
|
|
|
|
{
|
|
|
|
if(args > 1 && arg[1] != -1)
|
|
|
|
key->modifiers = arg[1] - 1;
|
|
|
|
else
|
|
|
|
key->modifiers = 0;
|
|
|
|
|
|
|
|
key->type = csi_ss3s[cmd - 0x40].type;
|
|
|
|
key->code.sym = csi_ss3s[cmd - 0x40].sym;
|
|
|
|
key->modifiers &= ~(csi_ss3s[cmd - 0x40].modifier_mask);
|
|
|
|
key->modifiers |= csi_ss3s[cmd - 0x40].modifier_set;
|
|
|
|
|
|
|
|
if(key->code.sym == TERMKEY_SYM_UNKNOWN)
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
static void register_csi_ss3_full(TermKeyType type, TermKeySym sym, int modifier_set, int modifier_mask, unsigned char cmd)
|
|
|
|
{
|
|
|
|
if(cmd < 0x40 || cmd >= 0x80) {
|
|
|
|
return;
|
|
|
|
}
|
2008-10-07 00:53:25 +02:00
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
csi_ss3s[cmd - 0x40].type = type;
|
|
|
|
csi_ss3s[cmd - 0x40].sym = sym;
|
|
|
|
csi_ss3s[cmd - 0x40].modifier_set = modifier_set;
|
|
|
|
csi_ss3s[cmd - 0x40].modifier_mask = modifier_mask;
|
2012-04-24 17:33:13 +02:00
|
|
|
|
|
|
|
csi_handlers[cmd - 0x40] = &handle_csi_ss3_full;
|
2012-01-20 19:01:19 +01:00
|
|
|
}
|
2008-10-07 00:27:19 +02:00
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
static void register_csi_ss3(TermKeyType type, TermKeySym sym, unsigned char cmd)
|
|
|
|
{
|
|
|
|
register_csi_ss3_full(type, sym, 0, 0, cmd);
|
|
|
|
}
|
|
|
|
|
2012-04-24 17:33:13 +02:00
|
|
|
/*
|
|
|
|
* Handler for SS3 keys with kpad alternate representations
|
|
|
|
*/
|
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
static void register_ss3kpalt(TermKeyType type, TermKeySym sym, unsigned char cmd, char kpalt)
|
|
|
|
{
|
|
|
|
if(cmd < 0x40 || cmd >= 0x80) {
|
|
|
|
return;
|
|
|
|
}
|
2008-10-07 00:27:19 +02:00
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
ss3s[cmd - 0x40].type = type;
|
|
|
|
ss3s[cmd - 0x40].sym = sym;
|
|
|
|
ss3s[cmd - 0x40].modifier_set = 0;
|
|
|
|
ss3s[cmd - 0x40].modifier_mask = 0;
|
|
|
|
ss3_kpalts[cmd - 0x40] = kpalt;
|
|
|
|
}
|
2008-10-07 00:53:25 +02:00
|
|
|
|
2012-04-24 17:33:13 +02:00
|
|
|
/*
|
|
|
|
* Handler for CSI number ~ function keys
|
|
|
|
*/
|
|
|
|
|
|
|
|
static struct keyinfo csifuncs[35]; /* This value must be increased if more CSI function keys are added */
|
|
|
|
#define NCSIFUNCS (sizeof(csifuncs)/sizeof(csifuncs[0]))
|
|
|
|
|
|
|
|
static TermKeyResult handle_csifunc(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
|
|
|
|
{
|
|
|
|
if(args > 1 && arg[1] != -1)
|
|
|
|
key->modifiers = arg[1] - 1;
|
|
|
|
else
|
|
|
|
key->modifiers = 0;
|
|
|
|
|
|
|
|
key->type = TERMKEY_TYPE_KEYSYM;
|
|
|
|
|
|
|
|
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
|
|
|
|
key->code.sym = TERMKEY_SYM_UNKNOWN;
|
|
|
|
|
|
|
|
if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
|
|
|
|
#ifdef DEBUG
|
|
|
|
fprintf(stderr, "CSI: Unknown function key %ld\n", arg[0]);
|
|
|
|
#endif
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
static void register_csifunc(TermKeyType type, TermKeySym sym, int number)
|
|
|
|
{
|
|
|
|
if(number >= NCSIFUNCS) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
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
|
|
|
|
|
|
|
csi_handlers['~' - 0x40] = &handle_csifunc;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handler for CSI u extended Unicode keys
|
|
|
|
*/
|
|
|
|
|
2012-11-30 16:23:41 +01:00
|
|
|
static TermKeyResult handle_csi_u(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
|
2012-04-24 17:33:13 +02:00
|
|
|
{
|
2012-11-30 16:23:41 +01:00
|
|
|
switch(cmd) {
|
|
|
|
case 'u': {
|
|
|
|
if(args > 1 && arg[1] != -1)
|
|
|
|
key->modifiers = arg[1] - 1;
|
|
|
|
else
|
|
|
|
key->modifiers = 0;
|
|
|
|
|
|
|
|
int mod = key->modifiers;
|
|
|
|
key->type = TERMKEY_TYPE_KEYSYM;
|
|
|
|
(*tk->method.emit_codepoint)(tk, arg[0], key);
|
|
|
|
key->modifiers |= mod;
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
default:
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
}
|
2012-04-24 17:33:13 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* Handler for CSI M / CSI m mouse events in SRG and rxvt encodings
|
|
|
|
* Note: This does not handle X10 encoding
|
|
|
|
*/
|
|
|
|
|
2012-11-30 16:23:41 +01:00
|
|
|
static TermKeyResult handle_csi_m(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
|
2012-04-24 17:33:13 +02:00
|
|
|
{
|
|
|
|
int initial = cmd >> 8;
|
|
|
|
cmd &= 0xff;
|
|
|
|
|
2012-11-30 16:23:41 +01:00
|
|
|
switch(cmd) {
|
|
|
|
case 'M':
|
|
|
|
case 'm':
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
}
|
|
|
|
|
2012-04-24 17:33:13 +02:00
|
|
|
if(!initial && args >= 3) { // rxvt protocol
|
2012-04-24 18:42:01 +02:00
|
|
|
key->type = TERMKEY_TYPE_MOUSE;
|
2012-04-24 17:33:13 +02:00
|
|
|
key->code.mouse[0] = arg[0];
|
|
|
|
|
|
|
|
key->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
|
|
|
|
key->code.mouse[0] &= ~0x1c;
|
|
|
|
|
|
|
|
termkey_key_set_linecol(key, arg[1], arg[2]);
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(initial == '<' && args >= 3) { // SGR protocol
|
2012-04-24 18:42:01 +02:00
|
|
|
key->type = TERMKEY_TYPE_MOUSE;
|
2012-04-24 17:33:13 +02:00
|
|
|
key->code.mouse[0] = arg[0];
|
|
|
|
|
|
|
|
key->modifiers = (key->code.mouse[0] & 0x1c) >> 2;
|
|
|
|
key->code.mouse[0] &= ~0x1c;
|
|
|
|
|
|
|
|
termkey_key_set_linecol(key, arg[1], arg[2]);
|
|
|
|
|
|
|
|
if(cmd == 'm') // release
|
|
|
|
key->code.mouse[3] |= 0x80;
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TERMKEY_RES_NONE;
|
2012-01-20 19:01:19 +01:00
|
|
|
}
|
|
|
|
|
2012-11-30 16:01:20 +01:00
|
|
|
TermKeyResult termkey_interpret_mouse(TermKey *tk, const TermKeyKey *key, TermKeyMouseEvent *event, int *button, int *line, int *col)
|
|
|
|
{
|
|
|
|
if(key->type != TERMKEY_TYPE_MOUSE)
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
|
|
|
|
if(button)
|
|
|
|
*button = 0;
|
|
|
|
|
|
|
|
termkey_key_get_linecol(key, line, col);
|
|
|
|
|
|
|
|
if(!event)
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
|
|
|
|
int btn = 0;
|
|
|
|
|
|
|
|
int code = key->code.mouse[0];
|
|
|
|
|
|
|
|
int drag = code & 0x20;
|
|
|
|
|
|
|
|
code &= ~0x3c;
|
|
|
|
|
|
|
|
switch(code) {
|
|
|
|
case 0:
|
|
|
|
case 1:
|
|
|
|
case 2:
|
|
|
|
*event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS;
|
|
|
|
btn = code + 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 3:
|
|
|
|
*event = TERMKEY_MOUSE_RELEASE;
|
|
|
|
// no button hint
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 64:
|
|
|
|
case 65:
|
|
|
|
*event = drag ? TERMKEY_MOUSE_DRAG : TERMKEY_MOUSE_PRESS;
|
|
|
|
btn = code + 4 - 64;
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
*event = TERMKEY_MOUSE_UNKNOWN;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(button)
|
|
|
|
*button = btn;
|
|
|
|
|
|
|
|
if(key->code.mouse[3] & 0x80)
|
|
|
|
*event = TERMKEY_MOUSE_RELEASE;
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
2012-04-24 18:27:48 +02:00
|
|
|
/*
|
2012-11-30 17:12:26 +01:00
|
|
|
* Handler for CSI ? R position reports
|
2012-11-30 16:36:06 +01:00
|
|
|
* A plain CSI R with no arguments is probably actually <F3>
|
2012-04-24 18:27:48 +02:00
|
|
|
*/
|
|
|
|
|
2012-11-30 16:23:41 +01:00
|
|
|
static TermKeyResult handle_csi_R(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
|
2012-04-24 18:27:48 +02:00
|
|
|
{
|
2012-11-30 16:23:41 +01:00
|
|
|
switch(cmd) {
|
2012-11-30 17:12:26 +01:00
|
|
|
case 'R'|'?'<<8:
|
|
|
|
if(args < 2)
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
|
|
|
|
key->type = TERMKEY_TYPE_POSITION;
|
|
|
|
termkey_key_set_linecol(key, arg[1], arg[0]);
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
|
2012-11-30 16:23:41 +01:00
|
|
|
default:
|
2012-11-30 17:12:26 +01:00
|
|
|
return handle_csi_ss3_full(tk, key, cmd, arg, args);
|
2012-11-30 16:23:41 +01:00
|
|
|
}
|
2012-04-24 18:27:48 +02:00
|
|
|
}
|
|
|
|
|
2012-11-30 16:01:20 +01:00
|
|
|
TermKeyResult termkey_interpret_position(TermKey *tk, const TermKeyKey *key, int *line, int *col)
|
|
|
|
{
|
|
|
|
if(key->type != TERMKEY_TYPE_POSITION)
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
|
|
|
|
termkey_key_get_linecol(key, line, col);
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
2012-11-30 17:34:47 +01:00
|
|
|
/*
|
|
|
|
* Handler for CSI $y mode status reports
|
|
|
|
*/
|
|
|
|
|
|
|
|
static TermKeyResult handle_csi_y(TermKey *tk, TermKeyKey *key, int cmd, long *arg, int args)
|
|
|
|
{
|
|
|
|
switch(cmd) {
|
|
|
|
case 'y'|'$'<<16:
|
|
|
|
case 'y'|'$'<<16 | '?'<<8:
|
|
|
|
if(args < 2)
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
|
|
|
|
key->type = TERMKEY_TYPE_MODEREPORT;
|
|
|
|
key->code.mouse[0] = (cmd >> 8);
|
|
|
|
key->code.mouse[1] = arg[0] >> 8;
|
|
|
|
key->code.mouse[2] = arg[0] & 0xff;
|
|
|
|
key->code.mouse[3] = arg[1];
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
|
|
|
|
default:
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
TermKeyResult termkey_interpret_modereport(TermKey *tk, const TermKeyKey *key, int *initial, int *mode, int *value)
|
|
|
|
{
|
|
|
|
if(key->type != TERMKEY_TYPE_MODEREPORT)
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
|
|
|
|
if(initial)
|
|
|
|
*initial = key->code.mouse[0];
|
|
|
|
|
|
|
|
if(mode)
|
|
|
|
*mode = (key->code.mouse[1] << 8) | key->code.mouse[2];
|
|
|
|
|
|
|
|
if(value)
|
|
|
|
*value = key->code.mouse[3];
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
2012-11-30 14:52:56 +01:00
|
|
|
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
|
|
|
|
|
|
|
|
static TermKeyResult parse_csi(TermKey *tk, size_t introlen, size_t *csi_len, long args[], size_t *nargs, unsigned long *commandp)
|
|
|
|
{
|
|
|
|
size_t csi_end = introlen;
|
|
|
|
|
|
|
|
while(csi_end < tk->buffcount) {
|
|
|
|
if(CHARAT(csi_end) >= 0x40 && CHARAT(csi_end) < 0x80)
|
|
|
|
break;
|
|
|
|
csi_end++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(csi_end >= tk->buffcount)
|
|
|
|
return TERMKEY_RES_AGAIN;
|
|
|
|
|
|
|
|
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
|
|
|
|
while(p < csi_end) {
|
|
|
|
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;
|
|
|
|
}
|
2012-11-30 15:43:00 +01:00
|
|
|
else if(c >= 0x20 && c <= 0x2f) {
|
|
|
|
*commandp |= c << 16;
|
|
|
|
break;
|
|
|
|
}
|
2012-11-30 14:52:56 +01:00
|
|
|
|
|
|
|
p++;
|
|
|
|
}
|
|
|
|
|
2012-11-30 16:31:04 +01:00
|
|
|
if(present)
|
|
|
|
argi++;
|
2012-11-30 14:52:56 +01:00
|
|
|
|
|
|
|
*nargs = argi;
|
|
|
|
*csi_len = csi_end + 1;
|
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
2012-11-30 16:01:20 +01:00
|
|
|
TermKeyResult termkey_interpret_csi(TermKey *tk, const TermKeyKey *key, long args[], size_t *nargs, unsigned long *cmd)
|
|
|
|
{
|
|
|
|
size_t dummy;
|
|
|
|
|
|
|
|
if(tk->hightide == 0)
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
if(key->type != TERMKEY_TYPE_UNKNOWN_CSI)
|
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
|
|
|
|
return parse_csi(tk, 0, &dummy, args, nargs, cmd);
|
|
|
|
}
|
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
static int register_keys(void)
|
|
|
|
{
|
|
|
|
int i;
|
|
|
|
|
|
|
|
for(i = 0; i < 64; i++) {
|
|
|
|
csi_ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
|
|
|
|
ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
|
|
|
|
ss3_kpalts[i] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
for(i = 0; i < NCSIFUNCS; i++)
|
|
|
|
csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
|
|
|
|
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_UP, 'A');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DOWN, 'B');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_RIGHT, 'C');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_LEFT, 'D');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_BEGIN, 'E');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 'F');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 'H');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_FUNCTION, 1, 'P');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_FUNCTION, 2, 'Q');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_FUNCTION, 3, 'R');
|
|
|
|
register_csi_ss3(TERMKEY_TYPE_FUNCTION, 4, 'S');
|
|
|
|
|
|
|
|
register_csi_ss3_full(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_TAB, TERMKEY_KEYMOD_SHIFT, TERMKEY_KEYMOD_SHIFT, 'Z');
|
|
|
|
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPENTER, 'M', 0);
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPEQUALS, 'X', '=');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMULT, 'j', '*');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPLUS, 'k', '+');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPCOMMA, 'l', ',');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPMINUS, 'm', '-');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPPERIOD, 'n', '.');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KPDIV, 'o', '/');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP0, 'p', '0');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP1, 'q', '1');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP2, 'r', '2');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP3, 's', '3');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP4, 't', '4');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP5, 'u', '5');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP6, 'v', '6');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP7, 'w', '7');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP8, 'x', '8');
|
|
|
|
register_ss3kpalt(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_KP9, 'y', '9');
|
|
|
|
|
|
|
|
register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_FIND, 1);
|
|
|
|
register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_INSERT, 2);
|
|
|
|
register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_DELETE, 3);
|
|
|
|
register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_SELECT, 4);
|
|
|
|
register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEUP, 5);
|
|
|
|
register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_PAGEDOWN, 6);
|
|
|
|
register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_HOME, 7);
|
|
|
|
register_csifunc(TERMKEY_TYPE_KEYSYM, TERMKEY_SYM_END, 8);
|
|
|
|
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 1, 11);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 2, 12);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 3, 13);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 4, 14);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 5, 15);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 6, 17);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 7, 18);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 8, 19);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 9, 20);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 10, 21);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 11, 23);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 12, 24);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 13, 25);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 14, 26);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 15, 28);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 16, 29);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 17, 31);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 18, 32);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 19, 33);
|
|
|
|
register_csifunc(TERMKEY_TYPE_FUNCTION, 20, 34);
|
|
|
|
|
2012-11-30 16:23:41 +01:00
|
|
|
csi_handlers['u' - 0x40] = &handle_csi_u;
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2012-11-30 16:23:41 +01:00
|
|
|
csi_handlers['M' - 0x40] = &handle_csi_m;
|
|
|
|
csi_handlers['m' - 0x40] = &handle_csi_m;
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2012-11-30 16:23:41 +01:00
|
|
|
csi_handlers['R' - 0x40] = &handle_csi_R;
|
2012-04-24 18:27:48 +02:00
|
|
|
|
2012-11-30 17:34:47 +01:00
|
|
|
csi_handlers['y' - 0x40] = &handle_csi_y;
|
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
keyinfo_initialised = 1;
|
|
|
|
return 1;
|
|
|
|
}
|
2008-10-07 00:53:25 +02:00
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
static void *new_driver(TermKey *tk, const char *term)
|
2008-10-07 00:27:19 +02:00
|
|
|
{
|
2012-01-20 19:01:19 +01:00
|
|
|
if(!keyinfo_initialised)
|
|
|
|
if(!register_keys())
|
|
|
|
return NULL;
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKeyCsi *csi = malloc(sizeof *csi);
|
2008-10-10 00:19:10 +02:00
|
|
|
if(!csi)
|
|
|
|
return NULL;
|
2008-10-07 00:27:19 +02:00
|
|
|
|
2008-10-07 00:53:25 +02:00
|
|
|
csi->tk = tk;
|
|
|
|
|
2008-10-07 00:27:19 +02:00
|
|
|
return csi;
|
|
|
|
}
|
|
|
|
|
2008-11-08 18:47:57 +01:00
|
|
|
static void free_driver(void *info)
|
2008-10-07 00:27:19 +02:00
|
|
|
{
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKeyCsi *csi = info;
|
2008-10-07 00:27:19 +02:00
|
|
|
|
|
|
|
free(csi);
|
|
|
|
}
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
static TermKeyResult peekkey_csi(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
|
2008-10-07 00:27:19 +02:00
|
|
|
{
|
2012-11-30 14:52:56 +01:00
|
|
|
size_t csi_len;
|
|
|
|
size_t args = 16;
|
|
|
|
long arg[16];
|
|
|
|
unsigned long cmd;
|
2008-10-07 00:27:19 +02:00
|
|
|
|
2012-11-30 14:52:56 +01:00
|
|
|
TermKeyResult ret = parse_csi(tk, introlen, &csi_len, arg, &args, &cmd);
|
2008-10-07 00:27:19 +02:00
|
|
|
|
2012-11-30 14:52:56 +01:00
|
|
|
if(ret == TERMKEY_RES_AGAIN) {
|
2008-10-08 01:44:33 +02:00
|
|
|
if(!force)
|
2008-10-07 00:27:19 +02:00
|
|
|
return TERMKEY_RES_AGAIN;
|
|
|
|
|
2008-10-08 01:12:41 +02:00
|
|
|
(*tk->method.emit_codepoint)(tk, '[', key);
|
2008-10-07 00:27:19 +02:00
|
|
|
key->modifiers |= TERMKEY_KEYMOD_ALT;
|
2008-12-10 01:23:47 +01:00
|
|
|
*nbytep = introlen;
|
2008-10-07 00:27:19 +02:00
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
2012-04-24 17:33:13 +02:00
|
|
|
if(cmd == 'M' && args < 3) { // Mouse in X10 encoding consumes the next 3 bytes also
|
2009-11-26 01:33:30 +01:00
|
|
|
tk->buffstart += csi_len;
|
|
|
|
tk->buffcount -= csi_len;
|
|
|
|
|
|
|
|
TermKeyResult mouse_result = (*tk->method.peekkey_mouse)(tk, key, nbytep);
|
|
|
|
|
|
|
|
tk->buffstart -= csi_len;
|
|
|
|
tk->buffcount += csi_len;
|
|
|
|
|
|
|
|
if(mouse_result == TERMKEY_RES_KEY)
|
|
|
|
*nbytep += csi_len;
|
|
|
|
|
|
|
|
return mouse_result;
|
|
|
|
}
|
2012-04-24 17:33:13 +02:00
|
|
|
|
|
|
|
TermKeyResult result = TERMKEY_RES_NONE;
|
|
|
|
|
|
|
|
// We know from the logic above that cmd must be >= 0x40 and < 0x80
|
2012-11-30 14:52:56 +01:00
|
|
|
if(csi_handlers[(cmd & 0xff) - 0x40])
|
|
|
|
result = (*csi_handlers[(cmd & 0xff) - 0x40])(tk, key, cmd, arg, args);
|
2012-04-24 17:33:13 +02:00
|
|
|
|
2012-11-30 15:35:23 +01:00
|
|
|
if(result == TERMKEY_RES_NONE) {
|
2008-11-12 14:02:30 +01:00
|
|
|
#ifdef DEBUG
|
2012-04-24 17:33:13 +02:00
|
|
|
switch(args) {
|
2008-11-12 13:44:33 +01:00
|
|
|
case 1:
|
2012-01-20 18:03:54 +01:00
|
|
|
fprintf(stderr, "CSI: Unknown arg1=%ld cmd=%c\n", arg[0], (char)cmd);
|
2008-11-12 13:44:33 +01:00
|
|
|
break;
|
|
|
|
case 2:
|
2012-01-20 18:03:54 +01:00
|
|
|
fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld cmd=%c\n", arg[0], arg[1], (char)cmd);
|
2008-11-12 13:44:33 +01:00
|
|
|
break;
|
|
|
|
case 3:
|
2012-01-20 18:03:54 +01:00
|
|
|
fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld cmd=%c\n", arg[0], arg[1], arg[2], (char)cmd);
|
2008-11-12 13:44:33 +01:00
|
|
|
break;
|
|
|
|
default:
|
2012-01-20 18:03:54 +01:00
|
|
|
fprintf(stderr, "CSI: Unknown arg1=%ld arg2=%ld arg3=%ld ... args=%d cmd=%c\n", arg[0], arg[1], arg[2], args, (char)cmd);
|
2008-11-12 13:44:33 +01:00
|
|
|
break;
|
|
|
|
}
|
2012-04-24 17:33:13 +02:00
|
|
|
#endif
|
2012-11-30 15:35:23 +01:00
|
|
|
key->type = TERMKEY_TYPE_UNKNOWN_CSI;
|
|
|
|
key->code.number = cmd;
|
|
|
|
|
|
|
|
tk->hightide = csi_len - introlen;
|
|
|
|
*nbytep = introlen; // Do not yet eat the data bytes
|
|
|
|
return TERMKEY_RES_KEY;
|
2008-10-07 00:27:19 +02:00
|
|
|
}
|
|
|
|
|
2012-11-30 14:52:56 +01:00
|
|
|
*nbytep = csi_len;
|
2012-04-24 17:33:13 +02:00
|
|
|
return result;
|
2008-10-07 00:27:19 +02:00
|
|
|
}
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
static TermKeyResult peekkey_ss3(TermKey *tk, TermKeyCsi *csi, size_t introlen, TermKeyKey *key, int force, size_t *nbytep)
|
2008-10-07 00:27:19 +02:00
|
|
|
{
|
|
|
|
if(tk->buffcount < introlen + 1) {
|
2008-10-08 01:44:33 +02:00
|
|
|
if(!force)
|
2008-10-07 00:27:19 +02:00
|
|
|
return TERMKEY_RES_AGAIN;
|
|
|
|
|
2008-10-08 01:12:41 +02:00
|
|
|
(*tk->method.emit_codepoint)(tk, 'O', key);
|
2008-10-07 00:27:19 +02:00
|
|
|
key->modifiers |= TERMKEY_KEYMOD_ALT;
|
2008-12-10 01:23:47 +01:00
|
|
|
*nbytep = tk->buffcount;
|
2008-10-07 00:27:19 +02:00
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned char cmd = CHARAT(introlen);
|
|
|
|
|
|
|
|
if(cmd < 0x40 || cmd >= 0x80)
|
2008-11-12 13:51:19 +01:00
|
|
|
return TERMKEY_RES_NONE;
|
2008-10-07 00:27:19 +02:00
|
|
|
|
2012-01-20 19:01:19 +01:00
|
|
|
key->type = csi_ss3s[cmd - 0x40].type;
|
|
|
|
key->code.sym = csi_ss3s[cmd - 0x40].sym;
|
|
|
|
key->modifiers = csi_ss3s[cmd - 0x40].modifier_set;
|
2008-10-07 00:27:19 +02:00
|
|
|
|
|
|
|
if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
|
2012-01-20 19:01:19 +01:00
|
|
|
if(tk->flags & TERMKEY_FLAG_CONVERTKP && ss3_kpalts[cmd - 0x40]) {
|
2008-10-07 00:27:19 +02:00
|
|
|
key->type = TERMKEY_TYPE_UNICODE;
|
2012-01-20 19:01:19 +01:00
|
|
|
key->code.codepoint = ss3_kpalts[cmd - 0x40];
|
2008-10-07 00:27:19 +02:00
|
|
|
key->modifiers = 0;
|
|
|
|
|
|
|
|
key->utf8[0] = key->code.codepoint;
|
|
|
|
key->utf8[1] = 0;
|
|
|
|
}
|
2008-11-12 13:51:19 +01:00
|
|
|
else {
|
2012-01-20 19:01:19 +01:00
|
|
|
key->type = ss3s[cmd - 0x40].type;
|
|
|
|
key->code.sym = ss3s[cmd - 0x40].sym;
|
|
|
|
key->modifiers = ss3s[cmd - 0x40].modifier_set;
|
2008-11-12 13:51:19 +01:00
|
|
|
}
|
2008-10-07 00:27:19 +02:00
|
|
|
}
|
|
|
|
|
2008-11-12 13:51:19 +01:00
|
|
|
if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
|
2008-11-12 14:02:30 +01:00
|
|
|
#ifdef DEBUG
|
2012-01-20 19:13:37 +01:00
|
|
|
fprintf(stderr, "CSI: Unknown SS3 %c (0x%02x)\n", (char)cmd, cmd);
|
2008-11-12 14:02:30 +01:00
|
|
|
#endif
|
2008-11-12 13:51:19 +01:00
|
|
|
return TERMKEY_RES_NONE;
|
|
|
|
}
|
|
|
|
|
2008-12-10 01:23:47 +01:00
|
|
|
*nbytep = introlen + 1;
|
2008-10-07 00:27:19 +02:00
|
|
|
|
|
|
|
return TERMKEY_RES_KEY;
|
|
|
|
}
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
static TermKeyResult peekkey(TermKey *tk, void *info, TermKeyKey *key, int force, size_t *nbytep)
|
2008-10-07 00:27:19 +02:00
|
|
|
{
|
|
|
|
if(tk->buffcount == 0)
|
|
|
|
return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
TermKeyCsi *csi = info;
|
2008-11-08 18:43:51 +01:00
|
|
|
|
2008-10-07 00:27:19 +02:00
|
|
|
// Now we're sure at least 1 byte is valid
|
|
|
|
unsigned char b0 = CHARAT(0);
|
|
|
|
|
2008-11-03 15:46:42 +01:00
|
|
|
if(b0 == 0x1b && tk->buffcount > 1 && CHARAT(1) == '[') {
|
2008-12-10 01:23:47 +01:00
|
|
|
return peekkey_csi(tk, csi, 2, key, force, nbytep);
|
2008-11-03 15:46:42 +01:00
|
|
|
}
|
|
|
|
else if(b0 == 0x1b && tk->buffcount > 1 && CHARAT(1) == 'O') {
|
2008-12-10 01:23:47 +01:00
|
|
|
return peekkey_ss3(tk, csi, 2, key, force, nbytep);
|
2008-10-07 00:27:19 +02:00
|
|
|
}
|
|
|
|
else if(b0 == 0x8f) {
|
2008-12-10 01:23:47 +01:00
|
|
|
return peekkey_ss3(tk, csi, 1, key, force, nbytep);
|
2008-10-07 00:27:19 +02:00
|
|
|
}
|
|
|
|
else if(b0 == 0x9b) {
|
2008-12-10 01:23:47 +01:00
|
|
|
return peekkey_csi(tk, csi, 1, key, force, nbytep);
|
2008-10-07 00:27:19 +02:00
|
|
|
}
|
2008-10-08 01:36:27 +02:00
|
|
|
else
|
2008-11-09 20:45:43 +01:00
|
|
|
return TERMKEY_RES_NONE;
|
2008-10-07 00:27:19 +02:00
|
|
|
}
|
|
|
|
|
2009-07-15 21:40:44 +02:00
|
|
|
struct TermKeyDriver termkey_driver_csi = {
|
2008-11-08 18:56:44 +01:00
|
|
|
.name = "CSI",
|
|
|
|
|
2008-10-07 00:36:14 +02:00
|
|
|
.new_driver = new_driver,
|
|
|
|
.free_driver = free_driver,
|
|
|
|
|
2008-12-10 01:23:47 +01:00
|
|
|
.peekkey = peekkey,
|
2008-10-07 00:36:14 +02:00
|
|
|
};
|