--- /dev/null
+///////////////////////////////////////////////////////////////////////////////
+//Telnet Win32 : an ANSI telnet client.
+//Copyright (C) 1998-2000 Paul Brannan
+//Copyright (C) 1998 I.Ioannou
+//Copyright (C) 1997 Brad Johnson
+//
+//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 the Free Software
+//Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+//
+//I.Ioannou
+//roryt@hol.gr
+//
+///////////////////////////////////////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////////
+//
+// Module: tconsole.cpp
+//
+// Contents: screen functions
+//
+// Product: telnet
+//
+//
+// Revisions: Mar. 29, 2000 pbranna@clemson (Paul Brannan)
+// June 15, 1998 pbranna@clemson.edu
+// May 16, 1998 pbranna@clemson.edu
+// 05. Sep.1997 roryt@hol.gr (I.Ioannou)
+// 11.May,1997 roryt@hol.gr
+// 06.April,1997 roryt@hol.gr
+// 30.M\84rz.1997 Titus_Boxberg@public.uni-hamburg.de
+// 5.Dec.1996 jbj@nounname.com
+// Version 2.0
+// 02.Apr.1995 igor.milavec@uni-lj.si
+// Original code
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#include <windows.h>
+#include "tconsole.h"
+
+// argsused doesn't work on MSVC++
+#ifdef __BORLANDC__
+#pragma argsused
+#endif
+
+TConsole::TConsole(HANDLE h) {
+ hConsole = h;
+
+ GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
+
+ // Start with correct colors
+ int fg = ini.get_normal_fg();
+ int bg = ini.get_normal_bg();
+ if(fg == -1)
+ fg = defaultfg = origfg = ConsoleInfo.wAttributes & 0xF;
+ else
+ defaultfg = origfg = fg;
+ if(bg == -1)
+ bg = defaultbg = origbg = (ConsoleInfo.wAttributes >> 4) & 0xF;
+ else
+ defaultbg = origbg = bg;
+ wAttributes = fg | (bg << 4);
+ reverse = blink = underline = false;
+ SetConsoleTextAttribute(hConsole, wAttributes);
+
+ insert_mode = 0;
+
+ // Set the screen size
+ SetWindowSize(ini.get_term_width(), ini.get_term_height());
+
+ iScrollStart = -1;
+ iScrollEnd = -1;
+}
+
+TConsole::~TConsole() {
+ wAttributes = origfg | (origbg << 4);
+ SetCursorPosition(0, CON_HEIGHT);
+ SetConsoleTextAttribute(hConsole, wAttributes);
+ WriteCtrlChar('\x0a');
+}
+
+// Paul Brannan 8/2/98
+void TConsole::SetWindowSize(int width, int height) {
+ SMALL_RECT sr = {
+ CON_LEFT,
+ CON_TOP,
+ (width == -1) ? CON_RIGHT : CON_LEFT + width - 1,
+ (height == -1) ? CON_BOTTOM : CON_TOP + height - 1
+ };
+ ConsoleInfo.dwSize.X = width;
+ if(ConsoleInfo.dwSize.Y < height) ConsoleInfo.dwSize.Y = height;
+ SetConsoleScreenBufferSize(hConsole, ConsoleInfo.dwSize);
+ SetConsoleWindowInfo(hConsole, TRUE, &sr);
+ SetConsoleScreenBufferSize(hConsole, ConsoleInfo.dwSize);
+ sync();
+}
+
+// Paul Brannan 5/15/98
+void TConsole::sync() {
+ GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
+}
+
+void TConsole::HighVideo() {
+ wAttributes = wAttributes | (unsigned char) 8;
+}
+
+void TConsole::LowVideo() {
+ wAttributes = wAttributes & (unsigned char) (0xff-8);
+}
+
+void TConsole::Normal() {
+ // I.Ioannou 11 May 1997
+ // Color 7 is correct on some systems (for example Linux)
+ // but not with others (for example SCO)
+ // we must preserve the colors :
+ // 06/04/98 thanks to Paul a .ini parameter from now on
+
+ BlinkOff();
+ UnderlineOff();
+ if(ini.get_preserve_colors()) {
+ ReverseOff();
+ LowVideo();
+ } else {
+ fg = defaultfg;
+ bg = defaultbg;
+ wAttributes = (unsigned char)fg | (bg << 4);
+ reverse = false;
+ }
+}
+
+void TConsole::SetForeground(unsigned char wAttrib) {
+ if(reverse) bg = wAttrib; else fg = wAttrib;
+ wAttributes = (wAttributes & (unsigned char)0x88) |
+ (unsigned char)fg | (bg << 4);
+}
+
+void TConsole::SetBackground(unsigned char wAttrib) {
+ if(reverse) fg = wAttrib; else bg = wAttrib;
+ wAttributes = (wAttributes & (unsigned char)0x88) |
+ (unsigned char)fg | (bg << 4);
+}
+
+// As far as I can tell, there's no such thing as blink in Windows Console.
+// I tried using some inline asm to turn off high-intensity backgrounds,
+// but I got a BSOD. Perhaps there is an undocumented function?
+// (Paul Brannan 6/27/98)
+void TConsole::BlinkOn() {
+ blink = 1;
+ if(underline) {
+ UlBlinkOn();
+ } else {
+ if(ini.get_blink_bg() != -1) {
+ wAttributes &= 0x8f; // turn off bg
+ wAttributes |= ini.get_blink_bg() << 4;
+ }
+ if(ini.get_blink_fg() != -1) {
+ wAttributes &= 0xf8; // turn off fg
+ wAttributes |= ini.get_blink_fg();
+ }
+ if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
+ wAttributes |= 0x80;
+ }
+}
+
+// Added by I.Ioannou 06 April, 1997
+void TConsole::BlinkOff() {
+ blink = 0;
+ if(underline) {
+ UlBlinkOff();
+ } else {
+ if(ini.get_blink_bg() != -1) {
+ wAttributes &= 0x8f; // turn off bg
+ wAttributes |= defaultbg << 4;
+ }
+ if(ini.get_blink_fg() != -1) {
+ wAttributes &= 0xf8; // turn off fg
+ wAttributes |= defaultfg;
+ }
+ if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
+ wAttributes &= 0x7f;
+ }
+}
+
+// Paul Brannan 6/27/98
+void TConsole::UnderlineOn() {
+ underline = 1;
+ if(blink) {
+ UlBlinkOn();
+ } else {
+ if(ini.get_underline_bg() != -1) {
+ wAttributes &= 0x8f; // turn off bg
+ wAttributes |= ini.get_underline_bg() << 4;
+ }
+ if(ini.get_underline_fg() != -1) {
+ wAttributes &= 0xf8; // turn off fg
+ wAttributes |= ini.get_underline_fg();
+ }
+ if(ini.get_underline_bg() == -1 && ini.get_underline_fg() == -1)
+ wAttributes |= 0x80;
+ }
+}
+
+// Paul Brannan 6/27/98
+void TConsole::UnderlineOff() {
+ underline = 0;
+ if(blink) {
+ UlBlinkOff();
+ } else {
+ if(ini.get_blink_bg() != -1) {
+ wAttributes &= 0x8f; // turn off bg
+ wAttributes |= defaultbg << 4;
+ }
+ if(ini.get_blink_fg() != -1) {
+ wAttributes &= 0xf8; // turn off fg
+ wAttributes |= defaultfg;
+ }
+ if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
+ wAttributes &= 0x7f;
+ }
+}
+
+// Paul Brannan 6/27/98
+void TConsole::UlBlinkOn() {
+ if(ini.get_ulblink_bg() != -1) {
+ wAttributes &= 0x8f; // turn off bg
+ wAttributes |= ini.get_ulblink_bg() << 4;
+ }
+ if(ini.get_ulblink_fg() != -1) {
+ wAttributes &= 0xf8; // turn off fg
+ wAttributes |= ini.get_ulblink_fg();
+ }
+ if(ini.get_ulblink_bg() == -1 && ini.get_ulblink_fg() == -1)
+ wAttributes |= 0x80;
+}
+
+// Paul Brannan 6/27/98
+void TConsole::UlBlinkOff() {
+ if(blink) {
+ BlinkOn();
+ } else if(underline) {
+ UnderlineOn();
+ } else {
+ Normal();
+ }
+}
+
+// Paul Brannan 6/26/98
+void TConsole::Lightbg() {
+ WORD *pAttributes = new WORD[CON_COLS];
+ DWORD Result;
+
+ // Paul Brannan 8/5/98
+ // Correction: processing more than one line at a time causes a segfault
+ // if the screen width != 80
+ for(int i = CON_TOP; i <= CON_BOTTOM; i++) {
+ COORD Coord = {CON_LEFT, i};
+
+ ReadConsoleOutputAttribute(hConsole, pAttributes, (DWORD)(CON_COLS),
+ Coord, &Result);
+
+ for(DWORD j = 0; j < Result; j++) pAttributes[j] |= 0x80;
+
+ WriteConsoleOutputAttribute(hConsole, pAttributes, Result, Coord,
+ &Result);
+ }
+
+ delete[] pAttributes; // clean up
+
+ wAttributes |= (unsigned char)0x80;
+ bg |= 8;
+}
+
+// Paul Brannan 6/26/98
+void TConsole::Darkbg() {
+ WORD *pAttributes = new WORD[CON_COLS];
+ DWORD Result;
+
+ // Paul Brannan 8/5/98
+ // Correction: processing more than one line at a time causes a segfault
+ // if the screen width != 80
+ for(int i = CON_TOP; i <= CON_BOTTOM; i++) {
+ COORD Coord = {CON_LEFT, i};
+
+ ReadConsoleOutputAttribute(hConsole, pAttributes, (DWORD)(CON_COLS),
+ Coord, &Result);
+
+ for(DWORD j = 0; j < Result; j++) pAttributes[j] &= 0x7f;
+
+ WriteConsoleOutputAttribute(hConsole, pAttributes, Result, Coord,
+ &Result);
+ }
+
+ delete[] pAttributes; // clean up
+
+
+ wAttributes &= (unsigned char)0x7f;
+ bg &= 7;
+}
+
+// Added by I.Ioannou 11.May,1997
+void TConsole::ReverseOn() {
+ if (!reverse) {
+ reverse = true;
+
+ // atl : forground attributes without the intensity
+ // ath : backgound attributes without the blink
+ // bl : the blink state
+ // ints : the intensity
+ unsigned char atl = wAttributes & (unsigned char) 0x07;
+ unsigned char ath = wAttributes & (unsigned char) 0x70;
+ unsigned char bl = wAttributes & (unsigned char) 0x80;
+ unsigned char ints = wAttributes & (unsigned char) 0x08;
+ wAttributes = bl | (atl << 4) | ints | (ath >> 4);
+ }
+}
+
+// Added by I.Ioannou 11.May,1997
+void TConsole::ReverseOff() {
+ if (reverse) {
+ reverse = false;
+ wAttributes = fg | (bg << 4);
+ }
+}
+
+unsigned long TConsole::WriteText(const char *pszString, unsigned long cbString) {
+ DWORD Result;
+
+ if(insert_mode) {
+ InsertCharacter(cbString);
+ }
+
+ WriteConsoleOutputCharacter(hConsole, (char *)pszString, cbString,
+ ConsoleInfo.dwCursorPosition, &Result);
+ FillConsoleOutputAttribute(hConsole, wAttributes, cbString,
+ ConsoleInfo.dwCursorPosition, &Result);
+ return Result;
+}
+
+// Formerly ConWriteString (Paul Brannan 6/28/98)
+unsigned long TConsole::WriteStringFast(const char* pszString, unsigned long cbString) {
+ DWORD Result;
+
+ SetConsoleTextAttribute(hConsole, wAttributes);
+
+ //check to see if the line is longer than the display
+ if (!getLineWrap() && ((unsigned)CON_CUR_X + cbString) >= (unsigned)CON_COLS) {
+ // Take care of the last line last colum exception...
+ // The display scrolls up if you use the normal char out
+ // function even if you only write to the last place
+ // on the line. :-(
+ if ((unsigned)CON_CUR_Y >= (unsigned)CON_HEIGHT) {
+ unsigned long iFakeResult = cbString;
+ cbString = CON_COLS - CON_CUR_X - 1;
+
+ // FIX ME !!! This will avoid the exception when cbString
+ // is <= 0 but still doesn't work :-(
+ if (cbString > 0)
+ WriteConsole(hConsole, pszString, cbString, &Result, 0);
+
+ COORD dwBufferCoord;
+ dwBufferCoord.X = 0;
+ dwBufferCoord.Y = 0;
+
+ CHAR_INFO ciBuffer;
+ ciBuffer.Char.AsciiChar = *(pszString+cbString);
+ ciBuffer.Attributes = wAttributes;
+ SMALL_RECT srWriteRegion;
+ srWriteRegion.Top = (SHORT) CON_BOTTOM;
+ srWriteRegion.Bottom = (SHORT) CON_BOTTOM;
+ srWriteRegion.Left = (SHORT) CON_RIGHT;
+ srWriteRegion.Right = (SHORT) CON_RIGHT;
+
+ COORD bufSize = {1,1};
+
+ WriteConsoleOutput(hConsole, &ciBuffer, bufSize,
+ dwBufferCoord, &srWriteRegion);
+
+ // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
+ ConsoleInfo.dwCursorPosition.X = CON_RIGHT;
+
+ return iFakeResult; // Skip the chars that did not fit
+ }
+ // just write the line up to the end
+ else {
+ int iFakeResult = cbString;
+ cbString = CON_COLS - CON_CUR_X;
+
+ if(cbString > 0) {
+ WriteConsole(hConsole, pszString, cbString, &Result, 0);
+
+ // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
+ ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
+ }
+
+ return iFakeResult; // Skip the chars that did not fit
+ }
+ } else {
+ // If custom scrolling is enabled we must take care of it
+ if(iScrollStart != -1 || iScrollEnd != -1) {
+ return WriteString(pszString, cbString);
+ }
+
+ // Apparently VT100 terminals have an invisible "81st" column that
+ // can hold a cursor until another character is printed. I'm not sure
+ // exactly how to handle this, but here's a hack (Paul Brannan 5/28/98)
+ if(ini.get_vt100_mode() && cbString + (unsigned)CON_CUR_X == (unsigned)CON_COLS) {
+
+ cbString--;
+ if(cbString >= 0) WriteConsole(hConsole, pszString, cbString, &Result, 0);
+
+ COORD dwBufferCoord;
+ dwBufferCoord.X = 0;
+ dwBufferCoord.Y = 0;
+
+ CHAR_INFO ciBuffer;
+ ciBuffer.Char.AsciiChar = *(pszString+cbString);
+ ciBuffer.Attributes = wAttributes;
+ SMALL_RECT srWriteRegion;
+ srWriteRegion.Top = (SHORT) ConsoleInfo.dwCursorPosition.Y;
+ srWriteRegion.Bottom = (SHORT) ConsoleInfo.dwCursorPosition.Y;
+ srWriteRegion.Left = (SHORT) CON_RIGHT;
+ srWriteRegion.Right = (SHORT) CON_RIGHT;
+
+ COORD bufSize = {1,1};
+
+ WriteConsoleOutput(hConsole, &ciBuffer, bufSize,
+ dwBufferCoord, &srWriteRegion);
+
+ // Update the ConsoleInfo struct
+ ConsoleInfo.dwCursorPosition.X = CON_RIGHT + 1;
+
+ return Result + 1;
+ }
+
+ // normal line will wrap normally or not to the end of buffer
+ WriteConsole(hConsole, pszString, cbString, &Result, 0);
+
+ // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
+ // FIX ME!!! This is susceptible to the same problem as above.
+ // (e.g. we write out 160 characters)
+ ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
+ while(CON_CUR_X > CON_WIDTH) {
+ ConsoleInfo.dwCursorPosition.X -= ConsoleInfo.dwSize.X;
+ if((unsigned)CON_CUR_Y < (unsigned)CON_HEIGHT) {
+ ConsoleInfo.dwCursorPosition.Y++;
+ } else {
+ // If we aren't at the bottom of the window, then we need to
+ // scroll down (Paul Brannan 4/14/2000)
+ if(ConsoleInfo.srWindow.Bottom < ConsoleInfo.dwSize.Y - 1) {
+ ConsoleInfo.srWindow.Top++;
+ ConsoleInfo.srWindow.Bottom++;
+ ConsoleInfo.dwCursorPosition.Y++;
+ SetConsoleWindowInfo(hConsole, TRUE, &ConsoleInfo.srWindow);
+ }
+ }
+ }
+ }
+
+ return Result;
+
+}
+
+unsigned long TConsole::WriteString(const char* pszString, unsigned long cbString) {
+ DWORD Result = 0;
+
+ SetConsoleTextAttribute(hConsole, wAttributes);
+
+ //check to see if the line is longer than the display
+ if (!getLineWrap()){
+ unsigned long iFakeResult = cbString;
+ if((CON_CUR_X + cbString) >= (unsigned int)CON_COLS)
+ cbString = CON_COLS - CON_CUR_X;
+ if(cbString > 0)
+ Result = WriteText(pszString, cbString);
+
+ // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
+ ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
+ SetConsoleCursorPosition(hConsole, ConsoleInfo.dwCursorPosition);
+
+ return iFakeResult; // Skip the chars that did not fit
+ } else {
+ // Write up to the end of the line
+ unsigned long temp = cbString;
+ if((CON_CUR_X + temp) > (unsigned int)CON_COLS) {
+ temp = CON_COLS - CON_CUR_X;
+ } else {
+ Result = WriteText(pszString, temp);
+ ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
+ SetConsoleCursorPosition(hConsole, ConsoleInfo.dwCursorPosition);
+ return Result;
+ }
+ if(temp > 0) {
+ Result = WriteText(pszString, temp);
+ ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
+ temp = (unsigned short)Result;
+ }
+
+ // keep writing lines until we get to less than 80 chars left
+ while((temp + (unsigned int)CON_COLS) < cbString) {
+ index(); // LF
+ ConsoleInfo.dwCursorPosition.X = 0; // CR
+ Result = WriteText(&pszString[temp], CON_COLS);
+ temp += (unsigned short)Result;
+ }
+
+ // write out the last bit
+ if(temp < cbString) {
+ index();
+ ConsoleInfo.dwCursorPosition.X = 0;
+ Result = WriteText(&pszString[temp], cbString - temp);
+ temp += (unsigned short)Result;
+ }
+
+ // Apparently VT100 terminals have an invisible "81st" column that
+ // can hold a cursor until another character is printed. I'm not sure
+ // exactly how to handle this, but here's a hack (Paul Brannan 5/28/98)
+ if(!ini.get_vt100_mode() && cbString + (unsigned)ConsoleInfo.dwCursorPosition.X
+ == (unsigned int)CON_COLS) {
+ index();
+ ConsoleInfo.dwCursorPosition.X = 0;
+ }
+
+ SetConsoleCursorPosition(hConsole, ConsoleInfo.dwCursorPosition);
+
+ return temp;
+ }
+
+ return 0;
+}
+
+// This is for multi-character control strings (Paul Brannan 6/26/98)
+unsigned long TConsole::WriteCtrlString(const char *pszString, unsigned long cbString) {
+ unsigned long total = 0;
+ while(total < cbString) {
+ unsigned long Result = WriteCtrlChar(*(pszString + total));
+ if(Result == 0) {
+ Result = WriteStringFast(pszString + total, 1);
+ if(Result == 0) return total;
+ }
+ total += Result;
+ }
+ return total;
+}
+
+// This is for printing single control characters
+// WriteCtrlString uses this (Paul Brannan 6/26/98)
+unsigned long TConsole::WriteCtrlChar(char c) {
+ // The console does not handel the CR/LF chars as we might expect
+ // when using color. The attributes are not set correctly, so we
+ // must interpret them manualy to preserve the colors on the screen.
+
+ unsigned long Result = 0; // just in case (Paul Brannan 6/26/98)
+ switch (c) {
+ case '\x09': // horizontal tab
+ SetCursorPosition((((CON_CUR_X/8)+1)*8), CON_CUR_Y);
+ Result = 1;
+ break;
+
+ case '\x0a': // line feed
+ index();
+ Result = 1;
+ break;
+ case '\x0d': // carrage return
+ SetCursorPosition(CON_LEFT, CON_CUR_Y); // move to beginning of line
+ Result = 1;
+ break;
+ case '\b': // backspace
+ // Added support for backspace so the cursor position can be changed
+ // (Paul Brannan 5/25/98)
+ MoveCursorPosition(-1, 0);
+ Result = 1;
+ default : // else just write it like normal
+ break;
+ }
+
+ return Result;
+}
+
+void TConsole::index() {
+ // if on the last line scroll up
+ // This must work with scrolling (Paul Brannan 5/13/98)
+ if(iScrollEnd != -1 && (signed)CON_CUR_Y >= iScrollEnd) {
+ ScrollDown(iScrollStart, iScrollEnd, -1);
+ } else if ((iScrollEnd == -1 && (signed)CON_CUR_Y >= (signed)CON_HEIGHT)) {
+ DWORD Result;
+ WriteConsole(hConsole, "\n", 1, &Result, NULL);
+
+ // If we aren't at the bottom of the buffer, then we need to
+ // scroll down (Paul Brannan 4/14/2000)
+ if(iScrollEnd == -1 && ConsoleInfo.srWindow.Bottom < ConsoleInfo.dwSize.Y - 1) {
+ ConsoleInfo.srWindow.Top++;
+ ConsoleInfo.srWindow.Bottom++;
+ ConsoleInfo.dwCursorPosition.Y++;
+ // SetConsoleWindowInfo(hConsole, TRUE, &ConsoleInfo.srWindow);
+ } else {
+ ClearLine();
+ }
+ } else { // else move cursor down to the next line
+ SetCursorPosition(CON_CUR_X, CON_CUR_Y + 1);
+ }
+}
+
+void TConsole::reverse_index() {
+ // if on the top line scroll down
+ // This must work with scrolling (Paul Brannan 5/13/98)
+ // We should be comparing against iScrollStart, not iScrollEnd (PB 12/2/98)
+ if (iScrollStart == -1 && (signed)CON_CUR_Y <= 0) {
+ ScrollDown(iScrollStart, -1, 1);
+ } else if (iScrollStart != -1 && (signed)CON_CUR_Y <= iScrollStart) {
+ ScrollDown(iScrollStart, iScrollEnd, 1);
+ } else // else move cursor up to the previous line
+ SetCursorPosition(CON_CUR_X,CON_CUR_Y - 1);
+}
+
+void TConsole::ScrollDown( int iStartRow , int iEndRow, int bUp ){
+ CHAR_INFO ciChar;
+ SMALL_RECT srScrollWindow;
+
+ // Correction from I.Ioannou 11 May 1997
+ // check the scroll region
+ if (iStartRow < iScrollStart) iStartRow = iScrollStart;
+
+ // Correction from I.Ioannou 11 May 1997
+ // this will make Top the CON_TOP
+ if ( iStartRow == -1) iStartRow = 0;
+
+ // Correction from I.Ioannou 18 Aug 97
+ if ( iEndRow == -1) {
+ if ( iScrollEnd == -1 )
+ iEndRow = CON_HEIGHT;
+ else
+ iEndRow = ((CON_HEIGHT <= iScrollEnd) ? CON_HEIGHT : iScrollEnd);
+ }
+ //
+
+ if ( iStartRow > CON_HEIGHT) iStartRow = CON_HEIGHT;
+ if ( iEndRow > CON_HEIGHT) iEndRow = CON_HEIGHT;
+
+ srScrollWindow.Left = (CON_LEFT);
+ srScrollWindow.Right = (SHORT) (CON_RIGHT);
+ srScrollWindow.Top = (SHORT) (CON_TOP + iStartRow );
+ srScrollWindow.Bottom = (SHORT) (CON_TOP + iEndRow); // don't subtract 1 (PB 5/28)
+
+ ciChar.Char.AsciiChar = ' '; // fill with spaces
+ ciChar.Attributes = wAttributes; // fill with current attrib
+
+ // This should speed things up (Paul Brannan 9/2/98)
+ COORD dwDestOrg = {srScrollWindow.Left, srScrollWindow.Top + bUp};
+
+ // Note that iEndRow and iStartRow had better not be equal to -1 at this
+ // point. There are four cases to consider for out of bounds. Two of
+ // these cause the scroll window to be cleared; the others cause the
+ // scroll region to be modified. (Paul Brannan 12/3/98)
+ if(dwDestOrg.Y > CON_TOP + iEndRow) {
+ // We are scrolling past the end of the scroll region, so just
+ // clear the window instead (Paul Brannan 12/3/98)
+ ClearWindow(CON_TOP + iStartRow, CON_TOP + iEndRow);
+ return;
+ } else if(dwDestOrg.Y + (iEndRow-iStartRow+1) < CON_TOP + iStartRow) {
+ // We are scrolling past the end of the scroll region, so just
+ // clear the window instead (Paul Brannan 12/3/98)
+ ClearWindow(CON_TOP + iStartRow, CON_TOP + iEndRow);
+ return;
+ } else if(dwDestOrg.Y < CON_TOP + iStartRow) {
+ // Modify the scroll region (Paul Brannan 12/3/98)
+ dwDestOrg.Y = CON_TOP + iStartRow;
+ srScrollWindow.Top -= bUp;
+ } else if(dwDestOrg.Y + (iEndRow-iStartRow+1) > CON_TOP + iEndRow) {
+ // Modify the scroll region (Paul Brannan 12/3/98)
+ srScrollWindow.Bottom -= bUp;
+ }
+
+ ScrollConsoleScreenBuffer(hConsole, &srScrollWindow,
+ 0, dwDestOrg, &ciChar);
+}
+
+// This allows us to clear the screen with an arbitrary character
+// (Paul Brannan 6/26/98)
+void TConsole::ClearScreen(char c) {
+ DWORD dwWritten;
+ COORD Coord = {CON_LEFT, CON_TOP};
+ FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS)*
+ (DWORD)(CON_LINES), Coord, &dwWritten);
+ FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS)*
+ (DWORD)(CON_LINES), Coord, &dwWritten);
+}
+
+// Same as clear screen, but only affects the scroll region
+void TConsole::ClearWindow(int iStartRow, int iEndRow, char c) {
+ DWORD dwWritten;
+ COORD Coord = {CON_LEFT, CON_TOP + iStartRow};
+ FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS)*
+ (DWORD)(iEndRow-iStartRow+1), Coord, &dwWritten);
+ FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS)*
+ (DWORD)(CON_LINES), Coord, &dwWritten);
+}
+
+// Clear from cursor to end of screen
+void TConsole::ClearEOScreen(char c)
+{
+ DWORD dwWritten;
+ COORD Coord = {CON_LEFT, CON_TOP + CON_CUR_Y + 1};
+ FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS)*
+ (DWORD)(CON_HEIGHT - CON_CUR_Y), Coord, &dwWritten);
+ FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS)*
+ (DWORD)(CON_LINES - CON_CUR_Y), Coord, &dwWritten);
+ ClearEOLine();
+}
+
+// Clear from beginning of screen to cursor
+void TConsole::ClearBOScreen(char c)
+{
+ DWORD dwWritten;
+ COORD Coord = {CON_LEFT, CON_TOP};
+ FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS)*
+ (DWORD)(CON_CUR_Y), Coord, &dwWritten);
+ FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS)*
+ (DWORD)(CON_CUR_Y), Coord, &dwWritten);
+ ClearBOLine();
+}
+
+void TConsole::ClearLine(char c)
+{
+ DWORD dwWritten;
+ COORD Coord = {CON_LEFT, CON_TOP + CON_CUR_Y};
+ FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS),
+ Coord, &dwWritten);
+ FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS),
+ Coord, &dwWritten);
+ GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
+}
+
+void TConsole::ClearEOLine(char c)
+{
+ DWORD dwWritten;
+ COORD Coord = {CON_LEFT + CON_CUR_X, CON_TOP + CON_CUR_Y};
+ FillConsoleOutputAttribute(hConsole, wAttributes,
+ (DWORD)(CON_RIGHT - CON_CUR_X) +1, Coord, &dwWritten);
+ FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_RIGHT - CON_CUR_X) +1,
+ Coord, &dwWritten);
+ GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
+}
+
+void TConsole::ClearBOLine(char c)
+{
+ DWORD dwWritten;
+ COORD Coord = {CON_LEFT, CON_TOP + CON_CUR_Y};
+ FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_CUR_X) + 1, Coord,
+ &dwWritten);
+ FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_CUR_X) + 1,
+ Coord, &dwWritten);
+ GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
+}
+
+
+// Inserts blank lines to the cursor-y-position
+// scrolls down the rest. CURSOR MOVEMENT (to Col#1) ???
+void TConsole::InsertLine(int numlines)
+{
+ COORD to;
+ SMALL_RECT from;
+ SMALL_RECT clip;
+ CHAR_INFO fill;
+ int acty;
+
+ // Rest of screen would be deleted
+ if ( (acty = GetCursorY()) >= CON_LINES - numlines ) {
+ ClearEOScreen(); // delete rest of screen
+ return;
+ } /* IF */
+
+ // Else scroll down the part of the screen which is below the
+ // cursor.
+ from.Left = CON_LEFT;
+ from.Top = CON_TOP + (SHORT)acty;
+ from.Right = CON_LEFT + (SHORT)CON_COLS;
+ from.Bottom = CON_TOP + (SHORT)CON_LINES;
+
+ clip = from;
+ to.X = 0;
+ to.Y = (SHORT)(from.Top + numlines);
+
+ fill.Char.AsciiChar = ' ';
+ fill.Attributes = 7; // WHICH ATTRIBUTES TO TAKE FOR BLANK LINE ??
+
+ ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
+} /* InsertLine */
+
+// Inserts blank characters under the cursor
+void TConsole::InsertCharacter(int numchar)
+{
+ int actx;
+ SMALL_RECT from;
+ SMALL_RECT clip;
+ COORD to;
+ CHAR_INFO fill;
+
+ if ( (actx = GetCursorX()) >= CON_COLS - numchar ) {
+ ClearEOLine();
+ return;
+ } /* IF */
+
+ from.Left = CON_LEFT + (SHORT)actx;
+ from.Top = CON_TOP + (SHORT)GetCursorY();
+ from.Right = CON_LEFT + (SHORT)CON_COLS;
+ from.Bottom = CON_TOP + (SHORT)from.Top;
+
+ clip = from;
+ to.X = (SHORT)(actx + numchar);
+ to.Y = from.Top;
+
+ fill.Char.AsciiChar = ' ';
+ fill.Attributes = wAttributes; // WHICH ATTRIBUTES TO TAKE FOR BLANK CHAR ??
+
+ ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
+} /* InsertCharacter */
+
+// Deletes characters under the cursor
+// Note that there are cases in which all the following lines should shift by
+// a character, but we don't handle these. This could break some
+// VT102-applications, but it shouldn't be too much of an issue.
+void TConsole::DeleteCharacter(int numchar)
+{
+ int actx;
+ SMALL_RECT from;
+ SMALL_RECT clip;
+ COORD to;
+ CHAR_INFO fill;
+
+ if ( (actx = GetCursorX()) >= CON_COLS - numchar ) {
+ ClearEOLine();
+ return;
+ } /* IF */
+
+ from.Left = CON_LEFT + (SHORT)actx;
+ from.Top = CON_TOP + (SHORT)GetCursorY();
+ from.Right = CON_LEFT + (SHORT)CON_COLS;
+ from.Bottom = CON_TOP + from.Top;
+
+ clip = from;
+ to.X = (SHORT)(actx - numchar);
+ to.Y = from.Top;
+
+ fill.Char.AsciiChar = ' ';
+ fill.Attributes = wAttributes; // WHICH ATTRIBUTES TO TAKE FOR BLANK CHAR ??
+
+ ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
+} /* DeleteCharacter */
+
+void TConsole::SetRawCursorPosition(int x, int y) {
+ if (x > CON_WIDTH) x = CON_WIDTH;
+ if (x < 0) x = 0;
+ if (y > CON_HEIGHT) y = CON_HEIGHT;
+ if (y < 0) y = 0;
+ COORD Coord = {(short)(CON_LEFT + x), (short)(CON_TOP + y)};
+ SetConsoleCursorPosition(hConsole, Coord);
+
+ // Update the ConsoleInfo struct (Paul Brannan 5/9/98)
+ ConsoleInfo.dwCursorPosition.Y = Coord.Y;
+ ConsoleInfo.dwCursorPosition.X = Coord.X;
+
+ // bug fix in case we went too far (Paul Brannan 5/25/98)
+ if(ConsoleInfo.dwCursorPosition.X < CON_LEFT)
+ ConsoleInfo.dwCursorPosition.X = CON_LEFT;
+ if(ConsoleInfo.dwCursorPosition.X > CON_RIGHT)
+ ConsoleInfo.dwCursorPosition.X = CON_RIGHT;
+ if(ConsoleInfo.dwCursorPosition.Y < CON_TOP)
+ ConsoleInfo.dwCursorPosition.Y = CON_TOP;
+ if(ConsoleInfo.dwCursorPosition.Y > CON_BOTTOM)
+ ConsoleInfo.dwCursorPosition.Y = CON_BOTTOM;
+}
+
+// The new SetCursorPosition takes scroll regions into consideration
+// (Paul Brannan 6/27/98)
+void TConsole::SetCursorPosition(int x, int y) {
+ if (x > CON_WIDTH) x = CON_WIDTH;
+ if (x < 0) x = 0;
+ if(iScrollEnd != -1) {
+ if(y > iScrollEnd) y = iScrollEnd;
+ } else {
+ if(y > CON_HEIGHT) y = CON_HEIGHT;
+ }
+ if(iScrollStart != -1) {
+ if(y < iScrollStart) y = iScrollStart;
+ } else {
+ if(y < 0) y = 0;
+ }
+
+ COORD Coord = {(short)(CON_LEFT + x), (short)(CON_TOP + y)};
+ SetConsoleCursorPosition(hConsole, Coord);
+
+ // Update the ConsoleInfo struct
+ ConsoleInfo.dwCursorPosition.Y = Coord.Y;
+ ConsoleInfo.dwCursorPosition.X = Coord.X;
+}
+
+void TConsole::MoveCursorPosition(int x, int y) {
+ SetCursorPosition(CON_CUR_X + x, CON_CUR_Y + y);
+}
+
+void TConsole::SetExtendedMode(int iFunction, BOOL bEnable)
+{
+ // Probably should do something here...
+ // Should change the screen mode, but do we need this?
+}
+
+void TConsole::SetScroll(int start, int end) {
+ iScrollStart = start;
+ iScrollEnd = end;
+}
+
+void TConsole::Beep() {
+ if(ini.get_do_beep()) {
+ if(!ini.get_speaker_beep()) printit("\a");
+ else ::Beep(400, 100);
+ }
+}
+
+void TConsole::SetCursorSize(int pct) {
+ CONSOLE_CURSOR_INFO ci = {(pct != 0)?pct:1, pct != 0};
+ SetConsoleCursorInfo(hConsole, &ci);
+}
+
+void saveScreen(CHAR_INFO *chiBuffer) {
+ HANDLE hStdout;
+ CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
+ SMALL_RECT srctReadRect;
+ COORD coordBufSize;
+ COORD coordBufCoord;
+
+ hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
+
+ srctReadRect.Top = CON_TOP; /* top left: row 0, col 0 */
+ srctReadRect.Left = CON_LEFT;
+ srctReadRect.Bottom = CON_BOTTOM; /* bot. right: row 1, col 79 */
+ srctReadRect.Right = CON_RIGHT;
+
+ coordBufSize.Y = CON_BOTTOM-CON_TOP+1;
+ coordBufSize.X = CON_RIGHT-CON_LEFT+1;
+
+ coordBufCoord.X = CON_TOP;
+ coordBufCoord.Y = CON_LEFT;
+
+ ReadConsoleOutput(
+ hStdout, /* screen buffer to read from */
+ chiBuffer, /* buffer to copy into */
+ coordBufSize, /* col-row size of chiBuffer */
+
+ coordBufCoord, /* top left dest. cell in chiBuffer */
+ &srctReadRect); /* screen buffer source rectangle */
+}
+
+void restoreScreen(CHAR_INFO *chiBuffer) {
+ HANDLE hStdout;
+ CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
+ SMALL_RECT srctReadRect;
+ COORD coordBufSize;
+ COORD coordBufCoord;
+
+ hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
+
+ // restore screen
+ srctReadRect.Top = CON_TOP; /* top left: row 0, col 0 */
+ srctReadRect.Left = CON_LEFT;
+ srctReadRect.Bottom = CON_BOTTOM; /* bot. right: row 1, col 79 */
+ srctReadRect.Right = CON_RIGHT;
+
+ coordBufSize.Y = CON_BOTTOM-CON_TOP+1;
+ coordBufSize.X = CON_RIGHT-CON_LEFT+1;
+
+ coordBufCoord.X = CON_TOP;
+ coordBufCoord.Y = CON_LEFT;
+ WriteConsoleOutput(
+ hStdout, /* screen buffer to write to */
+ chiBuffer, /* buffer to copy from */
+ coordBufSize, /* col-row size of chiBuffer */
+ coordBufCoord, /* top left src cell in chiBuffer */
+ &srctReadRect); /* dest. screen buffer rectangle */
+ // end restore screen
+
+}
+
+CHAR_INFO* newBuffer() {
+ CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
+ HANDLE hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
+ GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
+ CHAR_INFO * chiBuffer;
+ chiBuffer = new CHAR_INFO[(CON_BOTTOM-CON_TOP+1)*(CON_RIGHT-CON_LEFT+1)];
+ return chiBuffer;
+}
+
+void deleteBuffer(CHAR_INFO* chiBuffer) {
+ delete[] chiBuffer;
+}
+