=== modified file 'driver-csi.c' --- driver-csi.c 2008-10-07 23:36:27 +0000 +++ driver-csi.c 2008-10-07 23:12:41 +0000 @@ -120,6 +120,8 @@ free(csi); } +#define UTF8_INVALID 0xFFFD + #define CHARAT(i) (tk->buffer[tk->buffstart + (i)]) static termkey_result getkey_csi(termkey_t *tk, size_t introlen, termkey_key *key) @@ -330,8 +332,96 @@ else if(b0 == 0x9b) { return getkey_csi(tk, 1, key); } - else - return (*tk->method.getkey_simple)(tk, key); + else 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; + } + + 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) === modified file 'termkey-internal.h' --- termkey-internal.h 2008-10-07 23:36:27 +0000 +++ termkey-internal.h 2008-10-07 23:12:41 +0000 @@ -49,10 +49,20 @@ struct { void (*eat_bytes)(termkey_t *tk, size_t count); void (*emit_codepoint)(termkey_t *tk, int codepoint, termkey_key *key); - termkey_result (*getkey_simple)(termkey_t *tk, termkey_key *key); } method; }; 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 === modified file 'termkey.c' --- termkey.c 2008-10-07 23:36:27 +0000 +++ termkey.c 2008-10-07 23:12:41 +0000 @@ -16,7 +16,6 @@ // Forwards for the "protected" methods static void eat_bytes(termkey_t *tk, size_t count); 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_full(termkey_t *tk, termkey_keysym sym, int modifier_set, int modifier_mask, unsigned char ctrl, const char *name); @@ -75,9 +74,8 @@ for(i = 0; i < 32; i++) tk->c0[i].sym = TERMKEY_SYM_NONE; - tk->method.eat_bytes = &eat_bytes; + tk->method.eat_bytes = &eat_bytes; 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_TAB, 0x09, "Tab"); @@ -172,16 +170,6 @@ } } -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) { int codepoint = key->code.codepoint; @@ -263,104 +251,6 @@ 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) { return (*tk->driver.getkey)(tk, key);