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