From c2a7e41fae342531dbd0b8ba74136ad90b060817 Mon Sep 17 00:00:00 2001 From: Linus Torvalds Date: Sat, 7 Jun 2008 11:48:44 -0700 Subject: [PATCH] Turn ESC+'[' into a CSI character This avoids the annoying behavior where we're on the command line, waiting for an ESC, and any control character sequence ends up finishing the command line and eating the first ESC. Signed-off-by: Linus Torvalds --- input.c | 3 ++ posix.c | 89 +++++++++++++++++++++++++++++++++++---------------------- 2 files changed, 58 insertions(+), 34 deletions(-) diff --git a/input.c b/input.c index dfac2a5..2df7155 100644 --- a/input.c +++ b/input.c @@ -338,11 +338,14 @@ int getcmd(void) #if VT220 proc_metac: #endif + if (c == 128+27) /* CSI */ + goto handle_CSI; /* process META prefix */ if (c == (CONTROL | '[')) { c = get1key(); #if VT220 if (c == '[' || c == 'O') { /* CSI P.K. */ +handle_CSI: c = get1key(); if (c >= 'A' && c <= 'D') return (SPEC | c | cmask); diff --git a/posix.c b/posix.c index c07e0ee..92db090 100644 --- a/posix.c +++ b/posix.c @@ -168,26 +168,56 @@ void ttflush(void) */ int ttgetc(void) { - static unsigned char pending; + static unsigned char buffer[32]; + static int pending; unsigned char c, second; - int n; + int count; - if (pending) { - c = pending; - pending = 0; - return c; + count = pending; + if (!count) { + count = read(0, buffer, sizeof(buffer)); + if (count <= 0) + return 0; + pending = count; } - n = read(0, &c, 1); - if (n != 1) - return 0; + c = buffer[0]; + if (c >= 32 && c < 128) + goto done; + + /* Special character - try to fill buffer */ + if (count == 1) { + int n; + ntermios.c_cc[VMIN] = 0; + ntermios.c_cc[VTIME] = 1; /* A .1 second lag */ + tcsetattr(0, TCSANOW, &ntermios); + + n = read(0, buffer + count, sizeof(buffer) - count); + + /* Undo timeout */ + ntermios.c_cc[VMIN] = 1; + ntermios.c_cc[VTIME] = 0; + tcsetattr(0, TCSANOW, &ntermios); + + if (n <= 0) + goto done; + pending += n; + } + second = buffer[1]; + + /* Turn ESC+'[' into CSI */ + if (c == 27 && second == '[') { + pending -= 2; + memmove(buffer, buffer+2, pending); + return 128+27; + } if (!utf8_mode()) - return c; + goto done; /* Normal 7-bit? */ if (!(c & 0x80)) - return c; + goto done; /* * Unexpected UTF-8 continuation character? Maybe @@ -195,7 +225,7 @@ int ttgetc(void) * character.. Regardless, just pass it on. */ if (!(c & 0x40)) - return c; + goto done; /* * Multi-byte sequences.. Right now we only @@ -204,33 +234,24 @@ int ttgetc(void) * anything else.. */ if (c & 0x3c) - return c; + goto done; + + if ((second & 0xc0) != 0x80) + goto done; /* - * Two-byte sequence representing 0x80-0xff.. We want - * to do this read with a timeout. + * Ok, it's a two-byte UTF-8 character that can be represented + * as a single-byte Latin1 character! */ - ntermios.c_cc[VMIN] = 1; - ntermios.c_cc[VTIME] = 10; /* 1 second */ - tcsetattr(0, TCSANOW, &ntermios); - - n = read(0, &second, 1); - - /* Undo timeout */ - ntermios.c_cc[VTIME] = 0; - tcsetattr(0, TCSANOW, &ntermios); - - if (n != 1) - return c; - - if ((second & 0xc0) != 0x80) { - pending = second; - return c; - } - c = (c << 6) | (second & 0x3f); + pending -= 2; + memmove(buffer, buffer+2, pending); - /* Ok, real UTF-8 character */ + return c; + +done: + pending--; + memmove(buffer, buffer+1, pending); return c; }