// clear the display of the line currently edited // bring cursor back to beginning of line void tty_Hide() { int len, buf_len; if( !tty_enabled ) { return; } if( input_hide ) { input_hide++; return; } // clear after cursor len = strlen( input_field.GetBuffer() ) - input_field.GetCursor(); while( len > 0 ) { tty_Right(); len--; } buf_len = strlen( input_field.GetBuffer() ); while( buf_len > 0 ) { tty_Del(); buf_len--; } input_hide++; }
// show the current line void tty_Show() { // int i; if( !tty_enabled ) { return; } assert( input_hide > 0 ); input_hide--; if( input_hide == 0 ) { char* buf = input_field.GetBuffer(); if( buf[0] ) { write( STDOUT_FILENO, buf, strlen( buf ) ); // RB begin #if defined(__ANDROID__) //__android_log_print(ANDROID_LOG_DEBUG, "RBDoom3_DEBUG", "%s", buf); #endif // RB end int back = strlen( buf ) - input_field.GetCursor(); while( back > 0 ) { tty_Left(); back--; } } } }
// show the current line void tty_Show() { // int i; if ( !tty_enabled ) { return; } assert( input_hide > 0 ); input_hide--; if ( input_hide == 0 ) { char *buf = input_field.GetBuffer(); if ( buf[0] ) { write( STDOUT_FILENO, buf, strlen( buf ) ); int back = strlen( buf ) - input_field.GetCursor(); while ( back > 0 ) { tty_Left(); back--; } } } }
// show the current line void tty_Show() { // int i; if ( !tty_enabled ) { return; } assert( input_hide > 0 ); input_hide--; if ( input_hide == 0 ) { char *buf = input_field.GetBuffer(); size_t len = strlen(buf); if ( len < 1 ) return; len = write( STDOUT_FILENO, buf, len ); if ( len < 1 ) return; len -= input_field.GetCursor(); while ( len > 0 ) { tty_Left(); len--; } } }
/* ================ DrawInput Draw the editline after a ] prompt ================ */ void idConsoleLocal::DrawInput() { int y, autoCompleteLength; y = vislines - ( SMALLCHAR_HEIGHT * 2 ); if( consoleField.GetAutoCompleteLength() != 0 ) { autoCompleteLength = strlen( consoleField.GetBuffer() ) - consoleField.GetAutoCompleteLength(); if( autoCompleteLength > 0 ) { renderSystem->DrawFilled( idVec4( 0.8f, 0.2f, 0.2f, 0.45f ), LOCALSAFE_LEFT + 2 * SMALLCHAR_WIDTH + consoleField.GetAutoCompleteLength() * SMALLCHAR_WIDTH, y + 2, autoCompleteLength * SMALLCHAR_WIDTH, SMALLCHAR_HEIGHT - 2 ); } } renderSystem->SetColor( idStr::ColorForIndex( C_COLOR_CYAN ) ); renderSystem->DrawSmallChar( LOCALSAFE_LEFT + 1 * SMALLCHAR_WIDTH, y, ']' ); consoleField.Draw( LOCALSAFE_LEFT + 2 * SMALLCHAR_WIDTH, y, SCREEN_WIDTH - 3 * SMALLCHAR_WIDTH, true ); }
/* ================ Posix_ConsoleInput Checks for a complete line of text typed in at the console. Return NULL if a complete line is not ready. ================ */ char* Posix_ConsoleInput() { if( tty_enabled ) { int ret; char key; bool hidden = false; while( ( ret = read( STDIN_FILENO, &key, 1 ) ) > 0 ) { if( !hidden ) { tty_Hide(); hidden = true; } switch( key ) { case 1: input_field.SetCursor( 0 ); break; case 5: input_field.SetCursor( strlen( input_field.GetBuffer() ) ); break; case 127: case 8: input_field.CharEvent( K_BACKSPACE ); break; case '\n': idStr::Copynz( input_ret, input_field.GetBuffer(), sizeof( input_ret ) ); assert( hidden ); tty_Show(); write( STDOUT_FILENO, &key, 1 ); input_field.Clear(); if( history_count < COMMAND_HISTORY ) { history[ history_count ] = input_ret; history_count++; } else { history[ history_start ] = input_ret; history_start++; history_start %= COMMAND_HISTORY; } history_current = 0; return input_ret; case '\t': input_field.AutoComplete(); break; case 27: { // enter escape sequence mode ret = read( STDIN_FILENO, &key, 1 ); if( ret <= 0 ) { Sys_Printf( "dropping sequence: '27' " ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } switch( key ) { case 79: ret = read( STDIN_FILENO, &key, 1 ); if( ret <= 0 ) { Sys_Printf( "dropping sequence: '27' '79' " ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } switch( key ) { case 72: // xterm only input_field.SetCursor( 0 ); break; case 70: // xterm only input_field.SetCursor( strlen( input_field.GetBuffer() ) ); break; default: Sys_Printf( "dropping sequence: '27' '79' '%d' ", key ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } break; case 91: { ret = read( STDIN_FILENO, &key, 1 ); if( ret <= 0 ) { Sys_Printf( "dropping sequence: '27' '91' " ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } switch( key ) { case 49: { ret = read( STDIN_FILENO, &key, 1 ); if( ret <= 0 || key != 126 ) { Sys_Printf( "dropping sequence: '27' '91' '49' '%d' ", key ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } // only screen and linux terms input_field.SetCursor( 0 ); break; } case 50: { ret = read( STDIN_FILENO, &key, 1 ); if( ret <= 0 || key != 126 ) { Sys_Printf( "dropping sequence: '27' '91' '50' '%d' ", key ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } // all terms input_field.KeyDownEvent( K_INS ); break; } case 52: { ret = read( STDIN_FILENO, &key, 1 ); if( ret <= 0 || key != 126 ) { Sys_Printf( "dropping sequence: '27' '91' '52' '%d' ", key ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } // only screen and linux terms input_field.SetCursor( strlen( input_field.GetBuffer() ) ); break; } case 51: { ret = read( STDIN_FILENO, &key, 1 ); if( ret <= 0 ) { Sys_Printf( "dropping sequence: '27' '91' '51' " ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } if( key == 126 ) { input_field.KeyDownEvent( K_DEL ); break; } Sys_Printf( "dropping sequence: '27' '91' '51' '%d'", key ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } case 65: case 66: { // history if( history_current == 0 ) { history_backup = input_field; } if( key == 65 ) { // up history_current++; } else { // down history_current--; } // history_current cycle: // 0: current edit // 1 .. Min( COMMAND_HISTORY, history_count ): back in history if( history_current < 0 ) { history_current = Min( COMMAND_HISTORY, history_count ); } else { history_current %= Min( COMMAND_HISTORY, history_count ) + 1; } int index = -1; if( history_current == 0 ) { input_field = history_backup; } else { index = history_start + Min( COMMAND_HISTORY, history_count ) - history_current; index %= COMMAND_HISTORY; assert( index >= 0 && index < COMMAND_HISTORY ); input_field.SetBuffer( history[ index ] ); } assert( hidden ); tty_Show(); return NULL; } case 67: input_field.KeyDownEvent( K_RIGHTARROW ); break; case 68: input_field.KeyDownEvent( K_LEFTARROW ); break; default: Sys_Printf( "dropping sequence: '27' '91' '%d' ", key ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } break; } default: Sys_Printf( "dropping sequence: '27' '%d' ", key ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } break; } default: if( key >= ' ' ) { input_field.CharEvent( key ); break; } Sys_Printf( "dropping sequence: '%d' ", key ); tty_FlushIn(); assert( hidden ); tty_Show(); return NULL; } } if( hidden ) { tty_Show(); } return NULL; } else { // disabled on OSX. works fine from a terminal, but launching from Finder is causing trouble // I'm pretty sure it could be re-enabled if needed, and just handling the Finder failure case right (TTimo) #ifndef __APPLE__ // no terminal support - read only complete lines int len; fd_set fdset; struct timeval timeout; FD_ZERO( &fdset ); FD_SET( STDIN_FILENO, &fdset ); 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, input_ret, sizeof( input_ret ) ); if( len == 0 ) { // EOF return NULL; } if( len < 1 ) { Sys_Printf( "read failed: %s\n", strerror( errno ) ); // something bad happened, cancel this line and print an error return NULL; } if( len == sizeof( input_ret ) ) { Sys_Printf( "read overflow\n" ); // things are likely to break, as input will be cut into pieces } input_ret[ len - 1 ] = '\0'; // rip off the \n and terminate return input_ret; #endif } return NULL; }
/* ==================== KeyDownEvent Handles history and console scrollback ==================== */ void idConsoleLocal::KeyDownEvent( int key ) { // Execute F key bindings if( key >= K_F1 && key <= K_F12 ) { idKeyInput::ExecKeyBinding( key ); return; } // ctrl-L clears screen if( key == K_L && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) { Clear(); return; } // enter finishes the line if( key == K_ENTER || key == K_KP_ENTER ) { common->Printf( "]%s\n", consoleField.GetBuffer() ); cmdSystem->BufferCommandText( CMD_EXEC_APPEND, consoleField.GetBuffer() ); // valid command cmdSystem->BufferCommandText( CMD_EXEC_APPEND, "\n" ); // copy line to history buffer if( consoleField.GetBuffer()[ 0 ] != '\n' && consoleField.GetBuffer()[ 0 ] != '\0' ) { consoleHistory.AddToHistory( consoleField.GetBuffer() ); } consoleField.Clear(); consoleField.SetWidthInChars( LINE_WIDTH ); const bool captureToImage = false; common->UpdateScreen( captureToImage );// force an update, because the command // may take some time return; } // command completion if( key == K_TAB ) { consoleField.AutoComplete(); return; } // command history (ctrl-p ctrl-n for unix style) if( ( key == K_UPARROW ) || ( key == K_P && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) ) { idStr hist = consoleHistory.RetrieveFromHistory( true ); if( !hist.IsEmpty() ) { consoleField.SetBuffer( hist ); } return; } if( ( key == K_DOWNARROW ) || ( key == K_N && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) ) { idStr hist = consoleHistory.RetrieveFromHistory( false ); if( !hist.IsEmpty() ) { consoleField.SetBuffer( hist ); } else // DG: if no more lines are in the history, show a blank line again { consoleField.Clear(); } // DG end return; } // console scrolling if( key == K_PGUP ) { PageUp(); lastKeyEvent = eventLoop->Milliseconds(); nextKeyEvent = CONSOLE_FIRSTREPEAT; return; } if( key == K_PGDN ) { PageDown(); lastKeyEvent = eventLoop->Milliseconds(); nextKeyEvent = CONSOLE_FIRSTREPEAT; return; } if( key == K_MWHEELUP ) { PageUp(); return; } if( key == K_MWHEELDOWN ) { PageDown(); return; } // ctrl-home = top of console if( key == K_HOME && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) { Top(); return; } // ctrl-end = bottom of console if( key == K_END && ( idKeyInput::IsDown( K_LCTRL ) || idKeyInput::IsDown( K_RCTRL ) ) ) { Bottom(); return; } // pass to the normal editline routine consoleField.KeyDownEvent( key ); }