File: win32\conproc.c

    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      
  432