diff --git a/reaction/Makefile b/reaction/Makefile index 1fc054f2..d87fde12 100644 --- a/reaction/Makefile +++ b/reaction/Makefile @@ -1417,10 +1417,17 @@ Q3OBJ = \ $(B)/client/sdl_input.o \ $(B)/client/sdl_snd.o \ \ - $(B)/client/con_passive.o \ $(B)/client/con_log.o \ $(B)/client/sys_main.o +ifeq ($(PLATFORM),mingw32) + Q3OBJ += \ + $(B)/client/con_passive.o +else + Q3OBJ += \ + $(B)/client/con_tty.o +endif + Q3R2OBJ = \ $(B)/renderergl2/tr_animation.o \ $(B)/renderergl2/tr_backend.o \ diff --git a/reaction/code/sys/con_tty.c b/reaction/code/sys/con_tty.c index 6e5e966c..8dcf0433 100644 --- a/reaction/code/sys/con_tty.c +++ b/reaction/code/sys/con_tty.c @@ -24,6 +24,10 @@ Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA #include "../qcommon/qcommon.h" #include "sys_local.h" +#ifndef DEDICATED +#include "../client/client.h" +#endif + #include #include #include @@ -45,6 +49,7 @@ static qboolean stdin_active; // general flag to tell about tty console mode static qboolean ttycon_on = qfalse; static int ttycon_hide = 0; +static int ttycon_show_overdue = 0; // some key codes that the terminal may be using, initialised on start up static int TTY_erase; @@ -60,6 +65,14 @@ static field_t TTY_con; static field_t ttyEditLines[ CON_HISTORY ]; static int hist_current = -1, hist_count = 0; +#ifndef DEDICATED +// Don't use "]" as it would be the same as in-game console, +// this makes it clear where input came from. +#define TTY_CONSOLE_PROMPT "tty]" +#else +#define TTY_CONSOLE_PROMPT "]" +#endif + /* ================== CON_FlushIn @@ -88,13 +101,14 @@ send "\b \b" static void CON_Back( void ) { char key; + size_t UNUSED_VAR size; key = '\b'; - write(STDOUT_FILENO, &key, 1); + size = write(STDOUT_FILENO, &key, 1); key = ' '; - write(STDOUT_FILENO, &key, 1); + size = write(STDOUT_FILENO, &key, 1); key = '\b'; - write(STDOUT_FILENO, &key, 1); + size = write(STDOUT_FILENO, &key, 1); } /* @@ -122,7 +136,10 @@ static void CON_Hide( void ) CON_Back(); } } - CON_Back(); // Delete "]" + // Delete prompt + for (i = strlen(TTY_CONSOLE_PROMPT); i > 0; i--) { + CON_Back(); + } ttycon_hide++; } } @@ -145,12 +162,13 @@ static void CON_Show( void ) ttycon_hide--; if (ttycon_hide == 0) { - write(STDOUT_FILENO, "]", 1); + size_t UNUSED_VAR size; + size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT)); if (TTY_con.cursor) { for (i=0; icursor) + return; + assert(hist_count <= CON_HISTORY); assert(hist_count >= 0); assert(hist_current >= -1); @@ -313,6 +336,8 @@ void CON_Init( void ) tc.c_cc[VTIME] = 0; tcsetattr (STDIN_FILENO, TCSADRAIN, &tc); ttycon_on = qtrue; + ttycon_hide = 1; // Mark as hidden, so prompt is shown in CON_Show + CON_Show(); } /* @@ -327,6 +352,7 @@ char *CON_Input( void ) int avail; char key; field_t *history; + size_t UNUSED_VAR size; if(ttycon_on) { @@ -351,13 +377,39 @@ char *CON_Input( void ) { if (key == '\n') { +#ifndef DEDICATED + // if not in the game explicitly prepend a slash if needed + if (clc.state != CA_ACTIVE && TTY_con.cursor && + TTY_con.buffer[0] != '/' && TTY_con.buffer[0] != '\\') + { + memmove(TTY_con.buffer + 1, TTY_con.buffer, sizeof(TTY_con.buffer) - 1); + TTY_con.buffer[0] = '\\'; + TTY_con.cursor++; + } + + if (TTY_con.buffer[0] == '/' || TTY_con.buffer[0] == '\\') { + Q_strncpyz(text, TTY_con.buffer + 1, sizeof(text)); + } else if (TTY_con.cursor) { + Com_sprintf(text, sizeof(text), "cmd say %s", TTY_con.buffer); + } else { + text[0] = '\0'; + } + + // push it in history + Hist_Add(&TTY_con); + CON_Hide(); + Com_Printf("%s%s\n", TTY_CONSOLE_PROMPT, TTY_con.buffer); + Field_Clear(&TTY_con); + CON_Show(); +#else // push it in history Hist_Add(&TTY_con); Q_strncpyz(text, TTY_con.buffer, sizeof(text)); Field_Clear(&TTY_con); key = '\n'; - write(STDOUT_FILENO, &key, 1); - write(STDOUT_FILENO, "]", 1); + size = write(STDOUT_FILENO, &key, 1); + size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT)); +#endif return text; } if (key == '\t') @@ -419,9 +471,9 @@ char *CON_Input( void ) return NULL; // push regular character TTY_con.buffer[TTY_con.cursor] = key; - TTY_con.cursor++; + TTY_con.cursor++; // next char will always be '\0' // print the current line (this is differential) - write(STDOUT_FILENO, &key, 1); + size = write(STDOUT_FILENO, &key, 1); } return NULL; @@ -462,6 +514,9 @@ CON_Print */ void CON_Print( const char *msg ) { + if (!msg[0]) + return; + CON_Hide( ); if( com_ansiColor && com_ansiColor->integer ) @@ -469,5 +524,25 @@ void CON_Print( const char *msg ) else fputs( msg, stderr ); - CON_Show( ); + if (!ttycon_on) { + // CON_Hide didn't do anything. + return; + } + + // Only print prompt when msg ends with a newline, otherwise the console + // might get garbled when output does not fit on one line. + if (msg[strlen(msg) - 1] == '\n') { + CON_Show(); + + // Run CON_Show the number of times it was deferred. + while (ttycon_show_overdue > 0) { + CON_Show(); + ttycon_show_overdue--; + } + } + else + { + // Defer calling CON_Show + ttycon_show_overdue++; + } }