diff --git a/driver-csi.c b/driver-csi.c index 1873e0d..7f6b008 100644 --- a/driver-csi.c +++ b/driver-csi.c @@ -708,7 +708,7 @@ free_driver (void *info) static termo_result_t peekkey_csi (termo_t *tk, termo_csi_t *csi, - size_t introlen, termo_key_t *key, int force, size_t *nbytep) + size_t introlen, termo_key_t *key, int flags, size_t *nbytep) { (void) csi; @@ -720,7 +720,7 @@ peekkey_csi (termo_t *tk, termo_csi_t *csi, termo_result_t ret = parse_csi (tk, introlen, &csi_len, arg, &args, &cmd); if (ret == TERMO_RES_AGAIN) { - if (!force) + if (!(flags & PEEKKEY_FORCE)) return TERMO_RES_AGAIN; (*tk->method.emit_codepoint) (tk, '[', key); @@ -789,13 +789,13 @@ peekkey_csi (termo_t *tk, termo_csi_t *csi, static termo_result_t peekkey_ss3 (termo_t *tk, termo_csi_t *csi, size_t introlen, - termo_key_t *key, int force, size_t *nbytep) + termo_key_t *key, int flags, size_t *nbytep) { (void) csi; if (tk->buffcount < introlen + 1) { - if (!force) + if (!(flags & PEEKKEY_FORCE)) return TERMO_RES_AGAIN; (*tk->method.emit_codepoint) (tk, 'O', key); @@ -847,7 +847,7 @@ peekkey_ss3 (termo_t *tk, termo_csi_t *csi, size_t introlen, static termo_result_t peekkey (termo_t *tk, void *info, - termo_key_t *key, int force, size_t *nbytep) + termo_key_t *key, int flags, size_t *nbytep) { if (tk->buffcount == 0) return tk->is_closed ? TERMO_RES_EOF : TERMO_RES_NONE; @@ -857,14 +857,16 @@ peekkey (termo_t *tk, void *info, // Now we're sure at least 1 byte is valid unsigned char b0 = CHARAT (0); + if (b0 == 0x1b && tk->buffcount == 1) + return TERMO_RES_AGAIN; if (b0 == 0x1b && tk->buffcount > 1 && CHARAT (1) == '[') - return peekkey_csi (tk, csi, 2, key, force, nbytep); + return peekkey_csi (tk, csi, 2, key, flags, nbytep); if (b0 == 0x1b && tk->buffcount > 1 && CHARAT (1) == 'O') - return peekkey_ss3 (tk, csi, 2, key, force, nbytep); + return peekkey_ss3 (tk, csi, 2, key, flags, nbytep); if (b0 == 0x8f) - return peekkey_ss3 (tk, csi, 1, key, force, nbytep); + return peekkey_ss3 (tk, csi, 1, key, flags, nbytep); if (b0 == 0x9b) - return peekkey_csi (tk, csi, 1, key, force, nbytep); + return peekkey_csi (tk, csi, 1, key, flags, nbytep); return TERMO_RES_NONE; } diff --git a/driver-ti.c b/driver-ti.c index 6ac213f..c94079f 100644 --- a/driver-ti.c +++ b/driver-ti.c @@ -466,7 +466,7 @@ free_driver (void *info) static termo_result_t peekkey (termo_t *tk, void *info, - termo_key_t *key, int force, size_t *nbytep) + termo_key_t *key, int flags, size_t *nbytep) { termo_ti_t *ti = info; @@ -512,7 +512,7 @@ peekkey (termo_t *tk, void *info, // If p is not NULL then we hadn't walked off the end yet, so we have a // partial match - if (p && !force) + if (p && !(flags & PEEKKEY_FORCE)) return TERMO_RES_AGAIN; return TERMO_RES_NONE; diff --git a/termo-internal.h b/termo-internal.h index adf3e8f..54948b0 100644 --- a/termo-internal.h +++ b/termo-internal.h @@ -37,6 +37,12 @@ struct termo_driver_node termo_driver_node_t *next; }; +enum peekey_flags +{ + PEEKKEY_FORCE = 1 << 0, + PEEKKEY_ALT_PREFIXED = 1 << 1 +}; + struct termo { int fd; @@ -75,7 +81,7 @@ struct termo void (*emit_codepoint) (termo_t *tk, uint32_t codepoint, termo_key_t *key); termo_result_t (*peekkey_simple) (termo_t *tk, - termo_key_t *key, int force, size_t *nbytes); + termo_key_t *key, int flags, size_t *nbytes); termo_result_t (*peekkey_mouse) (termo_t *tk, termo_key_t *key, size_t *nbytes); } diff --git a/termo.c b/termo.c index 130ff40..704116b 100644 --- a/termo.c +++ b/termo.c @@ -37,7 +37,7 @@ static termo_driver_t *drivers[] = // Forwards for the "protected" methods static void emit_codepoint (termo_t *tk, uint32_t codepoint, termo_key_t *key); static termo_result_t peekkey_simple (termo_t *tk, - termo_key_t *key, int force, size_t *nbytes); + termo_key_t *key, int flags, size_t *nbytes); static termo_result_t peekkey_mouse (termo_t *tk, termo_key_t *key, size_t *nbytes); @@ -860,7 +860,7 @@ termo_canonicalise (termo_t *tk, termo_key_t *key) } static termo_result_t -peekkey (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) +peekkey (termo_t *tk, termo_key_t *key, int flags, size_t *nbytep) { int again = 0; @@ -887,7 +887,7 @@ peekkey (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) termo_driver_node_t *p; for (p = tk->drivers; p; p = p->next) { - ret = (p->driver->peekkey) (tk, p->info, key, force, nbytep); + ret = (p->driver->peekkey) (tk, p->info, key, flags, nbytep); #ifdef DEBUG fprintf (stderr, "Driver %s yields %s\n", @@ -916,7 +916,7 @@ peekkey (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) return ret; case TERMO_RES_AGAIN: - if (!force) + if (!(flags & PEEKKEY_FORCE)) again = 1; case TERMO_RES_NONE: break; @@ -926,7 +926,7 @@ peekkey (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) if (again) return TERMO_RES_AGAIN; - ret = peekkey_simple (tk, key, force, nbytep); + ret = peekkey_simple (tk, key, flags, nbytep); #ifdef DEBUG fprintf (stderr, "getkey_simple(force=%d) yields %s\n", @@ -942,7 +942,7 @@ peekkey (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) } static termo_result_t -peekkey_simple (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) +peekkey_simple (termo_t *tk, termo_key_t *key, int flags, size_t *nbytep) { if (tk->buffcount == 0) return tk->is_closed ? TERMO_RES_EOF : TERMO_RES_NONE; @@ -950,12 +950,22 @@ peekkey_simple (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) unsigned char b0 = CHARAT (0); if (b0 == 0x1b) { + if (flags & PEEKKEY_ALT_PREFIXED) + { + // We got back here recursively, which means that no driver has + // returned TERMO_RES_AGAIN -> just return the Escape. Otherwise + // we would interpret an indefinite number of s as Alt+Esc. + (*tk->method.emit_codepoint) (tk, b0, key); + *nbytep = 1; + return TERMO_RES_KEY; + } + // Escape-prefixed value? Might therefore be Alt+key if (tk->buffcount == 1) { // This might be an press, or it may want to be part // of a longer sequence - if (!force) + if (!(flags & PEEKKEY_FORCE)) return TERMO_RES_AGAIN; (*tk->method.emit_codepoint) (tk, b0, key); @@ -968,7 +978,8 @@ peekkey_simple (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) tk->buffcount--; // Run the full driver - termo_result_t metakey_result = peekkey (tk, key, force, nbytep); + termo_result_t metakey_result = + peekkey (tk, key, flags | PEEKKEY_ALT_PREFIXED, nbytep); tk->buffstart--; tk->buffcount++; @@ -998,7 +1009,7 @@ peekkey_simple (termo_t *tk, termo_key_t *key, int force, size_t *nbytep) termo_result_t res = parse_multibyte (tk, tk->buffer + tk->buffstart, tk->buffcount, &codepoint, nbytep); - if (res == TERMO_RES_AGAIN && force) + if (res == TERMO_RES_AGAIN && (flags & PEEKKEY_FORCE)) { // There weren't enough bytes for a complete character but // caller demands an answer. About the best thing we can do here @@ -1158,7 +1169,7 @@ termo_getkey (termo_t *tk, termo_key_t *key) if (ret == TERMO_RES_AGAIN) // Call peekkey() again in force mode to obtain whatever it can - (void) peekkey (tk, key, 1, &nbytes); + (void) peekkey (tk, key, PEEKKEY_FORCE, &nbytes); // Don't eat it yet though return ret; @@ -1168,7 +1179,7 @@ termo_result_t termo_getkey_force (termo_t *tk, termo_key_t *key) { size_t nbytes = 0; - termo_result_t ret = peekkey (tk, key, 1, &nbytes); + termo_result_t ret = peekkey (tk, key, PEEKKEY_FORCE, &nbytes); if (ret == TERMO_RES_KEY) eat_bytes (tk, nbytes); diff --git a/tests/02getkey.c b/tests/02getkey.c index 94f71c7..b36eb9e 100644 --- a/tests/02getkey.c +++ b/tests/02getkey.c @@ -7,7 +7,7 @@ main (int argc, char *argv[]) termo_t *tk; termo_key_t key; - plan_tests (31); + plan_tests (38); tk = termo_new_abstract ("vt100", NULL, 0); @@ -86,6 +86,27 @@ main (int argc, char *argv[]) is_int (key.modifiers, TERMO_KEYMOD_CTRL, "key.modifiers after Ctrl-Escape"); + // Escape key in various amounts + + termo_push_bytes (tk, "\x1b\x1b", 2); + is_int (termo_getkey (tk, &key), TERMO_RES_AGAIN, + "two Escapes don't yield anything"); + is_int (termo_get_buffer_remaining (tk), 254, + "buffer free 254 after two Escapes"); + + termo_push_bytes (tk, "\x1b", 1); + is_int (termo_getkey (tk, &key), TERMO_RES_KEY, + "three Escapes yield Alt-Escape"); + is_int (termo_get_buffer_remaining (tk), 255, + "buffer free 255 after three Escapes"); + + is_int (key.type, TERMO_TYPE_KEYSYM, + "key.type after three Escapes"); + is_int (key.code.sym, TERMO_SYM_ESCAPE, + "key.code.sym after three Escapes"); + is_int (key.modifiers, TERMO_KEYMOD_ALT, + "key.modifiers after three Escapes"); + termo_destroy (tk); return exit_status ();