From 70a8c1e10c414629b25ade02474fbd4994de5c39 Mon Sep 17 00:00:00 2001 From: Martin Pulec Date: Tue, 26 Sep 2023 16:37:52 +0200 Subject: [PATCH] keycontrol: avoid mixing stdio and POSIX read API getchar() must not be used to read a character when there are more than one at once because otherwise won't next select() return and the key will remain in the stdio buffer. Fixed: `` (sleep 2; printf '\x18M'; sleep 50 ) | ./build/bin/uv -s testcard -r alsa --param disable-keyboard-control=no ``` when the 'M' key was not processed immediately but just at the end of the process. --- src/keyboard_control.cpp | 43 ++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 13 deletions(-) diff --git a/src/keyboard_control.cpp b/src/keyboard_control.cpp index 56d5149ed..9331c0d92 100644 --- a/src/keyboard_control.cpp +++ b/src/keyboard_control.cpp @@ -278,17 +278,33 @@ void keyboard_control::impl::stop() } #ifdef HAVE_TERMIOS_H -#define GETCH getchar +static int +GETCH() +{ + unsigned char ch = 0; + const ssize_t ret = read(0, &ch, sizeof ch); + return ret <= 0 ? (int) ret - 1 : ch; +} #else #define GETCH getch #endif -#define CHECK_EOF(x) do { if (x == EOF) { LOG(LOG_LEVEL_WARNING) << MOD_NAME "Unexpected EOF detected!\n"; return EOF; } } while(0) +#define CHECK_EOF(x) \ + do { \ + if ((x) < 0) { \ + LOG(LOG_LEVEL_WARNING) << MOD_NAME \ + "Unexpected " << ((x) == -1 ? "EOF" : "error") \ + << " detected!\n"; \ + return EOF; \ + } \ + } while (0) /** * Tries to parse at least some small subset of ANSI control sequences not to * be ArrowUp interpreted as '\033', '[' and 'A' individually. * + * @retval <0 on error + * * @todo * * improve coverage and/or find some suitable implemnation (ideally one file, * not ncurses) @@ -343,6 +359,7 @@ static int count_utf8_bytes(unsigned int i) { return count; } +/// @retval <0 on error static int64_t get_utf8_code(int c) { if (c < 0xc0) { LOG(LOG_LEVEL_WARNING) << MOD_NAME "Wrong UTF sequence!\n"; @@ -441,7 +458,9 @@ static string get_keycode_representation(int64_t ch) { /** * @returns next key either from keyboard or received via control socket. - * If m_should_exit is set, returns 0. + * @retval 0 if m_should_exit is set + * @retval -1 on EOF + * @retval -2 on error */ int64_t keyboard_control::impl::get_next_key() { @@ -516,16 +535,14 @@ void keyboard_control::impl::run() int64_t c; while ((c = get_next_key())) { - if (c == EOF) { - if (feof(stdin)) { - LOG(LOG_LEVEL_WARNING) << MOD_NAME "EOF detected! Exiting keyboard control.\n"; - break; - } - if (ferror(stdin)) { - LOG(LOG_LEVEL_WARNING) << MOD_NAME "Error detected!\n"; - clearerr(stdin); - continue; - } + if (c == -1) { + LOG(LOG_LEVEL_WARNING) << MOD_NAME + "EOF detected! Exiting keyboard control.\n"; + break; + } + if (c == -2) { + perror(MOD_NAME "Error detected"); + continue; } if (c == K_CTRL('X')) { m_locked_against_changes = !m_locked_against_changes; // ctrl-x pressed