From 0eb042555b1cd172e5fc722fd8c233efb1fb1059 Mon Sep 17 00:00:00 2001 From: Yamagi Burmeister Date: Sun, 3 Jun 2012 12:14:05 +0200 Subject: [PATCH] Add conproc.c and the coresponding header conproc.c implements support functions for the console windows used by the dedicated server. It was taken from ioQuake2 and cleaned up for the inclusion in Yamagi Quake II. --- Makefile | 4 +- src/windows/conproc.c | 459 +++++++++++++++++++++++++++++++++++ src/windows/header/conproc.h | 29 +++ src/windows/system.c | 2 +- 4 files changed, 492 insertions(+), 2 deletions(-) create mode 100644 src/windows/conproc.c create mode 100644 src/windows/header/conproc.h diff --git a/Makefile b/Makefile index 50cd0762..634c0b21 100644 --- a/Makefile +++ b/Makefile @@ -474,7 +474,9 @@ SERVER_OBJS_ := \ src/server/sv_world.o ifeq ($(OS), Windows) -SERVER_OBJS_ += +SERVER_OBJS_ += \ + src/windows/conproc.o \ + src/windows/system.o else SERVER_OBJS_ += \ src/unix/glob.o \ diff --git a/src/windows/conproc.c b/src/windows/conproc.c new file mode 100644 index 00000000..8c973294 --- /dev/null +++ b/src/windows/conproc.c @@ -0,0 +1,459 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * The "qhost" subsystem, hosting the console window. + * + * ======================================================================= + */ + +#include +#include +#include +#include "header/conproc.h" + +#define CCOM_WRITE_TEXT 0x2 +#define CCOM_GET_TEXT 0x3 +#define CCOM_GET_SCR_LINES 0x4 +#define CCOM_SET_SCR_LINES 0x5 + +HANDLE heventDone; +HANDLE hfileBuffer; +HANDLE heventChildSend; +HANDLE heventParentSend; +HANDLE hStdout; +HANDLE hStdin; + +LPVOID GetMappedBuffer(HANDLE hfileBuffer); +BOOL GetScreenBufferLines(int *piLines); +BOOL SetScreenBufferLines(int iLines); +BOOL ReadText(LPTSTR pszText, int iBeginLine, int iEndLine); +BOOL WriteText(LPCTSTR szText); +BOOL SetConsoleCXCY(HANDLE hStdout, int cx, int cy); +int CharToCode(char c); +unsigned int _stdcall RequestProc(void *arg); +void ReleaseMappedBuffer(LPVOID pBuffer); + +int ccom_argc; +char **ccom_argv; + +/* + * Returns the position (1 to argc-1) in the + * program's argument list where the given + * parameter apears, or 0 if not present + */ +int +CCheckParm(char *parm) +{ + int i; + + for (i = 1; i < ccom_argc; i++) + { + if (!ccom_argv[i]) + { + continue; + } + + if (!strcmp(parm, ccom_argv[i])) + { + return i; + } + } + + return 0; +} + +void +InitConProc(int argc, char **argv) +{ + unsigned threadAddr; + HANDLE hFile; + HANDLE heventParent; + HANDLE heventChild; + int t; + + ccom_argc = argc; + ccom_argv = argv; + + /* give QHOST a chance to hook into the console */ + if ((t = CCheckParm("-HFILE")) > 0) + { + if (t < argc) + { + hFile = (HANDLE)atoi(ccom_argv[t + 1]); + } + } + + if ((t = CCheckParm("-HPARENT")) > 0) + { + if (t < argc) + { + heventParent = (HANDLE)atoi(ccom_argv[t + 1]); + } + } + + if ((t = CCheckParm("-HCHILD")) > 0) + { + if (t < argc) + { + heventChild = (HANDLE)atoi(ccom_argv[t + 1]); + } + } + + /* ignore if we don't have all the events. */ + if (!hFile || !heventParent || !heventChild) + { + printf("Qhost not present.\n"); + return; + } + + printf("Initializing for qhost.\n"); + + hfileBuffer = hFile; + heventParentSend = heventParent; + heventChildSend = heventChild; + + /* so we'll know when to go away. */ + heventDone = CreateEvent(NULL, FALSE, FALSE, NULL); + + if (!heventDone) + { + printf("Couldn't create heventDone\n"); + return; + } + + if (!_beginthreadex(NULL, 0, RequestProc, NULL, 0, &threadAddr)) + { + CloseHandle(heventDone); + printf("Couldn't create QHOST thread\n"); + return; + } + + /* save off the input/output handles. */ + hStdout = GetStdHandle(STD_OUTPUT_HANDLE); + hStdin = GetStdHandle(STD_INPUT_HANDLE); + + /* force 80 character width, + at least 25 character height */ + SetConsoleCXCY(hStdout, 80, 25); +} + +void +DeinitConProc(void) +{ + if (heventDone) + { + SetEvent(heventDone); + } +} + +unsigned _stdcall +RequestProc(void *arg) +{ + int *pBuffer; + DWORD dwRet; + HANDLE heventWait[2]; + int iBeginLine, iEndLine; + + heventWait[0] = heventParentSend; + heventWait[1] = heventDone; + + while (1) + { + dwRet = WaitForMultipleObjects(2, heventWait, FALSE, INFINITE); + + /* heventDone fired, so we're exiting. */ + if (dwRet == WAIT_OBJECT_0 + 1) + { + break; + } + + pBuffer = (int *)GetMappedBuffer(hfileBuffer); + + /* hfileBuffer is invalid. Just leave. */ + if (!pBuffer) + { + printf("Invalid hfileBuffer\n"); + break; + } + + switch (pBuffer[0]) + { + case CCOM_WRITE_TEXT: + pBuffer[0] = WriteText((LPCTSTR)(pBuffer + 1)); + break; + + case CCOM_GET_TEXT: + iBeginLine = pBuffer[1]; + iEndLine = pBuffer[2]; + pBuffer[0] = ReadText((LPTSTR)(pBuffer + 1), iBeginLine, + iEndLine); + break; + + case CCOM_GET_SCR_LINES: + pBuffer[0] = GetScreenBufferLines(&pBuffer[1]); + break; + + case CCOM_SET_SCR_LINES: + pBuffer[0] = SetScreenBufferLines(pBuffer[1]); + break; + } + + ReleaseMappedBuffer(pBuffer); + SetEvent(heventChildSend); + } + + _endthreadex(0); + return 0; +} + +LPVOID +GetMappedBuffer(HANDLE hfileBuffer) +{ + LPVOID pBuffer; + + pBuffer = MapViewOfFile(hfileBuffer, + FILE_MAP_READ | FILE_MAP_WRITE, 0, 0, 0); + + return pBuffer; +} + +void +ReleaseMappedBuffer(LPVOID pBuffer) +{ + UnmapViewOfFile(pBuffer); +} + +BOOL +GetScreenBufferLines(int *piLines) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + BOOL bRet; + + bRet = GetConsoleScreenBufferInfo(hStdout, &info); + + if (bRet) + { + *piLines = info.dwSize.Y; + } + + return bRet; +} + +BOOL +SetScreenBufferLines(int iLines) +{ + return SetConsoleCXCY(hStdout, 80, iLines); +} + +BOOL +ReadText(LPTSTR pszText, int iBeginLine, int iEndLine) +{ + COORD coord; + DWORD dwRead; + BOOL bRet; + + coord.X = 0; + coord.Y = iBeginLine; + + bRet = ReadConsoleOutputCharacter(hStdout, pszText, + 80 * (iEndLine - iBeginLine + 1), coord, + &dwRead); + + /* Make sure it's null terminated. */ + if (bRet) + { + pszText[dwRead] = '\0'; + } + + return bRet; +} + +BOOL +WriteText(LPCTSTR szText) +{ + DWORD dwWritten; + INPUT_RECORD rec; + char upper, *sz; + + sz = (LPTSTR)szText; + + while (*sz) + { + /* 13 is the code for a carriage + return (\n) instead of 10. */ + if (*sz == 10) + { + *sz = 13; + } + + upper = toupper(*sz); + + rec.EventType = KEY_EVENT; + rec.Event.KeyEvent.bKeyDown = TRUE; + rec.Event.KeyEvent.wRepeatCount = 1; + rec.Event.KeyEvent.wVirtualKeyCode = upper; + rec.Event.KeyEvent.wVirtualScanCode = CharToCode(*sz); + rec.Event.KeyEvent.uChar.AsciiChar = *sz; + rec.Event.KeyEvent.uChar.UnicodeChar = *sz; + rec.Event.KeyEvent.dwControlKeyState = isupper(*sz) ? 0x80 : 0x0; + + WriteConsoleInput(hStdin, &rec, 1, &dwWritten); + + rec.Event.KeyEvent.bKeyDown = FALSE; + + WriteConsoleInput(hStdin, &rec, 1, &dwWritten); + + sz++; + } + + return TRUE; +} + +int +CharToCode(char c) +{ + char upper; + + upper = toupper(c); + + switch (c) + { + case 13: + return 28; + + default: + break; + } + + if (isalpha(c)) + { + return 30 + upper - 65; + } + + if (isdigit(c)) + { + return 1 + upper - 47; + } + + return c; +} + +BOOL +SetConsoleCXCY(HANDLE hStdout, int cx, int cy) +{ + CONSOLE_SCREEN_BUFFER_INFO info; + COORD coordMax; + + coordMax = GetLargestConsoleWindowSize(hStdout); + + if (cy > coordMax.Y) + { + cy = coordMax.Y; + } + + if (cx > coordMax.X) + { + cx = coordMax.X; + } + + if (!GetConsoleScreenBufferInfo(hStdout, &info)) + { + return FALSE; + } + + /* height */ + info.srWindow.Left = 0; + info.srWindow.Right = info.dwSize.X - 1; + info.srWindow.Top = 0; + info.srWindow.Bottom = cy - 1; + + if (cy < info.dwSize.Y) + { + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + { + return FALSE; + } + + info.dwSize.Y = cy; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + { + return FALSE; + } + } + else if (cy > info.dwSize.Y) + { + info.dwSize.Y = cy; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + { + return FALSE; + } + + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + { + return FALSE; + } + } + + if (!GetConsoleScreenBufferInfo(hStdout, &info)) + { + return FALSE; + } + + /* width */ + info.srWindow.Left = 0; + info.srWindow.Right = cx - 1; + info.srWindow.Top = 0; + info.srWindow.Bottom = info.dwSize.Y - 1; + + if (cx < info.dwSize.X) + { + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + { + return FALSE; + } + + info.dwSize.X = cx; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + { + return FALSE; + } + } + else if (cx > info.dwSize.X) + { + info.dwSize.X = cx; + + if (!SetConsoleScreenBufferSize(hStdout, info.dwSize)) + { + return FALSE; + } + + if (!SetConsoleWindowInfo(hStdout, TRUE, &info.srWindow)) + { + return FALSE; + } + } + + return TRUE; +} + diff --git a/src/windows/header/conproc.h b/src/windows/header/conproc.h new file mode 100644 index 00000000..011347de --- /dev/null +++ b/src/windows/header/conproc.h @@ -0,0 +1,29 @@ +/* + * Copyright (C) 1997-2001 Id Software, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or (at + * your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA + * 02111-1307, USA. + * + * ======================================================================= + * + * Header file to the "qhost" subsystem. + * + * ======================================================================= + */ + +void InitConProc(int argc, char **argv); +void DeinitConProc(void); + diff --git a/src/windows/system.c b/src/windows/system.c index 039f3a44..c18ca94d 100644 --- a/src/windows/system.c +++ b/src/windows/system.c @@ -34,7 +34,7 @@ #include #include "../common/header/common.h" -#include "conproc.h" +#include "header/conproc.h" #include "resource.h" #include "winquake.h"