Moved CSI-related code out of termkey.c into new driver-csi.c
This commit is contained in:
parent
d871cb39c6
commit
f5c6ecf9af
4
Makefile
4
Makefile
|
@ -7,10 +7,10 @@ endif
|
|||
|
||||
all: demo
|
||||
|
||||
demo: termkey.o demo.c
|
||||
demo: termkey.o driver-csi.o demo.c
|
||||
gcc $(CCFLAGS) $(LDFLAGS) -o $@ $^
|
||||
|
||||
termkey.o: termkey.c
|
||||
%.o: %.c
|
||||
gcc $(CCFLAGS) -o $@ -c $^
|
||||
|
||||
.PHONY: clean
|
||||
|
|
|
@ -0,0 +1,582 @@
|
|||
#include "termkey.h"
|
||||
#include "termkey-internal.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
struct keyinfo {
|
||||
termkey_type type;
|
||||
termkey_keysym sym;
|
||||
int modifier_mask;
|
||||
int modifier_set;
|
||||
};
|
||||
|
||||
typedef struct {
|
||||
// There are 32 C0 codes
|
||||
struct keyinfo c0[32];
|
||||
|
||||
// There are 64 codes 0x40 - 0x7F
|
||||
struct keyinfo csi_ss3s[64];
|
||||
struct keyinfo ss3s[64];
|
||||
char ss3_kpalts[64];
|
||||
|
||||
int ncsifuncs;
|
||||
struct keyinfo *csifuncs;
|
||||
} termkey_csi;
|
||||
|
||||
void *termkeycsi_new_driver(termkey_t *tk)
|
||||
{
|
||||
termkey_csi *csi = malloc(sizeof *csi);
|
||||
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 32; i++) {
|
||||
csi->c0[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
}
|
||||
|
||||
for(i = 0; i < 64; i++) {
|
||||
csi->csi_ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
csi->ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
csi->ss3_kpalts[i] = 0;
|
||||
}
|
||||
|
||||
csi->ncsifuncs = 32;
|
||||
|
||||
csi->csifuncs = malloc(sizeof(csi->csifuncs[0]) * csi->ncsifuncs);
|
||||
|
||||
for(i = 0; i < csi->ncsifuncs; i++)
|
||||
csi->csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
|
||||
return csi;
|
||||
}
|
||||
|
||||
void termkeycsi_free_driver(void *private)
|
||||
{
|
||||
termkey_csi *csi = private;
|
||||
|
||||
free(csi->csifuncs); csi->csifuncs = NULL;
|
||||
|
||||
free(csi);
|
||||
}
|
||||
|
||||
static inline void eatbytes(termkey_t *tk, size_t count)
|
||||
{
|
||||
if(count >= tk->buffcount) {
|
||||
tk->buffstart = 0;
|
||||
tk->buffcount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
tk->buffstart += count;
|
||||
tk->buffcount -= count;
|
||||
|
||||
size_t halfsize = tk->buffsize / 2;
|
||||
|
||||
if(tk->buffstart > halfsize) {
|
||||
memcpy(tk->buffer, tk->buffer + halfsize, halfsize);
|
||||
tk->buffstart -= halfsize;
|
||||
}
|
||||
}
|
||||
|
||||
#define UTF8_INVALID 0xFFFD
|
||||
|
||||
static int utf8_seqlen(int codepoint)
|
||||
{
|
||||
if(codepoint < 0x0000080) return 1;
|
||||
if(codepoint < 0x0000800) return 2;
|
||||
if(codepoint < 0x0010000) return 3;
|
||||
if(codepoint < 0x0200000) return 4;
|
||||
if(codepoint < 0x4000000) return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
static void fill_utf8(termkey_key *key)
|
||||
{
|
||||
int codepoint = key->code.codepoint;
|
||||
int nbytes = utf8_seqlen(codepoint);
|
||||
|
||||
key->utf8[nbytes] = 0;
|
||||
|
||||
// This is easier done backwards
|
||||
int b = nbytes;
|
||||
while(b > 1) {
|
||||
b--;
|
||||
key->utf8[b] = 0x80 | (codepoint & 0x3f);
|
||||
codepoint >>= 6;
|
||||
}
|
||||
|
||||
switch(nbytes) {
|
||||
case 1: key->utf8[0] = (codepoint & 0x7f); break;
|
||||
case 2: key->utf8[0] = 0xc0 | (codepoint & 0x1f); break;
|
||||
case 3: key->utf8[0] = 0xe0 | (codepoint & 0x0f); break;
|
||||
case 4: key->utf8[0] = 0xf0 | (codepoint & 0x07); break;
|
||||
case 5: key->utf8[0] = 0xf8 | (codepoint & 0x03); break;
|
||||
case 6: key->utf8[0] = 0xfc | (codepoint & 0x01); break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void do_codepoint(termkey_t *tk, int codepoint, termkey_key *key)
|
||||
{
|
||||
termkey_csi *csi = tk->driver_info;
|
||||
|
||||
if(codepoint < 0x20) {
|
||||
// C0 range
|
||||
key->code.codepoint = 0;
|
||||
key->modifiers = 0;
|
||||
|
||||
if(!(tk->flags & TERMKEY_FLAG_NOINTERPRET) && csi->c0[codepoint].sym != TERMKEY_SYM_UNKNOWN) {
|
||||
key->code.sym = csi->c0[codepoint].sym;
|
||||
key->modifiers |= csi->c0[codepoint].modifier_set;
|
||||
}
|
||||
|
||||
if(!key->code.sym) {
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = codepoint + 0x40;
|
||||
key->modifiers = TERMKEY_KEYMOD_CTRL;
|
||||
}
|
||||
else {
|
||||
key->type = TERMKEY_TYPE_KEYSYM;
|
||||
}
|
||||
}
|
||||
else if(codepoint == 0x20 && !(tk->flags & TERMKEY_FLAG_NOINTERPRET)) {
|
||||
// ASCII space
|
||||
key->type = TERMKEY_TYPE_KEYSYM;
|
||||
key->code.sym = TERMKEY_SYM_SPACE;
|
||||
key->modifiers = 0;
|
||||
}
|
||||
else if(codepoint == 0x7f && !(tk->flags & TERMKEY_FLAG_NOINTERPRET)) {
|
||||
// ASCII DEL
|
||||
key->type = TERMKEY_TYPE_KEYSYM;
|
||||
key->code.sym = TERMKEY_SYM_DEL;
|
||||
key->modifiers = 0;
|
||||
}
|
||||
else if(codepoint >= 0x20 && codepoint < 0x80) {
|
||||
// ASCII lowbyte range
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = codepoint;
|
||||
key->modifiers = 0;
|
||||
}
|
||||
else if(codepoint >= 0x80 && codepoint < 0xa0) {
|
||||
// UTF-8 never starts with a C1 byte. So we can be sure of these
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = codepoint - 0x40;
|
||||
key->modifiers = TERMKEY_KEYMOD_CTRL|TERMKEY_KEYMOD_ALT;
|
||||
}
|
||||
else {
|
||||
// UTF-8 codepoint
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = codepoint;
|
||||
key->modifiers = 0;
|
||||
}
|
||||
|
||||
if(key->type == TERMKEY_TYPE_UNICODE)
|
||||
fill_utf8(key);
|
||||
}
|
||||
|
||||
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
|
||||
|
||||
static termkey_result getkey_csi(termkey_t *tk, size_t introlen, termkey_key *key)
|
||||
{
|
||||
termkey_csi *csi = tk->driver_info;
|
||||
|
||||
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) {
|
||||
if(tk->waittime)
|
||||
return TERMKEY_RES_AGAIN;
|
||||
|
||||
do_codepoint(tk, '[', key);
|
||||
key->modifiers |= TERMKEY_KEYMOD_ALT;
|
||||
eatbytes(tk, introlen);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
unsigned char cmd = CHARAT(csi_end);
|
||||
int arg[16];
|
||||
char present = 0;
|
||||
int args = 0;
|
||||
|
||||
size_t p = introlen;
|
||||
|
||||
// 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) {
|
||||
arg[args] = c - '0';
|
||||
present = 1;
|
||||
}
|
||||
else {
|
||||
arg[args] = (arg[args] * 10) + c - '0';
|
||||
}
|
||||
}
|
||||
else if(c == ';') {
|
||||
if(!present)
|
||||
arg[args] = -1;
|
||||
present = 0;
|
||||
args++;
|
||||
|
||||
if(args > 16)
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
if(!present)
|
||||
arg[args] = -1;
|
||||
|
||||
args++;
|
||||
|
||||
eatbytes(tk, csi_end + 1);
|
||||
|
||||
if(args > 1 && arg[1] != -1)
|
||||
key->modifiers = arg[1] - 1;
|
||||
else
|
||||
key->modifiers = 0;
|
||||
|
||||
if(cmd == '~') {
|
||||
key->type = TERMKEY_TYPE_KEYSYM;
|
||||
|
||||
if(arg[0] == 27) {
|
||||
int mod = key->modifiers;
|
||||
do_codepoint(tk, arg[2], key);
|
||||
key->modifiers |= mod;
|
||||
}
|
||||
else if(arg[0] >= 0 && arg[0] < csi->ncsifuncs) {
|
||||
key->type = csi->csifuncs[arg[0]].type;
|
||||
key->code.sym = csi->csifuncs[arg[0]].sym;
|
||||
key->modifiers &= ~(csi->csifuncs[arg[0]].modifier_mask);
|
||||
key->modifiers |= csi->csifuncs[arg[0]].modifier_set;
|
||||
}
|
||||
else
|
||||
key->code.sym = TERMKEY_SYM_UNKNOWN;
|
||||
|
||||
if(key->code.sym == TERMKEY_SYM_UNKNOWN)
|
||||
fprintf(stderr, "CSI function key %d\n", arg[0]);
|
||||
}
|
||||
else {
|
||||
// We know from the logic above that cmd must be >= 0x40 and < 0x80
|
||||
key->type = csi->csi_ss3s[cmd - 0x40].type;
|
||||
key->code.sym = csi->csi_ss3s[cmd - 0x40].sym;
|
||||
key->modifiers &= ~(csi->csi_ss3s[cmd - 0x40].modifier_mask);
|
||||
key->modifiers |= csi->csi_ss3s[cmd - 0x40].modifier_set;
|
||||
|
||||
if(key->code.sym == TERMKEY_SYM_UNKNOWN)
|
||||
fprintf(stderr, "CSI arg1=%d arg2=%d cmd=%c\n", arg[0], arg[1], cmd);
|
||||
}
|
||||
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
static termkey_result getkey_ss3(termkey_t *tk, size_t introlen, termkey_key *key)
|
||||
{
|
||||
termkey_csi *csi = tk->driver_info;
|
||||
|
||||
if(tk->buffcount < introlen + 1) {
|
||||
if(tk->waittime)
|
||||
return TERMKEY_RES_AGAIN;
|
||||
|
||||
do_codepoint(tk, 'O', key);
|
||||
key->modifiers |= TERMKEY_KEYMOD_ALT;
|
||||
eatbytes(tk, tk->buffcount);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
unsigned char cmd = CHARAT(introlen);
|
||||
|
||||
eatbytes(tk, introlen + 1);
|
||||
|
||||
if(cmd < 0x40 || cmd >= 0x80)
|
||||
return TERMKEY_SYM_UNKNOWN;
|
||||
|
||||
key->type = csi->csi_ss3s[cmd - 0x40].type;
|
||||
key->code.sym = csi->csi_ss3s[cmd - 0x40].sym;
|
||||
key->modifiers = csi->csi_ss3s[cmd - 0x40].modifier_set;
|
||||
|
||||
if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
|
||||
if(tk->flags & TERMKEY_FLAG_CONVERTKP && csi->ss3_kpalts[cmd - 0x40]) {
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = csi->ss3_kpalts[cmd - 0x40];
|
||||
key->modifiers = 0;
|
||||
|
||||
key->utf8[0] = key->code.codepoint;
|
||||
key->utf8[1] = 0;
|
||||
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
key->type = csi->ss3s[cmd - 0x40].type;
|
||||
key->code.sym = csi->ss3s[cmd - 0x40].sym;
|
||||
key->modifiers = csi->ss3s[cmd - 0x40].modifier_set;
|
||||
}
|
||||
|
||||
if(key->code.sym == TERMKEY_SYM_UNKNOWN)
|
||||
fprintf(stderr, "SS3 %c (0x%02x)\n", cmd, cmd);
|
||||
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
termkey_result termkeycsi_getkey(termkey_t *tk, termkey_key *key)
|
||||
{
|
||||
if(tk->buffcount == 0)
|
||||
return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
|
||||
|
||||
// Now we're sure at least 1 byte is valid
|
||||
unsigned char b0 = CHARAT(0);
|
||||
|
||||
if(b0 == 0x1b) {
|
||||
if(tk->buffcount == 1) {
|
||||
// This might be an <Esc> press, or it may want to be part of a longer
|
||||
// sequence
|
||||
if(tk->waittime)
|
||||
return TERMKEY_RES_AGAIN;
|
||||
|
||||
do_codepoint(tk, b0, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
unsigned char b1 = CHARAT(1);
|
||||
|
||||
if(b1 == '[')
|
||||
return getkey_csi(tk, 2, key);
|
||||
|
||||
if(b1 == 'O')
|
||||
return getkey_ss3(tk, 2, key);
|
||||
|
||||
if(b1 == 0x1b) {
|
||||
do_codepoint(tk, b0, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
tk->buffstart++;
|
||||
|
||||
termkey_result metakey_result = termkey_getkey(tk, key);
|
||||
|
||||
switch(metakey_result) {
|
||||
case TERMKEY_RES_KEY:
|
||||
key->modifiers |= TERMKEY_KEYMOD_ALT;
|
||||
tk->buffstart--;
|
||||
eatbytes(tk, 1);
|
||||
break;
|
||||
|
||||
case TERMKEY_RES_NONE:
|
||||
case TERMKEY_RES_EOF:
|
||||
case TERMKEY_RES_AGAIN:
|
||||
break;
|
||||
}
|
||||
|
||||
return metakey_result;
|
||||
}
|
||||
else if(b0 == 0x8f) {
|
||||
return getkey_ss3(tk, 1, key);
|
||||
}
|
||||
else if(b0 == 0x9b) {
|
||||
return getkey_csi(tk, 1, key);
|
||||
}
|
||||
else if(b0 < 0xa0) {
|
||||
// Single byte C0, G0 or C1 - C1 is never UTF-8 initial byte
|
||||
do_codepoint(tk, b0, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
else if(tk->flags & TERMKEY_FLAG_UTF8) {
|
||||
// Some UTF-8
|
||||
int nbytes;
|
||||
int codepoint;
|
||||
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->modifiers = 0;
|
||||
|
||||
if(b0 < 0xc0) {
|
||||
// Starts with a continuation byte - that's not right
|
||||
do_codepoint(tk, UTF8_INVALID, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
else if(b0 < 0xe0) {
|
||||
nbytes = 2;
|
||||
codepoint = b0 & 0x1f;
|
||||
}
|
||||
else if(b0 < 0xf0) {
|
||||
nbytes = 3;
|
||||
codepoint = b0 & 0x0f;
|
||||
}
|
||||
else if(b0 < 0xf8) {
|
||||
nbytes = 4;
|
||||
codepoint = b0 & 0x07;
|
||||
}
|
||||
else if(b0 < 0xfc) {
|
||||
nbytes = 5;
|
||||
codepoint = b0 & 0x03;
|
||||
}
|
||||
else if(b0 < 0xfe) {
|
||||
nbytes = 6;
|
||||
codepoint = b0 & 0x01;
|
||||
}
|
||||
else {
|
||||
do_codepoint(tk, UTF8_INVALID, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
if(tk->buffcount < nbytes)
|
||||
return tk->waittime ? TERMKEY_RES_AGAIN : TERMKEY_RES_NONE;
|
||||
|
||||
for(int b = 1; b < nbytes; b++) {
|
||||
unsigned char cb = CHARAT(b);
|
||||
if(cb < 0x80 || cb >= 0xc0) {
|
||||
do_codepoint(tk, UTF8_INVALID, key);
|
||||
eatbytes(tk, b - 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
codepoint <<= 6;
|
||||
codepoint |= cb & 0x3f;
|
||||
}
|
||||
|
||||
// Check for overlong sequences
|
||||
if(nbytes > utf8_seqlen(codepoint))
|
||||
codepoint = UTF8_INVALID;
|
||||
|
||||
// Check for UTF-16 surrogates or invalid codepoints
|
||||
if((codepoint >= 0xD800 && codepoint <= 0xDFFF) ||
|
||||
codepoint == 0xFFFE ||
|
||||
codepoint == 0xFFFF)
|
||||
codepoint = UTF8_INVALID;
|
||||
|
||||
do_codepoint(tk, codepoint, key);
|
||||
eatbytes(tk, nbytes);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
else {
|
||||
// Non UTF-8 case - just report the raw byte
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = b0;
|
||||
key->modifiers = 0;
|
||||
|
||||
key->utf8[0] = key->code.codepoint;
|
||||
key->utf8[1] = 0;
|
||||
|
||||
eatbytes(tk, 1);
|
||||
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
return TERMKEY_SYM_NONE;
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_c0(termkey_t *tk, termkey_keysym sym, unsigned char ctrl, const char *name)
|
||||
{
|
||||
return termkey_register_c0_full(tk, sym, 0, 0, ctrl, name);
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_c0_full(termkey_t *tk, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char ctrl, const char *name)
|
||||
{
|
||||
termkey_csi *csi = tk->driver_info;
|
||||
|
||||
if(ctrl >= 0x20) {
|
||||
fprintf(stderr, "Cannot register C0 key at ctrl 0x%02x - out of bounds\n", ctrl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(name)
|
||||
sym = termkey_register_keyname(tk, sym, name);
|
||||
|
||||
csi->c0[ctrl].sym = sym;
|
||||
csi->c0[ctrl].modifier_set = modifier_set;
|
||||
csi->c0[ctrl].modifier_mask = modifier_mask;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_csi_ss3(termkey_t *tk, termkey_type type, termkey_keysym sym, unsigned char cmd, const char *name)
|
||||
{
|
||||
return termkey_register_csi_ss3_full(tk, type, sym, 0, 0, cmd, name);
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_csi_ss3_full(termkey_t *tk, termkey_type type, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char cmd, const char *name)
|
||||
{
|
||||
termkey_csi *csi = tk->driver_info;
|
||||
|
||||
if(cmd < 0x40 || cmd >= 0x80) {
|
||||
fprintf(stderr, "Cannot register CSI/SS3 key at cmd 0x%02x - out of bounds\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(name)
|
||||
sym = termkey_register_keyname(tk, sym, name);
|
||||
|
||||
csi->csi_ss3s[cmd - 0x40].type = type;
|
||||
csi->csi_ss3s[cmd - 0x40].sym = sym;
|
||||
csi->csi_ss3s[cmd - 0x40].modifier_set = modifier_set;
|
||||
csi->csi_ss3s[cmd - 0x40].modifier_mask = modifier_mask;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_ss3kpalt(termkey_t *tk, termkey_type type, termkey_keysym sym, unsigned char cmd, const char *name, char kpalt)
|
||||
{
|
||||
return termkey_register_ss3kpalt_full(tk, type, sym, 0, 0, cmd, name, kpalt);
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_ss3kpalt_full(termkey_t *tk, termkey_type type, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char cmd, const char *name, char kpalt)
|
||||
{
|
||||
termkey_csi *csi = tk->driver_info;
|
||||
|
||||
if(cmd < 0x40 || cmd >= 0x80) {
|
||||
fprintf(stderr, "Cannot register SS3 key at cmd 0x%02x - out of bounds\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(name)
|
||||
sym = termkey_register_keyname(tk, sym, name);
|
||||
|
||||
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;
|
||||
csi->ss3_kpalts[cmd - 0x40] = kpalt;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_csifunc(termkey_t *tk, termkey_type type, termkey_keysym sym, int number, const char *name)
|
||||
{
|
||||
return termkey_register_csifunc_full(tk, type, sym, 0, 0, number, name);
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_csifunc_full(termkey_t *tk, termkey_type type, termkey_keysym sym, int modifier_set, int modifier_mask, int number, const char *name)
|
||||
{
|
||||
termkey_csi *csi = tk->driver_info;
|
||||
|
||||
if(name)
|
||||
sym = termkey_register_keyname(tk, sym, name);
|
||||
|
||||
if(number >= csi->ncsifuncs) {
|
||||
struct keyinfo *new_csifuncs = realloc(csi->csifuncs, sizeof(new_csifuncs[0]) * (number + 1));
|
||||
csi->csifuncs = new_csifuncs;
|
||||
|
||||
// Fill in the hole
|
||||
for(int i = csi->ncsifuncs; i < number; i++)
|
||||
csi->csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
|
||||
csi->ncsifuncs = number + 1;
|
||||
}
|
||||
|
||||
csi->csifuncs[number].type = type;
|
||||
csi->csifuncs[number].sym = sym;
|
||||
csi->csifuncs[number].modifier_set = modifier_set;
|
||||
csi->csifuncs[number].modifier_mask = modifier_mask;
|
||||
|
||||
return sym;
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef GUARD_TERMKEY_INTERNAL_H_
|
||||
#define GUARD_TERMKEY_INTERNAL_H_
|
||||
|
||||
#include "termkey.h"
|
||||
|
||||
#include <stdint.h>
|
||||
#include <termios.h>
|
||||
|
||||
struct termkey_driver
|
||||
{
|
||||
void *(*new_driver)(void);
|
||||
void (*free_driver)(void *);
|
||||
};
|
||||
|
||||
struct termkey {
|
||||
int fd;
|
||||
int flags;
|
||||
unsigned char *buffer;
|
||||
size_t buffstart; // First offset in buffer
|
||||
size_t buffcount; // NUMBER of entires valid in buffer
|
||||
size_t buffsize; // Total malloc'ed size
|
||||
|
||||
struct termios restore_termios;
|
||||
char restore_termios_valid;
|
||||
|
||||
int waittime; // msec
|
||||
|
||||
char is_closed;
|
||||
|
||||
int nkeynames;
|
||||
const char **keynames;
|
||||
|
||||
struct termkey_driver driver;
|
||||
void *driver_info;
|
||||
};
|
||||
|
||||
void *termkeycsi_new_driver(termkey_t *t);
|
||||
|
||||
#endif
|
572
termkey.c
572
termkey.c
|
@ -1,49 +1,18 @@
|
|||
#include "termkey.h"
|
||||
#include "termkey-internal.h"
|
||||
|
||||
#include <errno.h>
|
||||
#include <poll.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <termios.h>
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
struct keyinfo {
|
||||
termkey_type type;
|
||||
termkey_keysym sym;
|
||||
int modifier_mask;
|
||||
int modifier_set;
|
||||
};
|
||||
|
||||
struct termkey {
|
||||
int fd;
|
||||
int flags;
|
||||
unsigned char *buffer;
|
||||
size_t buffstart; // First offset in buffer
|
||||
size_t buffcount; // NUMBER of entires valid in buffer
|
||||
size_t buffsize; // Total malloc'ed size
|
||||
|
||||
struct termios restore_termios;
|
||||
char restore_termios_valid;
|
||||
|
||||
int waittime; // msec
|
||||
|
||||
char is_closed;
|
||||
|
||||
int nkeynames;
|
||||
const char **keynames;
|
||||
|
||||
// There are 32 C0 codes
|
||||
struct keyinfo c0[32];
|
||||
|
||||
// There are 64 codes 0x40 - 0x7F
|
||||
struct keyinfo csi_ss3s[64];
|
||||
struct keyinfo ss3s[64];
|
||||
char ss3_kpalts[64];
|
||||
|
||||
int ncsifuncs;
|
||||
struct keyinfo *csifuncs;
|
||||
};
|
||||
// TODO: Move these into t->driver
|
||||
void *termkeycsi_new_driver(termkey_t *tk);
|
||||
void termkeycsi_free_driver(void *private);
|
||||
termkey_result termkeycsi_getkey(termkey_t *tk, termkey_key *key);
|
||||
// END TODO
|
||||
|
||||
termkey_t *termkey_new_full(int fd, int flags, size_t buffsize, int waittime)
|
||||
{
|
||||
|
@ -89,30 +58,14 @@ termkey_t *termkey_new_full(int fd, int flags, size_t buffsize, int waittime)
|
|||
|
||||
tk->is_closed = 0;
|
||||
|
||||
int i;
|
||||
|
||||
for(i = 0; i < 32; i++) {
|
||||
tk->c0[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
}
|
||||
|
||||
for(i = 0; i < 64; i++) {
|
||||
tk->csi_ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
tk->ss3s[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
tk->ss3_kpalts[i] = 0;
|
||||
}
|
||||
|
||||
// These numbers aren't too important; buffers will be grown if insufficient
|
||||
tk->nkeynames = 64;
|
||||
tk->ncsifuncs = 32;
|
||||
|
||||
tk->keynames = malloc(sizeof(tk->keynames[0]) * tk->nkeynames);
|
||||
tk->csifuncs = malloc(sizeof(tk->csifuncs[0]) * tk->ncsifuncs);
|
||||
|
||||
int i;
|
||||
for(i = 0; i < tk->nkeynames; i++)
|
||||
tk->keynames[i] = NULL;
|
||||
|
||||
for(i = 0; i < tk->ncsifuncs; i++)
|
||||
tk->csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
tk->driver_info = termkeycsi_new_driver(tk);
|
||||
|
||||
// Special built-in names
|
||||
termkey_register_keyname(tk, TERMKEY_SYM_NONE, "NONE");
|
||||
|
@ -214,7 +167,9 @@ void termkey_free(termkey_t *tk)
|
|||
{
|
||||
free(tk->buffer); tk->buffer = NULL;
|
||||
free(tk->keynames); tk->keynames = NULL;
|
||||
free(tk->csifuncs); tk->csifuncs = NULL;
|
||||
|
||||
termkeycsi_free_driver(tk->driver_info);
|
||||
tk->driver_info = NULL; /* Be nice to GC'ers, etc */
|
||||
|
||||
free(tk);
|
||||
}
|
||||
|
@ -237,414 +192,9 @@ int termkey_getwaittime(termkey_t *tk)
|
|||
return tk->waittime;
|
||||
}
|
||||
|
||||
static inline void eatbytes(termkey_t *tk, size_t count)
|
||||
{
|
||||
if(count >= tk->buffcount) {
|
||||
tk->buffstart = 0;
|
||||
tk->buffcount = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
tk->buffstart += count;
|
||||
tk->buffcount -= count;
|
||||
|
||||
size_t halfsize = tk->buffsize / 2;
|
||||
|
||||
if(tk->buffstart > halfsize) {
|
||||
memcpy(tk->buffer, tk->buffer + halfsize, halfsize);
|
||||
tk->buffstart -= halfsize;
|
||||
}
|
||||
}
|
||||
|
||||
#define UTF8_INVALID 0xFFFD
|
||||
|
||||
static int utf8_seqlen(int codepoint)
|
||||
{
|
||||
if(codepoint < 0x0000080) return 1;
|
||||
if(codepoint < 0x0000800) return 2;
|
||||
if(codepoint < 0x0010000) return 3;
|
||||
if(codepoint < 0x0200000) return 4;
|
||||
if(codepoint < 0x4000000) return 5;
|
||||
return 6;
|
||||
}
|
||||
|
||||
static void fill_utf8(termkey_key *key)
|
||||
{
|
||||
int codepoint = key->code.codepoint;
|
||||
int nbytes = utf8_seqlen(codepoint);
|
||||
|
||||
key->utf8[nbytes] = 0;
|
||||
|
||||
// This is easier done backwards
|
||||
int b = nbytes;
|
||||
while(b > 1) {
|
||||
b--;
|
||||
key->utf8[b] = 0x80 | (codepoint & 0x3f);
|
||||
codepoint >>= 6;
|
||||
}
|
||||
|
||||
switch(nbytes) {
|
||||
case 1: key->utf8[0] = (codepoint & 0x7f); break;
|
||||
case 2: key->utf8[0] = 0xc0 | (codepoint & 0x1f); break;
|
||||
case 3: key->utf8[0] = 0xe0 | (codepoint & 0x0f); break;
|
||||
case 4: key->utf8[0] = 0xf0 | (codepoint & 0x07); break;
|
||||
case 5: key->utf8[0] = 0xf8 | (codepoint & 0x03); break;
|
||||
case 6: key->utf8[0] = 0xfc | (codepoint & 0x01); break;
|
||||
}
|
||||
}
|
||||
|
||||
static inline void do_codepoint(termkey_t *tk, int codepoint, termkey_key *key)
|
||||
{
|
||||
if(codepoint < 0x20) {
|
||||
// C0 range
|
||||
key->code.codepoint = 0;
|
||||
key->modifiers = 0;
|
||||
|
||||
if(!(tk->flags & TERMKEY_FLAG_NOINTERPRET) && tk->c0[codepoint].sym != TERMKEY_SYM_UNKNOWN) {
|
||||
key->code.sym = tk->c0[codepoint].sym;
|
||||
key->modifiers |= tk->c0[codepoint].modifier_set;
|
||||
}
|
||||
|
||||
if(!key->code.sym) {
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = codepoint + 0x40;
|
||||
key->modifiers = TERMKEY_KEYMOD_CTRL;
|
||||
}
|
||||
else {
|
||||
key->type = TERMKEY_TYPE_KEYSYM;
|
||||
}
|
||||
}
|
||||
else if(codepoint == 0x20 && !(tk->flags & TERMKEY_FLAG_NOINTERPRET)) {
|
||||
// ASCII space
|
||||
key->type = TERMKEY_TYPE_KEYSYM;
|
||||
key->code.sym = TERMKEY_SYM_SPACE;
|
||||
key->modifiers = 0;
|
||||
}
|
||||
else if(codepoint == 0x7f && !(tk->flags & TERMKEY_FLAG_NOINTERPRET)) {
|
||||
// ASCII DEL
|
||||
key->type = TERMKEY_TYPE_KEYSYM;
|
||||
key->code.sym = TERMKEY_SYM_DEL;
|
||||
key->modifiers = 0;
|
||||
}
|
||||
else if(codepoint >= 0x20 && codepoint < 0x80) {
|
||||
// ASCII lowbyte range
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = codepoint;
|
||||
key->modifiers = 0;
|
||||
}
|
||||
else if(codepoint >= 0x80 && codepoint < 0xa0) {
|
||||
// UTF-8 never starts with a C1 byte. So we can be sure of these
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = codepoint - 0x40;
|
||||
key->modifiers = TERMKEY_KEYMOD_CTRL|TERMKEY_KEYMOD_ALT;
|
||||
}
|
||||
else {
|
||||
// UTF-8 codepoint
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = codepoint;
|
||||
key->modifiers = 0;
|
||||
}
|
||||
|
||||
if(key->type == TERMKEY_TYPE_UNICODE)
|
||||
fill_utf8(key);
|
||||
}
|
||||
|
||||
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
|
||||
|
||||
static termkey_result getkey_csi(termkey_t *tk, size_t introlen, termkey_key *key)
|
||||
{
|
||||
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) {
|
||||
if(tk->waittime)
|
||||
return TERMKEY_RES_AGAIN;
|
||||
|
||||
do_codepoint(tk, '[', key);
|
||||
key->modifiers |= TERMKEY_KEYMOD_ALT;
|
||||
eatbytes(tk, introlen);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
unsigned char cmd = CHARAT(csi_end);
|
||||
int arg[16];
|
||||
char present = 0;
|
||||
int args = 0;
|
||||
|
||||
size_t p = introlen;
|
||||
|
||||
// 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) {
|
||||
arg[args] = c - '0';
|
||||
present = 1;
|
||||
}
|
||||
else {
|
||||
arg[args] = (arg[args] * 10) + c - '0';
|
||||
}
|
||||
}
|
||||
else if(c == ';') {
|
||||
if(!present)
|
||||
arg[args] = -1;
|
||||
present = 0;
|
||||
args++;
|
||||
|
||||
if(args > 16)
|
||||
break;
|
||||
}
|
||||
|
||||
p++;
|
||||
}
|
||||
|
||||
if(!present)
|
||||
arg[args] = -1;
|
||||
|
||||
args++;
|
||||
|
||||
eatbytes(tk, csi_end + 1);
|
||||
|
||||
if(args > 1 && arg[1] != -1)
|
||||
key->modifiers = arg[1] - 1;
|
||||
else
|
||||
key->modifiers = 0;
|
||||
|
||||
if(cmd == '~') {
|
||||
key->type = TERMKEY_TYPE_KEYSYM;
|
||||
|
||||
if(arg[0] == 27) {
|
||||
int mod = key->modifiers;
|
||||
do_codepoint(tk, arg[2], key);
|
||||
key->modifiers |= mod;
|
||||
}
|
||||
else if(arg[0] >= 0 && arg[0] < tk->ncsifuncs) {
|
||||
key->type = tk->csifuncs[arg[0]].type;
|
||||
key->code.sym = tk->csifuncs[arg[0]].sym;
|
||||
key->modifiers &= ~(tk->csifuncs[arg[0]].modifier_mask);
|
||||
key->modifiers |= tk->csifuncs[arg[0]].modifier_set;
|
||||
}
|
||||
else
|
||||
key->code.sym = TERMKEY_SYM_UNKNOWN;
|
||||
|
||||
if(key->code.sym == TERMKEY_SYM_UNKNOWN)
|
||||
fprintf(stderr, "CSI function key %d\n", arg[0]);
|
||||
}
|
||||
else {
|
||||
// We know from the logic above that cmd must be >= 0x40 and < 0x80
|
||||
key->type = tk->csi_ss3s[cmd - 0x40].type;
|
||||
key->code.sym = tk->csi_ss3s[cmd - 0x40].sym;
|
||||
key->modifiers &= ~(tk->csi_ss3s[cmd - 0x40].modifier_mask);
|
||||
key->modifiers |= tk->csi_ss3s[cmd - 0x40].modifier_set;
|
||||
|
||||
if(key->code.sym == TERMKEY_SYM_UNKNOWN)
|
||||
fprintf(stderr, "CSI arg1=%d arg2=%d cmd=%c\n", arg[0], arg[1], cmd);
|
||||
}
|
||||
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
static termkey_result getkey_ss3(termkey_t *tk, size_t introlen, termkey_key *key)
|
||||
{
|
||||
if(tk->buffcount < introlen + 1) {
|
||||
if(tk->waittime)
|
||||
return TERMKEY_RES_AGAIN;
|
||||
|
||||
do_codepoint(tk, 'O', key);
|
||||
key->modifiers |= TERMKEY_KEYMOD_ALT;
|
||||
eatbytes(tk, tk->buffcount);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
unsigned char cmd = CHARAT(introlen);
|
||||
|
||||
eatbytes(tk, introlen + 1);
|
||||
|
||||
if(cmd < 0x40 || cmd >= 0x80)
|
||||
return TERMKEY_SYM_UNKNOWN;
|
||||
|
||||
key->type = tk->csi_ss3s[cmd - 0x40].type;
|
||||
key->code.sym = tk->csi_ss3s[cmd - 0x40].sym;
|
||||
key->modifiers = tk->csi_ss3s[cmd - 0x40].modifier_set;
|
||||
|
||||
if(key->code.sym == TERMKEY_SYM_UNKNOWN) {
|
||||
if(tk->flags & TERMKEY_FLAG_CONVERTKP && tk->ss3_kpalts[cmd - 0x40]) {
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = tk->ss3_kpalts[cmd - 0x40];
|
||||
key->modifiers = 0;
|
||||
|
||||
key->utf8[0] = key->code.codepoint;
|
||||
key->utf8[1] = 0;
|
||||
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
key->type = tk->ss3s[cmd - 0x40].type;
|
||||
key->code.sym = tk->ss3s[cmd - 0x40].sym;
|
||||
key->modifiers = tk->ss3s[cmd - 0x40].modifier_set;
|
||||
}
|
||||
|
||||
if(key->code.sym == TERMKEY_SYM_UNKNOWN)
|
||||
fprintf(stderr, "SS3 %c (0x%02x)\n", cmd, cmd);
|
||||
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
|
||||
{
|
||||
if(tk->buffcount == 0)
|
||||
return tk->is_closed ? TERMKEY_RES_EOF : TERMKEY_RES_NONE;
|
||||
|
||||
// Now we're sure at least 1 byte is valid
|
||||
unsigned char b0 = CHARAT(0);
|
||||
|
||||
if(b0 == 0x1b) {
|
||||
if(tk->buffcount == 1) {
|
||||
// This might be an <Esc> press, or it may want to be part of a longer
|
||||
// sequence
|
||||
if(tk->waittime)
|
||||
return TERMKEY_RES_AGAIN;
|
||||
|
||||
do_codepoint(tk, b0, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
unsigned char b1 = CHARAT(1);
|
||||
|
||||
if(b1 == '[')
|
||||
return getkey_csi(tk, 2, key);
|
||||
|
||||
if(b1 == 'O')
|
||||
return getkey_ss3(tk, 2, key);
|
||||
|
||||
if(b1 == 0x1b) {
|
||||
do_codepoint(tk, b0, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
tk->buffstart++;
|
||||
|
||||
termkey_result metakey_result = termkey_getkey(tk, key);
|
||||
|
||||
switch(metakey_result) {
|
||||
case TERMKEY_RES_KEY:
|
||||
key->modifiers |= TERMKEY_KEYMOD_ALT;
|
||||
tk->buffstart--;
|
||||
eatbytes(tk, 1);
|
||||
break;
|
||||
|
||||
case TERMKEY_RES_NONE:
|
||||
case TERMKEY_RES_EOF:
|
||||
case TERMKEY_RES_AGAIN:
|
||||
break;
|
||||
}
|
||||
|
||||
return metakey_result;
|
||||
}
|
||||
else if(b0 == 0x8f) {
|
||||
return getkey_ss3(tk, 1, key);
|
||||
}
|
||||
else if(b0 == 0x9b) {
|
||||
return getkey_csi(tk, 1, key);
|
||||
}
|
||||
else if(b0 < 0xa0) {
|
||||
// Single byte C0, G0 or C1 - C1 is never UTF-8 initial byte
|
||||
do_codepoint(tk, b0, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
else if(tk->flags & TERMKEY_FLAG_UTF8) {
|
||||
// Some UTF-8
|
||||
int nbytes;
|
||||
int codepoint;
|
||||
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->modifiers = 0;
|
||||
|
||||
if(b0 < 0xc0) {
|
||||
// Starts with a continuation byte - that's not right
|
||||
do_codepoint(tk, UTF8_INVALID, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
else if(b0 < 0xe0) {
|
||||
nbytes = 2;
|
||||
codepoint = b0 & 0x1f;
|
||||
}
|
||||
else if(b0 < 0xf0) {
|
||||
nbytes = 3;
|
||||
codepoint = b0 & 0x0f;
|
||||
}
|
||||
else if(b0 < 0xf8) {
|
||||
nbytes = 4;
|
||||
codepoint = b0 & 0x07;
|
||||
}
|
||||
else if(b0 < 0xfc) {
|
||||
nbytes = 5;
|
||||
codepoint = b0 & 0x03;
|
||||
}
|
||||
else if(b0 < 0xfe) {
|
||||
nbytes = 6;
|
||||
codepoint = b0 & 0x01;
|
||||
}
|
||||
else {
|
||||
do_codepoint(tk, UTF8_INVALID, key);
|
||||
eatbytes(tk, 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
if(tk->buffcount < nbytes)
|
||||
return tk->waittime ? TERMKEY_RES_AGAIN : TERMKEY_RES_NONE;
|
||||
|
||||
for(int b = 1; b < nbytes; b++) {
|
||||
unsigned char cb = CHARAT(b);
|
||||
if(cb < 0x80 || cb >= 0xc0) {
|
||||
do_codepoint(tk, UTF8_INVALID, key);
|
||||
eatbytes(tk, b - 1);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
codepoint <<= 6;
|
||||
codepoint |= cb & 0x3f;
|
||||
}
|
||||
|
||||
// Check for overlong sequences
|
||||
if(nbytes > utf8_seqlen(codepoint))
|
||||
codepoint = UTF8_INVALID;
|
||||
|
||||
// Check for UTF-16 surrogates or invalid codepoints
|
||||
if((codepoint >= 0xD800 && codepoint <= 0xDFFF) ||
|
||||
codepoint == 0xFFFE ||
|
||||
codepoint == 0xFFFF)
|
||||
codepoint = UTF8_INVALID;
|
||||
|
||||
do_codepoint(tk, codepoint, key);
|
||||
eatbytes(tk, nbytes);
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
else {
|
||||
// Non UTF-8 case - just report the raw byte
|
||||
key->type = TERMKEY_TYPE_UNICODE;
|
||||
key->code.codepoint = b0;
|
||||
key->modifiers = 0;
|
||||
|
||||
key->utf8[0] = key->code.codepoint;
|
||||
key->utf8[1] = 0;
|
||||
|
||||
eatbytes(tk, 1);
|
||||
|
||||
return TERMKEY_RES_KEY;
|
||||
}
|
||||
|
||||
return TERMKEY_SYM_NONE;
|
||||
return termkeycsi_getkey(tk, key);
|
||||
}
|
||||
|
||||
termkey_result termkey_getkey_force(termkey_t *tk, termkey_key *key)
|
||||
|
@ -758,104 +308,6 @@ const char *termkey_get_keyname(termkey_t *tk, termkey_keysym sym)
|
|||
return "UNKNOWN";
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_c0(termkey_t *tk, termkey_keysym sym, unsigned char ctrl, const char *name)
|
||||
{
|
||||
return termkey_register_c0_full(tk, sym, 0, 0, ctrl, name);
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_c0_full(termkey_t *tk, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char ctrl, const char *name)
|
||||
{
|
||||
if(ctrl >= 0x20) {
|
||||
fprintf(stderr, "Cannot register C0 key at ctrl 0x%02x - out of bounds\n", ctrl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(name)
|
||||
sym = termkey_register_keyname(tk, sym, name);
|
||||
|
||||
tk->c0[ctrl].sym = sym;
|
||||
tk->c0[ctrl].modifier_set = modifier_set;
|
||||
tk->c0[ctrl].modifier_mask = modifier_mask;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_csi_ss3(termkey_t *tk, termkey_type type, termkey_keysym sym, unsigned char cmd, const char *name)
|
||||
{
|
||||
return termkey_register_csi_ss3_full(tk, type, sym, 0, 0, cmd, name);
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_csi_ss3_full(termkey_t *tk, termkey_type type, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char cmd, const char *name)
|
||||
{
|
||||
if(cmd < 0x40 || cmd >= 0x80) {
|
||||
fprintf(stderr, "Cannot register CSI/SS3 key at cmd 0x%02x - out of bounds\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(name)
|
||||
sym = termkey_register_keyname(tk, sym, name);
|
||||
|
||||
tk->csi_ss3s[cmd - 0x40].type = type;
|
||||
tk->csi_ss3s[cmd - 0x40].sym = sym;
|
||||
tk->csi_ss3s[cmd - 0x40].modifier_set = modifier_set;
|
||||
tk->csi_ss3s[cmd - 0x40].modifier_mask = modifier_mask;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_ss3kpalt(termkey_t *tk, termkey_type type, termkey_keysym sym, unsigned char cmd, const char *name, char kpalt)
|
||||
{
|
||||
return termkey_register_ss3kpalt_full(tk, type, sym, 0, 0, cmd, name, kpalt);
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_ss3kpalt_full(termkey_t *tk, termkey_type type, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char cmd, const char *name, char kpalt)
|
||||
{
|
||||
if(cmd < 0x40 || cmd >= 0x80) {
|
||||
fprintf(stderr, "Cannot register SS3 key at cmd 0x%02x - out of bounds\n", cmd);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if(name)
|
||||
sym = termkey_register_keyname(tk, sym, name);
|
||||
|
||||
tk->ss3s[cmd - 0x40].type = type;
|
||||
tk->ss3s[cmd - 0x40].sym = sym;
|
||||
tk->ss3s[cmd - 0x40].modifier_set = modifier_set;
|
||||
tk->ss3s[cmd - 0x40].modifier_mask = modifier_mask;
|
||||
tk->ss3_kpalts[cmd - 0x40] = kpalt;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_csifunc(termkey_t *tk, termkey_type type, termkey_keysym sym, int number, const char *name)
|
||||
{
|
||||
return termkey_register_csifunc_full(tk, type, sym, 0, 0, number, name);
|
||||
}
|
||||
|
||||
termkey_keysym termkey_register_csifunc_full(termkey_t *tk, termkey_type type, termkey_keysym sym, int modifier_set, int modifier_mask, int number, const char *name)
|
||||
{
|
||||
if(name)
|
||||
sym = termkey_register_keyname(tk, sym, name);
|
||||
|
||||
if(number >= tk->ncsifuncs) {
|
||||
struct keyinfo *new_csifuncs = realloc(tk->csifuncs, sizeof(new_csifuncs[0]) * (number + 1));
|
||||
tk->csifuncs = new_csifuncs;
|
||||
|
||||
// Fill in the hole
|
||||
for(int i = tk->ncsifuncs; i < number; i++)
|
||||
tk->csifuncs[i].sym = TERMKEY_SYM_UNKNOWN;
|
||||
|
||||
tk->ncsifuncs = number + 1;
|
||||
}
|
||||
|
||||
tk->csifuncs[number].type = type;
|
||||
tk->csifuncs[number].sym = sym;
|
||||
tk->csifuncs[number].modifier_set = modifier_set;
|
||||
tk->csifuncs[number].modifier_mask = modifier_mask;
|
||||
|
||||
return sym;
|
||||
}
|
||||
|
||||
size_t termkey_snprint_key(termkey_t *tk, char *buffer, size_t len, termkey_key *key, termkey_format format)
|
||||
{
|
||||
size_t pos = 0;
|
||||
|
|
Loading…
Reference in New Issue