From efb309d4cdb2f4c3926b0550d9dc1661c1e4a091 Mon Sep 17 00:00:00 2001 From: Rob Landley Date: Thu, 7 Jan 2016 14:34:47 -0600 Subject: Make scan_key() specify timeout in miliseconds, split out terminal_probesize(), add function key definitions and shift/ctrl/alt cursor keys. --- lib/interestingtimes.c | 56 +++++++++++++++++++++++++-------------------- lib/lib.h | 5 ++-- toys/example/test_scankey.c | 19 ++++++++++++--- toys/other/hexedit.c | 2 +- 4 files changed, 51 insertions(+), 31 deletions(-) diff --git a/lib/interestingtimes.c b/lib/interestingtimes.c index 612d9d6e..70fd4f9b 100644 --- a/lib/interestingtimes.c +++ b/lib/interestingtimes.c @@ -46,31 +46,28 @@ int terminal_size(unsigned *xx, unsigned *yy) return x || y; } -// Wrapper that parses results from ANSI probe. If block|2 query size and -// send ANSI probe if we can't. (Probe queries xterm size through -// serial connection, when local TTY doesn't know and only remote end knows.) -// Otherwise acts like scan_key() -int scan_key_getsize(char *scratch, int block, unsigned *xx, unsigned *yy) +// Query terminal size, sending ANSI probe if necesary. (Probe queries xterm +// size through serial connection, when local TTY doesn't know but remote does.) +// Returns 0 if ANSI probe sent, 1 if size determined from tty or environment + +int terminal_probesize(unsigned *xx, unsigned *yy) { - int key; + if (terminal_size(xx, yy) && (!xx || *xx) && (!yy || *yy)) return 1; - if (block&2) { - struct pollfd pfd; + // Send probe: bookmark cursor position, jump to bottom right, + // query position, return cursor to bookmarked position. + xprintf("\e[s\e[999C\e[999B\e[6n\e[u"); - if (terminal_size(xx, yy)) { - if (!(block&1)) return -2; - } else { - // Send probe: bookmark cursor position, jump to bottom right, - // query position, return cursor to bookmarked position. - xprintf("\e[s\e[999C\e[999B\e[6n\e[u"); + return 0; +} - // Wait up to a quarter second for a result - memset(&pfd, 0, sizeof(struct pollfd)); - pfd.events = POLLIN; - xpoll(&pfd, 0, 250); - } - } - while (512&(key = scan_key(scratch, block&1))) { +// Wrapper that parses results from ANSI probe to update screensize. +// Otherwise acts like scan_key() +int scan_key_getsize(char *scratch, int miliwait, unsigned *xx, unsigned *yy) +{ + int key; + + while (512&(key = scan_key(scratch, miliwait))) { if (key<0) break; if (xx) *xx = (key>>10)&1023; if (yy) *yy = (key>>20)&1023; @@ -120,20 +117,27 @@ struct scan_key_list { {"UP", "\033[A"}, {"DOWN", "\033[B"}, {"RIGHT", "\033[C"}, {"LEFT", "\033[D"}, {"PGUP", "\033[5~"}, {"PGDN", "\033[6~"}, {"HOME", "\033OH"}, {"END", "\033OF"}, {"INSERT", "\033[2~"}, + + {"F1", "\033OP"}, {"F2", "\033OQ"}, {"F3", "\033OR"}, {"F4", "\033OS"}, + {"F5", "\033[15~"}, {"F6", "\033[17~"}, {"F7", "\033[18~"}, + {"F8", "\033[19~"}, {"F9", "\033[20~"}, + {"SUP", "\033[1;2A"}, {"AUP", "\033[1;3A"}, {"CUP", "\033[1;5A"}, {"SDOWN", "\033[1;2B"}, {"ADOWN", "\033[1;3B"}, {"CDOWN", "\033[1;5B"}, {"SRIGHT", "\033[1;2C"}, {"ARIGHT", "\033[1;3C"}, {"CRIGHT", "\033[1;5C"}, - {"SLEFT", "\033[1;2D"}, {"ALEFT", "\033[1;3D"}, {"CLEFT", "\033[1;5D"} + {"SLEFT", "\033[1;2D"}, {"ALEFT", "\033[1;3D"}, {"CLEFT", "\033[1;5D"}, + {"SF1", "\033O1;2P"}, {"AF1", "\033O1;3P"}, {"CF1", "\033[1;5P"} ); // Scan stdin for a keypress, parsing known escape sequences +// Blocks for miliwait miliseconds, none 0, forever if -1 // Returns: 0-255=literal, -1=EOF, -2=NONE, 256-...=index into scan_key_list // >512 is x<<9+y<<21 // scratch space is necessary because last char of !seq could start new seq // Zero out first byte of scratch before first call to scan_key // block=0 allows fetching multiple characters before updating display -int scan_key(char *scratch, int block) +int scan_key(char *scratch, int miliwait) { struct pollfd pfd; int maybe, i, j; @@ -151,7 +155,8 @@ int scan_key(char *scratch, int block) // Check for return from terminal size probe memset(pos, 0, 6*sizeof(int)); - sscanf(scratch+1, "\033%n[%n%3u%n,%n%3u%nR%n", pos, pos+1, &y, + scratch[(1+*scratch)&15] = 0; + sscanf(scratch+1, "\033%n[%n%3u%n;%n%3u%nR%n", pos, pos+1, &y, pos+2, pos+3, &x, pos+4, pos+5); if (pos[5]) { // Recognized X/Y position, consume and return @@ -180,7 +185,8 @@ int scan_key(char *scratch, int block) // Need more data to decide // 30 miliseconds is about the gap between characters at 300 baud - if (maybe || !block) if (!xpoll(&pfd, 1, 30*maybe)) break; + if (maybe || miliwait != -1) + if (!xpoll(&pfd, 1, maybe ? 30 : miliwait)) break; // Read 1 byte so we don't overshoot sequence match. (We can deviate // and fail to match, but match consumes entire buffer.) diff --git a/lib/lib.h b/lib/lib.h index d56cdbe3..ade7c59b 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -221,9 +221,10 @@ int draw_rstr(char *start, int width, int (*escout)(FILE *out, wchar_t wc)); // interestingtimes.c int xgettty(void); int terminal_size(unsigned *xx, unsigned *yy); -int scan_key_getsize(char *scratch, int block, unsigned *xx, unsigned *yy); +int terminal_probesize(unsigned *xx, unsigned *yy); +int scan_key_getsize(char *scratch, int miliwait, unsigned *xx, unsigned *yy); int set_terminal(int fd, int raw, struct termios *old); -int scan_key(char *scratch, int block); +int scan_key(char *scratch, int miliwait); void tty_esc(char *s); void tty_jump(int x, int y); void tty_reset(void); diff --git a/toys/example/test_scankey.c b/toys/example/test_scankey.c index 65c07204..57177416 100644 --- a/toys/example/test_scankey.c +++ b/toys/example/test_scankey.c @@ -1,6 +1,8 @@ /* test_scankey.c - collate incoming ansi escape sequences. * * Copyright 2015 Rob Landley + * + * TODO sigwinch USE_TEST_SCANKEY(NEWTOY(test_scankey, 0, 0)) @@ -37,10 +39,21 @@ void test_scankey_main(void) tty_jump(x, y); xputc(c); t[1&++tick] = time(0); - key = scan_key_getsize(scratch, !!t[0]+2*(t[0] != t[1]), &width, &height); + if (t[0] != t[1]) terminal_probesize(&width, &height); + // Don't block first time through, to force header print + key = scan_key_getsize(scratch, -1*!!t[0], &width, &height); tty_jump(0, 0); - printf("ESC to exit: key=%d x=%d y=%d width=%d height=%d ", - key, x, y, width, height); + printf("ESC to exit: "); + // Print unknown escape sequence + if (*scratch) { + printf("key=[ESC"); + // Fetch rest of sequence after deviation, time gap determines end + while (0<(key = scan_key_getsize(scratch, 0, &width, &height))) + printf("%c", key); + printf("] "); + } else printf("key=%d ", key); + printf("x=%d y=%d width=%d height=%d\033[K", x, y, width, height); + fflush(0); if (key == -2) continue; if (key <= ' ') break; diff --git a/toys/other/hexedit.c b/toys/other/hexedit.c index c45ef1ca..3c362dbd 100644 --- a/toys/other/hexedit.c +++ b/toys/other/hexedit.c @@ -176,7 +176,7 @@ void hexedit_main(void) xflush(); // Wait for next key - key = scan_key(keybuf, 1); + key = scan_key(keybuf, -1); // Exit for q, ctrl-c, ctrl-d, escape, or EOF if (key==-1 || key==3 || key==4 || key==27 || key=='q') break; highlight(x, y, 2); -- cgit v1.2.3