debug_io_con.cpp 6.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230
  1. /*
  2. ** Command & Conquer Generals Zero Hour(tm)
  3. ** Copyright 2025 Electronic Arts Inc.
  4. **
  5. ** This program is free software: you can redistribute it and/or modify
  6. ** it under the terms of the GNU General Public License as published by
  7. ** the Free Software Foundation, either version 3 of the License, or
  8. ** (at your option) any later version.
  9. **
  10. ** This program is distributed in the hope that it will be useful,
  11. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. ** 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, see <http://www.gnu.org/licenses/>.
  17. */
  18. /////////////////////////////////////////////////////////////////////////EA-V1
  19. // $File: //depot/GeneralsMD/Staging/code/Libraries/Source/debug/debug_io_con.cpp $
  20. // $Author: mhoffe $
  21. // $Revision: #1 $
  22. // $DateTime: 2003/07/03 11:55:26 $
  23. //
  24. // ©2003 Electronic Arts
  25. //
  26. // Debug I/O class con (console window)
  27. //////////////////////////////////////////////////////////////////////////////
  28. #include "_pch.h"
  29. #include <stdlib.h>
  30. #include <new> // needed for placement new prototype
  31. DebugIOCon::DebugIOCon(void):
  32. m_inputUsed(0), m_inputRead(0)
  33. {
  34. // check: is there already a console window open?
  35. m_allocatedConsole=AllocConsole()!=0;
  36. if (m_allocatedConsole)
  37. {
  38. HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
  39. SetConsoleMode(h,0);
  40. // make screen buffer same size as currently displayed area
  41. // (prevents that our input line gets scrolled out of view)
  42. h=GetStdHandle(STD_OUTPUT_HANDLE);
  43. CONSOLE_SCREEN_BUFFER_INFO info;
  44. GetConsoleScreenBufferInfo(h,&info);
  45. COORD newSize;
  46. newSize.X=info.srWindow.Right+1;
  47. newSize.Y=info.srWindow.Bottom+1;
  48. SetConsoleScreenBufferSize(h,newSize);
  49. // hide cursor
  50. CONSOLE_CURSOR_INFO ci;
  51. ci.dwSize=1;
  52. ci.bVisible=FALSE;
  53. SetConsoleCursorInfo(h,&ci);
  54. Write(StringType::Other,NULL,"\n\nEA/Debug console open\n\n");
  55. }
  56. }
  57. DebugIOCon::~DebugIOCon()
  58. {
  59. // close console if we allocated it
  60. if (m_allocatedConsole)
  61. FreeConsole();
  62. }
  63. int DebugIOCon::Read(char *buf, int maxchar)
  64. {
  65. // We are not supporting reading from the console
  66. // unless we allocated that console ourselves.
  67. // The reason for that is that if we didn't allocate
  68. // the console ourselves we're running as a console
  69. // process and if we'd be reading data from the console
  70. // we would probably be snatching away keyboard data
  71. // for the process that is using that console.
  72. if (!m_allocatedConsole)
  73. return 0;
  74. // are we doing a continuous read?
  75. if (m_inputRead)
  76. {
  77. int numRead;
  78. if (maxchar>m_inputUsed-m_inputRead)
  79. {
  80. // return all
  81. numRead=m_inputUsed-m_inputRead;
  82. memcpy(buf,m_input+m_inputRead,numRead);
  83. m_inputRead=m_inputUsed=0;
  84. }
  85. else
  86. {
  87. // return partially
  88. numRead=maxchar;
  89. memcpy(buf,m_input+m_inputRead,numRead);
  90. m_inputRead+=maxchar;
  91. }
  92. return numRead;
  93. }
  94. // update our input buffer
  95. HANDLE h=GetStdHandle(STD_INPUT_HANDLE);
  96. bool returnChars=false;
  97. for (;;)
  98. {
  99. DWORD dwRecords;
  100. if (!GetNumberOfConsoleInputEvents(h,&dwRecords))
  101. break;
  102. if (!dwRecords)
  103. break;
  104. INPUT_RECORD record;
  105. ReadConsoleInput(h,&record,1,&dwRecords);
  106. if (record.EventType!=KEY_EVENT)
  107. continue;
  108. KEY_EVENT_RECORD &key=record.Event.KeyEvent;
  109. if (!key.bKeyDown||!key.uChar.AsciiChar)
  110. continue;
  111. if (key.uChar.AsciiChar=='\r'||
  112. key.uChar.AsciiChar=='\n')
  113. {
  114. m_input[m_inputUsed++]='\n';
  115. returnChars=true;
  116. break;
  117. }
  118. /// @todo_opt if somebody wants this can be improved by adding support for cursor keys, history, etc
  119. if (key.uChar.AsciiChar=='\b')
  120. {
  121. if (m_inputUsed)
  122. m_inputUsed--;
  123. }
  124. else if (((unsigned char)key.uChar.AsciiChar)>=' ')
  125. {
  126. if (m_inputUsed<sizeof(m_input)-1)
  127. m_input[m_inputUsed++]=key.uChar.AsciiChar;
  128. }
  129. }
  130. // update screen
  131. h=GetStdHandle(STD_OUTPUT_HANDLE);
  132. CONSOLE_SCREEN_BUFFER_INFO info;
  133. GetConsoleScreenBufferInfo(h,&info);
  134. CHAR_INFO ci[sizeof(m_input)+1];
  135. for (unsigned k=0;k<=sizeof(m_input);k++)
  136. {
  137. ci[k].Char.AsciiChar=k<m_inputUsed?m_input[k]:' ';
  138. ci[k].Attributes=BACKGROUND_GREEN|FOREGROUND_BLUE|FOREGROUND_GREEN
  139. |FOREGROUND_RED|FOREGROUND_INTENSITY;
  140. }
  141. // fake another cursor
  142. if (GetTickCount()&512)
  143. ci[m_inputUsed].Attributes=BACKGROUND_BLUE|BACKGROUND_GREEN
  144. |BACKGROUND_RED|BACKGROUND_INTENSITY|FOREGROUND_GREEN;
  145. COORD srcSize,srcCoord;
  146. srcSize.X=sizeof(m_input); srcSize.Y=1;
  147. srcCoord.X=srcCoord.Y=0;
  148. SMALL_RECT r;
  149. r.Left=r.Top=r.Bottom=0; r.Right=info.dwSize.X-1;
  150. WriteConsoleOutput(h,ci+(m_inputUsed<=info.dwSize.X?0:m_inputUsed-info.dwSize.X),
  151. srcSize,srcCoord,&r);
  152. // return data now?
  153. if (returnChars&&m_inputUsed>1)
  154. {
  155. *buf=*m_input;
  156. m_inputRead=1;
  157. return 1;
  158. }
  159. return 0;
  160. }
  161. void DebugIOCon::Write(StringType type, const char *src, const char *str)
  162. {
  163. if (type==StringType::StructuredCmdReply||!str)
  164. return;
  165. DWORD dwDummy;
  166. WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),str,strlen(str),&dwDummy,NULL);
  167. }
  168. void DebugIOCon::Execute(class Debug& dbg, const char *cmd, bool structuredCmd,
  169. unsigned argn, const char * const * argv)
  170. {
  171. if (!cmd||!strcmp(cmd,"help"))
  172. {
  173. dbg << "con I/O help:\n"
  174. " add [ <width> [ <height> ] ]\n"
  175. " create con I/O (optionally specifying the window size)\n";
  176. }
  177. else if (!strcmp(cmd,"add"))
  178. {
  179. if (argn>0&&m_allocatedConsole)
  180. {
  181. // resize our console area
  182. HANDLE h=GetStdHandle(STD_OUTPUT_HANDLE);
  183. COORD newSize;
  184. newSize.X=atoi(argv[0]);
  185. newSize.Y=argn>1?atoi(argv[1]):25;
  186. SMALL_RECT sr;
  187. sr.Left=sr.Top=0;
  188. sr.Right=newSize.X-1;
  189. sr.Bottom=newSize.Y-1;
  190. SetConsoleWindowInfo(h,TRUE,&sr);
  191. SetConsoleScreenBufferSize(h,newSize);
  192. SetConsoleWindowInfo(h,TRUE,&sr);
  193. }
  194. }
  195. }
  196. DebugIOInterface *DebugIOCon::Create(void)
  197. {
  198. return new (DebugAllocMemory(sizeof(DebugIOCon))) DebugIOCon();
  199. }
  200. void DebugIOCon::Delete(void)
  201. {
  202. this->~DebugIOCon();
  203. DebugFreeMemory(this);
  204. }