Moved single byte and UTF-8 sequence recombiner out of driver-csi.c back into termkey.c
This commit is contained in:
parent
d46f72fc1a
commit
ac6cae29bb
94
driver-csi.c
94
driver-csi.c
|
@ -120,8 +120,6 @@ static void free_driver(void *private)
|
||||||
free(csi);
|
free(csi);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define UTF8_INVALID 0xFFFD
|
|
||||||
|
|
||||||
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
|
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
|
||||||
|
|
||||||
static termkey_result getkey_csi(termkey_t *tk, size_t introlen, termkey_key *key)
|
static termkey_result getkey_csi(termkey_t *tk, size_t introlen, termkey_key *key)
|
||||||
|
@ -332,96 +330,8 @@ static termkey_result getkey(termkey_t *tk, termkey_key *key)
|
||||||
else if(b0 == 0x9b) {
|
else if(b0 == 0x9b) {
|
||||||
return getkey_csi(tk, 1, key);
|
return getkey_csi(tk, 1, key);
|
||||||
}
|
}
|
||||||
else if(b0 < 0xa0) {
|
else
|
||||||
// Single byte C0, G0 or C1 - C1 is never UTF-8 initial byte
|
return (*tk->method.getkey_simple)(tk, key);
|
||||||
(*tk->method.emit_codepoint)(tk, b0, key);
|
|
||||||
(*tk->method.eat_bytes)(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
|
|
||||||
(*tk->method.emit_codepoint)(tk, UTF8_INVALID, key);
|
|
||||||
(*tk->method.eat_bytes)(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 {
|
|
||||||
(*tk->method.emit_codepoint)(tk, UTF8_INVALID, key);
|
|
||||||
(*tk->method.eat_bytes)(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) {
|
|
||||||
(*tk->method.emit_codepoint)(tk, UTF8_INVALID, key);
|
|
||||||
(*tk->method.eat_bytes)(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;
|
|
||||||
|
|
||||||
(*tk->method.emit_codepoint)(tk, codepoint, key);
|
|
||||||
(*tk->method.eat_bytes)(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;
|
|
||||||
|
|
||||||
(*tk->method.eat_bytes)(tk, 1);
|
|
||||||
|
|
||||||
return TERMKEY_RES_KEY;
|
|
||||||
}
|
|
||||||
|
|
||||||
return TERMKEY_SYM_NONE;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static termkey_keysym register_csi_ss3(termkey_csi *csi, termkey_type type, termkey_keysym sym, unsigned char cmd, const char *name)
|
static termkey_keysym register_csi_ss3(termkey_csi *csi, termkey_type type, termkey_keysym sym, unsigned char cmd, const char *name)
|
||||||
|
|
|
@ -49,20 +49,10 @@ struct termkey {
|
||||||
struct {
|
struct {
|
||||||
void (*eat_bytes)(termkey_t *tk, size_t count);
|
void (*eat_bytes)(termkey_t *tk, size_t count);
|
||||||
void (*emit_codepoint)(termkey_t *tk, int codepoint, termkey_key *key);
|
void (*emit_codepoint)(termkey_t *tk, int codepoint, termkey_key *key);
|
||||||
|
termkey_result (*getkey_simple)(termkey_t *tk, termkey_key *key);
|
||||||
} method;
|
} method;
|
||||||
};
|
};
|
||||||
|
|
||||||
extern struct termkey_driver termkey_driver_csi;
|
extern struct termkey_driver termkey_driver_csi;
|
||||||
|
|
||||||
// Keep this here for now since it's tiny
|
|
||||||
static inline 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
110
termkey.c
110
termkey.c
|
@ -16,6 +16,7 @@ static struct termkey_driver *drivers[] = {
|
||||||
// Forwards for the "protected" methods
|
// Forwards for the "protected" methods
|
||||||
static void eat_bytes(termkey_t *tk, size_t count);
|
static void eat_bytes(termkey_t *tk, size_t count);
|
||||||
static void emit_codepoint(termkey_t *tk, int codepoint, termkey_key *key);
|
static void emit_codepoint(termkey_t *tk, int codepoint, termkey_key *key);
|
||||||
|
static termkey_result getkey_simple(termkey_t *tk, termkey_key *key);
|
||||||
|
|
||||||
static termkey_keysym register_c0(termkey_t *tk, termkey_keysym sym, unsigned char ctrl, const char *name);
|
static termkey_keysym register_c0(termkey_t *tk, termkey_keysym sym, unsigned char ctrl, const char *name);
|
||||||
static termkey_keysym register_c0_full(termkey_t *tk, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char ctrl, const char *name);
|
static termkey_keysym register_c0_full(termkey_t *tk, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char ctrl, const char *name);
|
||||||
|
@ -76,6 +77,7 @@ termkey_t *termkey_new_full(int fd, int flags, size_t buffsize, int waittime)
|
||||||
|
|
||||||
tk->method.eat_bytes = &eat_bytes;
|
tk->method.eat_bytes = &eat_bytes;
|
||||||
tk->method.emit_codepoint = &emit_codepoint;
|
tk->method.emit_codepoint = &emit_codepoint;
|
||||||
|
tk->method.getkey_simple = &getkey_simple;
|
||||||
|
|
||||||
register_c0(tk, TERMKEY_SYM_BACKSPACE, 0x08, "Backspace");
|
register_c0(tk, TERMKEY_SYM_BACKSPACE, 0x08, "Backspace");
|
||||||
register_c0(tk, TERMKEY_SYM_TAB, 0x09, "Tab");
|
register_c0(tk, TERMKEY_SYM_TAB, 0x09, "Tab");
|
||||||
|
@ -170,6 +172,16 @@ static void eat_bytes(termkey_t *tk, size_t count)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static inline 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)
|
static void fill_utf8(termkey_key *key)
|
||||||
{
|
{
|
||||||
int codepoint = key->code.codepoint;
|
int codepoint = key->code.codepoint;
|
||||||
|
@ -251,6 +263,104 @@ static void emit_codepoint(termkey_t *tk, int codepoint, termkey_key *key)
|
||||||
fill_utf8(key);
|
fill_utf8(key);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#define UTF8_INVALID 0xFFFD
|
||||||
|
|
||||||
|
#define CHARAT(i) (tk->buffer[tk->buffstart + (i)])
|
||||||
|
|
||||||
|
static termkey_result getkey_simple(termkey_t *tk, termkey_key *key)
|
||||||
|
{
|
||||||
|
unsigned char b0 = CHARAT(0);
|
||||||
|
|
||||||
|
if(b0 < 0xa0) {
|
||||||
|
// Single byte C0, G0 or C1 - C1 is never UTF-8 initial byte
|
||||||
|
(*tk->method.emit_codepoint)(tk, b0, key);
|
||||||
|
(*tk->method.eat_bytes)(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
|
||||||
|
(*tk->method.emit_codepoint)(tk, UTF8_INVALID, key);
|
||||||
|
(*tk->method.eat_bytes)(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 {
|
||||||
|
(*tk->method.emit_codepoint)(tk, UTF8_INVALID, key);
|
||||||
|
(*tk->method.eat_bytes)(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) {
|
||||||
|
(*tk->method.emit_codepoint)(tk, UTF8_INVALID, key);
|
||||||
|
(*tk->method.eat_bytes)(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;
|
||||||
|
|
||||||
|
(*tk->method.emit_codepoint)(tk, codepoint, key);
|
||||||
|
(*tk->method.eat_bytes)(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;
|
||||||
|
|
||||||
|
(*tk->method.eat_bytes)(tk, 1);
|
||||||
|
|
||||||
|
return TERMKEY_RES_KEY;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
|
termkey_result termkey_getkey(termkey_t *tk, termkey_key *key)
|
||||||
{
|
{
|
||||||
return (*tk->driver.getkey)(tk, key);
|
return (*tk->driver.getkey)(tk, key);
|
||||||
|
|
Loading…
Reference in New Issue