00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023 #include "../client/client.h"
00024 #include "win_local.h"
00025 #include "resource.h"
00026 #include <errno.h>
00027 #include <float.h>
00028 #include <fcntl.h>
00029 #include <stdio.h>
00030 #include <direct.h>
00031 #include <io.h>
00032 #include <conio.h>
00033
00034 #define COPY_ID 1
00035 #define QUIT_ID 2
00036 #define CLEAR_ID 3
00037
00038 #define ERRORBOX_ID 10
00039 #define ERRORTEXT_ID 11
00040
00041 #define EDIT_ID 100
00042 #define INPUT_ID 101
00043
00044 typedef struct
00045 {
00046 HWND hWnd;
00047 HWND hwndBuffer;
00048
00049 HWND hwndButtonClear;
00050 HWND hwndButtonCopy;
00051 HWND hwndButtonQuit;
00052
00053 HWND hwndErrorBox;
00054 HWND hwndErrorText;
00055
00056 HBITMAP hbmLogo;
00057 HBITMAP hbmClearBitmap;
00058
00059 HBRUSH hbrEditBackground;
00060 HBRUSH hbrErrorBackground;
00061
00062 HFONT hfBufferFont;
00063 HFONT hfButtonFont;
00064
00065 HWND hwndInputLine;
00066
00067 char errorString[80];
00068
00069 char consoleText[512], returnedText[512];
00070 int visLevel;
00071 qboolean quitOnClose;
00072 int windowWidth, windowHeight;
00073
00074 WNDPROC SysInputLineWndProc;
00075
00076 } WinConData;
00077
00078 static WinConData s_wcd;
00079
00080 static LONG WINAPI ConWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00081 {
00082 char *cmdString;
00083 static qboolean s_timePolarity;
00084
00085 switch (uMsg)
00086 {
00087 case WM_ACTIVATE:
00088 if ( LOWORD( wParam ) != WA_INACTIVE )
00089 {
00090 SetFocus( s_wcd.hwndInputLine );
00091 }
00092
00093 if ( com_viewlog && ( com_dedicated && !com_dedicated->integer ) )
00094 {
00095
00096 if ( com_viewlog->integer == 1 )
00097 {
00098 if ( HIWORD( wParam ) )
00099 {
00100 Cvar_Set( "viewlog", "2" );
00101 }
00102 }
00103 else if ( com_viewlog->integer == 2 )
00104 {
00105 if ( !HIWORD( wParam ) )
00106 {
00107 Cvar_Set( "viewlog", "1" );
00108 }
00109 }
00110 }
00111 break;
00112
00113 case WM_CLOSE:
00114 if ( ( com_dedicated && com_dedicated->integer ) )
00115 {
00116 cmdString = CopyString( "quit" );
00117 Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString );
00118 }
00119 else if ( s_wcd.quitOnClose )
00120 {
00121 PostQuitMessage( 0 );
00122 }
00123 else
00124 {
00125 Sys_ShowConsole( 0, qfalse );
00126 Cvar_Set( "viewlog", "0" );
00127 }
00128 return 0;
00129 case WM_CTLCOLORSTATIC:
00130 if ( ( HWND ) lParam == s_wcd.hwndBuffer )
00131 {
00132 SetBkColor( ( HDC ) wParam, RGB( 0x00, 0x00, 0xB0 ) );
00133 SetTextColor( ( HDC ) wParam, RGB( 0xff, 0xff, 0x00 ) );
00134
00135 #if 0 // this draws a background in the edit box, but there are issues with this
00136 if ( ( hdcScaled = CreateCompatibleDC( ( HDC ) wParam ) ) != 0 )
00137 {
00138 if ( SelectObject( ( HDC ) hdcScaled, s_wcd.hbmLogo ) )
00139 {
00140 StretchBlt( ( HDC ) wParam, 0, 0, 512, 384,
00141 hdcScaled, 0, 0, 512, 384,
00142 SRCCOPY );
00143 }
00144 DeleteDC( hdcScaled );
00145 }
00146 #endif
00147 return ( long ) s_wcd.hbrEditBackground;
00148 }
00149 else if ( ( HWND ) lParam == s_wcd.hwndErrorBox )
00150 {
00151 if ( s_timePolarity & 1 )
00152 {
00153 SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
00154 SetTextColor( ( HDC ) wParam, RGB( 0xff, 0x0, 0x00 ) );
00155 }
00156 else
00157 {
00158 SetBkColor( ( HDC ) wParam, RGB( 0x80, 0x80, 0x80 ) );
00159 SetTextColor( ( HDC ) wParam, RGB( 0x00, 0x0, 0x00 ) );
00160 }
00161 return ( long ) s_wcd.hbrErrorBackground;
00162 }
00163 break;
00164
00165 case WM_COMMAND:
00166 if ( wParam == COPY_ID )
00167 {
00168 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
00169 SendMessage( s_wcd.hwndBuffer, WM_COPY, 0, 0 );
00170 }
00171 else if ( wParam == QUIT_ID )
00172 {
00173 if ( s_wcd.quitOnClose )
00174 {
00175 PostQuitMessage( 0 );
00176 }
00177 else
00178 {
00179 cmdString = CopyString( "quit" );
00180 Sys_QueEvent( 0, SE_CONSOLE, 0, 0, strlen( cmdString ) + 1, cmdString );
00181 }
00182 }
00183 else if ( wParam == CLEAR_ID )
00184 {
00185 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
00186 SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, FALSE, ( LPARAM ) "" );
00187 UpdateWindow( s_wcd.hwndBuffer );
00188 }
00189 break;
00190 case WM_CREATE:
00191
00192
00193 s_wcd.hbrEditBackground = CreateSolidBrush( RGB( 0x00, 0x00, 0xB0 ) );
00194 s_wcd.hbrErrorBackground = CreateSolidBrush( RGB( 0x80, 0x80, 0x80 ) );
00195 SetTimer( hWnd, 1, 1000, NULL );
00196 break;
00197 case WM_ERASEBKGND:
00198 #if 0
00199 HDC hdcScaled;
00200 HGDIOBJ oldObject;
00201
00202 #if 1 // a single, large image
00203 hdcScaled = CreateCompatibleDC( ( HDC ) wParam );
00204 assert( hdcScaled != 0 );
00205
00206 if ( hdcScaled )
00207 {
00208 oldObject = SelectObject( ( HDC ) hdcScaled, s_wcd.hbmLogo );
00209 assert( oldObject != 0 );
00210 if ( oldObject )
00211 {
00212 StretchBlt( ( HDC ) wParam, 0, 0, s_wcd.windowWidth, s_wcd.windowHeight,
00213 hdcScaled, 0, 0, 512, 384,
00214 SRCCOPY );
00215 }
00216 DeleteDC( hdcScaled );
00217 hdcScaled = 0;
00218 }
00219 #else // a repeating brush
00220 {
00221 HBRUSH hbrClearBrush;
00222 RECT r;
00223
00224 GetWindowRect( hWnd, &r );
00225
00226 r.bottom = r.bottom - r.top + 1;
00227 r.right = r.right - r.left + 1;
00228 r.top = 0;
00229 r.left = 0;
00230
00231 hbrClearBrush = CreatePatternBrush( s_wcd.hbmClearBitmap );
00232
00233 assert( hbrClearBrush != 0 );
00234
00235 if ( hbrClearBrush )
00236 {
00237 FillRect( ( HDC ) wParam, &r, hbrClearBrush );
00238 DeleteObject( hbrClearBrush );
00239 }
00240 }
00241 #endif
00242 return 1;
00243 #endif
00244 return DefWindowProc( hWnd, uMsg, wParam, lParam );
00245 case WM_TIMER:
00246 if ( wParam == 1 )
00247 {
00248 s_timePolarity = !s_timePolarity;
00249 if ( s_wcd.hwndErrorBox )
00250 {
00251 InvalidateRect( s_wcd.hwndErrorBox, NULL, FALSE );
00252 }
00253 }
00254 break;
00255 }
00256
00257 return DefWindowProc( hWnd, uMsg, wParam, lParam );
00258 }
00259
00260 LONG WINAPI InputLineWndProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00261 {
00262 char inputBuffer[1024];
00263
00264 switch ( uMsg )
00265 {
00266 case WM_KILLFOCUS:
00267 if ( ( HWND ) wParam == s_wcd.hWnd ||
00268 ( HWND ) wParam == s_wcd.hwndErrorBox )
00269 {
00270 SetFocus( hWnd );
00271 return 0;
00272 }
00273 break;
00274
00275 case WM_CHAR:
00276 if ( wParam == 13 )
00277 {
00278 GetWindowText( s_wcd.hwndInputLine, inputBuffer, sizeof( inputBuffer ) );
00279 strncat( s_wcd.consoleText, inputBuffer, sizeof( s_wcd.consoleText ) - strlen( s_wcd.consoleText ) - 5 );
00280 strcat( s_wcd.consoleText, "\n" );
00281 SetWindowText( s_wcd.hwndInputLine, "" );
00282
00283 Sys_Print( va( "]%s\n", inputBuffer ) );
00284
00285 return 0;
00286 }
00287 }
00288
00289 return CallWindowProc( s_wcd.SysInputLineWndProc, hWnd, uMsg, wParam, lParam );
00290 }
00291
00292
00293
00294
00295 void Sys_CreateConsole( void )
00296 {
00297 HDC hDC;
00298 WNDCLASS wc;
00299 RECT rect;
00300 const char *DEDCLASS = "Q3 WinConsole";
00301 int nHeight;
00302 int swidth, sheight;
00303 int DEDSTYLE = WS_POPUPWINDOW | WS_CAPTION | WS_MINIMIZEBOX;
00304
00305 memset( &wc, 0, sizeof( wc ) );
00306
00307 wc.style = 0;
00308 wc.lpfnWndProc = (WNDPROC) ConWndProc;
00309 wc.cbClsExtra = 0;
00310 wc.cbWndExtra = 0;
00311 wc.hInstance = g_wv.hInstance;
00312 wc.hIcon = LoadIcon( g_wv.hInstance, MAKEINTRESOURCE(IDI_ICON1));
00313 wc.hCursor = LoadCursor (NULL,IDC_ARROW);
00314 wc.hbrBackground = (void *)COLOR_WINDOW;
00315 wc.lpszMenuName = 0;
00316 wc.lpszClassName = DEDCLASS;
00317
00318 if ( !RegisterClass (&wc) )
00319 return;
00320
00321 rect.left = 0;
00322 rect.right = 540;
00323 rect.top = 0;
00324 rect.bottom = 450;
00325 AdjustWindowRect( &rect, DEDSTYLE, FALSE );
00326
00327 hDC = GetDC( GetDesktopWindow() );
00328 swidth = GetDeviceCaps( hDC, HORZRES );
00329 sheight = GetDeviceCaps( hDC, VERTRES );
00330 ReleaseDC( GetDesktopWindow(), hDC );
00331
00332 s_wcd.windowWidth = rect.right - rect.left + 1;
00333 s_wcd.windowHeight = rect.bottom - rect.top + 1;
00334
00335 s_wcd.hWnd = CreateWindowEx( 0,
00336 DEDCLASS,
00337 "Quake 3 Console",
00338 DEDSTYLE,
00339 ( swidth - 600 ) / 2, ( sheight - 450 ) / 2 , rect.right - rect.left + 1, rect.bottom - rect.top + 1,
00340 NULL,
00341 NULL,
00342 g_wv.hInstance,
00343 NULL );
00344
00345 if ( s_wcd.hWnd == NULL )
00346 {
00347 return;
00348 }
00349
00350
00351
00352
00353 hDC = GetDC( s_wcd.hWnd );
00354 nHeight = -MulDiv( 8, GetDeviceCaps( hDC, LOGPIXELSY), 72);
00355
00356 s_wcd.hfBufferFont = CreateFont( nHeight,
00357 0,
00358 0,
00359 0,
00360 FW_LIGHT,
00361 0,
00362 0,
00363 0,
00364 DEFAULT_CHARSET,
00365 OUT_DEFAULT_PRECIS,
00366 CLIP_DEFAULT_PRECIS,
00367 DEFAULT_QUALITY,
00368 FF_MODERN | FIXED_PITCH,
00369 "Courier New" );
00370
00371 ReleaseDC( s_wcd.hWnd, hDC );
00372
00373
00374
00375
00376 s_wcd.hwndInputLine = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_BORDER |
00377 ES_LEFT | ES_AUTOHSCROLL,
00378 6, 400, 528, 20,
00379 s_wcd.hWnd,
00380 ( HMENU ) INPUT_ID,
00381 g_wv.hInstance, NULL );
00382
00383
00384
00385
00386 s_wcd.hwndButtonCopy = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
00387 5, 425, 72, 24,
00388 s_wcd.hWnd,
00389 ( HMENU ) COPY_ID,
00390 g_wv.hInstance, NULL );
00391 SendMessage( s_wcd.hwndButtonCopy, WM_SETTEXT, 0, ( LPARAM ) "copy" );
00392
00393 s_wcd.hwndButtonClear = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
00394 82, 425, 72, 24,
00395 s_wcd.hWnd,
00396 ( HMENU ) CLEAR_ID,
00397 g_wv.hInstance, NULL );
00398 SendMessage( s_wcd.hwndButtonClear, WM_SETTEXT, 0, ( LPARAM ) "clear" );
00399
00400 s_wcd.hwndButtonQuit = CreateWindow( "button", NULL, BS_PUSHBUTTON | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
00401 462, 425, 72, 24,
00402 s_wcd.hWnd,
00403 ( HMENU ) QUIT_ID,
00404 g_wv.hInstance, NULL );
00405 SendMessage( s_wcd.hwndButtonQuit, WM_SETTEXT, 0, ( LPARAM ) "quit" );
00406
00407
00408
00409
00410
00411 s_wcd.hwndBuffer = CreateWindow( "edit", NULL, WS_CHILD | WS_VISIBLE | WS_VSCROLL | WS_BORDER |
00412 ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL | ES_READONLY,
00413 6, 40, 526, 354,
00414 s_wcd.hWnd,
00415 ( HMENU ) EDIT_ID,
00416 g_wv.hInstance, NULL );
00417 SendMessage( s_wcd.hwndBuffer, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
00418
00419 s_wcd.SysInputLineWndProc = ( WNDPROC ) SetWindowLong( s_wcd.hwndInputLine, GWL_WNDPROC, ( long ) InputLineWndProc );
00420 SendMessage( s_wcd.hwndInputLine, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
00421
00422 ShowWindow( s_wcd.hWnd, SW_SHOWDEFAULT);
00423 UpdateWindow( s_wcd.hWnd );
00424 SetForegroundWindow( s_wcd.hWnd );
00425 SetFocus( s_wcd.hwndInputLine );
00426
00427 s_wcd.visLevel = 1;
00428 }
00429
00430
00431
00432
00433 void Sys_DestroyConsole( void ) {
00434 if ( s_wcd.hWnd ) {
00435 ShowWindow( s_wcd.hWnd, SW_HIDE );
00436 CloseWindow( s_wcd.hWnd );
00437 DestroyWindow( s_wcd.hWnd );
00438 s_wcd.hWnd = 0;
00439 }
00440 }
00441
00442
00443
00444
00445 void Sys_ShowConsole( int visLevel, qboolean quitOnClose )
00446 {
00447 s_wcd.quitOnClose = quitOnClose;
00448
00449 if ( visLevel == s_wcd.visLevel )
00450 {
00451 return;
00452 }
00453
00454 s_wcd.visLevel = visLevel;
00455
00456 if ( !s_wcd.hWnd )
00457 return;
00458
00459 switch ( visLevel )
00460 {
00461 case 0:
00462 ShowWindow( s_wcd.hWnd, SW_HIDE );
00463 break;
00464 case 1:
00465 ShowWindow( s_wcd.hWnd, SW_SHOWNORMAL );
00466 SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
00467 break;
00468 case 2:
00469 ShowWindow( s_wcd.hWnd, SW_MINIMIZE );
00470 break;
00471 default:
00472 Sys_Error( "Invalid visLevel %d sent to Sys_ShowConsole\n", visLevel );
00473 break;
00474 }
00475 }
00476
00477
00478
00479
00480 char *Sys_ConsoleInput( void )
00481 {
00482 if ( s_wcd.consoleText[0] == 0 )
00483 {
00484 return NULL;
00485 }
00486
00487 strcpy( s_wcd.returnedText, s_wcd.consoleText );
00488 s_wcd.consoleText[0] = 0;
00489
00490 return s_wcd.returnedText;
00491 }
00492
00493
00494
00495
00496 void Conbuf_AppendText( const char *pMsg )
00497 {
00498 #define CONSOLE_BUFFER_SIZE 16384
00499
00500 char buffer[CONSOLE_BUFFER_SIZE*2];
00501 char *b = buffer;
00502 const char *msg;
00503 int bufLen;
00504 int i = 0;
00505 static unsigned long s_totalChars;
00506
00507
00508
00509
00510 if ( strlen( pMsg ) > CONSOLE_BUFFER_SIZE - 1 )
00511 {
00512 msg = pMsg + strlen( pMsg ) - CONSOLE_BUFFER_SIZE + 1;
00513 }
00514 else
00515 {
00516 msg = pMsg;
00517 }
00518
00519
00520
00521
00522 while ( msg[i] && ( ( b - buffer ) < sizeof( buffer ) - 1 ) )
00523 {
00524 if ( msg[i] == '\n' && msg[i+1] == '\r' )
00525 {
00526 b[0] = '\r';
00527 b[1] = '\n';
00528 b += 2;
00529 i++;
00530 }
00531 else if ( msg[i] == '\r' )
00532 {
00533 b[0] = '\r';
00534 b[1] = '\n';
00535 b += 2;
00536 }
00537 else if ( msg[i] == '\n' )
00538 {
00539 b[0] = '\r';
00540 b[1] = '\n';
00541 b += 2;
00542 }
00543 else if ( Q_IsColorString( &msg[i] ) )
00544 {
00545 i++;
00546 }
00547 else
00548 {
00549 *b= msg[i];
00550 b++;
00551 }
00552 i++;
00553 }
00554 *b = 0;
00555 bufLen = b - buffer;
00556
00557 s_totalChars += bufLen;
00558
00559
00560
00561
00562 if ( s_totalChars > 0x7fff )
00563 {
00564 SendMessage( s_wcd.hwndBuffer, EM_SETSEL, 0, -1 );
00565 s_totalChars = bufLen;
00566 }
00567
00568
00569
00570
00571 SendMessage( s_wcd.hwndBuffer, EM_LINESCROLL, 0, 0xffff );
00572 SendMessage( s_wcd.hwndBuffer, EM_SCROLLCARET, 0, 0 );
00573 SendMessage( s_wcd.hwndBuffer, EM_REPLACESEL, 0, (LPARAM) buffer );
00574 }
00575
00576
00577
00578
00579 void Sys_SetErrorText( const char *buf )
00580 {
00581 Q_strncpyz( s_wcd.errorString, buf, sizeof( s_wcd.errorString ) );
00582
00583 if ( !s_wcd.hwndErrorBox )
00584 {
00585 s_wcd.hwndErrorBox = CreateWindow( "static", NULL, WS_CHILD | WS_VISIBLE | SS_SUNKEN,
00586 6, 5, 526, 30,
00587 s_wcd.hWnd,
00588 ( HMENU ) ERRORBOX_ID,
00589 g_wv.hInstance, NULL );
00590 SendMessage( s_wcd.hwndErrorBox, WM_SETFONT, ( WPARAM ) s_wcd.hfBufferFont, 0 );
00591 SetWindowText( s_wcd.hwndErrorBox, s_wcd.errorString );
00592
00593 DestroyWindow( s_wcd.hwndInputLine );
00594 s_wcd.hwndInputLine = NULL;
00595 }
00596 }