/////////////////////////////////////////////////////////////////////////////// //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„rz.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 "precomp.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 color_fg = ini.get_normal_fg(); int color_bg = ini.get_normal_bg(); if(color_fg == -1) color_fg = defaultfg = origfg = ConsoleInfo.wAttributes & 0xF; else defaultfg = origfg = color_fg; if(color_bg == -1) color_bg = defaultbg = origbg = (ConsoleInfo.wAttributes >> 4) & 0xF; else defaultbg = origbg = color_bg; wAttributes = color_fg | (color_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((long)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; }