[NTDLL]
[reactos.git] / reactos / 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 <windows.h>
50 #include "tconsole.h"
51
52 // argsused doesn't work on MSVC++
53 #ifdef __BORLANDC__
54 #pragma argsused
55 #endif
56
57 TConsole::TConsole(HANDLE h) {
58 hConsole = h;
59
60 GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
61
62 // Start with correct colors
63 int color_fg = ini.get_normal_fg();
64 int color_bg = ini.get_normal_bg();
65 if(color_fg == -1)
66 color_fg = defaultfg = origfg = ConsoleInfo.wAttributes & 0xF;
67 else
68 defaultfg = origfg = color_fg;
69 if(color_bg == -1)
70 color_bg = defaultbg = origbg = (ConsoleInfo.wAttributes >> 4) & 0xF;
71 else
72 defaultbg = origbg = color_bg;
73 wAttributes = color_fg | (color_bg << 4);
74 reverse = blink = underline = false;
75 SetConsoleTextAttribute(hConsole, wAttributes);
76
77 insert_mode = 0;
78
79 // Set the screen size
80 SetWindowSize(ini.get_term_width(), ini.get_term_height());
81
82 iScrollStart = -1;
83 iScrollEnd = -1;
84 }
85
86 TConsole::~TConsole() {
87 wAttributes = origfg | (origbg << 4);
88 SetCursorPosition(0, CON_HEIGHT);
89 SetConsoleTextAttribute(hConsole, wAttributes);
90 WriteCtrlChar('\x0a');
91 }
92
93 // Paul Brannan 8/2/98
94 void TConsole::SetWindowSize(int width, int height) {
95 SMALL_RECT sr = {
96 CON_LEFT,
97 CON_TOP,
98 (width == -1) ? CON_RIGHT : CON_LEFT + width - 1,
99 (height == -1) ? CON_BOTTOM : CON_TOP + height - 1
100 };
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);
106 sync();
107 }
108
109 // Paul Brannan 5/15/98
110 void TConsole::sync() {
111 GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
112 }
113
114 void TConsole::HighVideo() {
115 wAttributes = wAttributes | (unsigned char) 8;
116 }
117
118 void TConsole::LowVideo() {
119 wAttributes = wAttributes & (unsigned char) (0xff-8);
120 }
121
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
128
129 BlinkOff();
130 UnderlineOff();
131 if(ini.get_preserve_colors()) {
132 ReverseOff();
133 LowVideo();
134 } else {
135 fg = defaultfg;
136 bg = defaultbg;
137 wAttributes = (unsigned char)fg | (bg << 4);
138 reverse = false;
139 }
140 }
141
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);
146 }
147
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);
152 }
153
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() {
159 blink = 1;
160 if(underline) {
161 UlBlinkOn();
162 } else {
163 if(ini.get_blink_bg() != -1) {
164 wAttributes &= 0x8f; // turn off bg
165 wAttributes |= ini.get_blink_bg() << 4;
166 }
167 if(ini.get_blink_fg() != -1) {
168 wAttributes &= 0xf8; // turn off fg
169 wAttributes |= ini.get_blink_fg();
170 }
171 if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
172 wAttributes |= 0x80;
173 }
174 }
175
176 // Added by I.Ioannou 06 April, 1997
177 void TConsole::BlinkOff() {
178 blink = 0;
179 if(underline) {
180 UlBlinkOff();
181 } else {
182 if(ini.get_blink_bg() != -1) {
183 wAttributes &= 0x8f; // turn off bg
184 wAttributes |= defaultbg << 4;
185 }
186 if(ini.get_blink_fg() != -1) {
187 wAttributes &= 0xf8; // turn off fg
188 wAttributes |= defaultfg;
189 }
190 if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
191 wAttributes &= 0x7f;
192 }
193 }
194
195 // Paul Brannan 6/27/98
196 void TConsole::UnderlineOn() {
197 underline = 1;
198 if(blink) {
199 UlBlinkOn();
200 } else {
201 if(ini.get_underline_bg() != -1) {
202 wAttributes &= 0x8f; // turn off bg
203 wAttributes |= ini.get_underline_bg() << 4;
204 }
205 if(ini.get_underline_fg() != -1) {
206 wAttributes &= 0xf8; // turn off fg
207 wAttributes |= ini.get_underline_fg();
208 }
209 if(ini.get_underline_bg() == -1 && ini.get_underline_fg() == -1)
210 wAttributes |= 0x80;
211 }
212 }
213
214 // Paul Brannan 6/27/98
215 void TConsole::UnderlineOff() {
216 underline = 0;
217 if(blink) {
218 UlBlinkOff();
219 } else {
220 if(ini.get_blink_bg() != -1) {
221 wAttributes &= 0x8f; // turn off bg
222 wAttributes |= defaultbg << 4;
223 }
224 if(ini.get_blink_fg() != -1) {
225 wAttributes &= 0xf8; // turn off fg
226 wAttributes |= defaultfg;
227 }
228 if(ini.get_blink_bg() == -1 && ini.get_blink_fg() == -1)
229 wAttributes &= 0x7f;
230 }
231 }
232
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;
238 }
239 if(ini.get_ulblink_fg() != -1) {
240 wAttributes &= 0xf8; // turn off fg
241 wAttributes |= ini.get_ulblink_fg();
242 }
243 if(ini.get_ulblink_bg() == -1 && ini.get_ulblink_fg() == -1)
244 wAttributes |= 0x80;
245 }
246
247 // Paul Brannan 6/27/98
248 void TConsole::UlBlinkOff() {
249 if(blink) {
250 BlinkOn();
251 } else if(underline) {
252 UnderlineOn();
253 } else {
254 Normal();
255 }
256 }
257
258 // Paul Brannan 6/26/98
259 void TConsole::Lightbg() {
260 WORD *pAttributes = new WORD[CON_COLS];
261 DWORD Result;
262
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};
268
269 ReadConsoleOutputAttribute(hConsole, pAttributes, (DWORD)(CON_COLS),
270 Coord, &Result);
271
272 for(DWORD j = 0; j < Result; j++) pAttributes[j] |= 0x80;
273
274 WriteConsoleOutputAttribute(hConsole, pAttributes, Result, Coord,
275 &Result);
276 }
277
278 delete[] pAttributes; // clean up
279
280 wAttributes |= (unsigned char)0x80;
281 bg |= 8;
282 }
283
284 // Paul Brannan 6/26/98
285 void TConsole::Darkbg() {
286 WORD *pAttributes = new WORD[CON_COLS];
287 DWORD Result;
288
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};
294
295 ReadConsoleOutputAttribute(hConsole, pAttributes, (DWORD)(CON_COLS),
296 Coord, &Result);
297
298 for(DWORD j = 0; j < Result; j++) pAttributes[j] &= 0x7f;
299
300 WriteConsoleOutputAttribute(hConsole, pAttributes, Result, Coord,
301 &Result);
302 }
303
304 delete[] pAttributes; // clean up
305
306
307 wAttributes &= (unsigned char)0x7f;
308 bg &= 7;
309 }
310
311 // Added by I.Ioannou 11.May,1997
312 void TConsole::ReverseOn() {
313 if (!reverse) {
314 reverse = true;
315
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);
325 }
326 }
327
328 // Added by I.Ioannou 11.May,1997
329 void TConsole::ReverseOff() {
330 if (reverse) {
331 reverse = false;
332 wAttributes = fg | (bg << 4);
333 }
334 }
335
336 unsigned long TConsole::WriteText(const char *pszString, unsigned long cbString) {
337 DWORD Result;
338
339 if(insert_mode) {
340 InsertCharacter(cbString);
341 }
342
343 WriteConsoleOutputCharacter(hConsole, (char *)pszString, cbString,
344 ConsoleInfo.dwCursorPosition, &Result);
345 FillConsoleOutputAttribute(hConsole, wAttributes, cbString,
346 ConsoleInfo.dwCursorPosition, &Result);
347 return Result;
348 }
349
350 // Formerly ConWriteString (Paul Brannan 6/28/98)
351 unsigned long TConsole::WriteStringFast(const char* pszString, unsigned long cbString) {
352 DWORD Result;
353
354 SetConsoleTextAttribute(hConsole, wAttributes);
355
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
361 // on the line. :-(
362 if ((unsigned)CON_CUR_Y >= (unsigned)CON_HEIGHT) {
363 unsigned long iFakeResult = cbString;
364 cbString = CON_COLS - CON_CUR_X - 1;
365
366 // FIX ME !!! This will avoid the exception when cbString
367 // is <= 0 but still doesn't work :-(
368 if (cbString > 0)
369 WriteConsole(hConsole, pszString, cbString, &Result, 0);
370
371 COORD dwBufferCoord;
372 dwBufferCoord.X = 0;
373 dwBufferCoord.Y = 0;
374
375 CHAR_INFO ciBuffer;
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;
383
384 COORD bufSize = {1,1};
385
386 WriteConsoleOutput(hConsole, &ciBuffer, bufSize,
387 dwBufferCoord, &srWriteRegion);
388
389 // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
390 ConsoleInfo.dwCursorPosition.X = CON_RIGHT;
391
392 return iFakeResult; // Skip the chars that did not fit
393 }
394 // just write the line up to the end
395 else {
396 int iFakeResult = cbString;
397 cbString = CON_COLS - CON_CUR_X;
398
399 if(cbString > 0) {
400 WriteConsole(hConsole, pszString, cbString, &Result, 0);
401
402 // We need to update the ConsoleInfo struct now (Paul Brannan 5/9/98)
403 ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
404 }
405
406 return iFakeResult; // Skip the chars that did not fit
407 }
408 } else {
409 // If custom scrolling is enabled we must take care of it
410 if(iScrollStart != -1 || iScrollEnd != -1) {
411 return WriteString(pszString, cbString);
412 }
413
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) {
418
419 cbString--;
420 if((long)cbString >= 0) WriteConsole(hConsole, pszString, cbString, &Result, 0);
421
422 COORD dwBufferCoord;
423 dwBufferCoord.X = 0;
424 dwBufferCoord.Y = 0;
425
426 CHAR_INFO ciBuffer;
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;
434
435 COORD bufSize = {1,1};
436
437 WriteConsoleOutput(hConsole, &ciBuffer, bufSize,
438 dwBufferCoord, &srWriteRegion);
439
440 // Update the ConsoleInfo struct
441 ConsoleInfo.dwCursorPosition.X = CON_RIGHT + 1;
442
443 return Result + 1;
444 }
445
446 // normal line will wrap normally or not to the end of buffer
447 WriteConsole(hConsole, pszString, cbString, &Result, 0);
448
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++;
457 } else {
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);
465 }
466 }
467 }
468 }
469
470 return Result;
471
472 }
473
474 unsigned long TConsole::WriteString(const char* pszString, unsigned long cbString) {
475 DWORD Result = 0;
476
477 SetConsoleTextAttribute(hConsole, wAttributes);
478
479 //check to see if the line is longer than the display
480 if (!getLineWrap()){
481 unsigned long iFakeResult = cbString;
482 if((CON_CUR_X + cbString) >= (unsigned int)CON_COLS)
483 cbString = CON_COLS - CON_CUR_X;
484 if(cbString > 0)
485 Result = WriteText(pszString, cbString);
486
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);
490
491 return iFakeResult; // Skip the chars that did not fit
492 } else {
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;
497 } else {
498 Result = WriteText(pszString, temp);
499 ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
500 SetConsoleCursorPosition(hConsole, ConsoleInfo.dwCursorPosition);
501 return Result;
502 }
503 if(temp > 0) {
504 Result = WriteText(pszString, temp);
505 ConsoleInfo.dwCursorPosition.X += (unsigned short)Result;
506 temp = (unsigned short)Result;
507 }
508
509 // keep writing lines until we get to less than 80 chars left
510 while((temp + (unsigned int)CON_COLS) < cbString) {
511 index(); // LF
512 ConsoleInfo.dwCursorPosition.X = 0; // CR
513 Result = WriteText(&pszString[temp], CON_COLS);
514 temp += (unsigned short)Result;
515 }
516
517 // write out the last bit
518 if(temp < cbString) {
519 index();
520 ConsoleInfo.dwCursorPosition.X = 0;
521 Result = WriteText(&pszString[temp], cbString - temp);
522 temp += (unsigned short)Result;
523 }
524
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) {
530 index();
531 ConsoleInfo.dwCursorPosition.X = 0;
532 }
533
534 SetConsoleCursorPosition(hConsole, ConsoleInfo.dwCursorPosition);
535
536 return temp;
537 }
538
539 return 0;
540 }
541
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));
547 if(Result == 0) {
548 Result = WriteStringFast(pszString + total, 1);
549 if(Result == 0) return total;
550 }
551 total += Result;
552 }
553 return total;
554 }
555
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.
562
563 unsigned long Result = 0; // just in case (Paul Brannan 6/26/98)
564 switch (c) {
565 case '\x09': // horizontal tab
566 SetCursorPosition((((CON_CUR_X/8)+1)*8), CON_CUR_Y);
567 Result = 1;
568 break;
569
570 case '\x0a': // line feed
571 index();
572 Result = 1;
573 break;
574 case '\x0d': // carrage return
575 SetCursorPosition(CON_LEFT, CON_CUR_Y); // move to beginning of line
576 Result = 1;
577 break;
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);
582 Result = 1;
583 default : // else just write it like normal
584 break;
585 }
586
587 return Result;
588 }
589
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)) {
596 DWORD Result;
597 WriteConsole(hConsole, "\n", 1, &Result, NULL);
598
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);
606 } else {
607 ClearLine();
608 }
609 } else { // else move cursor down to the next line
610 SetCursorPosition(CON_CUR_X, CON_CUR_Y + 1);
611 }
612 }
613
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);
624 }
625
626 void TConsole::ScrollDown( int iStartRow , int iEndRow, int bUp ){
627 CHAR_INFO ciChar;
628 SMALL_RECT srScrollWindow;
629
630 // Correction from I.Ioannou 11 May 1997
631 // check the scroll region
632 if (iStartRow < iScrollStart) iStartRow = iScrollStart;
633
634 // Correction from I.Ioannou 11 May 1997
635 // this will make Top the CON_TOP
636 if ( iStartRow == -1) iStartRow = 0;
637
638 // Correction from I.Ioannou 18 Aug 97
639 if ( iEndRow == -1) {
640 if ( iScrollEnd == -1 )
641 iEndRow = CON_HEIGHT;
642 else
643 iEndRow = ((CON_HEIGHT <= iScrollEnd) ? CON_HEIGHT : iScrollEnd);
644 }
645 //
646
647 if ( iStartRow > CON_HEIGHT) iStartRow = CON_HEIGHT;
648 if ( iEndRow > CON_HEIGHT) iEndRow = CON_HEIGHT;
649
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)
654
655 ciChar.Char.AsciiChar = ' '; // fill with spaces
656 ciChar.Attributes = wAttributes; // fill with current attrib
657
658 // This should speed things up (Paul Brannan 9/2/98)
659 COORD dwDestOrg = {srScrollWindow.Left, srScrollWindow.Top + bUp};
660
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);
669 return;
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);
674 return;
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;
682 }
683
684 ScrollConsoleScreenBuffer(hConsole, &srScrollWindow,
685 0, dwDestOrg, &ciChar);
686 }
687
688 // This allows us to clear the screen with an arbitrary character
689 // (Paul Brannan 6/26/98)
690 void TConsole::ClearScreen(char c) {
691 DWORD dwWritten;
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);
697 }
698
699 // Same as clear screen, but only affects the scroll region
700 void TConsole::ClearWindow(int iStartRow, int iEndRow, char c) {
701 DWORD dwWritten;
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);
707 }
708
709 // Clear from cursor to end of screen
710 void TConsole::ClearEOScreen(char c)
711 {
712 DWORD dwWritten;
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);
718 ClearEOLine();
719 }
720
721 // Clear from beginning of screen to cursor
722 void TConsole::ClearBOScreen(char c)
723 {
724 DWORD dwWritten;
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);
730 ClearBOLine();
731 }
732
733 void TConsole::ClearLine(char c)
734 {
735 DWORD dwWritten;
736 COORD Coord = {CON_LEFT, CON_TOP + CON_CUR_Y};
737 FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_COLS),
738 Coord, &dwWritten);
739 FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_COLS),
740 Coord, &dwWritten);
741 GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
742 }
743
744 void TConsole::ClearEOLine(char c)
745 {
746 DWORD dwWritten;
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,
751 Coord, &dwWritten);
752 GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
753 }
754
755 void TConsole::ClearBOLine(char c)
756 {
757 DWORD dwWritten;
758 COORD Coord = {CON_LEFT, CON_TOP + CON_CUR_Y};
759 FillConsoleOutputCharacter(hConsole, c, (DWORD)(CON_CUR_X) + 1, Coord,
760 &dwWritten);
761 FillConsoleOutputAttribute(hConsole, wAttributes, (DWORD)(CON_CUR_X) + 1,
762 Coord, &dwWritten);
763 GetConsoleScreenBufferInfo(hConsole, &ConsoleInfo);
764 }
765
766
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)
770 {
771 COORD to;
772 SMALL_RECT from;
773 SMALL_RECT clip;
774 CHAR_INFO fill;
775 int acty;
776
777 // Rest of screen would be deleted
778 if ( (acty = GetCursorY()) >= CON_LINES - numlines ) {
779 ClearEOScreen(); // delete rest of screen
780 return;
781 } /* IF */
782
783 // Else scroll down the part of the screen which is below the
784 // cursor.
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;
789
790 clip = from;
791 to.X = 0;
792 to.Y = (SHORT)(from.Top + numlines);
793
794 fill.Char.AsciiChar = ' ';
795 fill.Attributes = 7; // WHICH ATTRIBUTES TO TAKE FOR BLANK LINE ??
796
797 ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
798 } /* InsertLine */
799
800 // Inserts blank characters under the cursor
801 void TConsole::InsertCharacter(int numchar)
802 {
803 int actx;
804 SMALL_RECT from;
805 SMALL_RECT clip;
806 COORD to;
807 CHAR_INFO fill;
808
809 if ( (actx = GetCursorX()) >= CON_COLS - numchar ) {
810 ClearEOLine();
811 return;
812 } /* IF */
813
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;
818
819 clip = from;
820 to.X = (SHORT)(actx + numchar);
821 to.Y = from.Top;
822
823 fill.Char.AsciiChar = ' ';
824 fill.Attributes = wAttributes; // WHICH ATTRIBUTES TO TAKE FOR BLANK CHAR ??
825
826 ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
827 } /* InsertCharacter */
828
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)
834 {
835 int actx;
836 SMALL_RECT from;
837 SMALL_RECT clip;
838 COORD to;
839 CHAR_INFO fill;
840
841 if ( (actx = GetCursorX()) >= CON_COLS - numchar ) {
842 ClearEOLine();
843 return;
844 } /* IF */
845
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;
850
851 clip = from;
852 to.X = (SHORT)(actx - numchar);
853 to.Y = from.Top;
854
855 fill.Char.AsciiChar = ' ';
856 fill.Attributes = wAttributes; // WHICH ATTRIBUTES TO TAKE FOR BLANK CHAR ??
857
858 ScrollConsoleScreenBuffer(hConsole, &from, &clip, to, &fill);
859 } /* DeleteCharacter */
860
861 void TConsole::SetRawCursorPosition(int x, int y) {
862 if (x > CON_WIDTH) x = CON_WIDTH;
863 if (x < 0) x = 0;
864 if (y > CON_HEIGHT) y = CON_HEIGHT;
865 if (y < 0) y = 0;
866 COORD Coord = {(short)(CON_LEFT + x), (short)(CON_TOP + y)};
867 SetConsoleCursorPosition(hConsole, Coord);
868
869 // Update the ConsoleInfo struct (Paul Brannan 5/9/98)
870 ConsoleInfo.dwCursorPosition.Y = Coord.Y;
871 ConsoleInfo.dwCursorPosition.X = Coord.X;
872
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;
882 }
883
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;
888 if (x < 0) x = 0;
889 if(iScrollEnd != -1) {
890 if(y > iScrollEnd) y = iScrollEnd;
891 } else {
892 if(y > CON_HEIGHT) y = CON_HEIGHT;
893 }
894 if(iScrollStart != -1) {
895 if(y < iScrollStart) y = iScrollStart;
896 } else {
897 if(y < 0) y = 0;
898 }
899
900 COORD Coord = {(short)(CON_LEFT + x), (short)(CON_TOP + y)};
901 SetConsoleCursorPosition(hConsole, Coord);
902
903 // Update the ConsoleInfo struct
904 ConsoleInfo.dwCursorPosition.Y = Coord.Y;
905 ConsoleInfo.dwCursorPosition.X = Coord.X;
906 }
907
908 void TConsole::MoveCursorPosition(int x, int y) {
909 SetCursorPosition(CON_CUR_X + x, CON_CUR_Y + y);
910 }
911
912 void TConsole::SetExtendedMode(int iFunction, BOOL bEnable)
913 {
914 // Probably should do something here...
915 // Should change the screen mode, but do we need this?
916 }
917
918 void TConsole::SetScroll(int start, int end) {
919 iScrollStart = start;
920 iScrollEnd = end;
921 }
922
923 void TConsole::Beep() {
924 if(ini.get_do_beep()) {
925 if(!ini.get_speaker_beep()) printit("\a");
926 else ::Beep(400, 100);
927 }
928 }
929
930 void TConsole::SetCursorSize(int pct) {
931 CONSOLE_CURSOR_INFO ci = {(pct != 0)?pct:1, pct != 0};
932 SetConsoleCursorInfo(hConsole, &ci);
933 }
934
935 void saveScreen(CHAR_INFO *chiBuffer) {
936 HANDLE hStdout;
937 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
938 SMALL_RECT srctReadRect;
939 COORD coordBufSize;
940 COORD coordBufCoord;
941
942 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
943 GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
944
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;
949
950 coordBufSize.Y = CON_BOTTOM-CON_TOP+1;
951 coordBufSize.X = CON_RIGHT-CON_LEFT+1;
952
953 coordBufCoord.X = CON_TOP;
954 coordBufCoord.Y = CON_LEFT;
955
956 ReadConsoleOutput(
957 hStdout, /* screen buffer to read from */
958 chiBuffer, /* buffer to copy into */
959 coordBufSize, /* col-row size of chiBuffer */
960
961 coordBufCoord, /* top left dest. cell in chiBuffer */
962 &srctReadRect); /* screen buffer source rectangle */
963 }
964
965 void restoreScreen(CHAR_INFO *chiBuffer) {
966 HANDLE hStdout;
967 CONSOLE_SCREEN_BUFFER_INFO ConsoleInfo;
968 SMALL_RECT srctReadRect;
969 COORD coordBufSize;
970 COORD coordBufCoord;
971
972 hStdout = GetStdHandle(STD_OUTPUT_HANDLE);
973 GetConsoleScreenBufferInfo(hStdout, &ConsoleInfo);
974
975 // restore screen
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;
980
981 coordBufSize.Y = CON_BOTTOM-CON_TOP+1;
982 coordBufSize.X = CON_RIGHT-CON_LEFT+1;
983
984 coordBufCoord.X = CON_TOP;
985 coordBufCoord.Y = CON_LEFT;
986 WriteConsoleOutput(
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
993
994 }
995
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)];
1002 return chiBuffer;
1003 }
1004
1005 void deleteBuffer(CHAR_INFO* chiBuffer) {
1006 delete[] chiBuffer;
1007 }
1008