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
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.
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.
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.
24 ///////////////////////////////////////////////////////////////////////////
26 ///////////////////////////////////////////////////////////////////////////////
28 // Module: tconsole.cpp
30 // Contents: screen functions
35 // Revisions: Mar. 29, 2000 pbranna@clemson (Paul Brannan)
36 // June 15, 1998 pbranna@clemson.edu
37 // May 16, 1998 pbranna@clemson.edu
38 // 05. Sep.1997 roryt@hol.gr (I.Ioannou)
39 // 11.May,1997 roryt@hol.gr
40 // 06.April,1997 roryt@hol.gr
41 // 30.M\84rz.1997 Titus_Boxberg@public.uni-hamburg.de
42 // 5.Dec.1996 jbj@nounname.com
44 // 02.Apr.1995 igor.milavec@uni-lj.si
47 ///////////////////////////////////////////////////////////////////////////////
52 // argsused doesn't work on MSVC++
57 TConsole::TConsole(HANDLE h
) {
60 GetConsoleScreenBufferInfo(hConsole
, &ConsoleInfo
);
62 // Start with correct colors
63 int color_fg
= ini
.get_normal_fg();
64 int color_bg
= ini
.get_normal_bg();
66 color_fg
= defaultfg
= origfg
= ConsoleInfo
.wAttributes
& 0xF;
68 defaultfg
= origfg
= color_fg
;
70 color_bg
= defaultbg
= origbg
= (ConsoleInfo
.wAttributes
>> 4) & 0xF;
72 defaultbg
= origbg
= color_bg
;
73 wAttributes
= color_fg
| (color_bg
<< 4);
74 reverse
= blink
= underline
= false;
75 SetConsoleTextAttribute(hConsole
, wAttributes
);
79 // Set the screen size
80 SetWindowSize(ini
.get_term_width(), ini
.get_term_height());
86 TConsole::~TConsole() {
87 wAttributes
= origfg
| (origbg
<< 4);
88 SetCursorPosition(0, CON_HEIGHT
);
89 SetConsoleTextAttribute(hConsole
, wAttributes
);
90 WriteCtrlChar('\x0a');
93 // Paul Brannan 8/2/98
94 void TConsole::SetWindowSize(int width
, int height
) {
98 (width
== -1) ? CON_RIGHT
: CON_LEFT
+ width
- 1,
99 (height
== -1) ? CON_BOTTOM
: CON_TOP
+ height
- 1
101 ConsoleInfo
.dwSize
.X
= width
;
102 if(ConsoleInfo
.dwSize
.Y
< height
) ConsoleInfo
.dwSize
.Y
= height
;
103 SetConsoleScreenBufferSize(hConsole
, ConsoleInfo
.dwSize
);
104 SetConsoleWindowInfo(hConsole
, TRUE
, &sr
);
105 SetConsoleScreenBufferSize(hConsole
, ConsoleInfo
.dwSize
);
109 // Paul Brannan 5/15/98
110 void TConsole::sync() {
111 GetConsoleScreenBufferInfo(hConsole
, &ConsoleInfo
);
114 void TConsole::HighVideo() {
115 wAttributes
= wAttributes
| (unsigned char) 8;
118 void TConsole::LowVideo() {
119 wAttributes
= wAttributes
& (unsigned char) (0xff-8);
122 void TConsole::Normal() {
123 // I.Ioannou 11 May 1997
124 // Color 7 is correct on some systems (for example Linux)
125 // but not with others (for example SCO)
126 // we must preserve the colors :
127 // 06/04/98 thanks to Paul a .ini parameter from now on
131 if(ini
.get_preserve_colors()) {
137 wAttributes
= (unsigned char)fg
| (bg
<< 4);
142 void TConsole::SetForeground(unsigned char wAttrib
) {
143 if(reverse
) bg
= wAttrib
; else fg
= wAttrib
;
144 wAttributes
= (wAttributes
& (unsigned char)0x88) |
145 (unsigned char)fg
| (bg
<< 4);
148 void TConsole::SetBackground(unsigned char wAttrib
) {
149 if(reverse
) fg
= wAttrib
; else bg
= wAttrib
;
150 wAttributes
= (wAttributes
& (unsigned char)0x88) |
151 (unsigned char)fg
| (bg
<< 4);
154 // As far as I can tell, there's no such thing as blink in Windows Console.
155 // I tried using some inline asm to turn off high-intensity backgrounds,
156 // but I got a BSOD. Perhaps there is an undocumented function?
157 // (Paul Brannan 6/27/98)
158 void TConsole::BlinkOn() {
163 if(ini
.get_blink_bg() != -1) {
164 wAttributes
&= 0x8f; // turn off bg
165 wAttributes
|= ini
.get_blink_bg() << 4;
167 if(ini
.get_blink_fg() != -1) {
168 wAttributes
&= 0xf8; // turn off fg
169 wAttributes
|= ini
.get_blink_fg();
171 if(ini
.get_blink_bg() == -1 && ini
.get_blink_fg() == -1)
176 // Added by I.Ioannou 06 April, 1997
177 void TConsole::BlinkOff() {
182 if(ini
.get_blink_bg() != -1) {
183 wAttributes
&= 0x8f; // turn off bg
184 wAttributes
|= defaultbg
<< 4;
186 if(ini
.get_blink_fg() != -1) {
187 wAttributes
&= 0xf8; // turn off fg
188 wAttributes
|= defaultfg
;
190 if(ini
.get_blink_bg() == -1 && ini
.get_blink_fg() == -1)
195 // Paul Brannan 6/27/98
196 void TConsole::UnderlineOn() {
201 if(ini
.get_underline_bg() != -1) {
202 wAttributes
&= 0x8f; // turn off bg
203 wAttributes
|= ini
.get_underline_bg() << 4;
205 if(ini
.get_underline_fg() != -1) {
206 wAttributes
&= 0xf8; // turn off fg
207 wAttributes
|= ini
.get_underline_fg();
209 if(ini
.get_underline_bg() == -1 && ini
.get_underline_fg() == -1)
214 // Paul Brannan 6/27/98
215 void TConsole::UnderlineOff() {
220 if(ini
.get_blink_bg() != -1) {
221 wAttributes
&= 0x8f; // turn off bg
222 wAttributes
|= defaultbg
<< 4;
224 if(ini
.get_blink_fg() != -1) {
225 wAttributes
&= 0xf8; // turn off fg
226 wAttributes
|= defaultfg
;
228 if(ini
.get_blink_bg() == -1 && ini
.get_blink_fg() == -1)
233 // Paul Brannan 6/27/98
234 void TConsole::UlBlinkOn() {
235 if(ini
.get_ulblink_bg() != -1) {
236 wAttributes
&= 0x8f; // turn off bg
237 wAttributes
|= ini
.get_ulblink_bg() << 4;
239 if(ini
.get_ulblink_fg() != -1) {
240 wAttributes
&= 0xf8; // turn off fg
241 wAttributes
|= ini
.get_ulblink_fg();
243 if(ini
.get_ulblink_bg() == -1 && ini
.get_ulblink_fg() == -1)
247 // Paul Brannan 6/27/98
248 void TConsole::UlBlinkOff() {
251 } else if(underline
) {
258 // Paul Brannan 6/26/98
259 void TConsole::Lightbg() {
260 WORD
*pAttributes
= new WORD
[CON_COLS
];
263 // Paul Brannan 8/5/98
264 // Correction: processing more than one line at a time causes a segfault
265 // if the screen width != 80
266 for(int i
= CON_TOP
; i
<= CON_BOTTOM
; i
++) {
267 COORD Coord
= {CON_LEFT
, i
};
269 ReadConsoleOutputAttribute(hConsole
, pAttributes
, (DWORD
)(CON_COLS
),
272 for(DWORD j
= 0; j
< Result
; j
++) pAttributes
[j
] |= 0x80;
274 WriteConsoleOutputAttribute(hConsole
, pAttributes
, Result
, Coord
,
278 delete[] pAttributes
; // clean up
280 wAttributes
|= (unsigned char)0x80;
284 // Paul Brannan 6/26/98
285 void TConsole::Darkbg() {
286 WORD
*pAttributes
= new WORD
[CON_COLS
];
289 // Paul Brannan 8/5/98
290 // Correction: processing more than one line at a time causes a segfault
291 // if the screen width != 80
292 for(int i
= CON_TOP
; i
<= CON_BOTTOM
; i
++) {
293 COORD Coord
= {CON_LEFT
, i
};
295 ReadConsoleOutputAttribute(hConsole
, pAttributes
, (DWORD
)(CON_COLS
),
298 for(DWORD j
= 0; j
< Result
; j
++) pAttributes
[j
] &= 0x7f;
300 WriteConsoleOutputAttribute(hConsole
, pAttributes
, Result
, Coord
,
304 delete[] pAttributes
; // clean up
307 wAttributes
&= (unsigned char)0x7f;
311 // Added by I.Ioannou 11.May,1997
312 void TConsole::ReverseOn() {
316 // atl : forground attributes without the intensity
317 // ath : backgound attributes without the blink
318 // bl : the blink state
319 // ints : the intensity
320 unsigned char atl
= wAttributes
& (unsigned char) 0x07;
321 unsigned char ath
= wAttributes
& (unsigned char) 0x70;
322 unsigned char bl
= wAttributes
& (unsigned char) 0x80;
323 unsigned char ints
= wAttributes
& (unsigned char) 0x08;
324 wAttributes
= bl
| (atl
<< 4) | ints
| (ath
>> 4);
328 // Added by I.Ioannou 11.May,1997
329 void TConsole::ReverseOff() {
332 wAttributes
= fg
| (bg
<< 4);
336 unsigned long TConsole::WriteText(const char *pszString
, unsigned long cbString
) {
340 InsertCharacter(cbString
);
343 WriteConsoleOutputCharacter(hConsole
, (char *)pszString
, cbString
,
344 ConsoleInfo
.dwCursorPosition
, &Result
);
345 FillConsoleOutputAttribute(hConsole
, wAttributes
, cbString
,
346 ConsoleInfo
.dwCursorPosition
, &Result
);
350 // Formerly ConWriteString (Paul Brannan 6/28/98)
351 unsigned long TConsole::WriteStringFast(const char* pszString
, unsigned long cbString
) {
354 SetConsoleTextAttribute(hConsole
, wAttributes
);
356 //check to see if the line is longer than the display
357 if (!getLineWrap() && ((unsigned)CON_CUR_X
+ cbString
) >= (unsigned)CON_COLS
) {
358 // Take care of the last line last colum exception...
359 // The display scrolls up if you use the normal char out
360 // function even if you only write to the last place
362 if ((unsigned)CON_CUR_Y
>= (unsigned)CON_HEIGHT
) {
363 unsigned long iFakeResult
= cbString
;
364 cbString
= CON_COLS
- CON_CUR_X
- 1;
366 // FIX ME !!! This will avoid the exception when cbString
367 // is <= 0 but still doesn't work :-(
369 WriteConsole(hConsole
, pszString
, cbString
, &Result
, 0);
376 ciBuffer
.Char
.AsciiChar
= *(pszString
+cbString
);
377 ciBuffer
.Attributes
= wAttributes
;
378 SMALL_RECT srWriteRegion
;
379 srWriteRegion
.Top
= (SHORT
) CON_BOTTOM
;
380 srWriteRegion
.Bottom
= (SHORT
) CON_BOTTOM
;
381 srWriteRegion
.Left
= (SHORT
) CON_RIGHT
;
382 srWriteRegion
.Right
= (SHORT
) CON_RIGHT
;
384 COORD bufSize
= {1,1};
386 WriteConsoleOutput(hConsole
, &ciBuffer
, bufSize
,
387 dwBufferCoord
, &srWriteRegion
);
389 // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
390 ConsoleInfo
.dwCursorPosition
.X
= CON_RIGHT
;
392 return iFakeResult
; // Skip the chars that did not fit
394 // just write the line up to the end
396 int iFakeResult
= cbString
;
397 cbString
= CON_COLS
- CON_CUR_X
;
400 WriteConsole(hConsole
, pszString
, cbString
, &Result
, 0);
402 // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
403 ConsoleInfo
.dwCursorPosition
.X
+= (unsigned short)Result
;
406 return iFakeResult
; // Skip the chars that did not fit
409 // If custom scrolling is enabled we must take care of it
410 if(iScrollStart
!= -1 || iScrollEnd
!= -1) {
411 return WriteString(pszString
, cbString
);
414 // Apparently VT100 terminals have an invisible "81st" column that
415 // can hold a cursor until another character is printed. I'm not sure
416 // exactly how to handle this, but here's a hack (Paul Brannan 5/28/98)
417 if(ini
.get_vt100_mode() && cbString
+ (unsigned)CON_CUR_X
== (unsigned)CON_COLS
) {
420 if((long)cbString
>= 0) WriteConsole(hConsole
, pszString
, cbString
, &Result
, 0);
427 ciBuffer
.Char
.AsciiChar
= *(pszString
+cbString
);
428 ciBuffer
.Attributes
= wAttributes
;
429 SMALL_RECT srWriteRegion
;
430 srWriteRegion
.Top
= (SHORT
) ConsoleInfo
.dwCursorPosition
.Y
;
431 srWriteRegion
.Bottom
= (SHORT
) ConsoleInfo
.dwCursorPosition
.Y
;
432 srWriteRegion
.Left
= (SHORT
) CON_RIGHT
;
433 srWriteRegion
.Right
= (SHORT
) CON_RIGHT
;
435 COORD bufSize
= {1,1};
437 WriteConsoleOutput(hConsole
, &ciBuffer
, bufSize
,
438 dwBufferCoord
, &srWriteRegion
);
440 // Update the ConsoleInfo struct
441 ConsoleInfo
.dwCursorPosition
.X
= CON_RIGHT
+ 1;
446 // normal line will wrap normally or not to the end of buffer
447 WriteConsole(hConsole
, pszString
, cbString
, &Result
, 0);
449 // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
450 // FIX ME!!! This is susceptible to the same problem as above.
451 // (e.g. we write out 160 characters)
452 ConsoleInfo
.dwCursorPosition
.X
+= (unsigned short)Result
;
453 while(CON_CUR_X
> CON_WIDTH
) {
454 ConsoleInfo
.dwCursorPosition
.X
-= ConsoleInfo
.dwSize
.X
;
455 if((unsigned)CON_CUR_Y
< (unsigned)CON_HEIGHT
) {
456 ConsoleInfo
.dwCursorPosition
.Y
++;
458 // If we aren't at the bottom of the window, then we need to
459 // scroll down (Paul Brannan 4/14/2000)
460 if(ConsoleInfo
.srWindow
.Bottom
< ConsoleInfo
.dwSize
.Y
- 1) {
461 ConsoleInfo
.srWindow
.Top
++;
462 ConsoleInfo
.srWindow
.Bottom
++;
463 ConsoleInfo
.dwCursorPosition
.Y
++;
464 SetConsoleWindowInfo(hConsole
, TRUE
, &ConsoleInfo
.srWindow
);
474 unsigned long TConsole::WriteString(const char* pszString
, unsigned long cbString
) {
477 SetConsoleTextAttribute(hConsole
, wAttributes
);
479 //check to see if the line is longer than the display
481 unsigned long iFakeResult
= cbString
;
482 if((CON_CUR_X
+ cbString
) >= (unsigned int)CON_COLS
)
483 cbString
= CON_COLS
- CON_CUR_X
;
485 Result
= WriteText(pszString
, cbString
);
487 // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
488 ConsoleInfo
.dwCursorPosition
.X
+= (unsigned short)Result
;
489 SetConsoleCursorPosition(hConsole
, ConsoleInfo
.dwCursorPosition
);
491 return iFakeResult
; // Skip the chars that did not fit
493 // Write up to the end of the line
494 unsigned long temp
= cbString
;
495 if((CON_CUR_X
+ temp
) > (unsigned int)CON_COLS
) {
496 temp
= CON_COLS
- CON_CUR_X
;
498 Result
= WriteText(pszString
, temp
);
499 ConsoleInfo
.dwCursorPosition
.X
+= (unsigned short)Result
;
500 SetConsoleCursorPosition(hConsole
, ConsoleInfo
.dwCursorPosition
);
504 Result
= WriteText(pszString
, temp
);
505 ConsoleInfo
.dwCursorPosition
.X
+= (unsigned short)Result
;
506 temp
= (unsigned short)Result
;
509 // keep writing lines until we get to less than 80 chars left
510 while((temp
+ (unsigned int)CON_COLS
) < cbString
) {
512 ConsoleInfo
.dwCursorPosition
.X
= 0; // CR
513 Result
= WriteText(&pszString
[temp
], CON_COLS
);
514 temp
+= (unsigned short)Result
;
517 // write out the last bit
518 if(temp
< cbString
) {
520 ConsoleInfo
.dwCursorPosition
.X
= 0;
521 Result
= WriteText(&pszString
[temp
], cbString
- temp
);
522 temp
+= (unsigned short)Result
;
525 // Apparently VT100 terminals have an invisible "81st" column that
526 // can hold a cursor until another character is printed. I'm not sure
527 // exactly how to handle this, but here's a hack (Paul Brannan 5/28/98)
528 if(!ini
.get_vt100_mode() && cbString
+ (unsigned)ConsoleInfo
.dwCursorPosition
.X
529 == (unsigned int)CON_COLS
) {
531 ConsoleInfo
.dwCursorPosition
.X
= 0;
534 SetConsoleCursorPosition(hConsole
, ConsoleInfo
.dwCursorPosition
);
542 // This is for multi-character control strings (Paul Brannan 6/26/98)
543 unsigned long TConsole::WriteCtrlString(const char *pszString
, unsigned long cbString
) {
544 unsigned long total
= 0;
545 while(total
< cbString
) {
546 unsigned long Result
= WriteCtrlChar(*(pszString
+ total
));
548 Result
= WriteStringFast(pszString
+ total
, 1);
549 if(Result
== 0) return total
;
556 // This is for printing single control characters
557 // WriteCtrlString uses this (Paul Brannan 6/26/98)
558 unsigned long TConsole::WriteCtrlChar(char c
) {
559 // The console does not handel the CR/LF chars as we might expect
560 // when using color. The attributes are not set correctly, so we
561 // must interpret them manualy to preserve the colors on the screen.
563 unsigned long Result
= 0; // just in case (Paul Brannan 6/26/98)
565 case '\x09': // horizontal tab
566 SetCursorPosition((((CON_CUR_X
/8)+1)*8), CON_CUR_Y
);
570 case '\x0a': // line feed
574 case '\x0d': // carrage return
575 SetCursorPosition(CON_LEFT
, CON_CUR_Y
); // move to beginning of line
578 case '\b': // backspace
579 // Added support for backspace so the cursor position can be changed
580 // (Paul Brannan 5/25/98)
581 MoveCursorPosition(-1, 0);
583 default : // else just write it like normal
590 void TConsole::index() {
591 // if on the last line scroll up
592 // This must work with scrolling (Paul Brannan 5/13/98)
593 if(iScrollEnd
!= -1 && (signed)CON_CUR_Y
>= iScrollEnd
) {
594 ScrollDown(iScrollStart
, iScrollEnd
, -1);
595 } else if ((iScrollEnd
== -1 && (signed)CON_CUR_Y
>= (signed)CON_HEIGHT
)) {
597 WriteConsole(hConsole
, "\n", 1, &Result
, NULL
);
599 // If we aren't at the bottom of the buffer, then we need to
600 // scroll down (Paul Brannan 4/14/2000)
601 if(iScrollEnd
== -1 && ConsoleInfo
.srWindow
.Bottom
< ConsoleInfo
.dwSize
.Y
- 1) {
602 ConsoleInfo
.srWindow
.Top
++;
603 ConsoleInfo
.srWindow
.Bottom
++;
604 ConsoleInfo
.dwCursorPosition
.Y
++;
605 // SetConsoleWindowInfo(hConsole, TRUE, &ConsoleInfo.srWindow);
609 } else { // else move cursor down to the next line
610 SetCursorPosition(CON_CUR_X
, CON_CUR_Y
+ 1);
614 void TConsole::reverse_index() {
615 // if on the top line scroll down
616 // This must work with scrolling (Paul Brannan 5/13/98)
617 // We should be comparing against iScrollStart, not iScrollEnd (PB 12/2/98)
618 if (iScrollStart
== -1 && (signed)CON_CUR_Y
<= 0) {
619 ScrollDown(iScrollStart
, -1, 1);
620 } else if (iScrollStart
!= -1 && (signed)CON_CUR_Y
<= iScrollStart
) {
621 ScrollDown(iScrollStart
, iScrollEnd
, 1);
622 } else // else move cursor up to the previous line
623 SetCursorPosition(CON_CUR_X
,CON_CUR_Y
- 1);
626 void TConsole::ScrollDown( int iStartRow
, int iEndRow
, int bUp
){
628 SMALL_RECT srScrollWindow
;
630 // Correction from I.Ioannou 11 May 1997
631 // check the scroll region
632 if (iStartRow
< iScrollStart
) iStartRow
= iScrollStart
;
634 // Correction from I.Ioannou 11 May 1997
635 // this will make Top the CON_TOP
636 if ( iStartRow
== -1) iStartRow
= 0;
638 // Correction from I.Ioannou 18 Aug 97
639 if ( iEndRow
== -1) {
640 if ( iScrollEnd
== -1 )
641 iEndRow
= CON_HEIGHT
;
643 iEndRow
= ((CON_HEIGHT
<= iScrollEnd
) ? CON_HEIGHT
: iScrollEnd
);
647 if ( iStartRow
> CON_HEIGHT
) iStartRow
= CON_HEIGHT
;
648 if ( iEndRow
> CON_HEIGHT
) iEndRow
= CON_HEIGHT
;
650 srScrollWindow
.Left
= (CON_LEFT
);
651 srScrollWindow
.Right
= (SHORT
) (CON_RIGHT
);
652 srScrollWindow
.Top
= (SHORT
) (CON_TOP
+ iStartRow
);
653 srScrollWindow
.Bottom
= (SHORT
) (CON_TOP
+ iEndRow
); // don't subtract 1 (PB 5/28)
655 ciChar
.Char
.AsciiChar
= ' '; // fill with spaces
656 ciChar
.Attributes
= wAttributes
; // fill with current attrib
658 // This should speed things up (Paul Brannan 9/2/98)
659 COORD dwDestOrg
= {srScrollWindow
.Left
, srScrollWindow
.Top
+ bUp
};
661 // Note that iEndRow and iStartRow had better not be equal to -1 at this
662 // point. There are four cases to consider for out of bounds. Two of
663 // these cause the scroll window to be cleared; the others cause the
664 // scroll region to be modified. (Paul Brannan 12/3/98)
665 if(dwDestOrg
.Y
> CON_TOP
+ iEndRow
) {
666 // We are scrolling past the end of the scroll region, so just
667 // clear the window instead (Paul Brannan 12/3/98)
668 ClearWindow(CON_TOP
+ iStartRow
, CON_TOP
+ iEndRow
);
670 } else if(dwDestOrg
.Y
+ (iEndRow
-iStartRow
+1) < CON_TOP
+ iStartRow
) {
671 // We are scrolling past the end of the scroll region, so just
672 // clear the window instead (Paul Brannan 12/3/98)
673 ClearWindow(CON_TOP
+ iStartRow
, CON_TOP
+ iEndRow
);
675 } else if(dwDestOrg
.Y
< CON_TOP
+ iStartRow
) {
676 // Modify the scroll region (Paul Brannan 12/3/98)
677 dwDestOrg
.Y
= CON_TOP
+ iStartRow
;
678 srScrollWindow
.Top
-= bUp
;
679 } else if(dwDestOrg
.Y
+ (iEndRow
-iStartRow
+1) > CON_TOP
+ iEndRow
) {
680 // Modify the scroll region (Paul Brannan 12/3/98)
681 srScrollWindow
.Bottom
-= bUp
;
684 ScrollConsoleScreenBuffer(hConsole
, &srScrollWindow
,
685 0, dwDestOrg
, &ciChar
);
688 // This allows us to clear the screen with an arbitrary character
689 // (Paul Brannan 6/26/98)
690 void TConsole::ClearScreen(char c
) {
692 COORD Coord
= {CON_LEFT
, CON_TOP
};
693 FillConsoleOutputCharacter(hConsole
, c
, (DWORD
)(CON_COLS
)*
694 (DWORD
)(CON_LINES
), Coord
, &dwWritten
);
695 FillConsoleOutputAttribute(hConsole
, wAttributes
, (DWORD
)(CON_COLS
)*
696 (DWORD
)(CON_LINES
), Coord
, &dwWritten
);
699 // Same as clear screen, but only affects the scroll region
700 void TConsole::ClearWindow(int iStartRow
, int iEndRow
, char c
) {
702 COORD Coord
= {CON_LEFT
, CON_TOP
+ iStartRow
};
703 FillConsoleOutputCharacter(hConsole
, c
, (DWORD
)(CON_COLS
)*
704 (DWORD
)(iEndRow
-iStartRow
+1), Coord
, &dwWritten
);
705 FillConsoleOutputAttribute(hConsole
, wAttributes
, (DWORD
)(CON_COLS
)*
706 (DWORD
)(CON_LINES
), Coord
, &dwWritten
);
709 // Clear from cursor to end of screen
710 void TConsole::ClearEOScreen(char c
)
713 COORD Coord
= {CON_LEFT
, CON_TOP
+ CON_CUR_Y
+ 1};
714 FillConsoleOutputCharacter(hConsole
, c
, (DWORD
)(CON_COLS
)*
715 (DWORD
)(CON_HEIGHT
- CON_CUR_Y
), Coord
, &dwWritten
);
716 FillConsoleOutputAttribute(hConsole
, wAttributes
, (DWORD
)(CON_COLS
)*
717 (DWORD
)(CON_LINES
- CON_CUR_Y
), Coord
, &dwWritten
);
721 // Clear from beginning of screen to cursor
722 void TConsole::ClearBOScreen(char c
)
725 COORD Coord
= {CON_LEFT
, CON_TOP
};
726 FillConsoleOutputCharacter(hConsole
, c
, (DWORD
)(CON_COLS
)*
727 (DWORD
)(CON_CUR_Y
), Coord
, &dwWritten
);
728 FillConsoleOutputAttribute(hConsole
, wAttributes
, (DWORD
)(CON_COLS
)*
729 (DWORD
)(CON_CUR_Y
), Coord
, &dwWritten
);
733 void TConsole::ClearLine(char c
)
736 COORD Coord
= {CON_LEFT
, CON_TOP
+ CON_CUR_Y
};
737 FillConsoleOutputCharacter(hConsole
, c
, (DWORD
)(CON_COLS
),
739 FillConsoleOutputAttribute(hConsole
, wAttributes
, (DWORD
)(CON_COLS
),
741 GetConsoleScreenBufferInfo(hConsole
, &ConsoleInfo
);
744 void TConsole::ClearEOLine(char c
)
747 COORD Coord
= {CON_LEFT
+ CON_CUR_X
, CON_TOP
+ CON_CUR_Y
};
748 FillConsoleOutputAttribute(hConsole
, wAttributes
,
749 (DWORD
)(CON_RIGHT
- CON_CUR_X
) +1, Coord
, &dwWritten
);
750 FillConsoleOutputCharacter(hConsole
, c
, (DWORD
)(CON_RIGHT
- CON_CUR_X
) +1,
752 GetConsoleScreenBufferInfo(hConsole
, &ConsoleInfo
);
755 void TConsole::ClearBOLine(char c
)
758 COORD Coord
= {CON_LEFT
, CON_TOP
+ CON_CUR_Y
};
759 FillConsoleOutputCharacter(hConsole
, c
, (DWORD
)(CON_CUR_X
) + 1, Coord
,
761 FillConsoleOutputAttribute(hConsole
, wAttributes
, (DWORD
)(CON_CUR_X
) + 1,
763 GetConsoleScreenBufferInfo(hConsole
, &ConsoleInfo
);
767 // Inserts blank lines to the cursor-y-position
768 // scrolls down the rest. CURSOR MOVEMENT (to Col#1) ???
769 void TConsole::InsertLine(int numlines
)
777 // Rest of screen would be deleted
778 if ( (acty
= GetCursorY()) >= CON_LINES
- numlines
) {
779 ClearEOScreen(); // delete rest of screen
783 // Else scroll down the part of the screen which is below the
785 from
.Left
= CON_LEFT
;
786 from
.Top
= CON_TOP
+ (SHORT
)acty
;
787 from
.Right
= CON_LEFT
+ (SHORT
)CON_COLS
;
788 from
.Bottom
= CON_TOP
+ (SHORT
)CON_LINES
;
792 to
.Y
= (SHORT
)(from
.Top
+ numlines
);
794 fill
.Char
.AsciiChar
= ' ';
795 fill
.Attributes
= 7; // WHICH ATTRIBUTES TO TAKE FOR BLANK LINE ??
797 ScrollConsoleScreenBuffer(hConsole
, &from
, &clip
, to
, &fill
);
800 // Inserts blank characters under the cursor
801 void TConsole::InsertCharacter(int numchar
)
809 if ( (actx
= GetCursorX()) >= CON_COLS
- numchar
) {
814 from
.Left
= CON_LEFT
+ (SHORT
)actx
;
815 from
.Top
= CON_TOP
+ (SHORT
)GetCursorY();
816 from
.Right
= CON_LEFT
+ (SHORT
)CON_COLS
;
817 from
.Bottom
= CON_TOP
+ (SHORT
)from
.Top
;
820 to
.X
= (SHORT
)(actx
+ numchar
);
823 fill
.Char
.AsciiChar
= ' ';
824 fill
.Attributes
= wAttributes
; // WHICH ATTRIBUTES TO TAKE FOR BLANK CHAR ??
826 ScrollConsoleScreenBuffer(hConsole
, &from
, &clip
, to
, &fill
);
827 } /* InsertCharacter */
829 // Deletes characters under the cursor
830 // Note that there are cases in which all the following lines should shift by
831 // a character, but we don't handle these. This could break some
832 // VT102-applications, but it shouldn't be too much of an issue.
833 void TConsole::DeleteCharacter(int numchar
)
841 if ( (actx
= GetCursorX()) >= CON_COLS
- numchar
) {
846 from
.Left
= CON_LEFT
+ (SHORT
)actx
;
847 from
.Top
= CON_TOP
+ (SHORT
)GetCursorY();
848 from
.Right
= CON_LEFT
+ (SHORT
)CON_COLS
;
849 from
.Bottom
= CON_TOP
+ from
.Top
;
852 to
.X
= (SHORT
)(actx
- numchar
);
855 fill
.Char
.AsciiChar
= ' ';
856 fill
.Attributes
= wAttributes
; // WHICH ATTRIBUTES TO TAKE FOR BLANK CHAR ??
858 ScrollConsoleScreenBuffer(hConsole
, &from
, &clip
, to
, &fill
);
859 } /* DeleteCharacter */
861 void TConsole::SetRawCursorPosition(int x
, int y
) {
862 if (x
> CON_WIDTH
) x
= CON_WIDTH
;
864 if (y
> CON_HEIGHT
) y
= CON_HEIGHT
;
866 COORD Coord
= {(short)(CON_LEFT
+ x
), (short)(CON_TOP
+ y
)};
867 SetConsoleCursorPosition(hConsole
, Coord
);
869 // Update the ConsoleInfo struct (Paul Brannan 5/9/98)
870 ConsoleInfo
.dwCursorPosition
.Y
= Coord
.Y
;
871 ConsoleInfo
.dwCursorPosition
.X
= Coord
.X
;
873 // bug fix in case we went too far (Paul Brannan 5/25/98)
874 if(ConsoleInfo
.dwCursorPosition
.X
< CON_LEFT
)
875 ConsoleInfo
.dwCursorPosition
.X
= CON_LEFT
;
876 if(ConsoleInfo
.dwCursorPosition
.X
> CON_RIGHT
)
877 ConsoleInfo
.dwCursorPosition
.X
= CON_RIGHT
;
878 if(ConsoleInfo
.dwCursorPosition
.Y
< CON_TOP
)
879 ConsoleInfo
.dwCursorPosition
.Y
= CON_TOP
;
880 if(ConsoleInfo
.dwCursorPosition
.Y
> CON_BOTTOM
)
881 ConsoleInfo
.dwCursorPosition
.Y
= CON_BOTTOM
;
884 // The new SetCursorPosition takes scroll regions into consideration
885 // (Paul Brannan 6/27/98)
886 void TConsole::SetCursorPosition(int x
, int y
) {
887 if (x
> CON_WIDTH
) x
= CON_WIDTH
;
889 if(iScrollEnd
!= -1) {
890 if(y
> iScrollEnd
) y
= iScrollEnd
;
892 if(y
> CON_HEIGHT
) y
= CON_HEIGHT
;
894 if(iScrollStart
!= -1) {
895 if(y
< iScrollStart
) y
= iScrollStart
;
900 COORD Coord
= {(short)(CON_LEFT
+ x
), (short)(CON_TOP
+ y
)};
901 SetConsoleCursorPosition(hConsole
, Coord
);
903 // Update the ConsoleInfo struct
904 ConsoleInfo
.dwCursorPosition
.Y
= Coord
.Y
;
905 ConsoleInfo
.dwCursorPosition
.X
= Coord
.X
;
908 void TConsole::MoveCursorPosition(int x
, int y
) {
909 SetCursorPosition(CON_CUR_X
+ x
, CON_CUR_Y
+ y
);
912 void TConsole::SetExtendedMode(int iFunction
, BOOL bEnable
)
914 // Probably should do something here...
915 // Should change the screen mode, but do we need this?
918 void TConsole::SetScroll(int start
, int end
) {
919 iScrollStart
= start
;
923 void TConsole::Beep() {
924 if(ini
.get_do_beep()) {
925 if(!ini
.get_speaker_beep()) printit("\a");
926 else ::Beep(400, 100);
930 void TConsole::SetCursorSize(int pct
) {
931 CONSOLE_CURSOR_INFO ci
= {(pct
!= 0)?pct
:1, pct
!= 0};
932 SetConsoleCursorInfo(hConsole
, &ci
);
935 void saveScreen(CHAR_INFO
*chiBuffer
) {
937 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
938 SMALL_RECT srctReadRect
;
942 hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
943 GetConsoleScreenBufferInfo(hStdout
, &ConsoleInfo
);
945 srctReadRect
.Top
= CON_TOP
; /* top left: row 0, col 0 */
946 srctReadRect
.Left
= CON_LEFT
;
947 srctReadRect
.Bottom
= CON_BOTTOM
; /* bot. right: row 1, col 79 */
948 srctReadRect
.Right
= CON_RIGHT
;
950 coordBufSize
.Y
= CON_BOTTOM
-CON_TOP
+1;
951 coordBufSize
.X
= CON_RIGHT
-CON_LEFT
+1;
953 coordBufCoord
.X
= CON_TOP
;
954 coordBufCoord
.Y
= CON_LEFT
;
957 hStdout
, /* screen buffer to read from */
958 chiBuffer
, /* buffer to copy into */
959 coordBufSize
, /* col-row size of chiBuffer */
961 coordBufCoord
, /* top left dest. cell in chiBuffer */
962 &srctReadRect
); /* screen buffer source rectangle */
965 void restoreScreen(CHAR_INFO
*chiBuffer
) {
967 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
968 SMALL_RECT srctReadRect
;
972 hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
973 GetConsoleScreenBufferInfo(hStdout
, &ConsoleInfo
);
976 srctReadRect
.Top
= CON_TOP
; /* top left: row 0, col 0 */
977 srctReadRect
.Left
= CON_LEFT
;
978 srctReadRect
.Bottom
= CON_BOTTOM
; /* bot. right: row 1, col 79 */
979 srctReadRect
.Right
= CON_RIGHT
;
981 coordBufSize
.Y
= CON_BOTTOM
-CON_TOP
+1;
982 coordBufSize
.X
= CON_RIGHT
-CON_LEFT
+1;
984 coordBufCoord
.X
= CON_TOP
;
985 coordBufCoord
.Y
= CON_LEFT
;
987 hStdout
, /* screen buffer to write to */
988 chiBuffer
, /* buffer to copy from */
989 coordBufSize
, /* col-row size of chiBuffer */
990 coordBufCoord
, /* top left src cell in chiBuffer */
991 &srctReadRect
); /* dest. screen buffer rectangle */
992 // end restore screen
996 CHAR_INFO
* newBuffer() {
997 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo
;
998 HANDLE hStdout
= GetStdHandle(STD_OUTPUT_HANDLE
);
999 GetConsoleScreenBufferInfo(hStdout
, &ConsoleInfo
);
1000 CHAR_INFO
* chiBuffer
;
1001 chiBuffer
= new CHAR_INFO
[(CON_BOTTOM
-CON_TOP
+1)*(CON_RIGHT
-CON_LEFT
+1)];
1005 void deleteBuffer(CHAR_INFO
* chiBuffer
) {