UFO: Alien Invasion
 All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
win_console.cpp
Go to the documentation of this file.
1 
6 /*
7 Copyright (C) 1997-2001 Id Software, Inc.
8 
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License
11 as published by the Free Software Foundation; either version 2
12 of the License, or (at your option) any later version.
13 
14 This program 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.
17 
18 See the GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, write to the Free Software
22 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
23 
24 */
25 
26 #include "../../common/common.h"
27 #include "win_local.h"
28 
29 #define CONSOLE_WINDOW_STYLE (WS_OVERLAPPED|WS_BORDER|WS_CAPTION|WS_SYSMENU|WS_MINIMIZEBOX|WS_CLIPCHILDREN|WS_GROUP)
30 #define CONSOLE_WINDOW_CLASS_NAME GAME_TITLE" Console"
31 
32 #ifdef DEDICATED_ONLY
33 #define CONSOLE_WINDOW_NAME GAME_TITLE" Dedicated Server Console"
34 #else
35 #define CONSOLE_WINDOW_NAME CONSOLE_WINDOW_CLASS_NAME
36 #endif
37 
38 #define MAX_OUTPUT 32768
39 #define MAX_PRINTMSG 8192
40 
41 typedef struct {
42  int outLen;
43  char cmdBuffer[MAXCMDLINE];
44  bool timerActive;
45  bool flashColor;
47  /* Window stuff */
48  HWND hWnd;
49  HWND hWndCopy;
50  HWND hWndClear;
51  HWND hWndQuit;
52  HWND hWndOutput;
53  HWND hWndInput;
54  HWND hWndMsg;
55  HFONT hFont;
56  HFONT hFontBold;
57  HBRUSH hBrushMsg;
58  HBRUSH hBrushOutput;
59  HBRUSH hBrushInput;
60  WNDPROC defOutputProc;
61  WNDPROC defInputProc;
62 } sysConsole_t;
63 
65 
66 int SV_CountPlayers(void);
67 
71 static void Sys_ConsoleLoop (bool error)
72 {
73  MSG msg;
74 
75  while (PeekMessage(&msg, nullptr, 0, 0, PM_NOREMOVE)) {
76  if (!GetMessage(&msg, nullptr, 0, 0)) {
77  if (error)
78  ExitProcess(1);
79  else
80  Sys_Quit();
81  }
82 
83  TranslateMessage(&msg);
84  DispatchMessage(&msg);
85  }
86 }
87 
92 const char* Sys_ConsoleInput (void)
93 {
94  static char buffer[MAXCMDLINE];
95 
96 #ifdef DEDICATED_ONLY
97  /* the client console is not visible after init stage and thus this is only
98  * needed for the server */
99  Sys_ConsoleLoop(false);
100 #endif
101 
102  /* empty command buffer? */
103  if (sys_console.cmdBuffer[0] == '\0')
104  return nullptr;
105 
106  Q_strncpyz(buffer, sys_console.cmdBuffer, sizeof(buffer));
107 
108  /* now we can clear the cmdBuffer */
109  sys_console.cmdBuffer[0] = '\0';
110 
111  return buffer;
112 }
113 
114 
115 void Sys_ConsoleOutput (const char* text)
116 {
117  char buffer[MAX_PRINTMSG];
118  int len = 0;
119 
120  /* skip color character */
121  if (*text == 1)
122  text++;
123 
124  /* Change \n to \r\n so it displays properly in the edit box */
125  while (*text) {
126  if (*text == '\n' && len < MAX_PRINTMSG - 2) {
127  buffer[len++] = '\r';
128  buffer[len++] = '\n';
129  } else if (len < MAX_PRINTMSG - 1) {
130  buffer[len++] = *text;
131  } else {
132  /* truncate */
133  buffer[len] = '\0';
134  break;
135  }
136 
137  text++;
138  }
139  buffer[len] = 0;
140 
141  sys_console.outLen += len;
142  if (sys_console.outLen >= MAX_OUTPUT) {
143  SendMessage(sys_console.hWndOutput, EM_SETSEL, 0, -1);
144  sys_console.outLen = len;
145  }
146 
147  /* Scroll down before adding more text */
148  SendMessage(sys_console.hWndOutput, EM_LINESCROLL, 0, 0xFFFF);
149  SendMessage(sys_console.hWndOutput, EM_SCROLLCARET, 0, 0);
150 
151  SendMessage(sys_console.hWndOutput, EM_REPLACESEL, FALSE, (LPARAM)buffer);
152 
153  /* Scroll down */
154  SendMessage(sys_console.hWndOutput, EM_LINESCROLL, 0, 0xFFFF);
155  SendMessage(sys_console.hWndOutput, EM_SCROLLCARET, 0, 0);
156 }
157 
162 void Sys_Backtrace (void)
163 {
164 #ifdef COMPILE_UFO
166 #endif
167 }
168 
169 void Sys_Error (const char* error, ...)
170 {
171  va_list argptr;
172  char text[1024];
173 
174  Sys_Backtrace();
175 
176 #ifdef COMPILE_MAP
177  Mem_Shutdown();
178 #endif
179 
180  va_start(argptr, error);
181  Q_vsnprintf(text, sizeof(text), error, argptr);
182  va_end(argptr);
183 
184  /* Echo to console */
185  Sys_ConsoleOutput("\n");
186  Sys_ConsoleOutput(text);
187  Sys_ConsoleOutput("\n");
188 
189  /* Display the message and set a timer so we can flash the text */
190  SetWindowText(sys_console.hWndMsg, text);
191  SetTimer(sys_console.hWnd, 1, 1000, nullptr);
192 
193  sys_console.timerActive = true;
194 
195  /* Show/hide everything we need */
196  ShowWindow(sys_console.hWndMsg, SW_SHOW);
197  ShowWindow(sys_console.hWndInput, SW_HIDE);
198 
199  Sys_ShowConsole(true);
200 
201  /* Wait for the user to quit */
202  while (1) {
203  Sys_ConsoleLoop(true);
204  /* Don't hog the CPU */
205  Sys_Sleep(25);
206  }
207 }
208 
209 void Sys_ShowConsole (bool show)
210 {
211  if (!show) {
212  ShowWindow(sys_console.hWnd, SW_HIDE);
213  return;
214  }
215 
216  ShowWindow(sys_console.hWnd, SW_SHOW);
217  UpdateWindow(sys_console.hWnd);
218  SetForegroundWindow(sys_console.hWnd);
219  SetFocus(sys_console.hWnd);
220 
221  /* Set the focus to the input edit box if possible */
222  SetFocus(sys_console.hWndInput);
223 
224  /* Scroll down */
225  SendMessage(sys_console.hWndOutput, EM_LINESCROLL, 0, 0xFFFF);
226  SendMessage(sys_console.hWndOutput, EM_SCROLLCARET, 0, 0);
227 }
228 
229 static LRESULT CALLBACK Sys_ConsoleProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
230 {
231  switch (uMsg) {
232  case WM_ACTIVATE:
233  if (LOWORD(wParam) != WA_INACTIVE) {
234  SetFocus(sys_console.hWndInput);
235  return 0;
236  }
237  break;
238 
239  case WM_CLOSE:
240  if (SV_CountPlayers()) {
241  const int ays = MessageBox(hWnd, "There are still players on the server! Really shut it down?", "WARNING!", MB_YESNO + MB_ICONEXCLAMATION);
242  if (ays == IDNO)
243  return TRUE;
244  }
245  Sys_Quit();
246  break;
247 
248  case WM_COMMAND:
249  if (HIWORD(wParam) == BN_CLICKED) {
250  if ((HWND)lParam == sys_console.hWndCopy) {
251  SendMessage(sys_console.hWndOutput, EM_SETSEL, 0, -1);
252  SendMessage(sys_console.hWndOutput, WM_COPY, 0, 0);
253  } else if ((HWND)lParam == sys_console.hWndClear) {
254  SendMessage(sys_console.hWndOutput, EM_SETSEL, 0, -1);
255  SendMessage(sys_console.hWndOutput, WM_CLEAR, 0, 0);
256  } else if ((HWND)lParam == sys_console.hWndQuit)
257  Sys_Quit();
258  } else if (HIWORD(wParam) == EN_VSCROLL)
259  InvalidateRect(sys_console.hWndOutput, nullptr, TRUE);
260  break;
261 
262  case WM_CTLCOLOREDIT:
263  if ((HWND)lParam == sys_console.hWndOutput) {
264  SetBkMode((HDC)wParam, TRANSPARENT);
265  SetBkColor((HDC)wParam, RGB(255, 255, 255));
266  SetTextColor((HDC)wParam, RGB(0, 0, 0));
267  return (LRESULT)sys_console.hBrushOutput;
268  } else if ((HWND)lParam == sys_console.hWndInput) {
269  SetBkMode((HDC)wParam, TRANSPARENT);
270  SetBkColor((HDC)wParam, RGB(255, 255, 255));
271  SetTextColor((HDC)wParam, RGB(0, 0, 0));
272  return (LRESULT)sys_console.hBrushInput;
273  }
274  break;
275 
276  case WM_CTLCOLORSTATIC:
277  if ((HWND)lParam == sys_console.hWndMsg) {
278  SetBkMode((HDC)wParam, TRANSPARENT);
279  SetBkColor((HDC)wParam, RGB(127, 127, 127));
280 
281  if (sys_console.flashColor)
282  SetTextColor((HDC)wParam, RGB(255, 0, 0));
283  else
284  SetTextColor((HDC)wParam, RGB(0, 0, 0));
285 
286  return (LRESULT)sys_console.hBrushMsg;
287  }
288  break;
289 
290  case WM_TIMER:
291  sys_console.flashColor = !sys_console.flashColor;
292  InvalidateRect(sys_console.hWndMsg, nullptr, TRUE);
293  break;
294 
295  case WM_CREATE:
296  SetTimer(sys_console.hWnd, 1, 500, nullptr);
297  break;
298  }
299 
300  return DefWindowProc(hWnd, uMsg, wParam, lParam);
301 }
302 
303 
304 static LONG WINAPI Sys_ConsoleEditProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
305 {
306  switch (uMsg) {
307  case WM_CHAR:
308  if (hWnd == sys_console.hWndInput) {
309  switch (wParam) {
310  case VK_RETURN:
311  if (GetWindowText(sys_console.hWndInput, sys_console.cmdBuffer, sizeof(sys_console.cmdBuffer))) {
312  SetWindowText(sys_console.hWndInput, "");
313  Com_Printf("]%s\n", sys_console.cmdBuffer);
314  }
315  /* Keep it from beeping */
316  return 0;
317  case VK_TAB:
318  /* command completion */
319  if (GetWindowText(sys_console.hWndInput, sys_console.cmdBuffer, sizeof(sys_console.cmdBuffer))) {
320  uint32_t inputpos = 0;
321  if (Com_ConsoleCompleteCommand(sys_console.cmdBuffer, sys_console.cmdBuffer, sizeof(sys_console.cmdBuffer), &inputpos, 0)) {
322  SetWindowText(sys_console.hWndInput, sys_console.cmdBuffer);
323  /* reset again - we don't want to execute yet */
324  sys_console.cmdBuffer[0] = '\0';
325  }
326  }
327  /* Keep it from beeping */
328  return 0;
329  }
330  } else if (hWnd == sys_console.hWndOutput)
331  return 0; /* Read only */
332  break;
333 
334  case WM_VSCROLL:
335  if (LOWORD(wParam) == SB_THUMBTRACK)
336  return 0;
337  break;
338  }
339 
340  if (hWnd == sys_console.hWndOutput)
341  return CallWindowProc(sys_console.defOutputProc, hWnd, uMsg, wParam, lParam);
342  else if (hWnd == sys_console.hWndInput)
343  return CallWindowProc(sys_console.defInputProc, hWnd, uMsg, wParam, lParam);
344  return 0;
345 }
346 
347 
352 {
353  if (sys_console.timerActive)
354  KillTimer(sys_console.hWnd, 1);
355 
356  if (sys_console.hBrushMsg)
357  DeleteObject(sys_console.hBrushMsg);
358  if (sys_console.hBrushOutput)
359  DeleteObject(sys_console.hBrushOutput);
360  if (sys_console.hBrushInput)
361  DeleteObject(sys_console.hBrushInput);
362 
363  if (sys_console.hFont)
364  DeleteObject(sys_console.hFont);
365  if (sys_console.hFontBold)
366  DeleteObject(sys_console.hFontBold);
367 
368  if (sys_console.defOutputProc)
369  SetWindowLongPtr(sys_console.hWndOutput, GWLP_WNDPROC, (LONG_PTR)sys_console.defOutputProc);
370  if (sys_console.defInputProc)
371  SetWindowLongPtr(sys_console.hWndInput, GWLP_WNDPROC, (LONG_PTR)sys_console.defInputProc);
372 
373  ShowWindow(sys_console.hWnd, SW_HIDE);
374  DestroyWindow(sys_console.hWnd);
376 
378 }
379 
380 void Sys_ConsoleInit (void)
381 {
382  WNDCLASSEX wc;
383  RECT r;
384 
386 
387  /* Center the window in the desktop */
388  const HDC hDC = GetDC(0);
389  int w = GetDeviceCaps(hDC, HORZRES);
390  int h = GetDeviceCaps(hDC, VERTRES);
391  ReleaseDC(0, hDC);
392 
393  r.left = (w - 540) / 2;
394  r.top = (h - 455) / 2;
395  r.right = r.left + 540;
396  r.bottom = r.top + 455;
397 
398  AdjustWindowRect(&r, CONSOLE_WINDOW_STYLE, FALSE);
399 
400  const int x = r.left;
401  const int y = r.top;
402  w = r.right - r.left;
403  h = r.bottom - r.top;
404 
405  wc.style = 0;
406  wc.lpfnWndProc = (WNDPROC)Sys_ConsoleProc;
407  wc.cbClsExtra = 0;
408  wc.cbWndExtra = 0;
409  wc.hInstance = global_hInstance;
410  wc.hIcon = LoadIcon(global_hInstance, MAKEINTRESOURCE(101));
411  wc.hIconSm = 0;
412  wc.hCursor = LoadCursor(nullptr, IDC_ARROW);
413  wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
414  wc.lpszMenuName = 0;
415  wc.lpszClassName = CONSOLE_WINDOW_CLASS_NAME;
416  wc.cbSize = sizeof(WNDCLASSEX);
417 
418  if (!RegisterClassEx(&wc)) {
419  MessageBox(nullptr, "Could not register console window class", "ERROR", MB_OK | MB_ICONERROR | MB_TASKMODAL);
420  exit(0);
421  }
422 
423  sys_console.hWnd = CreateWindowEx(0, CONSOLE_WINDOW_CLASS_NAME, CONSOLE_WINDOW_NAME, CONSOLE_WINDOW_STYLE, x, y, w, h, nullptr, nullptr, global_hInstance, nullptr);
424  if (!sys_console.hWnd) {
426  MessageBox(nullptr, "Could not create console window", "ERROR", MB_OK | MB_ICONERROR | MB_TASKMODAL);
427  exit(0);
428  }
429 
430  sys_console.hWndMsg = CreateWindowEx(0, "STATIC", "", WS_CHILD | SS_SUNKEN, 5, 5, 530, 30, sys_console.hWnd, nullptr, global_hInstance, nullptr);
431  sys_console.hWndOutput = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | WS_VSCROLL | ES_MULTILINE, 5, 40, 530, 350, sys_console.hWnd, nullptr, global_hInstance, nullptr);
432  sys_console.hWndInput = CreateWindowEx(0, "EDIT", "", WS_CHILD | WS_VISIBLE | WS_BORDER | ES_AUTOHSCROLL, 5, 395, 530, 20, sys_console.hWnd, nullptr, global_hInstance, nullptr);
433  sys_console.hWndCopy = CreateWindowEx(0, "BUTTON", "copy", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 5, 425, 70, 25, sys_console.hWnd, nullptr, global_hInstance, nullptr);
434  sys_console.hWndClear = CreateWindowEx(0, "BUTTON", "clear", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 80, 425, 70, 25, sys_console.hWnd, nullptr, global_hInstance, nullptr);
435  sys_console.hWndQuit = CreateWindowEx(0, "BUTTON", "quit", WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON, 465, 425, 70, 25, sys_console.hWnd, nullptr, global_hInstance, nullptr);
436 
437  /* Create and set fonts */
438  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");
439  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");
440 
441  SendMessage(sys_console.hWndMsg, WM_SETFONT, (WPARAM)sys_console.hFont, FALSE);
442  SendMessage(sys_console.hWndOutput, WM_SETFONT, (WPARAM)sys_console.hFont, FALSE);
443  SendMessage(sys_console.hWndInput, WM_SETFONT, (WPARAM)sys_console.hFont, FALSE);
444  SendMessage(sys_console.hWndCopy, WM_SETFONT, (WPARAM)sys_console.hFontBold, FALSE);
445  SendMessage(sys_console.hWndClear, WM_SETFONT, (WPARAM)sys_console.hFontBold, FALSE);
446  SendMessage(sys_console.hWndQuit, WM_SETFONT, (WPARAM)sys_console.hFontBold, FALSE);
447 
448  /* Create brushes */
449  sys_console.hBrushMsg = CreateSolidBrush(RGB(127, 127, 127));
450  sys_console.hBrushOutput = CreateSolidBrush(RGB(255, 255, 255));
451  sys_console.hBrushInput = CreateSolidBrush(RGB(255, 255, 255));
452 
453  /* Subclass edit boxes */
454  sys_console.defOutputProc = (WNDPROC)SetWindowLongPtr(sys_console.hWndOutput, GWLP_WNDPROC, (LONG_PTR)Sys_ConsoleEditProc);
455  sys_console.defInputProc = (WNDPROC)SetWindowLongPtr(sys_console.hWndInput, GWLP_WNDPROC, (LONG_PTR)Sys_ConsoleEditProc);
456 
457  /* Set text limit for input edit box */
458  SendMessage(sys_console.hWndInput, EM_SETLIMITTEXT, (WPARAM)(MAXCMDLINE - 1), 0);
459 
460  /* Make visible */
461  Sys_ShowConsole(true);
462 }
void Com_BreakIntoDebugger(void)
Definition: common.cpp:470
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition: shared.cpp:535
void Mem_Shutdown(void)
Definition: mem.cpp:603
void Sys_Backtrace(void)
On platforms supporting it, print a backtrace.
static void Sys_ConsoleLoop(bool error)
Dispatch window messages.
Definition: win_console.cpp:71
void Sys_ShowConsole(bool show)
void Sys_Error(const char *error,...)
#define CONSOLE_WINDOW_CLASS_NAME
Definition: win_console.cpp:30
void Sys_ConsoleOutput(const char *text)
HBRUSH hBrushOutput
Definition: win_console.cpp:58
static LRESULT CALLBACK Sys_ConsoleProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
void Com_Printf(const char *const fmt,...)
Definition: common.cpp:386
#define MAX_OUTPUT
Definition: win_console.cpp:38
HINSTANCE global_hInstance
Definition: win_shared.cpp:39
#define CONSOLE_WINDOW_NAME
Definition: win_console.cpp:35
void Sys_ConsoleShutdown(void)
Shutdown the console.
void Sys_BacktraceInit(void)
WNDPROC defInputProc
Definition: win_console.cpp:61
#define CONSOLE_WINDOW_STYLE
Definition: win_console.cpp:29
void Sys_Sleep(int milliseconds)
Calls the win32 sleep function.
Definition: unix_shared.cpp:68
Win32-specific UFO header file.
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition: shared.cpp:457
const char * Sys_ConsoleInput(void)
Handles input for the console window.
Definition: win_console.cpp:92
static LONG WINAPI Sys_ConsoleEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
int SV_CountPlayers(void)
Returns the number of spawned players.
Definition: sv_main.cpp:1096
#define MAXCMDLINE
Definition: common.h:307
bool Com_ConsoleCompleteCommand(const char *s, char *target, size_t bufSize, uint32_t *pos, uint32_t offset)
Console completion for command and variables.
Definition: common.cpp:717
QGL_EXTERN GLuint GLchar GLuint * len
Definition: r_gl.h:99
void Sys_ConsoleInit(void)
Initialize the console input (tty mode if possible)
char cmdBuffer[MAXCMDLINE]
Definition: win_console.cpp:43
void Sys_BacktraceShutdown(void)
#define MAX_PRINTMSG
Definition: win_console.cpp:39
WNDPROC defOutputProc
Definition: win_console.cpp:60
HBRUSH hBrushMsg
Definition: win_console.cpp:57
HBRUSH hBrushInput
Definition: win_console.cpp:59
void Sys_Quit(void)
static sysConsole_t sys_console
Definition: win_console.cpp:64