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 CONSOLE_SCREEN_BUFFER_INFO info; 48 int wheight, wwidth; 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_SafePrintf ("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_SafePrintf ("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_SafePrintf ("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 (char 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 366