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