tconsole.cpp
上传用户:tigerk9
上传日期:2020-03-10
资源大小:237k
文件大小:30k
源码类别:

Telnet客户端

开发平台:

Visual C++

  1. ///////////////////////////////////////////////////////////////////////////////
  2. //Telnet Win32 : an ANSI telnet client.
  3. //Copyright (C) 1998-2000 Paul Brannan
  4. //Copyright (C) 1998 I.Ioannou
  5. //Copyright (C) 1997 Brad Johnson
  6. //
  7. //This program is free software; you can redistribute it and/or
  8. //modify it under the terms of the GNU General Public License
  9. //as published by the Free Software Foundation; either version 2
  10. //of the License, or (at your option) any later version.
  11. //
  12. //This program is distributed in the hope that it will be useful,
  13. //but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. //MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15. //GNU General Public License for more details.
  16. //
  17. //You should have received a copy of the GNU General Public License
  18. //along with this program; if not, write to the Free Software
  19. //Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  20. //
  21. //I.Ioannou
  22. //roryt@hol.gr
  23. //
  24. ///////////////////////////////////////////////////////////////////////////
  25. ///////////////////////////////////////////////////////////////////////////////
  26. //
  27. // Module: tconsole.cpp
  28. //
  29. // Contents: screen functions
  30. //
  31. // Product: telnet
  32. //
  33. //
  34. // Revisions: Mar. 29, 2000 pbranna@clemson (Paul Brannan)
  35. //            June 15, 1998 pbranna@clemson.edu
  36. //            May 16, 1998 pbranna@clemson.edu
  37. //            05. Sep.1997  roryt@hol.gr (I.Ioannou)
  38. //            11.May,1997   roryt@hol.gr
  39. //            06.April,1997 roryt@hol.gr
  40. //            30.M剅z.1997  Titus_Boxberg@public.uni-hamburg.de
  41. //       5.Dec.1996    jbj@nounname.com
  42. //            Version 2.0
  43. //            02.Apr.1995 igor.milavec@uni-lj.si
  44. //   Original code
  45. //
  46. ///////////////////////////////////////////////////////////////////////////////
  47. #include <windows.h>
  48. #include "tconsole.h"
  49. // argsused doesn't work on MSVC++
  50. #ifdef __BORLANDC__
  51. #pragma argsused
  52. #endif
  53. TConsole::TConsole(HANDLE h) {
  54. hConsole = h;
  55. GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
  56. // Start with correct colors
  57. int fg = ini.get_normal_fg();
  58. int bg = ini.get_normal_bg();
  59. if(fg == -1)
  60. fg = defaultfg = origfg = ConsoleInfo.wAttributes & 0xF;
  61. else
  62. defaultfg = origfg = fg;
  63. if(bg == -1)
  64. bg = defaultbg = origbg = (ConsoleInfo.wAttributes >> 4) & 0xF;
  65. else
  66. defaultbg = origbg = bg;
  67. wAttributes = fg | (bg << 4);
  68. reverse = blink = underline = false;
  69. SetConsoleTextAttribute(hConsole, wAttributes);
  70. insert_mode = 0;
  71. // Set the screen size
  72. SetWindowSize(ini.get_term_width(), ini.get_term_height());
  73. iScrollStart = -1;
  74. iScrollEnd = -1;
  75. }
  76. TConsole::~TConsole() {
  77. wAttributes = origfg | (origbg << 4);
  78. SetCursorPosition(0, CON_HEIGHT);
  79. SetConsoleTextAttribute(hConsole, wAttributes);
  80. WriteCtrlChar('x0a');
  81. }
  82. // Paul Brannan 8/2/98
  83. void TConsole::SetWindowSize(int width, int height) {
  84. SMALL_RECT sr = {
  85. CON_LEFT,
  86. CON_TOP,
  87. (width == -1) ? CON_RIGHT : CON_LEFT + width - 1,
  88. (height == -1) ? CON_BOTTOM : CON_TOP + height - 1
  89. };
  90. ConsoleInfo.dwSize.X = width;
  91. if(ConsoleInfo.dwSize.Y < height) ConsoleInfo.dwSize.Y = height;
  92. SetConsoleScreenBufferSize(hConsole, ConsoleInfo.dwSize);
  93. SetConsoleWindowInfo(hConsole, TRUE, &sr);
  94. SetConsoleScreenBufferSize(hConsole, ConsoleInfo.dwSize);
  95. sync();
  96. }
  97. // Paul Brannan 5/15/98
  98. void TConsole::sync() {
  99. GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
  100. }
  101. void TConsole::HighVideo() {
  102. wAttributes = wAttributes | (unsigned char) 8;
  103. }
  104. void TConsole::LowVideo() {
  105. wAttributes = wAttributes & (unsigned char) (0xff-8);
  106. }
  107. void TConsole::Normal() {
  108. // I.Ioannou 11 May 1997
  109. // Color 7 is correct on some systems (for example Linux)
  110. // but not with others (for example SCO)
  111. // we must preserve the colors :
  112. // 06/04/98 thanks to Paul a .ini parameter from now on
  113. BlinkOff();
  114. UnderlineOff();
  115. if(ini.get_preserve_colors()) {
  116. ReverseOff();
  117. LowVideo();
  118. } else {
  119. fg = defaultfg;
  120. bg = defaultbg;
  121. wAttributes = (unsigned char)fg | (bg << 4);
  122. reverse = false;
  123. }
  124. }
  125. void TConsole::SetForeground(unsigned char wAttrib) {
  126. if(reverse) bg = wAttrib; else fg = wAttrib;
  127. wAttributes = (wAttributes & (unsigned char)0x88) | 
  128. (unsigned char)fg | (bg << 4);
  129. }
  130. void TConsole::SetBackground(unsigned char wAttrib) {
  131. if(reverse) fg = wAttrib; else bg = wAttrib;
  132. wAttributes = (wAttributes & (unsigned char)0x88) | 
  133. (unsigned char)fg | (bg << 4);
  134. }
  135. // As far as I can tell, there's no such thing as blink in Windows Console.
  136. // I tried using some inline asm to turn off high-intensity backgrounds,
  137. // but I got a BSOD.  Perhaps there is an undocumented function?
  138. // (Paul Brannan 6/27/98)
  139. void TConsole::BlinkOn() {
  140. blink = 1;
  141. if(underline) {
  142. UlBlinkOn();
  143. } else {
  144. if(ini.get_blink_bg() != -1) {
  145. wAttributes &= 0x8f; // turn off bg
  146. wAttributes |= ini.get_blink_bg() << 4;
  147. }
  148. if(ini.get_blink_fg() != -1) {
  149. wAttributes &= 0xf8; // turn off fg
  150. wAttributes |= ini.get_blink_fg();
  151. }
  152. if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
  153. wAttributes |= 0x80;
  154. }
  155. }
  156. // Added by I.Ioannou 06 April, 1997
  157. void TConsole::BlinkOff() {
  158. blink = 0;
  159. if(underline) {
  160. UlBlinkOff();
  161. } else {
  162. if(ini.get_blink_bg() != -1) {
  163. wAttributes &= 0x8f; // turn off bg
  164. wAttributes |= defaultbg << 4;
  165. }
  166. if(ini.get_blink_fg() != -1) {
  167. wAttributes &= 0xf8; // turn off fg
  168. wAttributes |= defaultfg;
  169. }
  170. if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
  171. wAttributes &= 0x7f;
  172. }
  173. }
  174. // Paul Brannan 6/27/98
  175. void TConsole::UnderlineOn() {
  176. underline = 1;
  177. if(blink) {
  178. UlBlinkOn();
  179. } else {
  180. if(ini.get_underline_bg() != -1) {
  181. wAttributes &= 0x8f; // turn off bg
  182. wAttributes |= ini.get_underline_bg() << 4;
  183. }
  184. if(ini.get_underline_fg() != -1) {
  185. wAttributes &= 0xf8; // turn off fg
  186. wAttributes |= ini.get_underline_fg();
  187. }
  188. if(ini.get_underline_bg() == -1 && ini.get_underline_fg() == -1)
  189. wAttributes |= 0x80;
  190. }
  191. }
  192. // Paul Brannan 6/27/98
  193. void TConsole::UnderlineOff() {
  194. underline = 0;
  195. if(blink) {
  196. UlBlinkOff();
  197. } else {
  198. if(ini.get_blink_bg() != -1) {
  199. wAttributes &= 0x8f; // turn off bg
  200. wAttributes |= defaultbg << 4;
  201. }
  202. if(ini.get_blink_fg() != -1) {
  203. wAttributes &= 0xf8; // turn off fg
  204. wAttributes |= defaultfg;
  205. }
  206. if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
  207. wAttributes &= 0x7f;
  208. }
  209. }
  210. // Paul Brannan 6/27/98
  211. void TConsole::UlBlinkOn() {
  212. if(ini.get_ulblink_bg() != -1) {
  213. wAttributes &= 0x8f; // turn off bg
  214. wAttributes |= ini.get_ulblink_bg() << 4;
  215. }
  216. if(ini.get_ulblink_fg() != -1) {
  217. wAttributes &= 0xf8; // turn off fg
  218. wAttributes |= ini.get_ulblink_fg();
  219. }
  220. if(ini.get_ulblink_bg() == -1 && ini.get_ulblink_fg() == -1)
  221. wAttributes |= 0x80;
  222. }
  223. // Paul Brannan 6/27/98
  224. void TConsole::UlBlinkOff() {
  225. if(blink) {
  226. BlinkOn();
  227. } else if(underline) {
  228. UnderlineOn();
  229. } else {
  230. Normal();
  231. }
  232. }
  233. // Paul Brannan 6/26/98
  234. void TConsole::Lightbg() {
  235. WORD *pAttributes = new WORD[CON_COLS];
  236. DWORD Result;
  237. // Paul Brannan 8/5/98
  238. // Correction: processing more than one line at a time causes a segfault
  239. // if the screen width != 80
  240. for(int i = CON_TOP; i <= CON_BOTTOM; i++) {
  241. COORD Coord = {CON_LEFT, i};
  242. ReadConsoleOutputAttribute(hConsole, pAttributes, (DWORD)(CON_COLS),
  243. Coord, &Result);
  244. for(DWORD j = 0; j < Result; j++) pAttributes[j] |= 0x80;
  245. WriteConsoleOutputAttribute(hConsole, pAttributes, Result, Coord,
  246. &Result);
  247. }
  248. delete[] pAttributes; // clean up
  249. wAttributes |= (unsigned char)0x80;
  250. bg |= 8;
  251. }
  252. // Paul Brannan 6/26/98
  253. void TConsole::Darkbg() {
  254. WORD *pAttributes = new WORD[CON_COLS];
  255. DWORD Result;
  256. // Paul Brannan 8/5/98
  257. // Correction: processing more than one line at a time causes a segfault
  258. // if the screen width != 80
  259. for(int i = CON_TOP; i <= CON_BOTTOM; i++) {
  260. COORD Coord = {CON_LEFT, i};
  261. ReadConsoleOutputAttribute(hConsole, pAttributes, (DWORD)(CON_COLS),
  262. Coord, &Result);
  263. for(DWORD j = 0; j < Result; j++) pAttributes[j] &= 0x7f;
  264. WriteConsoleOutputAttribute(hConsole, pAttributes, Result, Coord,
  265. &Result);
  266. }
  267. delete[] pAttributes; // clean up
  268. wAttributes &= (unsigned char)0x7f;
  269. bg &= 7;
  270. }
  271. // Added by I.Ioannou 11.May,1997
  272. void TConsole::ReverseOn() {
  273. if (!reverse) {
  274. reverse = true;
  275. // atl  : forground attributes without the intensity
  276. // ath  : backgound attributes without the blink
  277. // bl   : the blink state
  278. // ints : the intensity
  279. unsigned char atl   = wAttributes & (unsigned char) 0x07;
  280. unsigned char ath   = wAttributes & (unsigned char) 0x70;
  281. unsigned char bl    = wAttributes & (unsigned char) 0x80;
  282. unsigned char ints  = wAttributes & (unsigned char) 0x08;
  283. wAttributes = bl | (atl << 4) | ints | (ath >> 4);
  284. }
  285. }
  286. // Added by I.Ioannou 11.May,1997
  287. void TConsole::ReverseOff() {
  288. if (reverse) {
  289. reverse = false;
  290. wAttributes = fg | (bg << 4);
  291. }
  292. }
  293. unsigned long TConsole::WriteText(const char *pszString, unsigned long cbString) {
  294. DWORD Result;
  295. if(insert_mode) {
  296. InsertCharacter(cbString);
  297. }
  298. WriteConsoleOutputCharacter(hConsole, (char *)pszString, cbString,
  299. ConsoleInfo.dwCursorPosition, &Result);
  300. FillConsoleOutputAttribute(hConsole, wAttributes, cbString,
  301. ConsoleInfo.dwCursorPosition, &Result);
  302. return Result;
  303. }
  304. // Formerly ConWriteString (Paul Brannan 6/28/98)
  305. unsigned long TConsole::WriteStringFast(const char* pszString, unsigned long cbString) {
  306. DWORD Result;
  307. SetConsoleTextAttribute(hConsole, wAttributes);
  308. //check to see if the line is longer than the display
  309. if (!getLineWrap() && ((unsigned)CON_CUR_X + cbString) >= (unsigned)CON_COLS) {
  310. // Take care of the last line last colum exception...
  311. // The display scrolls up if you use the normal char out
  312. //   function even if you only write to the last place
  313. //   on the line. :-(
  314. if ((unsigned)CON_CUR_Y >= (unsigned)CON_HEIGHT) {
  315. unsigned long iFakeResult = cbString;
  316. cbString = CON_COLS - CON_CUR_X - 1;
  317. // FIX ME !!! This will avoid the exception when cbString
  318. // is <= 0 but still doesn't work :-(
  319. if (cbString > 0)
  320. WriteConsole(hConsole, pszString, cbString, &Result, 0);
  321. COORD dwBufferCoord;
  322. dwBufferCoord.X = 0;
  323. dwBufferCoord.Y = 0;
  324. CHAR_INFO ciBuffer;
  325. ciBuffer.Char.AsciiChar = *(pszString+cbString);
  326. ciBuffer.Attributes = wAttributes;
  327. SMALL_RECT srWriteRegion;
  328. srWriteRegion.Top = (SHORT) CON_BOTTOM;
  329. srWriteRegion.Bottom = (SHORT) CON_BOTTOM;
  330. srWriteRegion.Left = (SHORT) CON_RIGHT;
  331. srWriteRegion.Right = (SHORT) CON_RIGHT;
  332. COORD bufSize = {1,1};
  333. WriteConsoleOutput(hConsole, &ciBuffer, bufSize,
  334. dwBufferCoord, &srWriteRegion);
  335. // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
  336. ConsoleInfo.dwCursorPosition.X = CON_RIGHT;
  337. return iFakeResult; // Skip the chars that did not fit
  338. }
  339. // just write the line up to the end
  340. else {
  341. int iFakeResult = cbString;
  342. cbString = CON_COLS - CON_CUR_X;
  343. if(cbString > 0) {
  344. WriteConsole(hConsole, pszString, cbString, &Result, 0);
  345. // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
  346. ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
  347. }
  348. return iFakeResult; // Skip the chars that did not fit
  349. }
  350. } else {
  351. // If custom scrolling is enabled we must take care of it
  352. if(iScrollStart != -1 || iScrollEnd != -1) {
  353. return WriteString(pszString, cbString);
  354. }
  355. // Apparently VT100 terminals have an invisible "81st" column that
  356. // can hold a cursor until another character is printed.  I'm not sure
  357. // exactly how to handle this, but here's a hack (Paul Brannan 5/28/98)
  358. if(ini.get_vt100_mode() && cbString + (unsigned)CON_CUR_X == (unsigned)CON_COLS) {
  359. cbString--;
  360. if(cbString >= 0) WriteConsole(hConsole, pszString, cbString, &Result, 0);
  361. COORD dwBufferCoord;
  362. dwBufferCoord.X = 0;
  363. dwBufferCoord.Y = 0;
  364. CHAR_INFO ciBuffer;
  365. ciBuffer.Char.AsciiChar = *(pszString+cbString);
  366. ciBuffer.Attributes = wAttributes;
  367. SMALL_RECT srWriteRegion;
  368. srWriteRegion.Top =    (SHORT) ConsoleInfo.dwCursorPosition.Y;
  369. srWriteRegion.Bottom = (SHORT) ConsoleInfo.dwCursorPosition.Y;
  370. srWriteRegion.Left =   (SHORT) CON_RIGHT;
  371. srWriteRegion.Right =  (SHORT) CON_RIGHT;
  372. COORD bufSize = {1,1};
  373. WriteConsoleOutput(hConsole, &ciBuffer, bufSize,
  374. dwBufferCoord, &srWriteRegion);
  375. // Update the ConsoleInfo struct
  376. ConsoleInfo.dwCursorPosition.X = CON_RIGHT + 1;
  377. return Result + 1;
  378. }
  379. // normal line will wrap normally or not to the end of buffer
  380. WriteConsole(hConsole, pszString, cbString, &Result, 0);
  381. // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
  382. // FIX ME!!! This is susceptible to the same problem as above.
  383. // (e.g. we write out 160 characters)
  384. ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
  385. while(CON_CUR_X > CON_WIDTH) {
  386. ConsoleInfo.dwCursorPosition.X -= ConsoleInfo.dwSize.X;
  387. if((unsigned)CON_CUR_Y < (unsigned)CON_HEIGHT) {
  388. ConsoleInfo.dwCursorPosition.Y++;
  389. } else {
  390. // If we aren't at the bottom of the window, then we need to
  391. // scroll down (Paul Brannan 4/14/2000)
  392. if(ConsoleInfo.srWindow.Bottom < ConsoleInfo.dwSize.Y - 1) {
  393. ConsoleInfo.srWindow.Top++;
  394. ConsoleInfo.srWindow.Bottom++;
  395. ConsoleInfo.dwCursorPosition.Y++;
  396. SetConsoleWindowInfo(hConsole, TRUE, &ConsoleInfo.srWindow);
  397. }
  398. }
  399. }
  400. }
  401. return Result;
  402. }
  403. unsigned long TConsole::WriteString(const char* pszString, unsigned long cbString) {
  404. DWORD Result = 0;
  405. SetConsoleTextAttribute(hConsole, wAttributes);
  406. //check to see if the line is longer than the display
  407. if (!getLineWrap()){
  408. unsigned long iFakeResult = cbString;
  409. if((CON_CUR_X + cbString) >= (unsigned int)CON_COLS)
  410. cbString = CON_COLS - CON_CUR_X;
  411. if(cbString > 0)
  412. Result = WriteText(pszString, cbString);
  413. // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
  414. ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
  415. SetConsoleCursorPosition(hConsole, ConsoleInfo.dwCursorPosition);
  416. return iFakeResult; // Skip the chars that did not fit
  417. } else {
  418. // Write up to the end of the line
  419. unsigned long temp = cbString;
  420. if((CON_CUR_X + temp) > (unsigned int)CON_COLS) {
  421. temp = CON_COLS - CON_CUR_X;
  422. } else {
  423. Result = WriteText(pszString, temp);
  424. ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
  425. SetConsoleCursorPosition(hConsole, ConsoleInfo.dwCursorPosition);
  426. return Result;
  427. }
  428. if(temp > 0) {
  429. Result = WriteText(pszString, temp);
  430. ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
  431. temp = (unsigned short)Result;
  432. }
  433. // keep writing lines until we get to less than 80 chars left
  434. while((temp + (unsigned int)CON_COLS) < cbString) {
  435. index(); // LF
  436. ConsoleInfo.dwCursorPosition.X = 0; // CR
  437. Result = WriteText(&pszString[temp], CON_COLS);
  438. temp += (unsigned short)Result;
  439. }
  440. // write out the last bit
  441. if(temp < cbString) {
  442. index();
  443. ConsoleInfo.dwCursorPosition.X = 0;
  444. Result = WriteText(&pszString[temp], cbString - temp);
  445. temp += (unsigned short)Result;
  446. }
  447. // Apparently VT100 terminals have an invisible "81st" column that
  448. // can hold a cursor until another character is printed.  I'm not sure
  449. // exactly how to handle this, but here's a hack (Paul Brannan 5/28/98)
  450. if(!ini.get_vt100_mode() && cbString + (unsigned)ConsoleInfo.dwCursorPosition.X
  451. == (unsigned int)CON_COLS) {
  452. index();
  453. ConsoleInfo.dwCursorPosition.X = 0;
  454. }
  455. SetConsoleCursorPosition(hConsole, ConsoleInfo.dwCursorPosition);
  456. return temp;
  457. }
  458. return 0;
  459. }
  460. // This is for multi-character control strings (Paul Brannan 6/26/98)
  461. unsigned long TConsole::WriteCtrlString(const char *pszString, unsigned long cbString) {
  462. unsigned long total = 0;
  463. while(total < cbString) {
  464. unsigned long Result = WriteCtrlChar(*(pszString + total));
  465. if(Result == 0) {
  466. Result = WriteStringFast(pszString + total, 1);
  467. if(Result == 0) return total;
  468. }
  469. total += Result;
  470. }
  471. return total;
  472. }
  473. // This is for printing single control characters
  474. // WriteCtrlString uses this (Paul Brannan 6/26/98)
  475. unsigned long TConsole::WriteCtrlChar(char c) {
  476. // The console does not handel the CR/LF chars as we might expect
  477. // when using color. The attributes are not set correctly, so we
  478. // must interpret them manualy to preserve the colors on the screen.
  479. unsigned long Result = 0; // just in case (Paul Brannan 6/26/98)
  480. switch (c) {
  481.     case 'x09': // horizontal tab
  482. SetCursorPosition((((CON_CUR_X/8)+1)*8), CON_CUR_Y);
  483. Result = 1;
  484. break;
  485.     case 'x0a': // line feed
  486. index();
  487. Result = 1;
  488. break;
  489.     case 'x0d': // carrage return
  490. SetCursorPosition(CON_LEFT, CON_CUR_Y); // move to beginning of line
  491. Result = 1;
  492. break;
  493. case 'b': // backspace
  494. // Added support for backspace so the cursor position can be changed
  495. // (Paul Brannan 5/25/98)
  496. MoveCursorPosition(-1, 0);
  497. Result = 1;
  498.     default :    // else just write it like normal
  499. break;
  500. }
  501. return Result;
  502. }
  503. void TConsole::index() {
  504. // if on the last line scroll up
  505. // This must work with scrolling (Paul Brannan 5/13/98)
  506. if(iScrollEnd != -1 && (signed)CON_CUR_Y >= iScrollEnd) {
  507. ScrollDown(iScrollStart, iScrollEnd, -1);
  508. } else if ((iScrollEnd == -1 && (signed)CON_CUR_Y >= (signed)CON_HEIGHT)) {
  509. DWORD Result;
  510. WriteConsole(hConsole, "n", 1, &Result, NULL);
  511. // If we aren't at the bottom of the buffer, then we need to
  512. // scroll down (Paul Brannan 4/14/2000)
  513. if(iScrollEnd == -1 && ConsoleInfo.srWindow.Bottom < ConsoleInfo.dwSize.Y - 1) {
  514. ConsoleInfo.srWindow.Top++;
  515. ConsoleInfo.srWindow.Bottom++;
  516. ConsoleInfo.dwCursorPosition.Y++;
  517. // SetConsoleWindowInfo(hConsole, TRUE, &ConsoleInfo.srWindow);
  518. } else {
  519. ClearLine();
  520. }
  521. } else {     // else move cursor down to the next line
  522. SetCursorPosition(CON_CUR_X, CON_CUR_Y + 1);
  523. }
  524. }
  525. void TConsole::reverse_index() {
  526. // if on the top line scroll down
  527. // This must work with scrolling (Paul Brannan 5/13/98)
  528. // We should be comparing against iScrollStart, not iScrollEnd (PB 12/2/98)
  529. if (iScrollStart == -1 && (signed)CON_CUR_Y <= 0) {
  530. ScrollDown(iScrollStart, -1, 1);
  531. } else if (iScrollStart != -1 && (signed)CON_CUR_Y <= iScrollStart) {
  532. ScrollDown(iScrollStart, iScrollEnd, 1);
  533. } else       // else move cursor up to the previous line
  534. SetCursorPosition(CON_CUR_X,CON_CUR_Y - 1);
  535. }
  536. void TConsole::ScrollDown( int iStartRow , int iEndRow, int bUp ){
  537. CHAR_INFO ciChar;
  538. SMALL_RECT srScrollWindow;
  539. // Correction from I.Ioannou 11 May 1997
  540. // check the scroll region
  541. if (iStartRow < iScrollStart) iStartRow = iScrollStart;
  542. // Correction from I.Ioannou 11 May 1997
  543. // this will make Top the CON_TOP
  544. if ( iStartRow == -1) iStartRow = 0;
  545. // Correction from I.Ioannou 18 Aug 97
  546. if ( iEndRow == -1) {
  547. if ( iScrollEnd == -1 )
  548. iEndRow = CON_HEIGHT;
  549. else
  550. iEndRow = ((CON_HEIGHT <= iScrollEnd) ? CON_HEIGHT : iScrollEnd);
  551. }
  552. //
  553. if ( iStartRow > CON_HEIGHT) iStartRow = CON_HEIGHT;
  554. if ( iEndRow > CON_HEIGHT) iEndRow = CON_HEIGHT;
  555. srScrollWindow.Left =           (CON_LEFT);
  556. srScrollWindow.Right =  (SHORT) (CON_RIGHT);
  557. srScrollWindow.Top =    (SHORT) (CON_TOP + iStartRow );
  558. srScrollWindow.Bottom = (SHORT) (CON_TOP + iEndRow); // don't subtract 1 (PB 5/28)
  559. ciChar.Char.AsciiChar = ' ';           // fill with spaces
  560. ciChar.Attributes = wAttributes;       // fill with current attrib
  561. // This should speed things up (Paul Brannan 9/2/98)
  562. COORD dwDestOrg = {srScrollWindow.Left, srScrollWindow.Top + bUp};
  563. // Note that iEndRow and iStartRow had better not be equal to -1 at this
  564. // point.  There are four cases to consider for out of bounds.  Two of
  565. // these cause the scroll window to be cleared; the others cause the
  566. // scroll region to be modified.  (Paul Brannan 12/3/98)
  567. if(dwDestOrg.Y > CON_TOP + iEndRow) {
  568. // We are scrolling past the end of the scroll region, so just
  569. // clear the window instead (Paul Brannan 12/3/98)
  570. ClearWindow(CON_TOP + iStartRow, CON_TOP + iEndRow);
  571. return;
  572. } else if(dwDestOrg.Y + (iEndRow-iStartRow+1) < CON_TOP + iStartRow) {
  573. // We are scrolling past the end of the scroll region, so just
  574. // clear the window instead (Paul Brannan 12/3/98)
  575. ClearWindow(CON_TOP + iStartRow, CON_TOP + iEndRow);
  576. return;
  577. } else if(dwDestOrg.Y < CON_TOP + iStartRow) {
  578. // Modify the scroll region (Paul Brannan 12/3/98)
  579. dwDestOrg.Y = CON_TOP + iStartRow;
  580. srScrollWindow.Top -= bUp;
  581. } else  if(dwDestOrg.Y + (iEndRow-iStartRow+1) > CON_TOP + iEndRow) {
  582. // Modify the scroll region (Paul Brannan 12/3/98)
  583. srScrollWindow.Bottom -= bUp;
  584. }
  585. ScrollConsoleScreenBuffer(hConsole, &srScrollWindow,
  586. 0, dwDestOrg, &ciChar);
  587. }
  588. // This allows us to clear the screen with an arbitrary character
  589. // (Paul Brannan 6/26/98)
  590. void TConsole::ClearScreen(char c) {
  591. DWORD dwWritten;
  592. COORD Coord = {CON_LEFT, CON_TOP};
  593. FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS)*
  594. (DWORD)(CON_LINES), Coord, &dwWritten);
  595. FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS)*
  596. (DWORD)(CON_LINES), Coord, &dwWritten);
  597. }
  598. // Same as clear screen, but only affects the scroll region
  599. void TConsole::ClearWindow(int iStartRow, int iEndRow, char c) {
  600. DWORD dwWritten;
  601. COORD Coord = {CON_LEFT, CON_TOP + iStartRow};
  602. FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS)*
  603. (DWORD)(iEndRow-iStartRow+1), Coord, &dwWritten);
  604. FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS)*
  605. (DWORD)(CON_LINES), Coord, &dwWritten);
  606. }
  607. // Clear from cursor to end of screen
  608. void TConsole::ClearEOScreen(char c)
  609. {
  610. DWORD dwWritten;
  611. COORD Coord = {CON_LEFT, CON_TOP + CON_CUR_Y + 1};
  612. FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS)*
  613. (DWORD)(CON_HEIGHT - CON_CUR_Y), Coord, &dwWritten);
  614. FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS)*
  615. (DWORD)(CON_LINES - CON_CUR_Y), Coord, &dwWritten);
  616. ClearEOLine();
  617. }
  618. // Clear from beginning of screen to cursor
  619. void TConsole::ClearBOScreen(char c)
  620. {
  621. DWORD dwWritten;
  622. COORD Coord = {CON_LEFT, CON_TOP};
  623. FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS)*
  624. (DWORD)(CON_CUR_Y), Coord, &dwWritten);
  625. FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS)*
  626. (DWORD)(CON_CUR_Y), Coord, &dwWritten);
  627. ClearBOLine();
  628. }
  629. void TConsole::ClearLine(char c)
  630. {
  631. DWORD dwWritten;
  632. COORD Coord = {CON_LEFT, CON_TOP + CON_CUR_Y};
  633. FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS),
  634. Coord, &dwWritten);
  635. FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS),
  636. Coord, &dwWritten);
  637. GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
  638. }
  639. void TConsole::ClearEOLine(char c)
  640. {
  641. DWORD dwWritten;
  642. COORD Coord = {CON_LEFT + CON_CUR_X, CON_TOP + CON_CUR_Y};
  643. FillConsoleOutputAttribute(hConsole, wAttributes,
  644. (DWORD)(CON_RIGHT - CON_CUR_X) +1, Coord, &dwWritten);
  645. FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_RIGHT - CON_CUR_X) +1,
  646. Coord, &dwWritten);
  647. GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
  648. }
  649. void TConsole::ClearBOLine(char c)
  650. {
  651. DWORD dwWritten;
  652. COORD Coord = {CON_LEFT, CON_TOP + CON_CUR_Y};
  653. FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_CUR_X) + 1, Coord,
  654. &dwWritten);
  655. FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_CUR_X) + 1,
  656. Coord, &dwWritten);
  657. GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
  658. }
  659. // Inserts blank lines to the cursor-y-position
  660. // scrolls down the rest. CURSOR MOVEMENT (to Col#1) ???
  661. void TConsole::InsertLine(int numlines)
  662. {
  663. COORD to;
  664. SMALL_RECT from;
  665. SMALL_RECT clip;
  666. CHAR_INFO fill;
  667. int acty;
  668. // Rest of screen would be deleted
  669. if ( (acty = GetCursorY()) >= CON_LINES - numlines ) {
  670. ClearEOScreen();    // delete rest of screen
  671. return;
  672. } /* IF */
  673. // Else scroll down the part of the screen which is below the
  674. // cursor.
  675. from.Left = CON_LEFT;
  676. from.Top = CON_TOP + (SHORT)acty;
  677. from.Right = CON_LEFT + (SHORT)CON_COLS;
  678. from.Bottom = CON_TOP + (SHORT)CON_LINES;
  679. clip = from;
  680. to.X = 0;
  681. to.Y = (SHORT)(from.Top + numlines);
  682. fill.Char.AsciiChar = ' ';
  683. fill.Attributes = 7;  // WHICH ATTRIBUTES TO TAKE FOR BLANK LINE ??
  684. ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
  685. } /* InsertLine */
  686. // Inserts blank characters under the cursor
  687. void TConsole::InsertCharacter(int numchar)
  688. {
  689. int actx;
  690. SMALL_RECT from;
  691. SMALL_RECT clip;
  692. COORD to;
  693. CHAR_INFO fill;
  694. if ( (actx = GetCursorX()) >= CON_COLS - numchar ) {
  695. ClearEOLine();
  696. return;
  697. } /* IF */
  698. from.Left = CON_LEFT + (SHORT)actx;
  699. from.Top = CON_TOP + (SHORT)GetCursorY();
  700. from.Right = CON_LEFT + (SHORT)CON_COLS;
  701. from.Bottom = CON_TOP + (SHORT)from.Top;
  702. clip = from;
  703. to.X = (SHORT)(actx + numchar);
  704. to.Y = from.Top;
  705. fill.Char.AsciiChar = ' ';
  706. fill.Attributes = wAttributes; // WHICH ATTRIBUTES TO TAKE FOR BLANK CHAR ??
  707. ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
  708. } /* InsertCharacter */
  709. // Deletes characters under the cursor
  710. // Note that there are cases in which all the following lines should shift by
  711. // a character, but we don't handle these.  This could break some
  712. // VT102-applications, but it shouldn't be too much of an issue.
  713. void TConsole::DeleteCharacter(int numchar)
  714. {
  715. int actx;
  716. SMALL_RECT from;
  717. SMALL_RECT clip;
  718. COORD to;
  719. CHAR_INFO fill;
  720. if ( (actx = GetCursorX()) >= CON_COLS - numchar ) {
  721. ClearEOLine();
  722. return;
  723. } /* IF */
  724. from.Left = CON_LEFT + (SHORT)actx;
  725. from.Top = CON_TOP + (SHORT)GetCursorY();
  726. from.Right = CON_LEFT + (SHORT)CON_COLS;
  727. from.Bottom = CON_TOP + from.Top;
  728. clip = from;
  729. to.X = (SHORT)(actx - numchar);
  730. to.Y = from.Top;
  731. fill.Char.AsciiChar = ' ';
  732. fill.Attributes = wAttributes; // WHICH ATTRIBUTES TO TAKE FOR BLANK CHAR ??
  733. ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
  734. } /* DeleteCharacter */
  735. void TConsole::SetRawCursorPosition(int x, int y) {
  736. if (x > CON_WIDTH)  x = CON_WIDTH;
  737. if (x < 0) x = 0;
  738. if (y > CON_HEIGHT) y = CON_HEIGHT;
  739. if (y < 0) y = 0;
  740. COORD Coord = {(short)(CON_LEFT + x), (short)(CON_TOP + y)};
  741. SetConsoleCursorPosition(hConsole, Coord);
  742. // Update the ConsoleInfo struct (Paul Brannan 5/9/98)
  743. ConsoleInfo.dwCursorPosition.Y = Coord.Y;
  744. ConsoleInfo.dwCursorPosition.X = Coord.X;
  745. // bug fix in case we went too far (Paul Brannan 5/25/98)
  746. if(ConsoleInfo.dwCursorPosition.X < CON_LEFT)
  747. ConsoleInfo.dwCursorPosition.X = CON_LEFT;
  748. if(ConsoleInfo.dwCursorPosition.X > CON_RIGHT)
  749. ConsoleInfo.dwCursorPosition.X = CON_RIGHT;
  750. if(ConsoleInfo.dwCursorPosition.Y < CON_TOP)
  751. ConsoleInfo.dwCursorPosition.Y = CON_TOP;
  752. if(ConsoleInfo.dwCursorPosition.Y > CON_BOTTOM)
  753. ConsoleInfo.dwCursorPosition.Y = CON_BOTTOM;
  754. }
  755. // The new SetCursorPosition takes scroll regions into consideration
  756. // (Paul Brannan 6/27/98)
  757. void TConsole::SetCursorPosition(int x, int y) {
  758. if (x > CON_WIDTH)  x = CON_WIDTH;
  759. if (x < 0) x = 0;
  760. if(iScrollEnd != -1) {
  761. if(y > iScrollEnd) y = iScrollEnd;
  762. } else {
  763. if(y > CON_HEIGHT) y = CON_HEIGHT;
  764. }
  765. if(iScrollStart != -1) {
  766. if(y < iScrollStart) y = iScrollStart;
  767. } else {
  768. if(y < 0) y = 0;
  769. }
  770. COORD Coord = {(short)(CON_LEFT + x), (short)(CON_TOP + y)};
  771. SetConsoleCursorPosition(hConsole, Coord);
  772. // Update the ConsoleInfo struct
  773. ConsoleInfo.dwCursorPosition.Y = Coord.Y;
  774. ConsoleInfo.dwCursorPosition.X = Coord.X;
  775. }
  776. void TConsole::MoveCursorPosition(int x, int y) {
  777. SetCursorPosition(CON_CUR_X + x, CON_CUR_Y + y);
  778. }
  779. void TConsole::SetExtendedMode(int iFunction, BOOL bEnable)
  780. {
  781. // Probably should do something here...
  782. // Should change the screen mode, but do we need this?
  783. }
  784. void TConsole::SetScroll(int start, int end) {
  785. iScrollStart = start;
  786. iScrollEnd = end;
  787. }
  788. void TConsole::Beep() {
  789. if(ini.get_do_beep()) {
  790. if(!ini.get_speaker_beep()) printit("a");
  791. else ::Beep(400, 100);
  792. }
  793. }
  794. void TConsole::SetCursorSize(int pct) {
  795. CONSOLE_CURSOR_INFO ci = {(pct != 0)?pct:1, pct != 0};
  796. SetConsoleCursorInfo(hConsole, &ci);
  797. }
  798. void saveScreen(CHAR_INFO *chiBuffer) {
  799. HANDLE hStdout;
  800. CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
  801. SMALL_RECT srctReadRect;
  802. COORD coordBufSize;
  803. COORD coordBufCoord;
  804. hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  805. GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
  806.     srctReadRect.Top = CON_TOP;    /* top left: row 0, col 0  */
  807.     srctReadRect.Left = CON_LEFT;
  808.     srctReadRect.Bottom = CON_BOTTOM; /* bot. right: row 1, col 79 */
  809.     srctReadRect.Right = CON_RIGHT;
  810.     coordBufSize.Y = CON_BOTTOM-CON_TOP+1;
  811.     coordBufSize.X = CON_RIGHT-CON_LEFT+1;
  812.     coordBufCoord.X = CON_TOP;
  813.     coordBufCoord.Y = CON_LEFT;
  814.     ReadConsoleOutput(
  815. hStdout,        /* screen buffer to read from       */
  816. chiBuffer,      /* buffer to copy into              */
  817. coordBufSize,   /* col-row size of chiBuffer        */
  818. coordBufCoord,  /* top left dest. cell in chiBuffer */
  819. &srctReadRect); /* screen buffer source rectangle   */
  820. }
  821. void restoreScreen(CHAR_INFO *chiBuffer) {
  822. HANDLE hStdout;
  823. CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
  824. SMALL_RECT srctReadRect;
  825. COORD coordBufSize;
  826. COORD coordBufCoord;
  827. hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  828. GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
  829. // restore screen
  830.     srctReadRect.Top = CON_TOP;    /* top left: row 0, col 0  */
  831.     srctReadRect.Left = CON_LEFT;
  832.     srctReadRect.Bottom = CON_BOTTOM; /* bot. right: row 1, col 79 */
  833.     srctReadRect.Right = CON_RIGHT;
  834.     coordBufSize.Y = CON_BOTTOM-CON_TOP+1;
  835.     coordBufSize.X = CON_RIGHT-CON_LEFT+1;
  836.     coordBufCoord.X = CON_TOP;
  837.     coordBufCoord.Y = CON_LEFT;
  838.     WriteConsoleOutput(
  839.         hStdout, /* screen buffer to write to    */
  840.         chiBuffer,        /* buffer to copy from          */
  841.         coordBufSize,     /* col-row size of chiBuffer    */
  842.         coordBufCoord, /* top left src cell in chiBuffer  */
  843.         &srctReadRect); /* dest. screen buffer rectangle */
  844. // end restore screen
  845.     
  846. }
  847. CHAR_INFO* newBuffer() {
  848.     CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
  849.     HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
  850.     GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
  851.     CHAR_INFO * chiBuffer;
  852.     chiBuffer = new CHAR_INFO[(CON_BOTTOM-CON_TOP+1)*(CON_RIGHT-CON_LEFT+1)];
  853. return chiBuffer;
  854. }
  855. void deleteBuffer(CHAR_INFO* chiBuffer) {
  856. delete[] chiBuffer;
  857. }