mirror of
https://github.com/nillerusr/source-engine.git
synced 2026-08-08 01:39:36 +00:00
1
This commit is contained in:
@@ -0,0 +1,419 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// CTextConsoleUnix.cpp: Unix implementation of the TextConsole class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
|
||||
#include "TextConsoleUnix.h"
|
||||
#include "tier0/icommandline.h"
|
||||
#include "tier1/utllinkedlist.h"
|
||||
#include "filesystem.h"
|
||||
#include "../thirdparty/libedit-3.1/src/histedit.h"
|
||||
#include "tier0/vprof.h"
|
||||
|
||||
#define CONSOLE_LOG_FILE "console.log"
|
||||
|
||||
static pthread_mutex_t g_lock;
|
||||
static pthread_t g_threadid = (pthread_t)-1;
|
||||
CUtlLinkedList< CUtlString > g_Commands;
|
||||
static volatile int g_ProcessingCommands = false;
|
||||
|
||||
#if defined( LINUX )
|
||||
|
||||
// Dynamically load the libtinfo stuff. On servers without a tty attached,
|
||||
// we get to skip all of these dependencies on servers without ttys.
|
||||
#define TINFO_SYM(rc, fn, params, args, ret) \
|
||||
typedef rc (*DYNTINFOFN_##fn) params; \
|
||||
static DYNTINFOFN_##fn g_TINFO_##fn; \
|
||||
extern "C" rc fn params \
|
||||
{ \
|
||||
ret g_TINFO_##fn args; \
|
||||
}
|
||||
|
||||
TINFO_SYM(char *, tgoto, (char *string, int x, int y), (string, x, y), return);
|
||||
TINFO_SYM(int, tputs, (const char *str, int affcnt, int (*putc)(int)), (str, affcnt, putc), return);
|
||||
TINFO_SYM(int, tgetflag, (char *id), (id), return);
|
||||
TINFO_SYM(int, tgetnum, (char *id), (id), return);
|
||||
TINFO_SYM(int, tgetent, (char *bufp, const char *name), (bufp, name), return);
|
||||
TINFO_SYM(char *, tgetstr, (char *id, char **area), (id, area), return);
|
||||
|
||||
#endif // LINUX
|
||||
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
// init_tinfo_functions
|
||||
//----------------------------------------------------------------------------------------------------------------------
|
||||
static bool init_tinfo_functions()
|
||||
{
|
||||
#if !defined( LINUX )
|
||||
return true;
|
||||
#else
|
||||
static void *s_ncurses_handle = NULL;
|
||||
|
||||
if ( !s_ncurses_handle )
|
||||
{
|
||||
// Long time ago, ncurses was two libraries. So if libtinfo fails, try libncurses.
|
||||
static const char *names[] = { "libtinfo.so.5", "libncurses.so.5" };
|
||||
|
||||
for ( int i = 0; !s_ncurses_handle && ( i < ARRAYSIZE( names ) ); i++ )
|
||||
{
|
||||
bool bFailed = true;
|
||||
s_ncurses_handle = dlopen( names[i], RTLD_NOW );
|
||||
|
||||
if ( s_ncurses_handle )
|
||||
{
|
||||
bFailed = false;
|
||||
#define LOADTINFOFUNC(_handle, _func, _failed) \
|
||||
do { \
|
||||
g_TINFO_##_func = ( DYNTINFOFN_##_func )dlsym(_handle, #_func); \
|
||||
if ( !g_TINFO_##_func) \
|
||||
_failed = true; \
|
||||
} while (0)
|
||||
|
||||
LOADTINFOFUNC( s_ncurses_handle, tgoto, bFailed );
|
||||
LOADTINFOFUNC( s_ncurses_handle, tputs, bFailed );
|
||||
LOADTINFOFUNC( s_ncurses_handle, tgetflag, bFailed );
|
||||
LOADTINFOFUNC( s_ncurses_handle, tgetnum, bFailed );
|
||||
LOADTINFOFUNC( s_ncurses_handle, tgetent, bFailed );
|
||||
LOADTINFOFUNC( s_ncurses_handle, tgetstr, bFailed );
|
||||
#undef LOADTINFOFUNC
|
||||
}
|
||||
|
||||
if ( bFailed )
|
||||
s_ncurses_handle = NULL;
|
||||
}
|
||||
|
||||
if ( !s_ncurses_handle )
|
||||
{
|
||||
fprintf( stderr, "\nWARNING: Failed to load 32-bit libtinfo.so.5 or libncurses.so.5.\n"
|
||||
" Please install (lib32tinfo5 / ncurses-libs.i686 / equivalent) to enable readline.\n\n");
|
||||
}
|
||||
}
|
||||
|
||||
return !!s_ncurses_handle;
|
||||
#endif // LINUX
|
||||
}
|
||||
|
||||
static unsigned char editline_complete( EditLine *el, int ch __attribute__((__unused__)) )
|
||||
{
|
||||
static const char *s_cmds[] =
|
||||
{
|
||||
"cvarlist ",
|
||||
"find ",
|
||||
"help ",
|
||||
"maps ",
|
||||
"nextlevel",
|
||||
"quit",
|
||||
"status",
|
||||
"sv_cheats ",
|
||||
"tf_bot_quota ",
|
||||
"toggle ",
|
||||
"sv_dump_edicts",
|
||||
#ifdef STAGING_ONLY
|
||||
"tf_bot_use_items ",
|
||||
#endif
|
||||
};
|
||||
|
||||
const LineInfo *lf = el_line(el);
|
||||
const char *cmd = lf->buffer;
|
||||
size_t len = lf->cursor - cmd;
|
||||
|
||||
if ( len > 0 )
|
||||
{
|
||||
for (int i = 0; i < ARRAYSIZE(s_cmds); i++)
|
||||
{
|
||||
if ( len > strlen( s_cmds[i] ) )
|
||||
continue;
|
||||
|
||||
if ( !Q_strncmp( cmd, s_cmds[i], len ) )
|
||||
{
|
||||
if ( el_insertstr( el, s_cmds[i] + len ) == -1 )
|
||||
return CC_ERROR;
|
||||
else
|
||||
return CC_REFRESH;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return CC_ERROR;
|
||||
}
|
||||
|
||||
static const char *editline_prompt( EditLine *e )
|
||||
{
|
||||
// Something like: "\1\033[7m\1Srcds$\1\033[0m\1 "
|
||||
static const char *szPrompt = getenv( "SRCDS_PROMPT" );
|
||||
return szPrompt ? szPrompt : "";
|
||||
}
|
||||
|
||||
static void editline_cleanup_handler( void *arg )
|
||||
{
|
||||
if ( arg )
|
||||
{
|
||||
EditLine *el = (EditLine *)arg;
|
||||
el_end( el );
|
||||
}
|
||||
}
|
||||
|
||||
static bool add_command( const char *cmd, int cmd_len )
|
||||
{
|
||||
if ( cmd )
|
||||
{
|
||||
tmZone( TELEMETRY_LEVEL0, TMZF_NONE, "%s", __FUNCTION__ );
|
||||
|
||||
// Trim trailing whitespace.
|
||||
while ( ( cmd_len > 0 ) && isspace( cmd[ cmd_len - 1 ] ) )
|
||||
cmd_len--;
|
||||
|
||||
if ( cmd_len > 0 )
|
||||
{
|
||||
pthread_mutex_lock( &g_lock );
|
||||
if ( g_Commands.Count() < 32 )
|
||||
{
|
||||
CUtlString szCommand( cmd, cmd_len );
|
||||
g_Commands.AddToTail( szCommand );
|
||||
|
||||
g_ProcessingCommands = true;
|
||||
}
|
||||
pthread_mutex_unlock( &g_lock );
|
||||
|
||||
// Wait a bit until we've processed the command we added.
|
||||
for ( int i = 0; i < 6; i++ )
|
||||
{
|
||||
while ( g_ProcessingCommands )
|
||||
usleep( 500 );
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void *editline_threadproc( void *arg )
|
||||
{
|
||||
HistEvent ev;
|
||||
EditLine *el;
|
||||
History *myhistory;
|
||||
FILE *tty = (FILE *)arg;
|
||||
|
||||
ThreadSetDebugName( "libedit" );
|
||||
|
||||
// Set up state
|
||||
el = el_init( "srcds_linux", stdin, tty, stderr );
|
||||
el_set( el, EL_PROMPT, &editline_prompt );
|
||||
el_set( el, EL_EDITOR, "emacs" ); // or "vi"
|
||||
|
||||
// Hitting Ctrl+R will reset prompt.
|
||||
el_set( el, EL_BIND, "^R", "ed-redisplay", NULL );
|
||||
|
||||
/* Add a user-defined function */
|
||||
el_set( el, EL_ADDFN, "ed-complete", "Complete argument", editline_complete );
|
||||
/* Bind tab to it */
|
||||
el_set( el, EL_BIND, "^I", "ed-complete", NULL );
|
||||
|
||||
// Init history.
|
||||
myhistory = history_init();
|
||||
if (myhistory == 0)
|
||||
{
|
||||
fprintf( stderr, "history could not be initialized\n" );
|
||||
g_threadid = (pthread_t)-1;
|
||||
return (void *)-1;
|
||||
}
|
||||
|
||||
// History size.
|
||||
history( myhistory, &ev, H_SETSIZE, 800 );
|
||||
|
||||
// History callback.
|
||||
el_set( el, EL_HIST, history, myhistory );
|
||||
|
||||
// Source user's defaults.
|
||||
el_source( el, NULL );
|
||||
|
||||
pthread_cleanup_push( editline_cleanup_handler, el );
|
||||
|
||||
while ( g_threadid != (pthread_t)-1 )
|
||||
{
|
||||
// count is the number of characters read.
|
||||
// line is a const char* of our command line with the tailing \n
|
||||
int count;
|
||||
const char *line = el_gets( el, &count );
|
||||
|
||||
if ( add_command( line, count ) )
|
||||
{
|
||||
// Add command to history.
|
||||
history( myhistory, &ev, H_ENTER, line );
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cleanup_pop( 0 );
|
||||
|
||||
// Clean up...
|
||||
history_end( myhistory );
|
||||
el_end( el );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *fgets_threadproc( void *arg )
|
||||
{
|
||||
pthread_cleanup_push( editline_cleanup_handler, NULL );
|
||||
|
||||
while ( g_threadid != (pthread_t)-1 )
|
||||
{
|
||||
char cmd[ 512 ];
|
||||
|
||||
if ( fgets( cmd, sizeof( cmd ), stdin ) )
|
||||
{
|
||||
cmd[ sizeof(cmd) - 1 ] = 0;
|
||||
add_command( cmd, strlen( cmd ) );
|
||||
}
|
||||
}
|
||||
|
||||
pthread_cleanup_pop( 0 );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool CTextConsoleUnix::Init()
|
||||
{
|
||||
if( g_threadid != (pthread_t)-1 )
|
||||
{
|
||||
Assert( !"CTextConsoleUnix can only handle a single thread!" );
|
||||
return false;
|
||||
}
|
||||
|
||||
pthread_mutex_init( &g_lock, NULL );
|
||||
|
||||
// This code is for echo-ing key presses to the connected tty
|
||||
// (which is != STDOUT)
|
||||
if ( isatty( STDIN_FILENO ) )
|
||||
{
|
||||
const char *termid_str = ctermid( NULL );
|
||||
|
||||
m_tty = fopen( termid_str, "w+" );
|
||||
if ( !m_tty )
|
||||
{
|
||||
fprintf( stderr, "WARNING: Unable to open tty(%s) for output.\n", termid_str );
|
||||
m_tty = stdout;
|
||||
}
|
||||
|
||||
void *(*terminal_threadproc) (void *) = editline_threadproc;
|
||||
if ( !init_tinfo_functions() )
|
||||
terminal_threadproc = fgets_threadproc;
|
||||
|
||||
if ( pthread_create( &g_threadid, NULL, terminal_threadproc, (void *)m_tty ) != 0 )
|
||||
{
|
||||
g_threadid = (pthread_t)-1;
|
||||
fprintf( stderr, "WARNING: pthread_create failed: %s.\n", strerror(errno) );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
m_tty = fopen( "/dev/null", "w+" );
|
||||
if ( !m_tty )
|
||||
m_tty = stdout;
|
||||
}
|
||||
|
||||
m_bConDebug = CommandLine()->FindParm( "-condebug" ) != 0;
|
||||
if ( m_bConDebug && CommandLine()->FindParm( "-conclearlog" ) )
|
||||
g_pFullFileSystem->RemoveFile( CONSOLE_LOG_FILE, "GAME" );
|
||||
|
||||
return CTextConsole::Init();
|
||||
}
|
||||
|
||||
void CTextConsoleUnix::ShutDown()
|
||||
{
|
||||
if ( g_threadid != (pthread_t)-1 )
|
||||
{
|
||||
void *status = NULL;
|
||||
pthread_t tid = g_threadid;
|
||||
|
||||
g_threadid = (pthread_t)-1;
|
||||
|
||||
pthread_cancel( tid );
|
||||
pthread_join( tid, &status );
|
||||
}
|
||||
|
||||
pthread_mutex_destroy( &g_lock );
|
||||
}
|
||||
|
||||
void CTextConsoleUnix::Print( char * pszMsg )
|
||||
{
|
||||
int nChars = strlen( pszMsg );
|
||||
|
||||
if ( nChars > 0 )
|
||||
{
|
||||
if ( m_bConDebug )
|
||||
{
|
||||
FileHandle_t fh = g_pFullFileSystem->Open( CONSOLE_LOG_FILE, "a" );
|
||||
if ( fh != FILESYSTEM_INVALID_HANDLE )
|
||||
{
|
||||
g_pFullFileSystem->Write( pszMsg, nChars, fh );
|
||||
g_pFullFileSystem->Close( fh );
|
||||
}
|
||||
}
|
||||
|
||||
fwrite( pszMsg, 1, nChars, m_tty );
|
||||
}
|
||||
}
|
||||
|
||||
void CTextConsoleUnix::SetTitle( char *pszTitle )
|
||||
{
|
||||
}
|
||||
|
||||
void CTextConsoleUnix::SetStatusLine( char *pszStatus )
|
||||
{
|
||||
}
|
||||
|
||||
void CTextConsoleUnix::UpdateStatus()
|
||||
{
|
||||
}
|
||||
|
||||
char *CTextConsoleUnix::GetLine( int index, char *buf, int buflen )
|
||||
{
|
||||
if ( g_threadid != (pthread_t)-1 )
|
||||
{
|
||||
if ( g_Commands.Count() > 0 )
|
||||
{
|
||||
pthread_mutex_lock( &g_lock );
|
||||
|
||||
const CUtlString& psCommand = g_Commands[ g_Commands.Head() ];
|
||||
V_strncpy( buf, psCommand.Get(), buflen );
|
||||
g_Commands.Remove( g_Commands.Head() );
|
||||
|
||||
pthread_mutex_unlock( &g_lock );
|
||||
return buf;
|
||||
}
|
||||
else if ( index == 0 )
|
||||
{
|
||||
// We're being asked for the first command. Must be a new frame.
|
||||
// Reset the processed commands global.
|
||||
g_ProcessingCommands = false;
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int CTextConsoleUnix::GetWidth()
|
||||
{
|
||||
int nWidth = 0;
|
||||
struct winsize ws;
|
||||
|
||||
if ( ioctl( STDOUT_FILENO, TIOCGWINSZ, &ws ) == 0 )
|
||||
nWidth = (int)ws.ws_col;
|
||||
|
||||
if ( nWidth <= 1 )
|
||||
nWidth = 80;
|
||||
|
||||
return nWidth;
|
||||
}
|
||||
|
||||
#endif // !_WIN32
|
||||
@@ -0,0 +1,44 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// TextConsoleUnix.h: Unix interface for the TextConsole class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined TEXTCONSOLE_UNIX_H
|
||||
#define TEXTCONSOLE_UNIX_H
|
||||
|
||||
#ifndef _WIN32
|
||||
|
||||
#include <stdio.h>
|
||||
#include "textconsole.h"
|
||||
|
||||
class CTextConsoleUnix : public CTextConsole
|
||||
{
|
||||
public:
|
||||
virtual ~CTextConsoleUnix() { }
|
||||
|
||||
// CTextConsole
|
||||
bool Init();
|
||||
void ShutDown();
|
||||
void Print( char * pszMsg );
|
||||
|
||||
void SetTitle( char *pszTitle );
|
||||
void SetStatusLine( char *pszStatus );
|
||||
void UpdateStatus();
|
||||
|
||||
char * GetLine( int index, char *buf, int buflen );
|
||||
int GetWidth();
|
||||
|
||||
private:
|
||||
bool m_bConDebug;
|
||||
FILE *m_tty;
|
||||
};
|
||||
|
||||
#endif // _ndef WIN32
|
||||
|
||||
#endif // !defined TEXTCONSOLE_UNIX_H
|
||||
@@ -0,0 +1,644 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// CTextConsoleWin32.cpp: Win32 implementation of the TextConsole class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "TextConsoleWin32.h"
|
||||
#include "tier0/dbg.h"
|
||||
#include "utlvector.h"
|
||||
|
||||
// Could possibly switch all this code over to using readline. This:
|
||||
// http://mingweditline.sourceforge.net/?Description
|
||||
// readline() / add_history(char *)
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
BOOL WINAPI ConsoleHandlerRoutine( DWORD CtrlType )
|
||||
{
|
||||
NOTE_UNUSED( CtrlType );
|
||||
/* TODO ?
|
||||
if ( CtrlType != CTRL_C_EVENT && CtrlType != CTRL_BREAK_EVENT )
|
||||
m_System->Stop(); // don't quit on break or ctrl+c
|
||||
*/
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
// GetConsoleHwnd() helper function from MSDN Knowledge Base Article Q124103
|
||||
// needed, because HWND GetConsoleWindow(VOID) is not avaliable under Win95/98/ME
|
||||
|
||||
HWND GetConsoleHwnd(void)
|
||||
{
|
||||
typedef HWND (WINAPI *PFNGETCONSOLEWINDOW)( VOID );
|
||||
static PFNGETCONSOLEWINDOW s_pfnGetConsoleWindow = (PFNGETCONSOLEWINDOW) GetProcAddress( GetModuleHandle("kernel32"), "GetConsoleWindow" );
|
||||
if ( s_pfnGetConsoleWindow )
|
||||
return s_pfnGetConsoleWindow();
|
||||
|
||||
HWND hwndFound; // This is what is returned to the caller.
|
||||
char pszNewWindowTitle[1024]; // Contains fabricated WindowTitle
|
||||
char pszOldWindowTitle[1024]; // Contains original WindowTitle
|
||||
|
||||
// Fetch current window title.
|
||||
GetConsoleTitle( pszOldWindowTitle, 1024 );
|
||||
|
||||
// Format a "unique" NewWindowTitle.
|
||||
wsprintf( pszNewWindowTitle,"%d/%d", GetTickCount(), GetCurrentProcessId() );
|
||||
|
||||
// Change current window title.
|
||||
SetConsoleTitle(pszNewWindowTitle);
|
||||
|
||||
// Ensure window title has been updated.
|
||||
Sleep(40);
|
||||
|
||||
// Look for NewWindowTitle.
|
||||
hwndFound = FindWindow( NULL, pszNewWindowTitle );
|
||||
|
||||
// Restore original window title.
|
||||
|
||||
SetConsoleTitle( pszOldWindowTitle );
|
||||
|
||||
return hwndFound;
|
||||
}
|
||||
|
||||
CTextConsoleWin32::CTextConsoleWin32()
|
||||
{
|
||||
hinput = NULL;
|
||||
houtput = NULL;
|
||||
Attrib = 0;
|
||||
statusline[0] = '\0';
|
||||
}
|
||||
|
||||
bool CTextConsoleWin32::Init()
|
||||
{
|
||||
(void) AllocConsole();
|
||||
SetTitle( "SOURCE DEDICATED SERVER" );
|
||||
|
||||
hinput = GetStdHandle ( STD_INPUT_HANDLE );
|
||||
houtput = GetStdHandle ( STD_OUTPUT_HANDLE );
|
||||
|
||||
if ( !SetConsoleCtrlHandler( &ConsoleHandlerRoutine, TRUE) )
|
||||
{
|
||||
Print( "WARNING! TextConsole::Init: Could not attach console hook.\n" );
|
||||
}
|
||||
|
||||
Attrib = FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY ;
|
||||
|
||||
SetWindowPos( GetConsoleHwnd(), HWND_TOP, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_SHOWWINDOW );
|
||||
|
||||
memset( m_szConsoleText, 0, sizeof( m_szConsoleText ) );
|
||||
m_nConsoleTextLen = 0;
|
||||
m_nCursorPosition = 0;
|
||||
|
||||
memset( m_szSavedConsoleText, 0, sizeof( m_szSavedConsoleText ) );
|
||||
m_nSavedConsoleTextLen = 0;
|
||||
|
||||
memset( m_aszLineBuffer, 0, sizeof( m_aszLineBuffer ) );
|
||||
m_nTotalLines = 0;
|
||||
m_nInputLine = 0;
|
||||
m_nBrowseLine = 0;
|
||||
|
||||
// these are log messages, not related to console
|
||||
Msg( "\n" );
|
||||
Msg( "Console initialized.\n" );
|
||||
|
||||
return CTextConsole::Init();
|
||||
}
|
||||
|
||||
void CTextConsoleWin32::ShutDown( void )
|
||||
{
|
||||
FreeConsole();
|
||||
}
|
||||
|
||||
void CTextConsoleWin32::SetVisible( bool visible )
|
||||
{
|
||||
ShowWindow ( GetConsoleHwnd(), visible ? SW_SHOW : SW_HIDE );
|
||||
m_ConsoleVisible = visible;
|
||||
}
|
||||
|
||||
char * CTextConsoleWin32::GetLine( int index, char *buf, int buflen )
|
||||
{
|
||||
while ( 1 )
|
||||
{
|
||||
INPUT_RECORD recs[ 1024 ];
|
||||
unsigned long numread;
|
||||
unsigned long numevents;
|
||||
|
||||
if ( !GetNumberOfConsoleInputEvents( hinput, &numevents ) )
|
||||
{
|
||||
Error("CTextConsoleWin32::GetLine: !GetNumberOfConsoleInputEvents");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( numevents <= 0 )
|
||||
break;
|
||||
|
||||
if ( !ReadConsoleInput( hinput, recs, ARRAYSIZE( recs ), &numread ) )
|
||||
{
|
||||
Error("CTextConsoleWin32::GetLine: !ReadConsoleInput");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if ( numread == 0 )
|
||||
return NULL;
|
||||
|
||||
for ( int i=0; i < (int)numread; i++ )
|
||||
{
|
||||
INPUT_RECORD *pRec = &recs[i];
|
||||
if ( pRec->EventType != KEY_EVENT )
|
||||
continue;
|
||||
|
||||
if ( pRec->Event.KeyEvent.bKeyDown )
|
||||
{
|
||||
// check for cursor keys
|
||||
if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_UP )
|
||||
{
|
||||
ReceiveUpArrow();
|
||||
}
|
||||
else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_DOWN )
|
||||
{
|
||||
ReceiveDownArrow();
|
||||
}
|
||||
else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_LEFT )
|
||||
{
|
||||
ReceiveLeftArrow();
|
||||
}
|
||||
else if ( pRec->Event.KeyEvent.wVirtualKeyCode == VK_RIGHT )
|
||||
{
|
||||
ReceiveRightArrow();
|
||||
}
|
||||
else
|
||||
{
|
||||
char ch;
|
||||
int nLen;
|
||||
|
||||
ch = pRec->Event.KeyEvent.uChar.AsciiChar;
|
||||
switch ( ch )
|
||||
{
|
||||
case '\r': // Enter
|
||||
nLen = ReceiveNewline();
|
||||
if ( nLen )
|
||||
{
|
||||
strncpy( buf, m_szConsoleText, buflen );
|
||||
buf[ buflen - 1 ] = 0;
|
||||
return buf;
|
||||
}
|
||||
break;
|
||||
|
||||
case '\b': // Backspace
|
||||
ReceiveBackspace();
|
||||
break;
|
||||
|
||||
case '\t': // TAB
|
||||
ReceiveTab();
|
||||
break;
|
||||
|
||||
default:
|
||||
if ( ( ch >= ' ') && ( ch <= '~' ) ) // dont' accept nonprintable chars
|
||||
{
|
||||
ReceiveStandardChar( ch );
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void CTextConsoleWin32::Print( char * pszMsg )
|
||||
{
|
||||
if ( m_nConsoleTextLen )
|
||||
{
|
||||
int nLen;
|
||||
|
||||
nLen = m_nConsoleTextLen;
|
||||
|
||||
while ( nLen-- )
|
||||
{
|
||||
PrintRaw( "\b \b" );
|
||||
}
|
||||
}
|
||||
|
||||
PrintRaw( pszMsg );
|
||||
|
||||
if ( m_nConsoleTextLen )
|
||||
{
|
||||
PrintRaw( m_szConsoleText, m_nConsoleTextLen );
|
||||
}
|
||||
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
void CTextConsoleWin32::PrintRaw( const char * pszMsg, int nChars )
|
||||
{
|
||||
unsigned long dummy;
|
||||
|
||||
if ( houtput == NULL )
|
||||
{
|
||||
houtput = GetStdHandle ( STD_OUTPUT_HANDLE );
|
||||
if ( houtput == NULL )
|
||||
return;
|
||||
}
|
||||
|
||||
if ( nChars <= 0 )
|
||||
{
|
||||
nChars = strlen( pszMsg );
|
||||
if ( nChars <= 0 )
|
||||
return;
|
||||
}
|
||||
|
||||
// filter out ASCII BEL characters because windows actually plays a
|
||||
// bell sound, which can be used to lag the server in a DOS attack.
|
||||
char * pTempBuf = NULL;
|
||||
for ( int i = 0; i < nChars; ++i )
|
||||
{
|
||||
if ( pszMsg[i] == 0x07 /*BEL*/ )
|
||||
{
|
||||
if ( !pTempBuf )
|
||||
{
|
||||
pTempBuf = ( char * ) malloc( nChars );
|
||||
memcpy( pTempBuf, pszMsg, nChars );
|
||||
}
|
||||
pTempBuf[i] = '.';
|
||||
}
|
||||
}
|
||||
|
||||
WriteFile( houtput, pTempBuf ? pTempBuf : pszMsg, nChars, &dummy, NULL );
|
||||
|
||||
free( pTempBuf ); // usually NULL
|
||||
}
|
||||
|
||||
int CTextConsoleWin32::GetWidth( void )
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO csbi;
|
||||
int nWidth;
|
||||
|
||||
nWidth = 0;
|
||||
|
||||
if ( GetConsoleScreenBufferInfo( houtput, &csbi ) )
|
||||
{
|
||||
nWidth = csbi.dwSize.X;
|
||||
}
|
||||
|
||||
if ( nWidth <= 1 )
|
||||
nWidth = 80;
|
||||
|
||||
return nWidth;
|
||||
}
|
||||
|
||||
void CTextConsoleWin32::SetStatusLine( char * pszStatus )
|
||||
{
|
||||
strncpy( statusline, pszStatus, 80 );
|
||||
statusline[ 79 ] = '\0';
|
||||
UpdateStatus();
|
||||
}
|
||||
|
||||
void CTextConsoleWin32::UpdateStatus( void )
|
||||
{
|
||||
COORD coord;
|
||||
DWORD dwWritten = 0;
|
||||
WORD wAttrib[ 80 ];
|
||||
|
||||
for ( int i = 0; i < 80; i++ )
|
||||
{
|
||||
wAttrib[i] = Attrib; //FOREGROUND_GREEN | FOREGROUND_INTENSITY | BACKGROUND_INTENSITY ;
|
||||
}
|
||||
|
||||
coord.X = coord.Y = 0;
|
||||
|
||||
WriteConsoleOutputAttribute( houtput, wAttrib, 80, coord, &dwWritten );
|
||||
WriteConsoleOutputCharacter( houtput, statusline, 80, coord, &dwWritten );
|
||||
}
|
||||
|
||||
|
||||
void CTextConsoleWin32::SetTitle( char * pszTitle )
|
||||
{
|
||||
SetConsoleTitle( pszTitle );
|
||||
}
|
||||
|
||||
void CTextConsoleWin32::SetColor(WORD attrib)
|
||||
{
|
||||
Attrib = attrib;
|
||||
}
|
||||
|
||||
int CTextConsoleWin32::ReceiveNewline( void )
|
||||
{
|
||||
int nLen = 0;
|
||||
|
||||
PrintRaw( "\n" );
|
||||
|
||||
if ( m_nConsoleTextLen )
|
||||
{
|
||||
nLen = m_nConsoleTextLen;
|
||||
|
||||
m_szConsoleText[ m_nConsoleTextLen ] = 0;
|
||||
m_nConsoleTextLen = 0;
|
||||
m_nCursorPosition = 0;
|
||||
|
||||
// cache line in buffer, but only if it's not a duplicate of the previous line
|
||||
if ( ( m_nInputLine == 0 ) || ( strcmp( m_aszLineBuffer[ m_nInputLine - 1 ], m_szConsoleText ) ) )
|
||||
{
|
||||
strncpy( m_aszLineBuffer[ m_nInputLine ], m_szConsoleText, MAX_CONSOLE_TEXTLEN );
|
||||
|
||||
m_nInputLine++;
|
||||
|
||||
if ( m_nInputLine > m_nTotalLines )
|
||||
m_nTotalLines = m_nInputLine;
|
||||
|
||||
if ( m_nInputLine >= MAX_BUFFER_LINES )
|
||||
m_nInputLine = 0;
|
||||
|
||||
}
|
||||
|
||||
m_nBrowseLine = m_nInputLine;
|
||||
}
|
||||
|
||||
return nLen;
|
||||
}
|
||||
|
||||
|
||||
void CTextConsoleWin32::ReceiveBackspace( void )
|
||||
{
|
||||
int nCount;
|
||||
|
||||
if ( m_nCursorPosition == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_nConsoleTextLen--;
|
||||
m_nCursorPosition--;
|
||||
|
||||
PrintRaw( "\b" );
|
||||
|
||||
for ( nCount = m_nCursorPosition; nCount < m_nConsoleTextLen; nCount++ )
|
||||
{
|
||||
m_szConsoleText[ nCount ] = m_szConsoleText[ nCount + 1 ];
|
||||
PrintRaw( m_szConsoleText + nCount, 1 );
|
||||
}
|
||||
|
||||
PrintRaw( " " );
|
||||
|
||||
nCount = m_nConsoleTextLen;
|
||||
while ( nCount >= m_nCursorPosition )
|
||||
{
|
||||
PrintRaw( "\b" );
|
||||
nCount--;
|
||||
}
|
||||
|
||||
m_nBrowseLine = m_nInputLine;
|
||||
}
|
||||
|
||||
|
||||
void CTextConsoleWin32::ReceiveTab( void )
|
||||
{
|
||||
CUtlVector<char *> matches;
|
||||
|
||||
m_szConsoleText[ m_nConsoleTextLen ] = 0;
|
||||
|
||||
if ( matches.Count() == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( matches.Count() == 1 )
|
||||
{
|
||||
char * pszCmdName;
|
||||
char * pszRest;
|
||||
|
||||
pszCmdName = matches[0];
|
||||
pszRest = pszCmdName + strlen( m_szConsoleText );
|
||||
|
||||
if ( pszRest )
|
||||
{
|
||||
PrintRaw( pszRest );
|
||||
strcat( m_szConsoleText, pszRest );
|
||||
m_nConsoleTextLen += strlen( pszRest );
|
||||
|
||||
PrintRaw( " " );
|
||||
strcat( m_szConsoleText, " " );
|
||||
m_nConsoleTextLen++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
int nLongestCmd;
|
||||
int nTotalColumns;
|
||||
int nCurrentColumn;
|
||||
char * pszCurrentCmd;
|
||||
int i = 0;
|
||||
|
||||
nLongestCmd = 0;
|
||||
|
||||
pszCurrentCmd = matches[0];
|
||||
while ( pszCurrentCmd )
|
||||
{
|
||||
if ( (int)strlen( pszCurrentCmd) > nLongestCmd )
|
||||
{
|
||||
nLongestCmd = strlen( pszCurrentCmd);
|
||||
}
|
||||
|
||||
i++;
|
||||
pszCurrentCmd = (char *)matches[i];
|
||||
}
|
||||
|
||||
nTotalColumns = ( GetWidth() - 1 ) / ( nLongestCmd + 1 );
|
||||
nCurrentColumn = 0;
|
||||
|
||||
PrintRaw( "\n" );
|
||||
|
||||
// Would be nice if these were sorted, but not that big a deal
|
||||
pszCurrentCmd = matches[0];
|
||||
i = 0;
|
||||
while ( pszCurrentCmd )
|
||||
{
|
||||
char szFormatCmd[ 256 ];
|
||||
|
||||
nCurrentColumn++;
|
||||
|
||||
if ( nCurrentColumn > nTotalColumns )
|
||||
{
|
||||
PrintRaw( "\n" );
|
||||
nCurrentColumn = 1;
|
||||
}
|
||||
|
||||
Q_snprintf( szFormatCmd, sizeof(szFormatCmd), "%-*s ", nLongestCmd, pszCurrentCmd );
|
||||
PrintRaw( szFormatCmd );
|
||||
|
||||
i++;
|
||||
pszCurrentCmd = matches[i];
|
||||
}
|
||||
|
||||
PrintRaw( "\n" );
|
||||
PrintRaw( m_szConsoleText );
|
||||
// TODO: Tack on 'common' chars in all the matches, i.e. if I typed 'con' and all the
|
||||
// matches begin with 'connect_' then print the matches but also complete the
|
||||
// command up to that point at least.
|
||||
}
|
||||
|
||||
m_nCursorPosition = m_nConsoleTextLen;
|
||||
m_nBrowseLine = m_nInputLine;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void CTextConsoleWin32::ReceiveStandardChar( const char ch )
|
||||
{
|
||||
int nCount;
|
||||
|
||||
// If the line buffer is maxed out, ignore this char
|
||||
if ( m_nConsoleTextLen >= ( sizeof( m_szConsoleText ) - 2 ) )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
nCount = m_nConsoleTextLen;
|
||||
while ( nCount > m_nCursorPosition )
|
||||
{
|
||||
m_szConsoleText[ nCount ] = m_szConsoleText[ nCount - 1 ];
|
||||
nCount--;
|
||||
}
|
||||
|
||||
m_szConsoleText[ m_nCursorPosition ] = ch;
|
||||
|
||||
PrintRaw( m_szConsoleText + m_nCursorPosition, m_nConsoleTextLen - m_nCursorPosition + 1 );
|
||||
|
||||
m_nConsoleTextLen++;
|
||||
m_nCursorPosition++;
|
||||
|
||||
nCount = m_nConsoleTextLen;
|
||||
while ( nCount > m_nCursorPosition )
|
||||
{
|
||||
PrintRaw( "\b" );
|
||||
nCount--;
|
||||
}
|
||||
|
||||
m_nBrowseLine = m_nInputLine;
|
||||
}
|
||||
|
||||
|
||||
void CTextConsoleWin32::ReceiveUpArrow( void )
|
||||
{
|
||||
int nLastCommandInHistory;
|
||||
|
||||
nLastCommandInHistory = m_nInputLine + 1;
|
||||
if ( nLastCommandInHistory > m_nTotalLines )
|
||||
{
|
||||
nLastCommandInHistory = 0;
|
||||
}
|
||||
|
||||
if ( m_nBrowseLine == nLastCommandInHistory )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if ( m_nBrowseLine == m_nInputLine )
|
||||
{
|
||||
if ( m_nConsoleTextLen > 0 )
|
||||
{
|
||||
// Save off current text
|
||||
strncpy( m_szSavedConsoleText, m_szConsoleText, m_nConsoleTextLen );
|
||||
// No terminator, it's a raw buffer we always know the length of
|
||||
}
|
||||
|
||||
m_nSavedConsoleTextLen = m_nConsoleTextLen;
|
||||
}
|
||||
|
||||
m_nBrowseLine--;
|
||||
if ( m_nBrowseLine < 0 )
|
||||
{
|
||||
m_nBrowseLine = m_nTotalLines - 1;
|
||||
}
|
||||
|
||||
while ( m_nConsoleTextLen-- ) // delete old line
|
||||
{
|
||||
PrintRaw( "\b \b" );
|
||||
}
|
||||
|
||||
// copy buffered line
|
||||
PrintRaw( m_aszLineBuffer[ m_nBrowseLine ] );
|
||||
|
||||
strncpy( m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN );
|
||||
m_nConsoleTextLen = strlen( m_aszLineBuffer[ m_nBrowseLine ] );
|
||||
|
||||
m_nCursorPosition = m_nConsoleTextLen;
|
||||
}
|
||||
|
||||
|
||||
void CTextConsoleWin32::ReceiveDownArrow( void )
|
||||
{
|
||||
if ( m_nBrowseLine == m_nInputLine )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
m_nBrowseLine++;
|
||||
if ( m_nBrowseLine > m_nTotalLines )
|
||||
{
|
||||
m_nBrowseLine = 0;
|
||||
}
|
||||
|
||||
while ( m_nConsoleTextLen-- ) // delete old line
|
||||
{
|
||||
PrintRaw( "\b \b" );
|
||||
}
|
||||
|
||||
if ( m_nBrowseLine == m_nInputLine )
|
||||
{
|
||||
if ( m_nSavedConsoleTextLen > 0 )
|
||||
{
|
||||
// Restore current text
|
||||
strncpy( m_szConsoleText, m_szSavedConsoleText, m_nSavedConsoleTextLen );
|
||||
// No terminator, it's a raw buffer we always know the length of
|
||||
|
||||
PrintRaw( m_szConsoleText, m_nSavedConsoleTextLen );
|
||||
}
|
||||
|
||||
m_nConsoleTextLen = m_nSavedConsoleTextLen;
|
||||
}
|
||||
else
|
||||
{
|
||||
// copy buffered line
|
||||
PrintRaw( m_aszLineBuffer[ m_nBrowseLine ] );
|
||||
|
||||
strncpy( m_szConsoleText, m_aszLineBuffer[ m_nBrowseLine ], MAX_CONSOLE_TEXTLEN );
|
||||
|
||||
m_nConsoleTextLen = strlen( m_aszLineBuffer[ m_nBrowseLine ] );
|
||||
}
|
||||
|
||||
m_nCursorPosition = m_nConsoleTextLen;
|
||||
}
|
||||
|
||||
|
||||
void CTextConsoleWin32::ReceiveLeftArrow( void )
|
||||
{
|
||||
if ( m_nCursorPosition == 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PrintRaw( "\b" );
|
||||
m_nCursorPosition--;
|
||||
}
|
||||
|
||||
|
||||
void CTextConsoleWin32::ReceiveRightArrow( void )
|
||||
{
|
||||
if ( m_nCursorPosition == m_nConsoleTextLen )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
PrintRaw( m_szConsoleText + m_nCursorPosition, 1 );
|
||||
m_nCursorPosition++;
|
||||
}
|
||||
|
||||
#endif // _WIN32
|
||||
@@ -0,0 +1,82 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// TextConsoleWin32.h: Win32 interface for the TextConsole class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#if !defined TEXTCONSOLE_WIN32_H
|
||||
#define TEXTCONSOLE_WIN32_H
|
||||
#pragma once
|
||||
|
||||
#ifdef _WIN32
|
||||
|
||||
#include <windows.h>
|
||||
#include "TextConsole.h"
|
||||
|
||||
#define MAX_CONSOLE_TEXTLEN 256
|
||||
#define MAX_BUFFER_LINES 30
|
||||
|
||||
class CTextConsoleWin32 : public CTextConsole
|
||||
{
|
||||
public:
|
||||
CTextConsoleWin32();
|
||||
virtual ~CTextConsoleWin32() { };
|
||||
|
||||
// CTextConsole
|
||||
bool Init();
|
||||
void ShutDown( void );
|
||||
void Print( char *pszMsg );
|
||||
|
||||
void SetTitle( char * pszTitle );
|
||||
void SetStatusLine( char * pszStatus );
|
||||
void UpdateStatus( void );
|
||||
|
||||
char * GetLine( int index, char *buf, int buflen );
|
||||
int GetWidth( void );
|
||||
|
||||
void SetVisible( bool visible );
|
||||
|
||||
protected:
|
||||
// CTextConsoleWin32
|
||||
void SetColor( WORD );
|
||||
void PrintRaw( const char * pszMsg, int nChars = -1 );
|
||||
|
||||
private:
|
||||
char m_szConsoleText[ MAX_CONSOLE_TEXTLEN ]; // console text buffer
|
||||
int m_nConsoleTextLen; // console textbuffer length
|
||||
int m_nCursorPosition; // position in the current input line
|
||||
|
||||
// Saved input data when scrolling back through command history
|
||||
char m_szSavedConsoleText[ MAX_CONSOLE_TEXTLEN ]; // console text buffer
|
||||
int m_nSavedConsoleTextLen; // console textbuffer length
|
||||
|
||||
char m_aszLineBuffer[ MAX_BUFFER_LINES ][ MAX_CONSOLE_TEXTLEN ]; // command buffer last MAX_BUFFER_LINES commands
|
||||
int m_nInputLine; // Current line being entered
|
||||
int m_nBrowseLine; // current buffer line for up/down arrow
|
||||
int m_nTotalLines; // # of nonempty lines in the buffer
|
||||
|
||||
int ReceiveNewline( void );
|
||||
void ReceiveBackspace( void );
|
||||
void ReceiveTab( void );
|
||||
void ReceiveStandardChar( const char ch );
|
||||
void ReceiveUpArrow( void );
|
||||
void ReceiveDownArrow( void );
|
||||
void ReceiveLeftArrow( void );
|
||||
void ReceiveRightArrow( void );
|
||||
|
||||
private:
|
||||
HANDLE hinput; // standard input handle
|
||||
HANDLE houtput; // standard output handle
|
||||
WORD Attrib; // attrib colours for status bar
|
||||
|
||||
char statusline[81]; // first line in console is status line
|
||||
};
|
||||
|
||||
#endif // _WIN32
|
||||
|
||||
#endif // !defined TEXTCONSOLE_WIN32_H
|
||||
@@ -0,0 +1,428 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
#ifdef _WIN32
|
||||
// conproc.c -- support for qhost
|
||||
#include <stdio.h>
|
||||
#include <process.h>
|
||||
#include <windows.h>
|
||||
#include "conproc.h"
|
||||
#include "isys.h"
|
||||
#include "tier0/icommandline.h"
|
||||
#include "tier1/strtools.h"
|
||||
|
||||
static HANDLE heventDone;
|
||||
static HANDLE hfileBuffer;
|
||||
static HANDLE heventChildSend;
|
||||
static HANDLE heventParentSend;
|
||||
static HANDLE hStdout;
|
||||
static HANDLE hStdin;
|
||||
|
||||
/*
|
||||
==============
|
||||
SetConsoleCXCY
|
||||
|
||||
==============
|
||||
*/
|
||||
BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
COORD coordMax;
|
||||
|
||||
coordMax = GetLargestConsoleWindowSize(hStdout);
|
||||
|
||||
if (cy > coordMax.Y)
|
||||
cy = coordMax.Y;
|
||||
|
||||
if (cx > coordMax.X)
|
||||
cx = coordMax.X;
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(hStdout, &info))
|
||||
return FALSE;
|
||||
|
||||
// height
|
||||
info.srWindow.Left = 0;
|
||||
info.srWindow.Right = info.dwSize.X - 1;
|
||||
info.srWindow.Top = 0;
|
||||
info.srWindow.Bottom = cy - 1;
|
||||
|
||||
if (cy < info.dwSize.Y)
|
||||
{
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
|
||||
info.dwSize.Y = cy;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
}
|
||||
else if (cy > info.dwSize.Y)
|
||||
{
|
||||
info.dwSize.Y = cy;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!GetConsoleScreenBufferInfo(hStdout, &info))
|
||||
return FALSE;
|
||||
|
||||
// width
|
||||
info.srWindow.Left = 0;
|
||||
info.srWindow.Right = cx - 1;
|
||||
info.srWindow.Top = 0;
|
||||
info.srWindow.Bottom = info.dwSize.Y - 1;
|
||||
|
||||
if (cx < info.dwSize.X)
|
||||
{
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
|
||||
info.dwSize.X = cx;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
}
|
||||
else if (cx > info.dwSize.X)
|
||||
{
|
||||
info.dwSize.X = cx;
|
||||
|
||||
if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
|
||||
return FALSE;
|
||||
|
||||
if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow))
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
GetMappedBuffer
|
||||
|
||||
==============
|
||||
*/
|
||||
LPVOID GetMappedBuffer (HANDLE hfileBuffer)
|
||||
{
|
||||
LPVOID pBuffer;
|
||||
|
||||
pBuffer = MapViewOfFile (hfileBuffer,
|
||||
FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
|
||||
|
||||
return pBuffer;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
ReleaseMappedBuffer
|
||||
|
||||
==============
|
||||
*/
|
||||
void ReleaseMappedBuffer (LPVOID pBuffer)
|
||||
{
|
||||
UnmapViewOfFile (pBuffer);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
GetScreenBufferLines
|
||||
|
||||
==============
|
||||
*/
|
||||
BOOL GetScreenBufferLines (int *piLines)
|
||||
{
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
BOOL bRet;
|
||||
|
||||
bRet = GetConsoleScreenBufferInfo (hStdout, &info);
|
||||
|
||||
if (bRet)
|
||||
*piLines = info.dwSize.Y;
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
SetScreenBufferLines
|
||||
|
||||
==============
|
||||
*/
|
||||
BOOL SetScreenBufferLines (int iLines)
|
||||
{
|
||||
return SetConsoleCXCY (hStdout, 80, iLines);
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
ReadText
|
||||
|
||||
==============
|
||||
*/
|
||||
BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine)
|
||||
{
|
||||
COORD coord;
|
||||
DWORD dwRead;
|
||||
BOOL bRet;
|
||||
|
||||
coord.X = 0;
|
||||
coord.Y = iBeginLine;
|
||||
|
||||
bRet = ReadConsoleOutputCharacter(
|
||||
hStdout,
|
||||
pszText,
|
||||
80 * (iEndLine - iBeginLine + 1),
|
||||
coord,
|
||||
&dwRead);
|
||||
|
||||
// Make sure it's null terminated.
|
||||
if (bRet)
|
||||
pszText[dwRead] = '\0';
|
||||
|
||||
return bRet;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
CharToCode
|
||||
|
||||
==============
|
||||
*/
|
||||
int CharToCode (char c)
|
||||
{
|
||||
char upper;
|
||||
|
||||
upper = toupper(c);
|
||||
|
||||
switch (c)
|
||||
{
|
||||
case 13:
|
||||
return 28;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (V_isalpha(c))
|
||||
return (30 + upper - 65);
|
||||
|
||||
if (V_isdigit(c))
|
||||
return (1 + upper - 47);
|
||||
|
||||
return c;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
WriteText
|
||||
|
||||
==============
|
||||
*/
|
||||
BOOL WriteText (LPCTSTR szText)
|
||||
{
|
||||
DWORD dwWritten;
|
||||
INPUT_RECORD rec;
|
||||
char upper, *sz;
|
||||
|
||||
sz = (LPTSTR) szText;
|
||||
|
||||
while (*sz)
|
||||
{
|
||||
// 13 is the code for a carriage return (\n) instead of 10.
|
||||
if (*sz == 10)
|
||||
*sz = 13;
|
||||
|
||||
upper = toupper(*sz);
|
||||
|
||||
rec.EventType = KEY_EVENT;
|
||||
rec.Event.KeyEvent.bKeyDown = TRUE;
|
||||
rec.Event.KeyEvent.wRepeatCount = 1;
|
||||
rec.Event.KeyEvent.wVirtualKeyCode = upper;
|
||||
rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz);
|
||||
rec.Event.KeyEvent.uChar.AsciiChar = *sz;
|
||||
rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
|
||||
rec.Event.KeyEvent.dwControlKeyState = V_isupper(*sz) ? 0x80 : 0x0;
|
||||
|
||||
WriteConsoleInput(
|
||||
hStdin,
|
||||
&rec,
|
||||
1,
|
||||
&dwWritten);
|
||||
|
||||
rec.Event.KeyEvent.bKeyDown = FALSE;
|
||||
|
||||
WriteConsoleInput(
|
||||
hStdin,
|
||||
&rec,
|
||||
1,
|
||||
&dwWritten);
|
||||
|
||||
sz++;
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
RequestProc
|
||||
|
||||
==============
|
||||
*/
|
||||
unsigned _stdcall RequestProc (void *arg)
|
||||
{
|
||||
int *pBuffer;
|
||||
DWORD dwRet;
|
||||
HANDLE heventWait[2];
|
||||
int iBeginLine, iEndLine;
|
||||
|
||||
heventWait[0] = heventParentSend;
|
||||
heventWait[1] = heventDone;
|
||||
|
||||
while (1)
|
||||
{
|
||||
dwRet = WaitForMultipleObjects (2, heventWait, FALSE, INFINITE);
|
||||
|
||||
// heventDone fired, so we're exiting.
|
||||
if (dwRet == WAIT_OBJECT_0 + 1)
|
||||
break;
|
||||
|
||||
pBuffer = (int *) GetMappedBuffer (hfileBuffer);
|
||||
|
||||
// hfileBuffer is invalid. Just leave.
|
||||
if (!pBuffer)
|
||||
{
|
||||
sys->Printf ("Request Proc: Invalid -HFILE handle\n");
|
||||
break;
|
||||
}
|
||||
|
||||
switch (pBuffer[0])
|
||||
{
|
||||
case CCOM_WRITE_TEXT:
|
||||
// Param1 : Text
|
||||
pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1));
|
||||
break;
|
||||
|
||||
case CCOM_GET_TEXT:
|
||||
// Param1 : Begin line
|
||||
// Param2 : End line
|
||||
iBeginLine = pBuffer[1];
|
||||
iEndLine = pBuffer[2];
|
||||
pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine,
|
||||
iEndLine);
|
||||
break;
|
||||
|
||||
case CCOM_GET_SCR_LINES:
|
||||
// No params
|
||||
pBuffer[0] = GetScreenBufferLines (&pBuffer[1]);
|
||||
break;
|
||||
|
||||
case CCOM_SET_SCR_LINES:
|
||||
// Param1 : Number of lines
|
||||
pBuffer[0] = SetScreenBufferLines (pBuffer[1]);
|
||||
break;
|
||||
}
|
||||
|
||||
ReleaseMappedBuffer (pBuffer);
|
||||
SetEvent (heventChildSend);
|
||||
}
|
||||
|
||||
_endthreadex (0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
DeinitConProc
|
||||
|
||||
==============
|
||||
*/
|
||||
void DeinitConProc (void)
|
||||
{
|
||||
if ( heventDone )
|
||||
{
|
||||
SetEvent ( heventDone );
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
==============
|
||||
InitConProc
|
||||
|
||||
==============
|
||||
*/
|
||||
void InitConProc ( void )
|
||||
{
|
||||
unsigned threadAddr;
|
||||
HANDLE hFile = (HANDLE)0;
|
||||
HANDLE heventParent = (HANDLE)0;
|
||||
HANDLE heventChild = (HANDLE)0;
|
||||
int WantHeight = 50;
|
||||
const char *p;
|
||||
|
||||
// give external front ends a chance to hook into the console
|
||||
if ( CommandLine()->CheckParm ( "-HFILE", &p ) && p )
|
||||
{
|
||||
hFile = (HANDLE)atoi ( p );
|
||||
}
|
||||
|
||||
if ( CommandLine()->CheckParm ( "-HPARENT", &p ) && p )
|
||||
{
|
||||
heventParent = (HANDLE)atoi ( p );
|
||||
}
|
||||
|
||||
if ( CommandLine()->CheckParm ( "-HCHILD", &p ) && p )
|
||||
{
|
||||
heventChild = (HANDLE)atoi ( p );
|
||||
}
|
||||
|
||||
// ignore if we don't have all the events.
|
||||
if ( !hFile || !heventParent || !heventChild )
|
||||
{
|
||||
//sys->Printf ("\n\nNo external front end present.\n" );
|
||||
return;
|
||||
}
|
||||
|
||||
sys->Printf( "\n\nInitConProc: Setting up external control.\n" );
|
||||
|
||||
hfileBuffer = hFile;
|
||||
heventParentSend = heventParent;
|
||||
heventChildSend = heventChild;
|
||||
|
||||
// So we'll know when to go away.
|
||||
heventDone = CreateEvent (NULL, FALSE, FALSE, NULL);
|
||||
if (!heventDone)
|
||||
{
|
||||
sys->Printf ("InitConProc: Couldn't create heventDone\n");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!_beginthreadex (NULL, 0, RequestProc, NULL, 0, &threadAddr))
|
||||
{
|
||||
CloseHandle (heventDone);
|
||||
sys->Printf ("InitConProc: Couldn't create third party thread\n");
|
||||
return;
|
||||
}
|
||||
|
||||
// save off the input/output handles.
|
||||
hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
|
||||
hStdin = GetStdHandle (STD_INPUT_HANDLE);
|
||||
|
||||
if ( CommandLine()->CheckParm( "-conheight", &p ) && p )
|
||||
{
|
||||
WantHeight = atoi( p );
|
||||
}
|
||||
|
||||
// Force 80 character width, at least 25 character height
|
||||
SetConsoleCXCY( hStdout, 80, WantHeight );
|
||||
}
|
||||
#endif // _WIN32
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// conproc.h -- support for external server monitoring programs
|
||||
#ifndef INC_CONPROCH
|
||||
#define INC_CONPROCH
|
||||
|
||||
#define CCOM_WRITE_TEXT 0x2
|
||||
// Param1 : Text
|
||||
|
||||
#define CCOM_GET_TEXT 0x3
|
||||
// Param1 : Begin line
|
||||
// Param2 : End line
|
||||
|
||||
#define CCOM_GET_SCR_LINES 0x4
|
||||
// No params
|
||||
|
||||
#define CCOM_SET_SCR_LINES 0x5
|
||||
// Param1 : Number of lines
|
||||
|
||||
void InitConProc ( void );
|
||||
void DeinitConProc ( void );
|
||||
|
||||
void WriteStatusText( char *psz );
|
||||
|
||||
#endif // !INC_CONPROCH
|
||||
@@ -0,0 +1,22 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
// TextConsole.cpp: implementation of the TextConsole class.
|
||||
//
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "textconsole.h"
|
||||
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
// Construction/Destruction
|
||||
//////////////////////////////////////////////////////////////////////
|
||||
|
||||
bool CTextConsole::Init()
|
||||
{
|
||||
m_ConsoleVisible = true;
|
||||
return true;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
//========= Copyright Valve Corporation, All rights reserved. ============//
|
||||
//
|
||||
// Purpose:
|
||||
//
|
||||
// $NoKeywords: $
|
||||
//
|
||||
//=============================================================================//
|
||||
|
||||
#if !defined TEXTCONSOLE_H
|
||||
#define TEXTCONSOLE_H
|
||||
#pragma once
|
||||
|
||||
class CTextConsole
|
||||
{
|
||||
public:
|
||||
CTextConsole() : m_ConsoleVisible( true ) {}
|
||||
virtual ~CTextConsole() {};
|
||||
|
||||
virtual bool Init ();
|
||||
virtual void ShutDown() = 0;
|
||||
virtual void Print( char * pszMsg ) = 0;
|
||||
|
||||
virtual void SetTitle( char * pszTitle ) = 0;
|
||||
virtual void SetStatusLine( char * pszStatus ) = 0;
|
||||
virtual void UpdateStatus() = 0;
|
||||
|
||||
// Must be provided by children
|
||||
virtual char * GetLine( int index, char *buf, int buflen ) = 0;
|
||||
virtual int GetWidth() = 0;
|
||||
|
||||
virtual void SetVisible( bool visible ) { m_ConsoleVisible = visible; }
|
||||
virtual bool IsVisible() { return m_ConsoleVisible; }
|
||||
|
||||
protected:
|
||||
bool m_ConsoleVisible;
|
||||
};
|
||||
|
||||
#endif // !defined TEXTCONSOLE_H
|
||||
Reference in New Issue
Block a user