WarpZones:
[divverent/darkplaces.git] / sys_win.c
1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
3
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18
19 */
20 // sys_win.c -- Win32 system interface code
21
22 #include "quakedef.h"
23 #include <windows.h>
24 #include <mmsystem.h>
25 #ifdef SUPPORTDIRECTX
26 #include <dsound.h>
27 #endif
28 #include "errno.h"
29 #include "resource.h"
30 #include "conproc.h"
31 #include "direct.h"
32
33 HANDLE                          hinput, houtput;
34
35 #ifdef QHOST
36 static HANDLE   tevent;
37 static HANDLE   hFile;
38 static HANDLE   heventParent;
39 static HANDLE   heventChild;
40 #endif
41
42
43 /*
44 ===============================================================================
45
46 SYSTEM IO
47
48 ===============================================================================
49 */
50
51 void Sys_Error (const char *error, ...)
52 {
53         va_list         argptr;
54         char            text[MAX_INPUTLINE];
55         static int      in_sys_error0 = 0;
56         static int      in_sys_error1 = 0;
57         static int      in_sys_error2 = 0;
58         static int      in_sys_error3 = 0;
59
60         va_start (argptr, error);
61         dpvsnprintf (text, sizeof (text), error, argptr);
62         va_end (argptr);
63
64         Con_Printf ("Quake Error: %s\n", text);
65
66         // close video so the message box is visible, unless we already tried that
67         if (!in_sys_error0 && cls.state != ca_dedicated)
68         {
69                 in_sys_error0 = 1;
70                 VID_Shutdown();
71         }
72
73         if (!in_sys_error3 && cls.state != ca_dedicated)
74         {
75                 in_sys_error3 = true;
76                 MessageBox(NULL, text, "Quake Error", MB_OK | MB_SETFOREGROUND | MB_ICONSTOP);
77         }
78
79         if (!in_sys_error1)
80         {
81                 in_sys_error1 = 1;
82                 Host_Shutdown ();
83         }
84
85 // shut down QHOST hooks if necessary
86         if (!in_sys_error2)
87         {
88                 in_sys_error2 = 1;
89                 Sys_Shutdown ();
90         }
91
92         exit (1);
93 }
94
95 void Sys_Shutdown (void)
96 {
97 #ifdef QHOST
98         if (tevent)
99                 CloseHandle (tevent);
100 #endif
101
102         if (cls.state == ca_dedicated)
103                 FreeConsole ();
104
105 #ifdef QHOST
106 // shut down QHOST hooks if necessary
107         DeinitConProc ();
108 #endif
109 }
110
111 void Sys_PrintToTerminal(const char *text)
112 {
113         DWORD dummy;
114         extern HANDLE houtput;
115
116         if ((houtput != 0) && (houtput != INVALID_HANDLE_VALUE))
117                 WriteFile(houtput, text, (DWORD) strlen(text), &dummy, NULL);
118 }
119
120 char *Sys_ConsoleInput (void)
121 {
122         static char text[MAX_INPUTLINE];
123         static int len;
124         INPUT_RECORD recs[1024];
125         int ch;
126         DWORD numread, numevents, dummy;
127
128         if (cls.state != ca_dedicated)
129                 return NULL;
130
131         for ( ;; )
132         {
133                 if (!GetNumberOfConsoleInputEvents (hinput, &numevents))
134                 {
135                         cls.state = ca_disconnected;
136                         Sys_Error ("Error getting # of console events (error code %x)", (unsigned int)GetLastError());
137                 }
138
139                 if (numevents <= 0)
140                         break;
141
142                 if (!ReadConsoleInput(hinput, recs, 1, &numread))
143                 {
144                         cls.state = ca_disconnected;
145                         Sys_Error ("Error reading console input (error code %x)", (unsigned int)GetLastError());
146                 }
147
148                 if (numread != 1)
149                 {
150                         cls.state = ca_disconnected;
151                         Sys_Error ("Couldn't read console input (error code %x)", (unsigned int)GetLastError());
152                 }
153
154                 if (recs[0].EventType == KEY_EVENT)
155                 {
156                         if (!recs[0].Event.KeyEvent.bKeyDown)
157                         {
158                                 ch = recs[0].Event.KeyEvent.uChar.AsciiChar;
159
160                                 switch (ch)
161                                 {
162                                         case '\r':
163                                                 WriteFile(houtput, "\r\n", 2, &dummy, NULL);
164
165                                                 if (len)
166                                                 {
167                                                         text[len] = 0;
168                                                         len = 0;
169                                                         return text;
170                                                 }
171
172                                                 break;
173
174                                         case '\b':
175                                                 WriteFile(houtput, "\b \b", 3, &dummy, NULL);
176                                                 if (len)
177                                                 {
178                                                         len--;
179                                                 }
180                                                 break;
181
182                                         default:
183                                                 if (ch >= (int) (unsigned char) ' ')
184                                                 {
185                                                         WriteFile(houtput, &ch, 1, &dummy, NULL);
186                                                         text[len] = ch;
187                                                         len = (len + 1) & 0xff;
188                                                 }
189
190                                                 break;
191
192                                 }
193                         }
194                 }
195         }
196
197         return NULL;
198 }
199
200 char *Sys_GetClipboardData (void)
201 {
202         char *data = NULL;
203         char *cliptext;
204
205         if (OpenClipboard (NULL) != 0)
206         {
207                 HANDLE hClipboardData;
208
209                 if ((hClipboardData = GetClipboardData (CF_TEXT)) != 0)
210                 {
211                         if ((cliptext = (char *)GlobalLock (hClipboardData)) != 0)
212                         {
213                                 size_t allocsize;
214                                 allocsize = GlobalSize (hClipboardData) + 1;
215                                 data = (char *)Z_Malloc (allocsize);
216                                 strlcpy (data, cliptext, allocsize);
217                                 GlobalUnlock (hClipboardData);
218                         }
219                 }
220                 CloseClipboard ();
221         }
222         return data;
223 }
224
225 void Sys_InitConsole (void)
226 {
227 #ifdef QHOST
228         int t;
229
230         // initialize the windows dedicated server console if needed
231         tevent = CreateEvent(NULL, false, false, NULL);
232
233         if (!tevent)
234                 Sys_Error ("Couldn't create event");
235 #endif
236
237         houtput = GetStdHandle (STD_OUTPUT_HANDLE);
238         hinput = GetStdHandle (STD_INPUT_HANDLE);
239
240         // LordHavoc: can't check cls.state because it hasn't been initialized yet
241         // if (cls.state == ca_dedicated)
242         if (COM_CheckParm("-dedicated"))
243         {
244                 //if ((houtput == 0) || (houtput == INVALID_HANDLE_VALUE)) // LordHavoc: on Windows XP this is never 0 or invalid, but hinput is invalid
245                 {
246                         if (!AllocConsole ())
247                                 Sys_Error ("Couldn't create dedicated server console (error code %x)", (unsigned int)GetLastError());
248                         houtput = GetStdHandle (STD_OUTPUT_HANDLE);
249                         hinput = GetStdHandle (STD_INPUT_HANDLE);
250                 }
251                 if ((houtput == 0) || (houtput == INVALID_HANDLE_VALUE))
252                         Sys_Error ("Couldn't create dedicated server console");
253
254
255 #ifdef QHOST
256 #ifdef _WIN64
257 #define atoi _atoi64
258 #endif
259         // give QHOST a chance to hook into the console
260                 if ((t = COM_CheckParm ("-HFILE")) > 0)
261                 {
262                         if (t < com_argc)
263                                 hFile = (HANDLE)atoi (com_argv[t+1]);
264                 }
265
266                 if ((t = COM_CheckParm ("-HPARENT")) > 0)
267                 {
268                         if (t < com_argc)
269                                 heventParent = (HANDLE)atoi (com_argv[t+1]);
270                 }
271
272                 if ((t = COM_CheckParm ("-HCHILD")) > 0)
273                 {
274                         if (t < com_argc)
275                                 heventChild = (HANDLE)atoi (com_argv[t+1]);
276                 }
277
278                 InitConProc (hFile, heventParent, heventChild);
279 #endif
280         }
281
282 // because sound is off until we become active
283         S_BlockSound ();
284 }
285
286 /*
287 ==============================================================================
288
289 WINDOWS CRAP
290
291 ==============================================================================
292 */
293
294
295 /*
296 ==================
297 WinMain
298 ==================
299 */
300 HINSTANCE       global_hInstance;
301 const char      *argv[MAX_NUM_ARGVS];
302 char            program_name[MAX_OSPATH];
303
304 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
305 {
306         MEMORYSTATUS lpBuffer;
307
308         /* previous instances do not exist in Win32 */
309         if (hPrevInstance)
310                 return 0;
311
312         global_hInstance = hInstance;
313
314         lpBuffer.dwLength = sizeof(MEMORYSTATUS);
315         GlobalMemoryStatus (&lpBuffer);
316
317         program_name[sizeof(program_name)-1] = 0;
318         GetModuleFileNameA(NULL, program_name, sizeof(program_name) - 1);
319
320         com_argc = 1;
321         com_argv = argv;
322         argv[0] = program_name;
323
324         // FIXME: this tokenizer is rather redundent, call a more general one
325         while (*lpCmdLine && (com_argc < MAX_NUM_ARGVS))
326         {
327                 while (*lpCmdLine && ISWHITESPACE(*lpCmdLine))
328                         lpCmdLine++;
329
330                 if (!*lpCmdLine)
331                         break;
332
333                 if (*lpCmdLine == '\"')
334                 {
335                         // quoted string
336                         lpCmdLine++;
337                         argv[com_argc] = lpCmdLine;
338                         com_argc++;
339                         while (*lpCmdLine && (*lpCmdLine != '\"'))
340                                 lpCmdLine++;
341                 }
342                 else
343                 {
344                         // unquoted word
345                         argv[com_argc] = lpCmdLine;
346                         com_argc++;
347                         while (*lpCmdLine && !ISWHITESPACE(*lpCmdLine))
348                                 lpCmdLine++;
349                 }
350
351                 if (*lpCmdLine)
352                 {
353                         *lpCmdLine = 0;
354                         lpCmdLine++;
355                 }
356         }
357
358         Sys_ProvideSelfFD();
359
360         Host_Main();
361
362         /* return success of application */
363         return true;
364 }
365
366 #if 0
367 // unused, this file is only used when building windows client and vid_wgl provides WinMain() instead
368 int main (int argc, const char* argv[])
369 {
370         MEMORYSTATUS lpBuffer;
371
372         global_hInstance = GetModuleHandle (0);
373
374         lpBuffer.dwLength = sizeof(MEMORYSTATUS);
375         GlobalMemoryStatus (&lpBuffer);
376
377         program_name[sizeof(program_name)-1] = 0;
378         GetModuleFileNameA(NULL, program_name, sizeof(program_name) - 1);
379
380         com_argc = argc;
381         com_argv = argv;
382
383         Host_Main();
384
385         return true;
386 }
387 #endif
388
389 qboolean sys_supportsdlgetticks = false;
390 unsigned int Sys_SDL_GetTicks (void)
391 {
392         Sys_Error("Called Sys_SDL_GetTicks on non-SDL target");
393         return 0;
394 }
395 void Sys_SDL_Delay (unsigned int milliseconds)
396 {
397         Sys_Error("Called Sys_SDL_Delay on non-SDL target");
398 }