summaryrefslogtreecommitdiff
path: root/dedicated/console/TextConsoleWin32.cpp
diff options
context:
space:
mode:
authorFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
committerFluorescentCIAAfricanAmerican <[email protected]>2020-04-22 12:56:21 -0400
commit3bf9df6b2785fa6d951086978a3e66f49427166a (patch)
tree2c0f1f0c63c4832882bc93814ebd2c2b1c6224e5 /dedicated/console/TextConsoleWin32.cpp
downloadarchived-source-engine-2018-hl2-src-master.tar.xz
archived-source-engine-2018-hl2-src-master.zip
Diffstat (limited to 'dedicated/console/TextConsoleWin32.cpp')
-rw-r--r--dedicated/console/TextConsoleWin32.cpp644
1 files changed, 644 insertions, 0 deletions
diff --git a/dedicated/console/TextConsoleWin32.cpp b/dedicated/console/TextConsoleWin32.cpp
new file mode 100644
index 0000000..ece1eff
--- /dev/null
+++ b/dedicated/console/TextConsoleWin32.cpp
@@ -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