/*
** Command & Conquer Generals Zero Hour(tm)
** Copyright 2025 Electronic Arts 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 3 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, see .
*/
/////////////////////////////////////////////////////////////////////////EA-V1
// $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_io_con.cpp $
// $Author: mhoffe $
// $Revision: #1 $
// $DateTime: 2003/07/03 11:55:26 $
//
// ©2003 Electronic Arts
//
// Debug I/O class con (console window)
//////////////////////////////////////////////////////////////////////////////
#include "_pch.h"
#include
#include // needed for placement new prototype
DebugIOCon::DebugIOCon(void):
m_inputUsed(0), m_inputRead(0)
{
// check: is there already a console window open?
m_allocatedConsole=AllocConsole()!=0;
if (m_allocatedConsole)
{
HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
SetConsoleMode(h,0);
// make screen buffer same size as currently displayed area
// (prevents that our input line gets scrolled out of view)
h=GetStdHandle(STD_OUTPUT_HANDLE);
CONSOLE_SCREEN_BUFFER_INFO info;
GetConsoleScreenBufferInfo(h,&info);
COORD newSize;
newSize.X=info.srWindow.Right+1;
newSize.Y=info.srWindow.Bottom+1;
SetConsoleScreenBufferSize(h,newSize);
// hide cursor
CONSOLE_CURSOR_INFO ci;
ci.dwSize=1;
ci.bVisible=FALSE;
SetConsoleCursorInfo(h,&ci);
Write(StringType::Other,NULL,"\n\nEA/Debug console open\n\n");
}
}
DebugIOCon::~DebugIOCon()
{
// close console if we allocated it
if (m_allocatedConsole)
FreeConsole();
}
int DebugIOCon::Read(char *buf, int maxchar)
{
// We are not supporting reading from the console
// unless we allocated that console ourselves.
// The reason for that is that if we didn't allocate
// the console ourselves we're running as a console
// process and if we'd be reading data from the console
// we would probably be snatching away keyboard data
// for the process that is using that console.
if (!m_allocatedConsole)
return 0;
// are we doing a continuous read?
if (m_inputRead)
{
int numRead;
if (maxchar>m_inputUsed-m_inputRead)
{
// return all
numRead=m_inputUsed-m_inputRead;
memcpy(buf,m_input+m_inputRead,numRead);
m_inputRead=m_inputUsed=0;
}
else
{
// return partially
numRead=maxchar;
memcpy(buf,m_input+m_inputRead,numRead);
m_inputRead+=maxchar;
}
return numRead;
}
// update our input buffer
HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
bool returnChars=false;
for (;;)
{
DWORD dwRecords;
if (!GetNumberOfConsoleInputEvents(h,&dwRecords))
break;
if (!dwRecords)
break;
INPUT_RECORD record;
ReadConsoleInput(h,&record,1,&dwRecords);
if (record.EventType!=KEY_EVENT)
continue;
KEY_EVENT_RECORD &key=record.Event.KeyEvent;
if (!key.bKeyDown||!key.uChar.AsciiChar)
continue;
if (key.uChar.AsciiChar=='\r'||
key.uChar.AsciiChar=='\n')
{
m_input[m_inputUsed++]='\n';
returnChars=true;
break;
}
/// @todo_opt if somebody wants this can be improved by adding support for cursor keys, history, etc
if (key.uChar.AsciiChar=='\b')
{
if (m_inputUsed)
m_inputUsed--;
}
else if (((unsigned char)key.uChar.AsciiChar)>=' ')
{
if (m_inputUsed1)
{
*buf=*m_input;
m_inputRead=1;
return 1;
}
return 0;
}
void DebugIOCon::Write(StringType type, const char *src, const char *str)
{
if (type==StringType::StructuredCmdReply||!str)
return;
DWORD dwDummy;
WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),str,strlen(str),&dwDummy,NULL);
}
void DebugIOCon::Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
unsigned argn, const char * const * argv)
{
if (!cmd||!strcmp(cmd,"help"))
{
dbg << "con I/O help:\n"
" add [ [ ] ]\n"
" create con I/O (optionally specifying the window size)\n";
}
else if (!strcmp(cmd,"add"))
{
if (argn>0&&m_allocatedConsole)
{
// resize our console area
HANDLE h=GetStdHandle(STD_OUTPUT_HANDLE);
COORD newSize;
newSize.X=atoi(argv[0]);
newSize.Y=argn>1?atoi(argv[1]):25;
SMALL_RECT sr;
sr.Left=sr.Top=0;
sr.Right=newSize.X-1;
sr.Bottom=newSize.Y-1;
SetConsoleWindowInfo(h,TRUE,&sr);
SetConsoleScreenBufferSize(h,newSize);
SetConsoleWindowInfo(h,TRUE,&sr);
}
}
}
DebugIOInterface *DebugIOCon::Create(void)
{
return new (DebugAllocMemory(sizeof(DebugIOCon))) DebugIOCon();
}
void DebugIOCon::Delete(void)
{
this->~DebugIOCon();
DebugFreeMemory(this);
}