UFO: Alien Invasion
Loading...
Searching...
No Matches
win_console.cpp
Go to the documentation of this file.
1
5
6/*
7Copyright (C) 1997-2001 Id Software, Inc.
8
9This program is free software; you can redistribute it and/or
10modify it under the terms of the GNU General Public License
11as published by the Free Software Foundation; either version 2
12of the License, or (at your option) any later version.
13
14This program is distributed in the hope that it will be useful,
15but WITHOUT ANY WARRANTY; without even the implied warranty of
16MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
17
18See the GNU General Public License for more details.
19
20You should have received a copy of the GNU General Public License
21along with this program; if not, write to the Free Software
22Foundation, 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
41typedef struct {
42 int outLen;
46
47 /* Window stuff */
48 HWND hWnd;
54 HWND hWndMsg;
55 HFONT hFont;
56 HFONT hFontBold;
57 HBRUSH hBrushMsg;
61 WNDPROC defInputProc;
63
65
66int SV_CountPlayers(void);
67
71static 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
92const 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
115void 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
162void Sys_Backtrace (void)
163{
164#ifdef COMPILE_UFO
166#endif
167}
168
169void Sys_Error (const char* error, ...)
170{
171 va_list argptr;
172 char text[1024];
173
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
209void 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
229static 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
304static 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
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 Sys_Quit(void)
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:734
void Com_Printf(const char *const fmt,...)
Definition common.cpp:428
void Com_BreakIntoDebugger(void)
Definition common.cpp:512
definitions common between client and server, but not game lib
#define MAXCMDLINE
Definition common.h:285
void Mem_Shutdown(void)
Definition mem.cpp:518
QGL_EXTERN GLuint GLchar GLuint * len
Definition r_gl.h:99
void Q_strncpyz(char *dest, const char *src, size_t destsize)
Safe strncpy that ensures a trailing zero.
Definition shared.cpp:457
int Q_vsnprintf(char *str, size_t size, const char *format, va_list ap)
Safe (null terminating) vsnprintf implementation.
Definition shared.cpp:535
WNDPROC defOutputProc
HBRUSH hBrushInput
WNDPROC defInputProc
HBRUSH hBrushOutput
char cmdBuffer[MAXCMDLINE]
void Sys_Sleep(int milliseconds)
Calls the win32 sleep function.
void Sys_BacktraceShutdown(void)
void Sys_BacktraceInit(void)
void Sys_ConsoleInit(void)
Initialize the console input (tty mode if possible).
void Sys_Backtrace(void)
On platforms supporting it, print a backtrace.
#define CONSOLE_WINDOW_NAME
static LONG WINAPI Sys_ConsoleEditProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
#define MAX_PRINTMSG
void Sys_Error(const char *error,...)
#define MAX_OUTPUT
const char * Sys_ConsoleInput(void)
Handles input for the console window.
void Sys_ShowConsole(bool show)
void Sys_ConsoleShutdown(void)
Shutdown the console.
#define CONSOLE_WINDOW_STYLE
#define CONSOLE_WINDOW_CLASS_NAME
void Sys_ConsoleOutput(const char *text)
int SV_CountPlayers(void)
Returns the number of spawned players.
Definition sv_main.cpp:1096
static LRESULT CALLBACK Sys_ConsoleProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
static sysConsole_t sys_console
static void Sys_ConsoleLoop(bool error)
Dispatch window messages.
Win32-specific UFO header file.
HINSTANCE global_hInstance