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