win_syscon.cpp (15581B)
1 /* 2 =========================================================================== 3 4 Doom 3 BFG Edition GPL Source Code 5 Copyright (C) 1993-2012 id Software LLC, a ZeniMax Media company. 6 7 This file is part of the Doom 3 BFG Edition GPL Source Code ("Doom 3 BFG Edition Source Code"). 8 9 Doom 3 BFG Edition 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. 13 14 Doom 3 BFG Edition 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. 18 19 You should have received a copy of the GNU General Public License 20 along with Doom 3 BFG Edition Source Code. If not, see <http://www.gnu.org/licenses/>. 21 22 In addition, the Doom 3 BFG Edition 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 BFG Edition Source Code. If not, please request a copy in writing from id Software at the address below. 23 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. 25 26 =========================================================================== 27 */ 28 29 #pragma hdrstop 30 #include "../../idlib/precompiled.h" 31 32 #include <errno.h> 33 #include <float.h> 34 #include <fcntl.h> 35 #include <stdio.h> 36 #include <direct.h> 37 #include <io.h> 38 #include <conio.h> 39 40 #include "win_local.h" 41 #include "rc/doom_resource.h" 42 43 #define COPY_ID 1 44 #define QUIT_ID 2 45 #define CLEAR_ID 3 46 47 #define ERRORBOX_ID 10 48 #define ERRORTEXT_ID 11 49 50 #define EDIT_ID 100 51 #define INPUT_ID 101 52 53 #define COMMAND_HISTORY 64 54 55 typedef struct { 56 HWND hWnd; 57 HWND hwndBuffer; 58 59 HWND hwndButtonClear; 60 HWND hwndButtonCopy; 61 HWND hwndButtonQuit; 62 63 HWND hwndErrorBox; 64 HWND hwndErrorText; 65 66 HBITMAP hbmLogo; 67 HBITMAP hbmClearBitmap; 68 69 HBRUSH hbrEditBackground; 70 HBRUSH hbrErrorBackground; 71 72 HFONT hfBufferFont; 73 HFONT hfButtonFont; 74 75 HWND hwndInputLine; 76 77 char errorString[80]; 78 79 char consoleText[512], returnedText[512]; 80 bool quitOnClose; 81 int windowWidth, windowHeight; 82 83 WNDPROC SysInputLineWndProc; 84 85 idEditField historyEditLines[COMMAND_HISTORY]; 86 87 int nextHistoryLine;// the last line in the history buffer, not masked 88 int historyLine; // the line being displayed from history buffer 89 // will be <= nextHistoryLine 90 91 idEditField consoleField; 92 93 } WinConData; 94 95 static WinConData s_wcd; 96 97 static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 98 char *cmdString; 99 static bool s_timePolarity; 100 101 switch (uMsg) { 102 case WM_ACTIVATE: 103 if ( LOWORD( wParam ) != WA_INACTIVE ) { 104 SetFocus( s_wcd.hwndInputLine ); 105 } 106 break; 107 case WM_CLOSE: 108 if ( s_wcd.quitOnClose ) { 109 PostQuitMessage( 0 ); 110 } else { 111 Sys_ShowConsole( 0, false ); 112 win32.win_viewlog.SetBool( false ); 113 } 114 return 0; 115 case WM_CTLCOLORSTATIC: 116 if ( ( HWND ) lParam == s_wcd.hwndBuffer ) { 117 SetBkColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0x80 ) ); 118 SetTextColor( ( HDC ) wParam, RGB( 0xff, 0xff, 0x00 ) ); 119 return ( long ) s_wcd.hbrEditBackground; 120 } else if ( ( HWND ) lParam == s_wcd.hwndErrorBox ) { 121 if ( s_timePolarity & 1 ) { 122 SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) ); 123 SetTextColor( ( HDC ) wParam, RGB( 0xff, 0x0, 0x00 ) ); 124 } else { 125 SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) ); 126 SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x0, 0x00 ) ); 127 } 128 return ( long ) s_wcd.hbrErrorBackground; 129 } 130 break; 131 case WM_SYSCOMMAND: 132 if ( wParam == SC_CLOSE ) { 133 PostQuitMessage( 0 ); 134 } 135 break; 136 case WM_COMMAND: 137 if ( wParam == COPY_ID ) { 138 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 ); 139 SendMessage( s_wcd.hwndBuffer, WM_COPY, 0, 0 ); 140 } else if ( wParam == QUIT_ID ) { 141 if ( s_wcd.quitOnClose ) { 142 PostQuitMessage( 0 ); 143 } else { 144 cmdString = Mem_CopyString( "quit" ); 145 Sys_QueEvent( SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString, 0 ); 146 } 147 } else if ( wParam == CLEAR_ID ) { 148 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 ); 149 SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, FALSE, ( LPARAM ) "" ); 150 UpdateWindow( s_wcd.hwndBuffer ); 151 } 152 break; 153 case WM_CREATE: 154 s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0x80 ) ); 155 s_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) ); 156 SetTimer( hWnd, 1, 1000, NULL ); 157 break; 158 /* 159 case WM_ERASEBKGND: 160 HGDIOBJ oldObject; 161 HDC hdcScaled; 162 hdcScaled = CreateCompatibleDC( ( HDC ) wParam ); 163 assert( hdcScaled != 0 ); 164 if ( hdcScaled ) { 165 oldObject = SelectObject( ( HDC ) hdcScaled, s_wcd.hbmLogo ); 166 assert( oldObject != 0 ); 167 if ( oldObject ) 168 { 169 StretchBlt( ( HDC ) wParam, 0, 0, s_wcd.windowWidth, s_wcd.windowHeight, 170 hdcScaled, 0, 0, 512, 384, 171 SRCCOPY ); 172 } 173 DeleteDC( hdcScaled ); 174 hdcScaled = 0; 175 } 176 return 1; 177 */ 178 case WM_TIMER: 179 if ( wParam == 1 ) { 180 s_timePolarity = (bool)!s_timePolarity; 181 if ( s_wcd.hwndErrorBox ) { 182 InvalidateRect( s_wcd.hwndErrorBox, NULL, FALSE ); 183 } 184 } 185 break; 186 } 187 188 return DefWindowProc( hWnd, uMsg, wParam, lParam ); 189 } 190 191 LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { 192 int key, cursor; 193 switch ( uMsg ) { 194 case WM_KILLFOCUS: 195 if ( ( HWND ) wParam == s_wcd.hWnd || ( HWND ) wParam == s_wcd.hwndErrorBox ) { 196 SetFocus( hWnd ); 197 return 0; 198 } 199 break; 200 201 case WM_KEYDOWN: 202 key = ( ( lParam >> 16 ) & 0xFF ) | ( ( ( lParam >> 24 ) & 1 ) << 7 ); 203 204 // command history 205 if ( ( key == K_UPARROW ) || ( key == K_KP_8 ) ) { 206 if ( s_wcd.nextHistoryLine - s_wcd.historyLine < COMMAND_HISTORY && s_wcd.historyLine > 0 ) { 207 s_wcd.historyLine--; 208 } 209 s_wcd.consoleField = s_wcd.historyEditLines[ s_wcd.historyLine % COMMAND_HISTORY ]; 210 211 SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() ); 212 SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() ); 213 return 0; 214 } 215 216 if ( ( key == K_DOWNARROW ) || ( key == K_KP_2 ) ) { 217 if ( s_wcd.historyLine == s_wcd.nextHistoryLine ) { 218 return 0; 219 } 220 s_wcd.historyLine++; 221 s_wcd.consoleField = s_wcd.historyEditLines[ s_wcd.historyLine % COMMAND_HISTORY ]; 222 223 SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() ); 224 SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() ); 225 return 0; 226 } 227 break; 228 229 case WM_CHAR: 230 key = ( ( lParam >> 16 ) & 0xFF ) | ( ( ( lParam >> 24 ) & 1 ) << 7 ); 231 232 GetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer(), MAX_EDIT_LINE ); 233 SendMessage( s_wcd.hwndInputLine, EM_GETSEL, (WPARAM) NULL, (LPARAM) &cursor ); 234 s_wcd.consoleField.SetCursor( cursor ); 235 236 // enter the line 237 if ( key == K_ENTER || key == K_KP_ENTER ) { 238 strncat( s_wcd.consoleText, s_wcd.consoleField.GetBuffer(), sizeof( s_wcd.consoleText ) - strlen( s_wcd.consoleText ) - 5 ); 239 strcat( s_wcd.consoleText, "\n" ); 240 SetWindowText( s_wcd.hwndInputLine, "" ); 241 242 Sys_Printf( "]%s\n", s_wcd.consoleField.GetBuffer() ); 243 244 // copy line to history buffer 245 s_wcd.historyEditLines[s_wcd.nextHistoryLine % COMMAND_HISTORY] = s_wcd.consoleField; 246 s_wcd.nextHistoryLine++; 247 s_wcd.historyLine = s_wcd.nextHistoryLine; 248 249 s_wcd.consoleField.Clear(); 250 251 return 0; 252 } 253 254 // command completion 255 if ( key == K_TAB ) { 256 s_wcd.consoleField.AutoComplete(); 257 258 SetWindowText( s_wcd.hwndInputLine, s_wcd.consoleField.GetBuffer() ); 259 //s_wcd.consoleField.SetWidthInChars( strlen( s_wcd.consoleField.GetBuffer() ) ); 260 SendMessage( s_wcd.hwndInputLine, EM_SETSEL, s_wcd.consoleField.GetCursor(), s_wcd.consoleField.GetCursor() ); 261 262 return 0; 263 } 264 265 // clear autocompletion buffer on normal key input 266 if ( ( key >= K_SPACE && key <= K_BACKSPACE ) || 267 ( key >= K_KP_SLASH && key <= K_KP_PLUS ) || ( key >= K_KP_STAR && key <= K_KP_EQUALS ) ) { 268 s_wcd.consoleField.ClearAutoComplete(); 269 } 270 break; 271 } 272 273 return CallWindowProc( s_wcd.SysInputLineWndProc, hWnd, uMsg, wParam, lParam ); 274 } 275 276 /* 277 ** Sys_CreateConsole 278 */ 279 void Sys_CreateConsole() { 280 HDC hDC; 281 WNDCLASS wc; 282 RECT rect; 283 const char *DEDCLASS = WIN32_CONSOLE_CLASS; 284 int nHeight; 285 int swidth, sheight; 286 int DEDSTYLE = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX; 287 int i; 288 289 memset( &wc, 0, sizeof( wc ) ); 290 291 wc.style = 0; 292 wc.lpfnWndProc = (WNDPROC) ConWndProc; 293 wc.cbClsExtra = 0; 294 wc.cbWndExtra = 0; 295 wc.hInstance = win32.hInstance; 296 wc.hIcon = LoadIcon( win32.hInstance, MAKEINTRESOURCE(IDI_ICON1)); 297 wc.hCursor = LoadCursor (NULL,IDC_ARROW); 298 wc.hbrBackground = (struct HBRUSH__ *)COLOR_WINDOW; 299 wc.lpszMenuName = 0; 300 wc.lpszClassName = DEDCLASS; 301 302 if ( !RegisterClass (&wc) ) { 303 return; 304 } 305 306 rect.left = 0; 307 rect.right = 540; 308 rect.top = 0; 309 rect.bottom = 450; 310 AdjustWindowRect( &rect, DEDSTYLE, FALSE ); 311 312 hDC = GetDC( GetDesktopWindow() ); 313 swidth = GetDeviceCaps( hDC, HORZRES ); 314 sheight = GetDeviceCaps( hDC, VERTRES ); 315 ReleaseDC( GetDesktopWindow(), hDC ); 316 317 s_wcd.windowWidth = rect.right - rect.left + 1; 318 s_wcd.windowHeight = rect.bottom - rect.top + 1; 319 320 //s_wcd.hbmLogo = LoadBitmap( win32.hInstance, MAKEINTRESOURCE( IDB_BITMAP_LOGO) ); 321 322 s_wcd.hWnd = CreateWindowEx( 0, 323 DEDCLASS, 324 GAME_NAME, 325 DEDSTYLE, 326 ( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1, 327 NULL, 328 NULL, 329 win32.hInstance, 330 NULL ); 331 332 if ( s_wcd.hWnd == NULL ) { 333 return; 334 } 335 336 // 337 // create fonts 338 // 339 hDC = GetDC( s_wcd.hWnd ); 340 nHeight = -MulDiv( 8, GetDeviceCaps( hDC, LOGPIXELSY ), 72 ); 341 342 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" ); 343 344 ReleaseDC( s_wcd.hWnd, hDC ); 345 346 // 347 // create the input line 348 // 349 s_wcd.hwndInputLine = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER | 350 ES_LEFT | ES_AUTOHSCROLL, 351 6, 400, 528, 20, 352 s_wcd.hWnd, 353 ( HMENU ) INPUT_ID, // child window ID 354 win32.hInstance, NULL ); 355 356 // 357 // create the buttons 358 // 359 s_wcd.hwndButtonCopy = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 360 5, 425, 72, 24, 361 s_wcd.hWnd, 362 ( HMENU ) COPY_ID, // child window ID 363 win32.hInstance, NULL ); 364 SendMessage( s_wcd.hwndButtonCopy, WM_SETTEXT, 0, ( LPARAM ) "copy" ); 365 366 s_wcd.hwndButtonClear = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 367 82, 425, 72, 24, 368 s_wcd.hWnd, 369 ( HMENU ) CLEAR_ID, // child window ID 370 win32.hInstance, NULL ); 371 SendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) "clear" ); 372 373 s_wcd.hwndButtonQuit = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON, 374 462, 425, 72, 24, 375 s_wcd.hWnd, 376 ( HMENU ) QUIT_ID, // child window ID 377 win32.hInstance, NULL ); 378 SendMessage( s_wcd.hwndButtonQuit, WM_SETTEXT, 0, ( LPARAM ) "quit" ); 379 380 381 // 382 // create the scrollbuffer 383 // 384 s_wcd.hwndBuffer = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER | 385 ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY, 386 6, 40, 526, 354, 387 s_wcd.hWnd, 388 ( HMENU ) EDIT_ID, // child window ID 389 win32.hInstance, NULL ); 390 SendMessage( s_wcd.hwndBuffer, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 ); 391 392 s_wcd.SysInputLineWndProc = ( WNDPROC ) SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, ( long ) InputLineWndProc ); 393 SendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 ); 394 395 // don't show it now that we have a splash screen up 396 if ( win32.win_viewlog.GetBool() ) { 397 ShowWindow( s_wcd.hWnd, SW_SHOWDEFAULT); 398 UpdateWindow( s_wcd.hWnd ); 399 SetForegroundWindow( s_wcd.hWnd ); 400 SetFocus( s_wcd.hwndInputLine ); 401 } 402 403 404 405 s_wcd.consoleField.Clear(); 406 407 for ( i = 0 ; i < COMMAND_HISTORY ; i++ ) { 408 s_wcd.historyEditLines[i].Clear(); 409 } 410 } 411 412 /* 413 ** Sys_DestroyConsole 414 */ 415 void Sys_DestroyConsole() { 416 if ( s_wcd.hWnd ) { 417 ShowWindow( s_wcd.hWnd, SW_HIDE ); 418 CloseWindow( s_wcd.hWnd ); 419 DestroyWindow( s_wcd.hWnd ); 420 s_wcd.hWnd = 0; 421 } 422 } 423 424 /* 425 ** Sys_ShowConsole 426 */ 427 void Sys_ShowConsole( int visLevel, bool quitOnClose ) { 428 429 s_wcd.quitOnClose = quitOnClose; 430 431 if ( !s_wcd.hWnd ) { 432 return; 433 } 434 435 switch ( visLevel ) { 436 case 0: 437 ShowWindow( s_wcd.hWnd, SW_HIDE ); 438 break; 439 case 1: 440 ShowWindow( s_wcd.hWnd, SW_SHOWNORMAL ); 441 SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff ); 442 break; 443 case 2: 444 ShowWindow( s_wcd.hWnd, SW_MINIMIZE ); 445 break; 446 default: 447 Sys_Error( "Invalid visLevel %d sent to Sys_ShowConsole\n", visLevel ); 448 break; 449 } 450 } 451 452 /* 453 ** Sys_ConsoleInput 454 */ 455 char *Sys_ConsoleInput() { 456 457 if ( s_wcd.consoleText[0] == 0 ) { 458 return NULL; 459 } 460 461 strcpy( s_wcd.returnedText, s_wcd.consoleText ); 462 s_wcd.consoleText[0] = 0; 463 464 return s_wcd.returnedText; 465 } 466 467 /* 468 ** Conbuf_AppendText 469 */ 470 void Conbuf_AppendText( const char *pMsg ) 471 { 472 #define CONSOLE_BUFFER_SIZE 16384 473 474 char buffer[CONSOLE_BUFFER_SIZE*2]; 475 char *b = buffer; 476 const char *msg; 477 int bufLen; 478 int i = 0; 479 static unsigned long s_totalChars; 480 481 // 482 // if the message is REALLY long, use just the last portion of it 483 // 484 if ( strlen( pMsg ) > CONSOLE_BUFFER_SIZE - 1 ) { 485 msg = pMsg + strlen( pMsg ) - CONSOLE_BUFFER_SIZE + 1; 486 } else { 487 msg = pMsg; 488 } 489 490 // 491 // copy into an intermediate buffer 492 // 493 while ( msg[i] && ( ( b - buffer ) < sizeof( buffer ) - 1 ) ) { 494 if ( msg[i] == '\n' && msg[i+1] == '\r' ) { 495 b[0] = '\r'; 496 b[1] = '\n'; 497 b += 2; 498 i++; 499 } else if ( msg[i] == '\r' ) { 500 b[0] = '\r'; 501 b[1] = '\n'; 502 b += 2; 503 } else if ( msg[i] == '\n' ) { 504 b[0] = '\r'; 505 b[1] = '\n'; 506 b += 2; 507 } else if ( idStr::IsColor( &msg[i] ) ) { 508 i++; 509 } else { 510 *b= msg[i]; 511 b++; 512 } 513 i++; 514 } 515 *b = 0; 516 bufLen = b - buffer; 517 518 s_totalChars += bufLen; 519 520 // 521 // replace selection instead of appending if we're overflowing 522 // 523 if ( s_totalChars > 0x7000 ) { 524 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 ); 525 s_totalChars = bufLen; 526 } 527 528 // 529 // put this text into the windows console 530 // 531 SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff ); 532 SendMessage( s_wcd.hwndBuffer, EM_SCROLLCARET, 0, 0 ); 533 SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, 0, (LPARAM) buffer ); 534 } 535 536 /* 537 ** Win_SetErrorText 538 */ 539 void Win_SetErrorText( const char *buf ) { 540 idStr::Copynz( s_wcd.errorString, buf, sizeof( s_wcd.errorString ) ); 541 if ( !s_wcd.hwndErrorBox ) { 542 s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN, 543 6, 5, 526, 30, 544 s_wcd.hWnd, 545 ( HMENU ) ERRORBOX_ID, // child window ID 546 win32.hInstance, NULL ); 547 SendMessage( s_wcd.hwndErrorBox, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 ); 548 SetWindowText( s_wcd.hwndErrorBox, s_wcd.errorString ); 549 550 DestroyWindow( s_wcd.hwndInputLine ); 551 s_wcd.hwndInputLine = NULL; 552 } 553 }