/* ** 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); }