win_console.c

Go to the documentation of this file.
00001 
00006 /*
00007 Copyright (C) 1997-2001 Id Software, Inc.
00008 
00009 This program is free software; you can redistribute it and/or
00010 modify it under the terms of the GNU General Public License
00011 as published by the Free Software Foundation; either version 2
00012 of the License, or (at your option) any later version.
00013 
00014 This program is distributed in the hope that it will be useful,
00015 but WITHOUT ANY WARRANTY; without even the implied warranty of
00016 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
00017 
00018 See the GNU General Public License for more details.
00019 
00020 You should have received a copy of the GNU General Public License
00021 along with this program; if not, write to the Free Software
00022 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
00023 
00024 */
00025 
00026 #include "../../common/common.h"
00027 #include "win_local.h"
00028 
00029 #define CONSOLE_WINDOW_STYLE        (WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_CLIPCHILDREN|WS_GROUP)
00030 #define CONSOLE_WINDOW_CLASS_NAME   GAME_TITLE" Console"
00031 
00032 #ifdef DEDICATED_ONLY
00033 #define CONSOLE_WINDOW_NAME         GAME_TITLE" Dedicated Server Console"
00034 #else
00035 #define CONSOLE_WINDOW_NAME         CONSOLE_WINDOW_CLASS_NAME
00036 #endif
00037 
00038 #define MAX_OUTPUT                  32768
00039 #define MAX_PRINTMSG                8192
00040 
00041 typedef struct {
00042     int         outLen;                 
00043     char        cmdBuffer[MAXCMDLINE];  
00044     qboolean    timerActive;            
00045     qboolean    flashColor;             
00047     /* Window stuff */
00048     HWND        hWnd;
00049     HWND        hWndCopy;
00050     HWND        hWndClear;
00051     HWND        hWndQuit;
00052     HWND        hWndOutput;
00053     HWND        hWndInput;
00054     HWND        hWndMsg;
00055     HFONT       hFont;
00056     HFONT       hFontBold;
00057     HBRUSH      hBrushMsg;
00058     HBRUSH      hBrushOutput;
00059     HBRUSH      hBrushInput;
00060     WNDPROC     defOutputProc;
00061     WNDPROC     defInputProc;
00062 } sysConsole_t;
00063 
00064 static sysConsole_t sys_console;
00065 
00066 int SV_CountPlayers(void);
00067 
00071 static void Sys_ConsoleLoop (qboolean error)
00072 {
00073     MSG msg;
00074 
00075     while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE)) {
00076         if (!GetMessage(&msg, NULL, 0, 0)) {
00077             if (error)
00078                 ExitProcess(1);
00079             else
00080                 Sys_Quit();
00081         }
00082 
00083         TranslateMessage(&msg);
00084         DispatchMessage(&msg);
00085     }
00086 }
00087 
00092 const char *Sys_ConsoleInput (void)
00093 {
00094     static char buffer[MAXCMDLINE];
00095 
00096 #ifdef DEDICATED_ONLY
00097     /* the client console is not visible after init stage and thus this is only
00098      * needed for the server */
00099     Sys_ConsoleLoop(qfalse);
00100 #endif
00101 
00102     /* empty command buffer? */
00103     if (sys_console.cmdBuffer[0] == '\0')
00104         return NULL;
00105 
00106     Q_strncpyz(buffer, sys_console.cmdBuffer, sizeof(buffer));
00107 
00108     /* now we can clear the cmdBuffer */
00109     sys_console.cmdBuffer[0] = '\0';
00110 
00111     return buffer;
00112 }
00113 
00114 
00115 void Sys_ConsoleOutput (const char *text)
00116 {
00117     char buffer[MAX_PRINTMSG];
00118     int len = 0;
00119 
00120     /* skip color char */
00121     if (*text == 1)
00122         text++;
00123 
00124     /* Change \n to \r\n so it displays properly in the edit box */
00125     while (*text) {
00126         if (*text == '\n' && len < MAX_PRINTMSG - 2) {
00127             buffer[len++] = '\r';
00128             buffer[len++] = '\n';
00129         } else if (len < MAX_PRINTMSG - 1) {
00130             buffer[len++] = *text;
00131         } else {
00132             /* truncate */
00133             buffer[len] = '\0';
00134             break;
00135         }
00136 
00137         text++;
00138     }
00139     buffer[len] = 0;
00140 
00141     sys_console.outLen += len;
00142     if (sys_console.outLen >= MAX_OUTPUT) {
00143         SendMessage(sys_console.hWndOutput, EM_SETSEL, 0, -1);
00144         sys_console.outLen = len;
00145     }
00146 
00147     /* Scroll down before adding more text */
00148     SendMessage(sys_console.hWndOutput, EM_LINESCROLL, 0, 0xFFFF);
00149     SendMessage(sys_console.hWndOutput, EM_SCROLLCARET, 0, 0);
00150 
00151     SendMessage(sys_console.hWndOutput, EM_REPLACESEL, FALSE, (LPARAM)buffer);
00152 
00153     /* Scroll down */
00154     SendMessage(sys_console.hWndOutput, EM_LINESCROLL, 0, 0xFFFF);
00155     SendMessage(sys_console.hWndOutput, EM_SCROLLCARET, 0, 0);
00156 }
00157 
00161 void Sys_Backtrace (void)
00162 {
00163 }
00164 
00165 void Sys_Error (const char *error, ...)
00166 {
00167     va_list argptr;
00168     char text[1024];
00169 
00170     Sys_Backtrace();
00171 
00172 #ifdef COMPILE_MAP
00173     Mem_Shutdown();
00174 #endif
00175 
00176     va_start(argptr, error);
00177     Q_vsnprintf(text, sizeof(text), error, argptr);
00178     va_end(argptr);
00179 
00180     /* Echo to console */
00181     Sys_ConsoleOutput("\n");
00182     Sys_ConsoleOutput(text);
00183     Sys_ConsoleOutput("\n");
00184 
00185     /* Display the message and set a timer so we can flash the text */
00186     SetWindowText(sys_console.hWndMsg, text);
00187     SetTimer(sys_console.hWnd, 1, 1000, NULL);
00188 
00189     sys_console.timerActive = qtrue;
00190 
00191     /* Show/hide everything we need */
00192     ShowWindow(sys_console.hWndMsg, SW_SHOW);
00193     ShowWindow(sys_console.hWndInput, SW_HIDE);
00194 
00195     Sys_ShowConsole(qtrue);
00196 
00197     /* Wait for the user to quit */
00198     while (1) {
00199         Sys_ConsoleLoop(qtrue);
00200         /* Don't hog the CPU */
00201         Sys_Sleep(25);
00202     }
00203 }
00204 
00205 
00206 void Sys_ShowConsole (qboolean show)
00207 {
00208     if (!show) {
00209         ShowWindow(sys_console.hWnd, SW_HIDE);
00210         return;
00211     }
00212 
00213     ShowWindow(sys_console.hWnd, SW_SHOW);
00214     UpdateWindow(sys_console.hWnd);
00215     SetForegroundWindow(sys_console.hWnd);
00216     SetFocus(sys_console.hWnd);
00217 
00218     /* Set the focus to the input edit box if possible */
00219     SetFocus(sys_console.hWndInput);
00220 
00221     /* Scroll down */
00222     SendMessage(sys_console.hWndOutput, EM_LINESCROLL, 0, 0xFFFF);
00223     SendMessage(sys_console.hWndOutput, EM_SCROLLCARET, 0, 0);
00224 }
00225 
00226 static LONG WINAPI Sys_ConsoleProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00227 {
00228     switch (uMsg) {
00229     case WM_ACTIVATE:
00230         if (LOWORD(wParam) != WA_INACTIVE) {
00231             SetFocus(sys_console.hWndInput);
00232             return 0;
00233         }
00234         break;
00235 
00236     case WM_CLOSE:
00237         if (SV_CountPlayers()) {
00238             const int ays = MessageBox(hWnd, "There are still players on the server! Really shut it down?", "WARNING!", MB_YESNO + MB_ICONEXCLAMATION);
00239             if (ays == IDNO)
00240                 return TRUE;
00241         }
00242         Sys_Quit();
00243         break;
00244 
00245     case WM_COMMAND:
00246         if (HIWORD(wParam) == BN_CLICKED) {
00247             if ((HWND)lParam == sys_console.hWndCopy) {
00248                 SendMessage(sys_console.hWndOutput, EM_SETSEL, 0, -1);
00249                 SendMessage(sys_console.hWndOutput, WM_COPY, 0, 0);
00250             } else if ((HWND)lParam == sys_console.hWndClear) {
00251                 SendMessage(sys_console.hWndOutput, EM_SETSEL, 0, -1);
00252                 SendMessage(sys_console.hWndOutput, WM_CLEAR, 0, 0);
00253             } else if ((HWND)lParam == sys_console.hWndQuit)
00254                 Sys_Quit();
00255         } else if (HIWORD(wParam) == EN_VSCROLL)
00256             InvalidateRect(sys_console.hWndOutput, NULL, TRUE);
00257         break;
00258 
00259     case WM_CTLCOLOREDIT:
00260         if ((HWND)lParam == sys_console.hWndOutput) {
00261             SetBkMode((HDC)wParam, TRANSPARENT);
00262             SetBkColor((HDC)wParam, RGB(255, 255, 255));
00263             SetTextColor((HDC)wParam, RGB(0, 0, 0));
00264             return (LONG)sys_console.hBrushOutput;
00265         } else if ((HWND)lParam == sys_console.hWndInput) {
00266             SetBkMode((HDC)wParam, TRANSPARENT);
00267             SetBkColor((HDC)wParam, RGB(255, 255, 255));
00268             SetTextColor((HDC)wParam, RGB(0, 0, 0));
00269             return (LONG)sys_console.hBrushInput;
00270         }
00271         break;
00272 
00273     case WM_CTLCOLORSTATIC:
00274         if ((HWND)lParam == sys_console.hWndMsg) {
00275             SetBkMode((HDC)wParam, TRANSPARENT);
00276             SetBkColor((HDC)wParam, RGB(127, 127, 127));
00277 
00278             if (sys_console.flashColor)
00279                 SetTextColor((HDC)wParam, RGB(255, 0, 0));
00280             else
00281                 SetTextColor((HDC)wParam, RGB(0, 0, 0));
00282 
00283             return (LONG)sys_console.hBrushMsg;
00284         }
00285         break;
00286 
00287     case WM_TIMER:
00288         sys_console.flashColor = !sys_console.flashColor;
00289         InvalidateRect(sys_console.hWndMsg, NULL, TRUE);
00290         break;
00291 
00292     case WM_CREATE:
00293         SetTimer(sys_console.hWnd, 1, 500, NULL);
00294         break;
00295     }
00296 
00297     return DefWindowProc(hWnd, uMsg, wParam, lParam);
00298 }
00299 
00300 
00301 static LONG WINAPI Sys_ConsoleEditProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
00302 {
00303     switch (uMsg) {
00304     case WM_CHAR:
00305         if (hWnd == sys_console.hWndInput) {
00306             switch (wParam) {
00307             case VK_RETURN:
00308                 if (GetWindowText(sys_console.hWndInput, sys_console.cmdBuffer, sizeof(sys_console.cmdBuffer))) {
00309                     SetWindowText(sys_console.hWndInput, "");
00310                     Com_Printf("]%s\n", sys_console.cmdBuffer);
00311                 }
00312                 /* Keep it from beeping */
00313                 return 0;
00314             case VK_TAB:
00315                 /* command completion */
00316                 if (GetWindowText(sys_console.hWndInput, sys_console.cmdBuffer, sizeof(sys_console.cmdBuffer))) {
00317                     int inputpos = 0;
00318                     if (Com_ConsoleCompleteCommand(sys_console.cmdBuffer, sys_console.cmdBuffer, MAXCMDLINE, &inputpos, 0)) {
00319                         SetWindowText(sys_console.hWndInput, sys_console.cmdBuffer);
00320                         /* reset again - we don't want to execute yet */
00321                         sys_console.cmdBuffer[0] = '\0';
00322                     }
00323                 }
00324                 /* Keep it from beeping */
00325                 return 0;
00326             }
00327         } else if (hWnd == sys_console.hWndOutput)
00328             return 0;   /* Read only */
00329         break;
00330 
00331     case WM_VSCROLL:
00332         if (LOWORD(wParam) == SB_THUMBTRACK)
00333             return 0;
00334         break;
00335     }
00336 
00337     if (hWnd == sys_console.hWndOutput)
00338         return CallWindowProc(sys_console.defOutputProc, hWnd, uMsg, wParam, lParam);
00339     else if (hWnd == sys_console.hWndInput)
00340         return CallWindowProc(sys_console.defInputProc, hWnd, uMsg, wParam, lParam);
00341     return 0;
00342 }
00343 
00344 
00348 void Sys_ConsoleShutdown (void)
00349 {
00350     if (sys_console.timerActive)
00351         KillTimer(sys_console.hWnd, 1);
00352 
00353     if (sys_console.hBrushMsg)
00354         DeleteObject(sys_console.hBrushMsg);
00355     if (sys_console.hBrushOutput)
00356         DeleteObject(sys_console.hBrushOutput);
00357     if (sys_console.hBrushInput)
00358         DeleteObject(sys_console.hBrushInput);
00359 
00360     if (sys_console.hFont)
00361         DeleteObject(sys_console.hFont);
00362     if (sys_console.hFontBold)
00363         DeleteObject(sys_console.hFontBold);
00364 
00365     if (sys_console.defOutputProc)
00366         SetWindowLong(sys_console.hWndOutput, GWL_WNDPROC, (LONG)sys_console.defOutputProc);
00367     if (sys_console.defInputProc)
00368         SetWindowLong(sys_console.hWndInput, GWL_WNDPROC, (LONG)sys_console.defInputProc);
00369 
00370     ShowWindow(sys_console.hWnd, SW_HIDE);
00371     DestroyWindow(sys_console.hWnd);
00372     UnregisterClass(CONSOLE_WINDOW_CLASS_NAME, global_hInstance);
00373 }
00374 
00375 void Sys_ConsoleInit (void)
00376 {
00377     WNDCLASSEX wc;
00378     HDC hDC;
00379     RECT r;
00380     int x, y, w, h;
00381 
00382     /* Center the window in the desktop */
00383     hDC = GetDC(0);
00384     w = GetDeviceCaps(hDC, HORZRES);
00385     h = GetDeviceCaps(hDC, VERTRES);
00386     ReleaseDC(0, hDC);
00387 
00388     r.left = (w - 540) / 2;
00389     r.top = (h - 455) / 2;
00390     r.right = r.left + 540;
00391     r.bottom = r.top + 455;
00392 
00393     AdjustWindowRect(&r, CONSOLE_WINDOW_STYLE, FALSE);
00394 
00395     x = r.left;
00396     y = r.top;
00397     w = r.right - r.left;
00398     h = r.bottom - r.top;
00399 
00400     wc.style = 0;
00401     wc.lpfnWndProc = (WNDPROC)Sys_ConsoleProc;
00402     wc.cbClsExtra = 0;
00403     wc.cbWndExtra = 0;
00404     wc.hInstance = global_hInstance;
00405     wc.hIcon = LoadIcon(global_hInstance, MAKEINTRESOURCE(101));
00406     wc.hIconSm = 0;
00407     wc.hCursor = LoadCursor(NULL, IDC_ARROW);
00408     wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
00409     wc.lpszMenuName = 0;
00410     wc.lpszClassName = CONSOLE_WINDOW_CLASS_NAME;
00411     wc.cbSize = sizeof(WNDCLASSEX);
00412 
00413     if (!RegisterClassEx(&wc)) {
00414         MessageBox(NULL, "Could not register console window class", "ERROR", MB_OK | MB_ICONERROR | MB_TASKMODAL);
00415         exit(0);
00416     }
00417 
00418     sys_console.hWnd = CreateWindowEx(0, CONSOLE_WINDOW_CLASS_NAME, CONSOLE_WINDOW_NAME, CONSOLE_WINDOW_STYLE, x, y, w, h, NULL, NULL, global_hInstance, NULL);
00419     if (!sys_console.hWnd) {
00420         UnregisterClass(CONSOLE_WINDOW_CLASS_NAME, global_hInstance);
00421         MessageBox(NULL, "Could not create console window", "ERROR", MB_OK | MB_ICONERROR | MB_TASKMODAL);
00422         exit(0);
00423     }
00424 
00425     sys_console.hWndMsg = CreateWindowEx(0, "STATIC", "", WS_CHILD | SS_SUNKEN, 5, 5, 530, 30, sys_console.hWnd, NULL, global_hInstance, NULL);
00426     sys_console.hWndOutput = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_MULTILINE, 5, 40, 530, 350, sys_console.hWnd, NULL, global_hInstance, NULL);
00427     sys_console.hWndInput = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 5, 395, 530, 20, sys_console.hWnd, NULL, global_hInstance, NULL);
00428     sys_console.hWndCopy = CreateWindowEx(0, "BUTTON", "copy", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 5, 425, 70, 25, sys_console.hWnd, NULL, global_hInstance, NULL);
00429     sys_console.hWndClear = CreateWindowEx(0, "BUTTON", "clear", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 80, 425, 70, 25, sys_console.hWnd, NULL, global_hInstance, NULL);
00430     sys_console.hWndQuit = CreateWindowEx(0, "BUTTON", "quit", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 465, 425, 70, 25, sys_console.hWnd, NULL, global_hInstance, NULL);
00431 
00432     /* Create and set fonts */
00433     sys_console.hFont = CreateFont(14, 0, 0, 0, FW_LIGHT, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, FIXED_PITCH | FF_MODERN, "Courier New");
00434     sys_console.hFontBold = CreateFont(20, 0, 0, 0, FW_SEMIBOLD, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, "System");
00435 
00436     SendMessage(sys_console.hWndMsg, WM_SETFONT, (WPARAM)sys_console.hFont, FALSE);
00437     SendMessage(sys_console.hWndOutput, WM_SETFONT, (WPARAM)sys_console.hFont, FALSE);
00438     SendMessage(sys_console.hWndInput, WM_SETFONT, (WPARAM)sys_console.hFont, FALSE);
00439     SendMessage(sys_console.hWndCopy, WM_SETFONT, (WPARAM)sys_console.hFontBold, FALSE);
00440     SendMessage(sys_console.hWndClear, WM_SETFONT, (WPARAM)sys_console.hFontBold, FALSE);
00441     SendMessage(sys_console.hWndQuit, WM_SETFONT, (WPARAM)sys_console.hFontBold, FALSE);
00442 
00443     /* Create brushes */
00444     sys_console.hBrushMsg = CreateSolidBrush(RGB(127, 127, 127));
00445     sys_console.hBrushOutput = CreateSolidBrush(RGB(255, 255, 255));
00446     sys_console.hBrushInput = CreateSolidBrush(RGB(255, 255, 255));
00447 
00448     /* Subclass edit boxes */
00449     sys_console.defOutputProc = (WNDPROC)SetWindowLong(sys_console.hWndOutput, GWL_WNDPROC, (LONG)Sys_ConsoleEditProc);
00450     sys_console.defInputProc = (WNDPROC)SetWindowLong(sys_console.hWndInput, GWL_WNDPROC, (LONG)Sys_ConsoleEditProc);
00451 
00452     /* Set text limit for input edit box */
00453     SendMessage(sys_console.hWndInput, EM_SETLIMITTEXT, (WPARAM)(MAXCMDLINE - 1), 0);
00454 
00455     /* Make visible */
00456     Sys_ShowConsole(qtrue);
00457 }

Generated by  doxygen 1.6.2