quakeforge/nq/source/conproc.c

350 lines
7.0 KiB
C

/*
conproc.c
@description@
Copyright (C) 1996-1997 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:
Free Software Foundation, Inc.
59 Temple Place - Suite 330
Boston, MA 02111-1307, USA
*/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
static __attribute__ ((unused)) const char rcsid[] =
"$Id$";
#include <ctype.h>
#include "winquake.h"
#include "QF/console.h"
#include "conproc.h"
HANDLE heventDone;
HANDLE hfileBuffer;
HANDLE heventChildSend;
HANDLE heventParentSend;
HANDLE hStdout;
HANDLE hStdin;
DWORD RequestProc (DWORD dwNichts);
LPVOID GetMappedBuffer (HANDLE hfileBuffer);
void ReleaseMappedBuffer (LPVOID pBuffer);
BOOL GetScreenBufferLines (int *piLines);
BOOL SetScreenBufferLines (int iLines);
BOOL ReadText (LPTSTR pszText, int iBeginLine, int iEndLine);
BOOL WriteText (LPCTSTR szText);
int CharToCode (char c);
BOOL SetConsoleCXCY (HANDLE hStdout, int cx, int cy);
void
InitConProc (HANDLE hFile, HANDLE heventParent, HANDLE heventChild)
{
DWORD dwID;
// ignore if we don't have all the events.
if (!hFile || !heventParent || !heventChild)
return;
hfileBuffer = hFile;
heventParentSend = heventParent;
heventChildSend = heventChild;
// so we'll know when to go away.
heventDone = CreateEvent (NULL, FALSE, FALSE, NULL);
if (!heventDone) {
Con_Printf ("Couldn't create heventDone\n");
return;
}
if (!CreateThread (NULL,
0, (LPTHREAD_START_ROUTINE) RequestProc, 0, 0, &dwID)) {
CloseHandle (heventDone);
Con_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);
}
DWORD
RequestProc (DWORD dwNichts)
{
int iBeginLine, iEndLine;
int *pBuffer;
DWORD dwRet;
HANDLE heventWait[2];
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) {
Con_Printf ("Invalid hfileBuffer\n");
break;
}
switch (pBuffer[0]) {
case CCOM_WRITE_TEXT:
// Param1 : Text
pBuffer[0] = WriteText ((LPCTSTR) (pBuffer + 1));
break;
case CCOM_GET_TEXT:
// Param1 : Begin line
// Param2 : End line
iBeginLine = pBuffer[1];
iEndLine = pBuffer[2];
pBuffer[0] = ReadText ((LPTSTR) (pBuffer + 1), iBeginLine,
iEndLine);
break;
case CCOM_GET_SCR_LINES:
// No params
pBuffer[0] = GetScreenBufferLines (&pBuffer[1]);
break;
case CCOM_SET_SCR_LINES:
// Param1 : Number of lines
pBuffer[0] = SetScreenBufferLines (pBuffer[1]);
break;
}
ReleaseMappedBuffer (pBuffer);
SetEvent (heventChildSend);
}
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)
{
BOOL bRet;
COORD coord;
DWORD dwRead;
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)
{
char upper, *sz;
DWORD dwWritten;
INPUT_RECORD rec;
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;
}