From 64df78228794a27612dbb848ade690804b41db3c Mon Sep 17 00:00:00 2001 From: Hanicef <gustaf@hanicef.me> Date: Sun, 19 May 2024 12:20:03 +0200 Subject: [PATCH] Refactor TTY input handling --- src/dedicated/i_system.c | 76 +++++++++++++--------------------------- src/sdl/i_system.c | 76 +++++++++++++--------------------------- 2 files changed, 50 insertions(+), 102 deletions(-) diff --git a/src/dedicated/i_system.c b/src/dedicated/i_system.c index 858dfaf202..29a3e9511d 100644 --- a/src/dedicated/i_system.c +++ b/src/dedicated/i_system.c @@ -705,10 +705,9 @@ typedef struct static feild_t tty_con; -// when printing general stuff to stdout stderr (Sys_Printf) -// we need to disable the tty console stuff -// this increments so we can recursively disable -static INT32 ttycon_hide = 0; +// lock to prevent clearing partial lines, since not everything +// printed ends on a newline. +static boolean ttycon_ateol = true; // some key codes that the terminal may be using // TTimo NOTE: I'm not sure how relevant this is static INT32 tty_erase; @@ -736,63 +735,31 @@ static inline void tty_FlushIn(void) // TTimo NOTE: it seems on some terminals just sending '\b' is not enough // so for now, in any case we send "\b \b" .. yeah well .. // (there may be a way to find out if '\b' alone would work though) +// Hanicef NOTE: using \b this way is unreliable because of terminal state, +// it's better to use \r to reset the cursor to the beginning of the +// line and clear from there. static void tty_Back(void) { - char key; - ssize_t d; - key = '\b'; - d = write(STDOUT_FILENO, &key, 1); - key = ' '; - d = write(STDOUT_FILENO, &key, 1); - key = '\b'; - d = write(STDOUT_FILENO, &key, 1); - (void)d; -} - -static void tty_Clear(void) -{ - size_t i; + write(STDOUT_FILENO, "\r", 1); if (tty_con.cursor>0) { - for (i=0; i<tty_con.cursor; i++) - { - tty_Back(); - } - } - -} - -// clear the display of the line currently edited -// bring cursor back to beginning of line -static inline void tty_Hide(void) -{ - //I_Assert(consolevent); - if (ttycon_hide) - { - ttycon_hide++; - return; + write(STDOUT_FILENO, tty_con.buffer, tty_con.cursor); } - tty_Clear(); - ttycon_hide++; + write(STDOUT_FILENO, " \b", 2); } -// show the current line -// FIXME TTimo need to position the cursor if needed?? -static inline void tty_Show(void) +static void tty_Clear(void) { size_t i; - ssize_t d; - //I_Assert(consolevent); - I_Assert(ttycon_hide>0); - ttycon_hide--; - if (ttycon_hide == 0 && tty_con.cursor) + write(STDOUT_FILENO, "\r", 1); + if (tty_con.cursor>0) { for (i=0; i<tty_con.cursor; i++) { - d = write(STDOUT_FILENO, tty_con.buffer+i, 1); + write(STDOUT_FILENO, " ", 1); } + write(STDOUT_FILENO, "\r", 1); } - (void)d; } // never exit without calling this, or your terminal will be left in a pretty bad state @@ -900,6 +867,11 @@ static void I_GetConsoleEvents(void) tty_con.cursor = 0; ev.key = KEY_ENTER; } + else if (key == 0x4) // ^D, aka EOF + { + // shut down, most unix programs behave this way + I_Quit(); + } else continue; } else if (tty_con.cursor < sizeof(tty_con.buffer)) @@ -1152,18 +1124,20 @@ void I_OutputMsg(const char *fmt, ...) } #else #ifdef HAVE_TERMIOS - if (consolevent) + if (consolevent && ttycon_ateol) { - tty_Hide(); + tty_Clear(); + ttycon_ateol = false; } #endif if (!framebuffer) fprintf(stderr, "%s", txt); #ifdef HAVE_TERMIOS - if (consolevent) + if (consolevent && txt[strlen(txt)-1] == '\n') { - tty_Show(); + write(STDOUT_FILENO, tty_con.buffer, tty_con.cursor); + ttycon_ateol = true; } #endif diff --git a/src/sdl/i_system.c b/src/sdl/i_system.c index 2d051888dc..8227cd52ce 100644 --- a/src/sdl/i_system.c +++ b/src/sdl/i_system.c @@ -466,10 +466,9 @@ typedef struct feild_t tty_con; -// when printing general stuff to stdout stderr (Sys_Printf) -// we need to disable the tty console stuff -// this increments so we can recursively disable -static INT32 ttycon_hide = 0; +// lock to prevent clearing partial lines, since not everything +// printed ends on a newline. +static boolean ttycon_ateol = true; // some key codes that the terminal may be using // TTimo NOTE: I'm not sure how relevant this is static INT32 tty_erase; @@ -497,63 +496,31 @@ static inline void tty_FlushIn(void) // TTimo NOTE: it seems on some terminals just sending '\b' is not enough // so for now, in any case we send "\b \b" .. yeah well .. // (there may be a way to find out if '\b' alone would work though) +// Hanicef NOTE: using \b this way is unreliable because of terminal state, +// it's better to use \r to reset the cursor to the beginning of the +// line and clear from there. static void tty_Back(void) { - char key; - ssize_t d; - key = '\b'; - d = write(STDOUT_FILENO, &key, 1); - key = ' '; - d = write(STDOUT_FILENO, &key, 1); - key = '\b'; - d = write(STDOUT_FILENO, &key, 1); - (void)d; -} - -static void tty_Clear(void) -{ - size_t i; + write(STDOUT_FILENO, "\r", 1); if (tty_con.cursor>0) { - for (i=0; i<tty_con.cursor; i++) - { - tty_Back(); - } - } - -} - -// clear the display of the line currently edited -// bring cursor back to beginning of line -static inline void tty_Hide(void) -{ - //I_Assert(consolevent); - if (ttycon_hide) - { - ttycon_hide++; - return; + write(STDOUT_FILENO, tty_con.buffer, tty_con.cursor); } - tty_Clear(); - ttycon_hide++; + write(STDOUT_FILENO, " \b", 2); } -// show the current line -// FIXME TTimo need to position the cursor if needed?? -static inline void tty_Show(void) +static void tty_Clear(void) { size_t i; - ssize_t d; - //I_Assert(consolevent); - I_Assert(ttycon_hide>0); - ttycon_hide--; - if (ttycon_hide == 0 && tty_con.cursor) + write(STDOUT_FILENO, "\r", 1); + if (tty_con.cursor>0) { for (i=0; i<tty_con.cursor; i++) { - d = write(STDOUT_FILENO, tty_con.buffer+i, 1); + write(STDOUT_FILENO, " ", 1); } + write(STDOUT_FILENO, "\r", 1); } - (void)d; } // never exit without calling this, or your terminal will be left in a pretty bad state @@ -661,6 +628,11 @@ void I_GetConsoleEvents(void) tty_con.cursor = 0; ev.key = KEY_ENTER; } + else if (key == 0x4) // ^D, aka EOF + { + // shut down, most unix programs behave this way + I_Quit(); + } else continue; } else if (tty_con.cursor < sizeof (tty_con.buffer)) @@ -959,18 +931,20 @@ void I_OutputMsg(const char *fmt, ...) } #else #ifdef HAVE_TERMIOS - if (consolevent) + if (consolevent && ttycon_ateol) { - tty_Hide(); + tty_Clear(); + ttycon_ateol = false; } #endif if (!framebuffer) fprintf(stderr, "%s", txt); #ifdef HAVE_TERMIOS - if (consolevent) + if (consolevent && txt[strlen(txt)-1] == '\n') { - tty_Show(); + write(STDOUT_FILENO, tty_con.buffer, tty_con.cursor); + ttycon_ateol = true; } #endif -- GitLab