/* ================== CON_Hist_Load ================== */ void CON_Hist_Load( void ) { fileHandle_t f; long len = FS_FOpenFileRead("conhist.log", &f, qtrue); if (f) { field_t tf {}; for (long i = 0; i < len; i++) { char c; FS_Read(&c, 1, f); if (c == '\n') { Hist_Add(&tf); tf = {}; } else { tf.buffer[tf.cursor++] = c; } } FS_FCloseFile(f); } }
/* ================== CON_Input ================== */ char *CON_Input( void ) { // we use this when sending back commands static char text[MAX_EDIT_LINE]; int avail; char key; field_t *history; size_t size; if(ttycon_on) { avail = read(STDIN_FILENO, &key, 1); if (avail != -1) { // we have something // backspace? // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere if ((key == TTY_erase) || (key == 127) || (key == 8)) { if (TTY_con.cursor > 0) { TTY_con.cursor--; TTY_con.buffer[TTY_con.cursor] = '\0'; CON_Back(); } return NULL; } // check if this is a control char if ((key) && (key) < ' ') { if (key == '\n') { // push it in history Hist_Add(&TTY_con); Q_strncpyz(text, TTY_con.buffer, sizeof(text)); Field_Clear(&TTY_con); key = '\n'; size = write(1, &key, 1); size = write( 1, "]", 1 ); return text; } if (key == '\t') { CON_Hide(); Field_AutoComplete( &TTY_con ); CON_Show(); return NULL; } avail = read(STDIN_FILENO, &key, 1); if (avail != -1) { // VT 100 keys if (key == '[' || key == 'O') { avail = read(STDIN_FILENO, &key, 1); if (avail != -1) { switch (key) { case 'A': history = Hist_Prev(); if (history) { CON_Hide(); TTY_con = *history; CON_Show(); } CON_FlushIn(); return NULL; break; case 'B': history = Hist_Next(); CON_Hide(); if (history) { TTY_con = *history; } else { Field_Clear(&TTY_con); } CON_Show(); CON_FlushIn(); return NULL; break; case 'C': return NULL; case 'D': return NULL; } } } } Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase); CON_FlushIn(); return NULL; } if (TTY_con.cursor >= sizeof(text) - 1) return NULL; // push regular character TTY_con.buffer[TTY_con.cursor] = key; TTY_con.cursor++; // print the current line (this is differential) size = write(STDOUT_FILENO, &key, 1); } return NULL; } else if (stdin_active) { int len; fd_set fdset; struct timeval timeout; FD_ZERO(&fdset); FD_SET(STDIN_FILENO, &fdset); // stdin timeout.tv_sec = 0; timeout.tv_usec = 0; if(select (STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(STDIN_FILENO, &fdset)) return NULL; len = read(STDIN_FILENO, text, sizeof(text)); if (len == 0) { // eof! stdin_active = qfalse; return NULL; } if (len < 1) return NULL; text[len-1] = 0; // rip off the /n and terminate return text; } return NULL; }
/* ================== CON_Input ================== */ char *CON_Input( void ) { INPUT_RECORD buff[ MAX_EDIT_LINE ]; DWORD count = 0, events = 0; WORD key = 0; int i; int newlinepos = -1; if ( !GetNumberOfConsoleInputEvents( qconsole_hin, &events ) ) { return NULL; } if ( events < 1 ) { return NULL; } // if we have overflowed, start dropping oldest input events if ( events >= MAX_EDIT_LINE ) { ReadConsoleInput( qconsole_hin, buff, 1, &events ); return NULL; } if ( !ReadConsoleInput( qconsole_hin, buff, events, &count ) ) { return NULL; } FlushConsoleInputBuffer( qconsole_hin ); for ( i = 0; i < count; i++ ) { if ( buff[ i ].EventType != KEY_EVENT ) { continue; } if ( !buff[ i ].Event.KeyEvent.bKeyDown ) { continue; } key = buff[ i ].Event.KeyEvent.wVirtualKeyCode; if ( key == VK_RETURN ) { newlinepos = i; break; } else if ( key == VK_UP ) { Q_strncpyz( qconsole_line, Hist_Prev(), sizeof( qconsole_line ) ); qconsole_linelen = strlen( qconsole_line ); break; } else if ( key == VK_DOWN ) { const char *history = Hist_Next(); if ( history ) { Q_strncpyz( qconsole_line, history, sizeof( qconsole_line ) ); qconsole_linelen = strlen( qconsole_line ); } else if ( qconsole_linelen ) { Hist_Add( qconsole_line ); qconsole_line[ 0 ] = '\0'; qconsole_linelen = 0; } break; } else if ( key == VK_TAB ) { field_t f; Q_strncpyz( f.buffer, qconsole_line, sizeof( f.buffer ) ); Field_AutoComplete( &f, "]" ); Q_strncpyz( qconsole_line, f.buffer, sizeof( qconsole_line ) ); qconsole_linelen = strlen( qconsole_line ); break; } if ( qconsole_linelen < sizeof( qconsole_line ) - 1 ) { char c = buff[ i ].Event.KeyEvent.uChar.AsciiChar; if ( key == VK_BACK ) { int pos = ( qconsole_linelen > 0 ) ? qconsole_linelen - 1 : 0; qconsole_line[ pos ] = '\0'; qconsole_linelen = pos; } else if ( c ) { qconsole_line[ qconsole_linelen++ ] = c; qconsole_line[ qconsole_linelen ] = '\0'; } } } CON_Show(); if ( newlinepos < 0 ) { return NULL; } if ( !qconsole_linelen ) { Com_Printf( "\n" ); return NULL; } Hist_Add( qconsole_line ); Com_Printf( "]%s\n", qconsole_line ); qconsole_linelen = 0; return qconsole_line; }
/* ================== CON_Input ================== */ char *CON_Input(void) { // we use this when sending back commands static char text[MAX_EDIT_LINE]; int avail; char key; field_t *history; size_t UNUSED_VAR size; if(ttycon_on) { avail = read(STDIN_FILENO, &key, 1); if(avail != -1) { // we have something // backspace? // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere if((key == TTY_erase) || (key == 127) || (key == 8)) { if(TTY_con.cursor > 0) { TTY_con.cursor--; TTY_con.buffer[TTY_con.cursor] = '\0'; CON_Back(); } return NULL; } // check if this is a control char if((key) && (key) < ' ') { 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'; size = write(STDOUT_FILENO, &key, 1); size = write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT)); #endif return text; } if(key == '\t') { CON_Hide(); Field_AutoComplete(&TTY_con); CON_Show(); return NULL; } avail = read(STDIN_FILENO, &key, 1); if(avail != -1) { // VT 100 keys if(key == '[' || key == 'O') { avail = read(STDIN_FILENO, &key, 1); if(avail != -1) { switch (key) { case 'A': history = Hist_Prev(); if(history) { CON_Hide(); TTY_con = *history; CON_Show(); } CON_FlushIn(); return NULL; break; case 'B': history = Hist_Next(); CON_Hide(); if(history) { TTY_con = *history; } else { Field_Clear(&TTY_con); } CON_Show(); CON_FlushIn(); return NULL; break; case 'C': return NULL; case 'D': return NULL; } } } } Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase); CON_FlushIn(); return NULL; } if(TTY_con.cursor >= sizeof(text) - 1) return NULL; // push regular character TTY_con.buffer[TTY_con.cursor] = key; TTY_con.cursor++; // next char will always be '\0' // print the current line (this is differential) size = write(STDOUT_FILENO, &key, 1); } return NULL; } else if(stdin_active) { int len; fd_set fdset; struct timeval timeout; FD_ZERO(&fdset); FD_SET(STDIN_FILENO, &fdset); // stdin timeout.tv_sec = 0; timeout.tv_usec = 0; if(select(STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(STDIN_FILENO, &fdset)) return NULL; len = read(STDIN_FILENO, text, sizeof(text)); if(len == 0) { // eof! stdin_active = qfalse; return NULL; } if(len < 1) return NULL; text[len - 1] = 0; // rip off the /n and terminate return text; } return NULL; }
char *Sys_ConsoleInput(void) { // we use this when sending back commands static char text[256]; int i; int avail; char key; field_t *history; if (ttycon && ttycon->value) { avail = read(0, &key, 1); if (avail != -1) { // we have something // backspace? // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere if ((key == tty_erase) || (key == 127) || (key == 8)) { if (tty_con.cursor > 0) { tty_con.cursor--; tty_con.buffer[tty_con.cursor] = '\0'; tty_Back(); } return NULL; } // check if this is a control char if ((key) && (key) < ' ') { if (key == '\n') { // push it in history Hist_Add(&tty_con); strcpy(text, tty_con.buffer); Field_Clear(&tty_con); key = '\n'; write(1, &key, 1); return text; } if (key == '\t') { tty_Hide(); Field_CompleteCommand( &tty_con ); // Field_CompleteCommand does weird things to the string, do a cleanup // it adds a '\' at the beginning of the string // cursor doesn't reflect actual length of the string that's sent back tty_con.cursor = strlen(tty_con.buffer); if (tty_con.cursor>0) { if (tty_con.buffer[0] == '\\') { for (i=0; i<=tty_con.cursor; i++) { tty_con.buffer[i] = tty_con.buffer[i+1]; } tty_con.cursor--; } } tty_Show(); return NULL; } avail = read(0, &key, 1); if (avail != -1) { // VT 100 keys if (key == '[' || key == 'O') { avail = read(0, &key, 1); if (avail != -1) { switch (key) { case 'A': history = Hist_Prev(); if (history) { tty_Hide(); tty_con = *history; tty_Show(); } tty_FlushIn(); return NULL; break; case 'B': history = Hist_Next(); tty_Hide(); if (history) { tty_con = *history; } else { Field_Clear(&tty_con); } tty_Show(); tty_FlushIn(); return NULL; break; case 'C': return NULL; case 'D': return NULL; } } } } Com_DPrintf("droping ISCTL sequence: %d, tty_erase: %d\n", key, tty_erase); tty_FlushIn(); return NULL; } // push regular character tty_con.buffer[tty_con.cursor] = key; tty_con.cursor++; // print the current line (this is differential) write(1, &key, 1); } return NULL; } else { int len; fd_set fdset; struct timeval timeout; if (!com_dedicated || !com_dedicated->value) return NULL; if (!stdin_active) return NULL; FD_ZERO(&fdset); FD_SET(0, &fdset); // stdin timeout.tv_sec = 0; timeout.tv_usec = 0; if (select (1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(0, &fdset)) { return NULL; } len = read (0, text, sizeof(text)); if (len == 0) { // eof! stdin_active = qfalse; return NULL; } if (len < 1) return NULL; text[len-1] = 0; // rip off the /n and terminate return text; } }
/* ================== CON_Input ================== */ char *CON_Input(void) { int chr, num_chars = 0; static char text[MAX_EDIT_LINE]; static int lasttime = -1; if (!curses_on) return CON_Input_tty(); if (com_ansiColor->modified) { CON_Resize(); com_ansiColor->modified = qfalse; } if (Com_RealTime(NULL) != lasttime) { lasttime = Com_RealTime(NULL); CON_UpdateClock(); num_chars++; } while (1) { chr = getch(); num_chars++; // Special characters switch (chr) { case ERR: if (num_chars > 1) { werase(inputwin); if (input_field.cursor < input_field.scroll) { input_field.scroll = input_field.cursor - INPUT_SCROLL; if (input_field.scroll < 0) input_field.scroll = 0; } else if (input_field.cursor >= input_field.scroll + input_field.widthInChars) input_field.scroll = input_field.cursor - input_field.widthInChars + INPUT_SCROLL; CON_ColorPrint(inputwin, input_field.buffer + input_field.scroll, qfalse); #ifdef _WIN32 wrefresh(inputwin); // If this is not done the cursor moves strangely #else wnoutrefresh(inputwin); #endif CON_UpdateCursor(); doupdate(); } return NULL; case '\n': case '\r': case KEY_ENTER: if (!input_field.buffer[0]) continue; Hist_Add(input_field.buffer); strcpy(text, input_field.buffer); Field_Clear(&input_field); werase(inputwin); wnoutrefresh(inputwin); CON_UpdateCursor(); //doupdate(); Com_Printf(PROMPT "^7%s\n", text); return text; case '\t': case KEY_STAB: Field_AutoComplete(&input_field, PROMPT); input_field.cursor = strlen(input_field.buffer); continue; case '\f': CON_Resize(); continue; case KEY_LEFT: if (input_field.cursor > 0) input_field.cursor--; continue; case KEY_RIGHT: if (input_field.cursor < strlen(input_field.buffer)) input_field.cursor++; continue; case KEY_UP: Q_strncpyz(input_field.buffer, Hist_Prev(), sizeof(input_field.buffer)); input_field.cursor = strlen(input_field.buffer); continue; case KEY_DOWN: Q_strncpyz(input_field.buffer, Hist_Next(input_field.buffer), sizeof(input_field.buffer)); input_field.cursor = strlen(input_field.buffer); continue; case KEY_HOME: input_field.cursor = 0; continue; case KEY_END: input_field.cursor = strlen(input_field.buffer); continue; case KEY_NPAGE: if (lastline > scrollline + LOG_LINES) { scrollline += LOG_SCROLL; if (scrollline + LOG_LINES > lastline) scrollline = lastline - LOG_LINES; pnoutrefresh(logwin, scrollline, 0, 2, 1, LOG_LINES + 1, LOG_COLS + 1); CON_DrawScrollBar(); } continue; case KEY_PPAGE: if (scrollline > 0) { scrollline -= LOG_SCROLL; if (scrollline < 0) scrollline = 0; pnoutrefresh(logwin, scrollline, 0, 2, 1, LOG_LINES + 1, LOG_COLS + 1); CON_DrawScrollBar(); } continue; case '\b': case 127: case KEY_BACKSPACE: if (input_field.cursor <= 0) continue; input_field.cursor--; // Fall through case KEY_DC: if (input_field.cursor < strlen(input_field.buffer)) { memmove(input_field.buffer + input_field.cursor, input_field.buffer + input_field.cursor + 1, strlen(input_field.buffer) - input_field.cursor); } continue; } // Normal characters if (chr >= ' ' && chr < 256 && strlen(input_field.buffer) + 1 < sizeof(input_field.buffer)) { memmove(input_field.buffer + input_field.cursor + 1, input_field.buffer + input_field.cursor, strlen(input_field.buffer) - input_field.cursor); input_field.buffer[input_field.cursor] = chr; input_field.cursor++; } } }
/* ================== CON_Input ================== */ char *CON_Input( void ) { // we use this when sending back commands static char text[MAX_EDIT_LINE]; int avail; char key; if(ttycon_on) { CON_CheckRep(); avail = read(STDIN_FILENO, &key, 1); if (avail != -1) { // we have something // disable hibernation for ten seconds to workaround console input lagg svs.hibernation.disableUntil = svs.time + 10000; // backspace? // NOTE TTimo testing a lot of values .. seems it's the only way to get it to work everywhere if ((key == TTY_erase) || (key == 127) || (key == 8)) { if (TTY_con.cursor > 0) { TTY_con.cursor--; TTY_con.buffer[TTY_con.cursor] = '\0'; CON_Back(); } return NULL; } // check if this is a control char if ((key) && (key) < ' ') { if (key == '\n') { #ifndef DEDICATED if (TTY_con.buffer[0] == '/' || TTY_con.buffer[0] == '\\') { Q_strncpyz(text, TTY_con.buffer + 1, sizeof(text)); } else if (TTY_con.cursor) { Q_strncpyz(text, TTY_con.buffer, sizeof(text)); } else { text[0] = '\0'; } // push it in history Hist_Add(); 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(); Q_strncpyz(text, TTY_con.buffer, sizeof(text)); Field_Clear(&TTY_con); key = '\n'; write(STDOUT_FILENO, &key, 1); write(STDOUT_FILENO, TTY_CONSOLE_PROMPT, strlen(TTY_CONSOLE_PROMPT)); #endif return text; } if (key == '\t') { CON_Hide(); Field_AutoComplete( &TTY_con ); CON_Show(); return NULL; } avail = read(STDIN_FILENO, &key, 1); if (avail != -1) { // VT 100 keys if (key == '[' || key == 'O') { avail = read(STDIN_FILENO, &key, 1); if (avail != -1) { switch (key) { case 'A': Hist_Prev(); CON_FlushIn(); return NULL; break; case 'B': Hist_Next(); CON_FlushIn(); return NULL; break; case 'C': return NULL; case 'D': return NULL; } } } } Com_DPrintf("droping ISCTL sequence: %d, TTY_erase: %d\n", key, TTY_erase); CON_FlushIn(); return NULL; } if (TTY_con.cursor >= (int)sizeof(text) - 1) return NULL; // push regular character TTY_con.buffer[TTY_con.cursor] = key; TTY_con.cursor++; // next char will always be '\0' // print the current line (this is differential) write(STDOUT_FILENO, &key, 1); } return NULL; } else if (stdin_active) { int len; fd_set fdset; struct timeval timeout; FD_ZERO(&fdset); FD_SET(STDIN_FILENO, &fdset); // stdin timeout.tv_sec = 0; timeout.tv_usec = 0; if(select (STDIN_FILENO + 1, &fdset, NULL, NULL, &timeout) == -1 || !FD_ISSET(STDIN_FILENO, &fdset)) return NULL; len = read(STDIN_FILENO, text, sizeof(text)); if (len == 0) { // eof! stdin_active = qfalse; return NULL; } if (len < 1) return NULL; text[len-1] = 0; // rip off the /n and terminate return text; } return NULL; }