Fix engine not starting on Windows if linked against SDL > 2.0.5
[xonotic/darkplaces.git] / conproc.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 // conproc.c
21
22 #include "quakedef.h"
23
24 #include <windows.h>
25 #include <wchar.h>
26 #include "conproc.h"
27
28 HANDLE  heventDone;
29 HANDLE  hfileBuffer;
30 HANDLE  heventChildSend;
31 HANDLE  heventParentSend;
32 HANDLE  hStdout;
33 HANDLE  hStdin;
34
35 DWORD RequestProc (DWORD dwNichts);
36 LPVOID GetMappedBuffer (HANDLE hfileBuffer);
37 void ReleaseMappedBuffer (LPVOID pBuffer);
38 BOOL GetScreenBufferLines (int *piLines);
39 BOOL SetScreenBufferLines (int iLines);
40 BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine);
41 BOOL WriteText (LPCTSTR szText);
42 int CharToCode (int c);
43 BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy);
44
45
46 void InitConProc (HANDLE hFile, HANDLE heventParent, HANDLE heventChild)
47 {
48         DWORD   dwID;
49
50 // ignore if we don't have all the events.
51         if (!hFile || !heventParent || !heventChild)
52                 return;
53
54         hfileBuffer = hFile;
55         heventParentSend = heventParent;
56         heventChildSend = heventChild;
57
58 // so we'll know when to go away.
59         heventDone = CreateEvent (NULL, false, false, NULL);
60
61         if (!heventDone)
62         {
63                 Con_Print("Couldn't create heventDone\n");
64                 return;
65         }
66
67         if (!CreateThread (NULL,
68                                            0,
69                                            (LPTHREAD_START_ROUTINE) RequestProc,
70                                            0,
71                                            0,
72                                            &dwID))
73         {
74                 CloseHandle (heventDone);
75                 Con_Print("Couldn't create QHOST thread\n");
76                 return;
77         }
78
79 // save off the input/output handles.
80         hStdout = GetStdHandle (STD_OUTPUT_HANDLE);
81         hStdin = GetStdHandle (STD_INPUT_HANDLE);
82
83 // force 80 character width, at least 25 character height
84         SetConsoleCXCY (hStdout, 80, 25);
85 }
86
87
88 void DeinitConProc (void)
89 {
90         if (heventDone)
91                 SetEvent (heventDone);
92 }
93
94
95 DWORD RequestProc (DWORD dwNichts)
96 {
97         int             *pBuffer;
98         DWORD   dwRet;
99         HANDLE  heventWait[2];
100         int             iBeginLine, iEndLine;
101         
102         heventWait[0] = heventParentSend;
103         heventWait[1] = heventDone;
104
105         while (1)
106         {
107                 dwRet = WaitForMultipleObjects (2, heventWait, false, INFINITE);
108
109         // heventDone fired, so we're exiting.
110                 if (dwRet == WAIT_OBJECT_0 + 1) 
111                         break;
112
113                 pBuffer = (int *) GetMappedBuffer (hfileBuffer);
114                 
115         // hfileBuffer is invalid.  Just leave.
116                 if (!pBuffer)
117                 {
118                         Con_Print("Invalid hfileBuffer\n");
119                         break;
120                 }
121
122                 switch (pBuffer[0])
123                 {
124                         case CCOM_WRITE_TEXT:
125                         // Param1 : Text
126                                 pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1));
127                                 break;
128
129                         case CCOM_GET_TEXT:
130                         // Param1 : Begin line
131                         // Param2 : End line
132                                 iBeginLine = pBuffer[1];
133                                 iEndLine = pBuffer[2];
134                                 pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine, 
135                                                                            iEndLine);
136                                 break;
137
138                         case CCOM_GET_SCR_LINES:
139                         // No params
140                                 pBuffer[0] = GetScreenBufferLines (&pBuffer[1]);
141                                 break;
142
143                         case CCOM_SET_SCR_LINES:
144                         // Param1 : Number of lines
145                                 pBuffer[0] = SetScreenBufferLines (pBuffer[1]);
146                                 break;
147                 }
148
149                 ReleaseMappedBuffer (pBuffer);
150                 SetEvent (heventChildSend);
151         }
152
153         return 0;
154 }
155
156
157 LPVOID GetMappedBuffer (HANDLE hfileBuffer)
158 {
159         LPVOID pBuffer;
160
161         pBuffer = MapViewOfFile (hfileBuffer,
162                                                         FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0);
163
164         return pBuffer;
165 }
166
167
168 void ReleaseMappedBuffer (LPVOID pBuffer)
169 {
170         UnmapViewOfFile (pBuffer);
171 }
172
173
174 BOOL GetScreenBufferLines (int *piLines)
175 {
176         CONSOLE_SCREEN_BUFFER_INFO      info;                                                     
177         BOOL                                            bRet;
178
179         bRet = GetConsoleScreenBufferInfo (hStdout, &info);
180                 
181         if (bRet)
182                 *piLines = info.dwSize.Y;
183
184         return bRet;
185 }
186
187
188 BOOL SetScreenBufferLines (int iLines)
189 {
190
191         return SetConsoleCXCY (hStdout, 80, iLines);
192 }
193
194
195 BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine)
196 {
197         COORD   coord;
198         DWORD   dwRead;
199         BOOL    bRet;
200
201         coord.X = 0;
202         coord.Y = iBeginLine;
203
204         bRet = ReadConsoleOutputCharacter(
205                 hStdout,
206                 pszText,
207                 80 * (iEndLine - iBeginLine + 1),
208                 coord,
209                 &dwRead);
210
211         // Make sure it's null terminated.
212         if (bRet)
213                 pszText[dwRead] = '\0';
214
215         return bRet;
216 }
217
218
219 BOOL WriteText (LPCTSTR szText)
220 {
221         DWORD                   dwWritten;
222         INPUT_RECORD    rec;
223         char                    upper, *sz;
224
225         sz = (LPTSTR) szText;
226
227         while (*sz)
228         {
229         // 13 is the code for a carriage return (\n) instead of 10.
230                 if (*sz == 10)
231                         *sz = 13;
232
233                 upper = toupper(*sz);
234
235                 rec.EventType = KEY_EVENT;
236                 rec.Event.KeyEvent.bKeyDown = true;
237                 rec.Event.KeyEvent.wRepeatCount = 1;
238                 rec.Event.KeyEvent.wVirtualKeyCode = upper;
239                 rec.Event.KeyEvent.wVirtualScanCode = CharToCode (*sz);
240                 rec.Event.KeyEvent.uChar.AsciiChar = *sz;
241                 rec.Event.KeyEvent.uChar.UnicodeChar = *sz;
242                 rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0; 
243
244                 WriteConsoleInput(
245                         hStdin,
246                         &rec,
247                         1,
248                         &dwWritten);
249
250                 rec.Event.KeyEvent.bKeyDown = false;
251
252                 WriteConsoleInput(
253                         hStdin,
254                         &rec,
255                         1,
256                         &dwWritten);
257
258                 sz++;
259         }
260
261         return true;
262 }
263
264
265 int CharToCode (int c)
266 {
267         char upper;
268                 
269         upper = toupper(c);
270
271         switch (c)
272         {
273                 case 13:
274                         return 28;
275
276                 default:
277                         break;
278         }
279
280         if (isalpha(c))
281                 return (30 + upper - 65); 
282
283         if (isdigit(c))
284                 return (1 + upper - 47);
285
286         return c;
287 }
288
289
290 BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy)
291 {
292         CONSOLE_SCREEN_BUFFER_INFO      info;
293         COORD                                           coordMax;
294  
295         coordMax = GetLargestConsoleWindowSize(hStdout);
296
297         if (cy > coordMax.Y)
298                 cy = coordMax.Y;
299
300         if (cx > coordMax.X)
301                 cx = coordMax.X;
302  
303         if (!GetConsoleScreenBufferInfo(hStdout, &info))
304                 return false;
305  
306 // height
307     info.srWindow.Left = 0;         
308     info.srWindow.Right = info.dwSize.X - 1;                
309     info.srWindow.Top = 0;
310     info.srWindow.Bottom = cy - 1;          
311  
312         if (cy < info.dwSize.Y)
313         {
314                 if (!SetConsoleWindowInfo(hStdout, true, &info.srWindow))
315                         return false;
316  
317                 info.dwSize.Y = cy;
318  
319                 if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
320                         return false;
321     }
322     else if (cy > info.dwSize.Y)
323     {
324                 info.dwSize.Y = cy;
325  
326                 if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
327                         return false;
328  
329                 if (!SetConsoleWindowInfo(hStdout, true, &info.srWindow))
330                         return false;
331     }
332  
333         if (!GetConsoleScreenBufferInfo(hStdout, &info))
334                 return false;
335  
336 // width
337         info.srWindow.Left = 0;         
338         info.srWindow.Right = cx - 1;
339         info.srWindow.Top = 0;
340         info.srWindow.Bottom = info.dwSize.Y - 1;               
341  
342         if (cx < info.dwSize.X)
343         {
344                 if (!SetConsoleWindowInfo(hStdout, true, &info.srWindow))
345                         return false;
346  
347                 info.dwSize.X = cx;
348     
349                 if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
350                         return false;
351         }
352         else if (cx > info.dwSize.X)
353         {
354                 info.dwSize.X = cx;
355  
356                 if (!SetConsoleScreenBufferSize(hStdout, info.dwSize))
357                         return false;
358  
359                 if (!SetConsoleWindowInfo(hStdout, true, &info.srWindow))
360                         return false;
361         }
362  
363         return true;
364 }
365