Team Fortress 2 Source Code as on 22/4/2020
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

428 lines
7.4 KiB

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