2 ===========================================================================
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
26 ===========================================================================
29 #include "../../idlib/precompiled.h"
40 #include "win_local.h"
41 #include "rc/AFEditor_resource.h"
42 #include "rc/doom_resource.h"
48 #define ERRORBOX_ID 10
49 #define ERRORTEXT_ID 11
54 #define COMMAND_HISTORY 64
68 HBITMAP hbmClearBitmap;
70 HBRUSH hbrEditBackground;
71 HBRUSH hbrErrorBackground;
80 char consoleText[512], returnedText[512];
82 int windowWidth, windowHeight;
84 WNDPROC SysInputLineWndProc;
86 idEditField historyEditLines[COMMAND_HISTORY];
88 int nextHistoryLine;// the last line in the history buffer, not masked
89 int historyLine; // the line being displayed from history buffer
90 // will be <= nextHistoryLine
92 idEditField consoleField;
96 static WinConData s_wcd;
98 static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
100 static bool s_timePolarity;
104 if ( LOWORD( wParam ) != WA_INACTIVE ) {
105 SetFocus( s_wcd.hwndInputLine );
109 if ( cvarSystem->IsInitialized() && com_skipRenderer.GetBool() ) {
110 cmdString = Mem_CopyString( "quit" );
111 Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString );
112 } else if ( s_wcd.quitOnClose ) {
113 PostQuitMessage( 0 );
115 Sys_ShowConsole( 0, false );
116 win32.win_viewlog.SetBool( false );
119 case WM_CTLCOLORSTATIC:
120 if ( ( HWND ) lParam == s_wcd.hwndBuffer ) {
121 SetBkColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0x80 ) );
122 SetTextColor( ( HDC ) wParam, RGB( 0xff, 0xff, 0x00 ) );
123 return ( long ) s_wcd.hbrEditBackground;
124 } else if ( ( HWND ) lParam == s_wcd.hwndErrorBox ) {
125 if ( s_timePolarity & 1 ) {
126 SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
127 SetTextColor( ( HDC ) wParam, RGB( 0xff, 0x0, 0x00 ) );
129 SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
130 SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x0, 0x00 ) );
132 return ( long ) s_wcd.hbrErrorBackground;
136 if ( wParam == SC_CLOSE ) {
137 PostQuitMessage( 0 );
141 if ( wParam == COPY_ID ) {
142 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
143 SendMessage( s_wcd.hwndBuffer, WM_COPY, 0, 0 );
144 } else if ( wParam == QUIT_ID ) {
145 if ( s_wcd.quitOnClose ) {
146 PostQuitMessage( 0 );
148 cmdString = Mem_CopyString( "quit" );
149 Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString );
151 } else if ( wParam == CLEAR_ID ) {
152 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
153 SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, FALSE, ( LPARAM ) "" );
154 UpdateWindow( s_wcd.hwndBuffer );
158 s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0x80 ) );
159 s_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) );
160 SetTimer( hWnd, 1, 1000, NULL );
166 hdcScaled = CreateCompatibleDC( ( HDC ) wParam );
167 assert( hdcScaled != 0 );
169 oldObject = SelectObject( ( HDC ) hdcScaled, s_wcd.hbmLogo );
170 assert( oldObject != 0 );
173 StretchBlt( ( HDC ) wParam, 0, 0, s_wcd.windowWidth, s_wcd.windowHeight,
174 hdcScaled, 0, 0, 512, 384,
177 DeleteDC( hdcScaled );
184 s_timePolarity = (bool)!s_timePolarity;
185 if ( s_wcd.hwndErrorBox ) {
186 InvalidateRect( s_wcd.hwndErrorBox, NULL, FALSE );
192 return DefWindowProc( hWnd, uMsg, wParam, lParam );
195 LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
199 if ( ( HWND ) wParam == s_wcd.hWnd || ( HWND ) wParam == s_wcd.hwndErrorBox ) {
206 key = MapKey( lParam );
209 if ( ( key == K_UPARROW ) || ( key == K_KP_UPARROW ) ) {
210 if ( s_wcd.nextHistoryLine - s_wcd.historyLine < COMMAND_HISTORY && s_wcd.historyLine > 0 ) {
213 s_wcd.consoleField = s_wcd.historyEditLines[ s_wcd.historyLine % COMMAND_HISTORY ];
215 SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() );
216 SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() );
220 if ( ( key == K_DOWNARROW ) || ( key == K_KP_DOWNARROW ) ) {
221 if ( s_wcd.historyLine == s_wcd.nextHistoryLine ) {
225 s_wcd.consoleField = s_wcd.historyEditLines[ s_wcd.historyLine % COMMAND_HISTORY ];
227 SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() );
228 SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() );
234 key = MapKey( lParam );
236 GetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer(), MAX_EDIT_LINE );
237 SendMessage( s_wcd.hwndInputLine, EM_GETSEL, (WPARAM) NULL, (LPARAM) &cursor );
238 s_wcd.consoleField.SetCursor( cursor );
241 if ( key == K_ENTER || key == K_KP_ENTER ) {
242 strncat( s_wcd.consoleText, s_wcd.consoleField.GetBuffer(), sizeof( s_wcd.consoleText ) - strlen( s_wcd.consoleText ) - 5 );
243 strcat( s_wcd.consoleText, "\n" );
244 SetWindowText( s_wcd.hwndInputLine, "" );
246 Sys_Printf( "]%s\n", s_wcd.consoleField.GetBuffer() );
248 // copy line to history buffer
249 s_wcd.historyEditLines[s_wcd.nextHistoryLine % COMMAND_HISTORY] = s_wcd.consoleField;
250 s_wcd.nextHistoryLine++;
251 s_wcd.historyLine = s_wcd.nextHistoryLine;
253 s_wcd.consoleField.Clear();
258 // command completion
259 if ( key == K_TAB ) {
260 s_wcd.consoleField.AutoComplete();
262 SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() );
263 //s_wcd.consoleField.SetWidthInChars( strlen( s_wcd.consoleField.GetBuffer() ) );
264 SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() );
269 // clear autocompletion buffer on normal key input
270 if ( ( key >= K_SPACE && key <= K_BACKSPACE ) ||
271 ( key >= K_KP_SLASH && key <= K_KP_PLUS ) || ( key >= K_KP_STAR && key <= K_KP_EQUALS ) ) {
272 s_wcd.consoleField.ClearAutoComplete();
277 return CallWindowProc( s_wcd.SysInputLineWndProc, hWnd, uMsg, wParam, lParam );
283 void Sys_CreateConsole( void ) {
287 const char *DEDCLASS = WIN32_CONSOLE_CLASS;
290 int DEDSTYLE = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX;
293 memset( &wc, 0, sizeof( wc ) );
296 wc.lpfnWndProc = (WNDPROC) ConWndProc;
299 wc.hInstance = win32.hInstance;
300 wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1));
301 wc.hCursor = LoadCursor (NULL,IDC_ARROW);
302 wc.hbrBackground = (struct HBRUSH__ *)COLOR_WINDOW;
304 wc.lpszClassName = DEDCLASS;
306 if ( !RegisterClass (&wc) ) {
314 AdjustWindowRect( &rect, DEDSTYLE, FALSE );
316 hDC = GetDC( GetDesktopWindow() );
317 swidth = GetDeviceCaps( hDC, HORZRES );
318 sheight = GetDeviceCaps( hDC, VERTRES );
319 ReleaseDC( GetDesktopWindow(), hDC );
321 s_wcd.windowWidth = rect.right - rect.left + 1;
322 s_wcd.windowHeight = rect.bottom - rect.top + 1;
324 //s_wcd.hbmLogo = LoadBitmap( win32.hInstance, MAKEINTRESOURCE( IDB_BITMAP_LOGO) );
326 s_wcd.hWnd = CreateWindowEx( 0,
330 ( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1,
336 if ( s_wcd.hWnd == NULL ) {
343 hDC = GetDC( s_wcd.hWnd );
344 nHeight = -MulDiv( 8, GetDeviceCaps( hDC, LOGPIXELSY ), 72 );
346 s_wcd.hfBufferFont = CreateFont( nHeight, 0, 0, 0, FW_LIGHT, 0, 0, 0, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FF_MODERN | FIXED_PITCH, "Courier New" );
348 ReleaseDC( s_wcd.hWnd, hDC );
351 // create the input line
353 s_wcd.hwndInputLine = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER |
354 ES_LEFT | ES_AUTOHSCROLL,
357 ( HMENU ) INPUT_ID, // child window ID
358 win32.hInstance, NULL );
361 // create the buttons
363 s_wcd.hwndButtonCopy = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
366 ( HMENU ) COPY_ID, // child window ID
367 win32.hInstance, NULL );
368 SendMessage( s_wcd.hwndButtonCopy, WM_SETTEXT, 0, ( LPARAM ) "copy" );
370 s_wcd.hwndButtonClear = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
373 ( HMENU ) CLEAR_ID, // child window ID
374 win32.hInstance, NULL );
375 SendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) "clear" );
377 s_wcd.hwndButtonQuit = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
380 ( HMENU ) QUIT_ID, // child window ID
381 win32.hInstance, NULL );
382 SendMessage( s_wcd.hwndButtonQuit, WM_SETTEXT, 0, ( LPARAM ) "quit" );
386 // create the scrollbuffer
388 s_wcd.hwndBuffer = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER |
389 ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
392 ( HMENU ) EDIT_ID, // child window ID
393 win32.hInstance, NULL );
394 SendMessage( s_wcd.hwndBuffer, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
396 s_wcd.SysInputLineWndProc = ( WNDPROC ) SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, ( long ) InputLineWndProc );
397 SendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
399 // don't show it now that we have a splash screen up
400 if ( win32.win_viewlog.GetBool() ) {
401 ShowWindow( s_wcd.hWnd, SW_SHOWDEFAULT);
402 UpdateWindow( s_wcd.hWnd );
403 SetForegroundWindow( s_wcd.hWnd );
404 SetFocus( s_wcd.hwndInputLine );
409 s_wcd.consoleField.Clear();
411 for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) {
412 s_wcd.historyEditLines[i].Clear();
417 ** Sys_DestroyConsole
419 void Sys_DestroyConsole( void ) {
421 ShowWindow( s_wcd.hWnd, SW_HIDE );
422 CloseWindow( s_wcd.hWnd );
423 DestroyWindow( s_wcd.hWnd );
431 void Sys_ShowConsole( int visLevel, bool quitOnClose ) {
433 s_wcd.quitOnClose = quitOnClose;
439 switch ( visLevel ) {
441 ShowWindow( s_wcd.hWnd, SW_HIDE );
444 ShowWindow( s_wcd.hWnd, SW_SHOWNORMAL );
445 SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
448 ShowWindow( s_wcd.hWnd, SW_MINIMIZE );
451 Sys_Error( "Invalid visLevel %d sent to Sys_ShowConsole\n", visLevel );
459 char *Sys_ConsoleInput( void ) {
461 if ( s_wcd.consoleText[0] == 0 ) {
465 strcpy( s_wcd.returnedText, s_wcd.consoleText );
466 s_wcd.consoleText[0] = 0;
468 return s_wcd.returnedText;
474 void Conbuf_AppendText( const char *pMsg )
476 #define CONSOLE_BUFFER_SIZE 16384
478 char buffer[CONSOLE_BUFFER_SIZE*2];
483 static unsigned long s_totalChars;
486 // if the message is REALLY long, use just the last portion of it
488 if ( strlen( pMsg ) > CONSOLE_BUFFER_SIZE - 1 ) {
489 msg = pMsg + strlen( pMsg ) - CONSOLE_BUFFER_SIZE + 1;
495 // copy into an intermediate buffer
497 while ( msg[i] && ( ( b - buffer ) < sizeof( buffer ) - 1 ) ) {
498 if ( msg[i] == '\n' && msg[i+1] == '\r' ) {
503 } else if ( msg[i] == '\r' ) {
507 } else if ( msg[i] == '\n' ) {
511 } else if ( idStr::IsColor( &msg[i] ) ) {
522 s_totalChars += bufLen;
525 // replace selection instead of appending if we're overflowing
527 if ( s_totalChars > 0x7000 ) {
528 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
529 s_totalChars = bufLen;
533 // put this text into the windows console
535 SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
536 SendMessage( s_wcd.hwndBuffer, EM_SCROLLCARET, 0, 0 );
537 SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, 0, (LPARAM) buffer );
543 void Win_SetErrorText( const char *buf ) {
544 idStr::Copynz( s_wcd.errorString, buf, sizeof( s_wcd.errorString ) );
545 if ( !s_wcd.hwndErrorBox ) {
546 s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN,
549 ( HMENU ) ERRORBOX_ID, // child window ID
550 win32.hInstance, NULL );
551 SendMessage( s_wcd.hwndErrorBox, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
552 SetWindowText( s_wcd.hwndErrorBox, s_wcd.errorString );
554 DestroyWindow( s_wcd.hwndInputLine );
555 s_wcd.hwndInputLine = NULL;