1 /* NetHack 3.6	nttty.c	$NHDT-Date: 1554215932 2019/04/02 14:38:52 $  $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.99 $ */
2 /* Copyright (c) NetHack PC Development Team 1993    */
3 /* NetHack may be freely redistributed.  See license for details. */
4 
5 /* tty.c - (Windows NT) version */
6 
7 /*
8  * Initial Creation 				M. Allison	1993/01/31
9  * Switch to low level console output routines	M. Allison	2003/10/01
10  * Restrict cursor movement until input pending	M. Lehotay	2003/10/02
11  * Call Unicode version of output API on NT     R. Chason   2005/10/28
12  * Use of back buffer to improve performance    B. House    2018/05/06
13  *
14  */
15 
16 #ifdef WIN32
17 #define NEED_VARARGS /* Uses ... */
18 #include "win32api.h"
19 #include "winos.h"
20 #include "hack.h"
21 #include "wintty.h"
22 #include <sys\types.h>
23 #include <sys\stat.h>
24 
25 extern boolean getreturn_enabled; /* from sys/share/pcsys.c */
26 extern int redirect_stdout;
27 
28 #ifdef TTY_GRAPHICS
29 /*
30  * Console Buffer Flipping Support
31  *
32  * To minimize the number of calls into the WriteConsoleOutputXXX methods,
33  * we implement a notion of a console back buffer which keeps the next frame
34  * of console output as it is being composed.  When ready to show the new
35  * frame, we compare this next frame to what is currently being output and
36  * only call WriteConsoleOutputXXX for those console values that need to
37  * change.
38  *
39  */
40 
41 #define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \
42                                                 | FOREGROUND_BLUE)
43 #define CONSOLE_CLEAR_CHARACTER (' ')
44 
45 #define CONSOLE_UNDEFINED_ATTRIBUTE (0)
46 #define CONSOLE_UNDEFINED_CHARACTER ('\0')
47 
48 typedef struct {
49     WCHAR   character;
50     WORD    attribute;
51 } cell_t;
52 
53 cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE };
54 cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
55                           CONSOLE_UNDEFINED_ATTRIBUTE };
56 
57 /*
58  * The following WIN32 Console API routines are used in this file.
59  *
60  * CreateFile
61  * GetConsoleScreenBufferInfo
62  * GetStdHandle
63  * SetConsoleCursorPosition
64  * SetConsoleTextAttribute
65  * SetConsoleCtrlHandler
66  * PeekConsoleInput
67  * ReadConsoleInput
68  * WriteConsoleOutputCharacter
69  * FillConsoleOutputAttribute
70  * GetConsoleOutputCP
71  */
72 
73 static BOOL FDECL(CtrlHandler, (DWORD));
74 static void FDECL(xputc_core, (char));
75 void FDECL(cmov, (int, int));
76 void FDECL(nocmov, (int, int));
77 int FDECL(process_keystroke,
78           (INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug));
79 static void NDECL(init_ttycolor);
80 static void NDECL(really_move_cursor);
81 static void NDECL(check_and_set_font);
82 static boolean NDECL(check_font_widths);
83 static void NDECL(set_known_good_console_font);
84 static void NDECL(restore_original_console_font);
85 extern void NDECL(safe_routines);
86 
87 /* Win32 Screen buffer,coordinate,console I/O information */
88 COORD ntcoord;
89 INPUT_RECORD ir;
90 static boolean orig_QuickEdit;
91 
92 /* Support for changing console font if existing glyph widths are too wide */
93 
94 /* Flag for whether NetHack was launched via the GUI, not the command line.
95  * The reason we care at all, is so that we can get
96  * a final RETURN at the end of the game when launched from the GUI
97  * to prevent the scoreboard (or panic message :-|) from vanishing
98  * immediately after it is displayed, yet not bother when started
99  * from the command line.
100  */
101 int GUILaunched = FALSE;
102 /* Flag for whether unicode is supported */
103 static boolean init_ttycolor_completed;
104 #ifdef PORT_DEBUG
105 static boolean display_cursor_info = FALSE;
106 #endif
107 #ifdef CHANGE_COLOR
108 static void NDECL(adjust_palette);
109 static int FDECL(match_color_name, (const char *));
110 typedef HWND(WINAPI *GETCONSOLEWINDOW)();
111 static HWND GetConsoleHandle(void);
112 static HWND GetConsoleHwnd(void);
113 static boolean altered_palette;
114 static COLORREF UserDefinedColors[CLR_MAX];
115 static COLORREF NetHackColors[CLR_MAX] = {
116     0x00000000, 0x00c80000, 0x0000c850, 0x00b4b432, 0x000000d2, 0x00800080,
117     0x000064b4, 0x00c0c0c0, 0x00646464, 0x00f06464, 0x0000ff00, 0x00ffff00,
118     0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
119 };
120 static COLORREF DefaultColors[CLR_MAX] = {
121     0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080,
122     0x00008080, 0x00c0c0c0, 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
123     0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
124 };
125 #endif
126 struct console_t {
127     WORD background;
128     WORD foreground;
129     WORD attr;
130     int current_nhcolor;
131     int current_nhattr[ATR_INVERSE+1];
132     COORD cursor;
133     HANDLE hConOut;
134     HANDLE hConIn;
135     CONSOLE_SCREEN_BUFFER_INFO origcsbi;
136     int width;
137     int height;
138     boolean has_unicode;
139     int buffer_size;
140     cell_t * front_buffer;
141     cell_t * back_buffer;
142     WCHAR cpMap[256];
143     boolean font_changed;
144     CONSOLE_FONT_INFOEX original_font_info;
145     UINT original_code_page;
146 } console = {
147     0,
148     (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
149     (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
150     NO_COLOR,
151     {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE},
152     {0, 0},
153     NULL,
154     NULL,
155     { 0 },
156     0,
157     0,
158     FALSE,
159     0,
160     NULL,
161     NULL,
162     { 0 },
163     FALSE,
164     { 0 },
165     0
166 };
167 
168 static DWORD ccount, acount;
169 #ifndef CLR_MAX
170 #define CLR_MAX 16
171 #endif
172 
173 int ttycolors[CLR_MAX];
174 int ttycolors_inv[CLR_MAX];
175 
176 #define MAX_OVERRIDES 256
177 unsigned char key_overrides[MAX_OVERRIDES];
178 static char nullstr[] = "";
179 char erase_char, kill_char;
180 #define DEFTEXTCOLOR ttycolors[7]
181 
182 /* dynamic keystroke handling .DLL support */
183 typedef int(__stdcall *PROCESS_KEYSTROKE)(HANDLE, INPUT_RECORD *, boolean *,
184                                           BOOLEAN_P, int);
185 
186 typedef int(__stdcall *NHKBHIT)(HANDLE, INPUT_RECORD *);
187 
188 typedef int(__stdcall *CHECKINPUT)(HANDLE, INPUT_RECORD *, DWORD *, BOOLEAN_P,
189                                    int, int *, coord *);
190 
191 typedef int(__stdcall *SOURCEWHERE)(char **);
192 
193 typedef int(__stdcall *SOURCEAUTHOR)(char **);
194 
195 typedef int(__stdcall *KEYHANDLERNAME)(char **, int);
196 
197 typedef struct {
198     char *              name;       // name without DLL extension
199     HANDLE              hLibrary;
200     PROCESS_KEYSTROKE   pProcessKeystroke;
201     NHKBHIT             pNHkbhit;
202     CHECKINPUT          pCheckInput;
203     SOURCEWHERE         pSourceWhere;
204     SOURCEAUTHOR        pSourceAuthor;
205     KEYHANDLERNAME      pKeyHandlerName;
206 } keyboard_handler_t;
207 
208 keyboard_handler_t keyboard_handler;
209 
210 
211 /* Console buffer flipping support */
212 
back_buffer_flip()213 static void back_buffer_flip()
214 {
215     cell_t * back = console.back_buffer;
216     cell_t * front = console.front_buffer;
217     COORD pos;
218     DWORD unused;
219 
220     for (pos.Y = 0; pos.Y < console.height; pos.Y++) {
221         for (pos.X = 0; pos.X < console.width; pos.X++) {
222             if (back->attribute != front->attribute) {
223                 WriteConsoleOutputAttribute(console.hConOut, &back->attribute,
224                                             1, pos, &unused);
225                 front->attribute = back->attribute;
226             }
227             if (back->character != front->character) {
228                 if (console.has_unicode) {
229                     WriteConsoleOutputCharacterW(console.hConOut,
230                         &back->character, 1, pos, &unused);
231                 } else {
232                     char ch = (char)back->character;
233                     WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos,
234                                                     &unused);
235                 }
236                 *front = *back;
237             }
238             back++;
239             front++;
240         }
241     }
242 }
243 
buffer_fill_to_end(cell_t * buffer,cell_t * fill,int x,int y)244 void buffer_fill_to_end(cell_t * buffer, cell_t * fill, int x, int y)
245 {
246     nhassert(x >= 0 && x < console.width);
247     nhassert(y >= 0 && ((y < console.height) || (y == console.height &&
248                                                  x == 0)));
249 
250     cell_t * dst = buffer + console.width * y + x;
251     cell_t * sentinel = buffer + console.buffer_size;
252     while (dst != sentinel)
253         *dst++ = *fill;
254 
255     if (iflags.debug.immediateflips && buffer == console.back_buffer)
256         back_buffer_flip();
257 }
258 
buffer_clear_to_end_of_line(cell_t * buffer,int x,int y)259 static void buffer_clear_to_end_of_line(cell_t * buffer, int x, int y)
260 {
261     nhassert(x >= 0 && x < console.width);
262     nhassert(y >= 0 && ((y < console.height) || (y == console.height &&
263                                                  x == 0)));
264     cell_t * dst = buffer + console.width * y + x;
265     cell_t *sentinel = buffer + console.width * (y + 1);
266 
267     while (dst != sentinel)
268         *dst++ = clear_cell;
269 
270     if (iflags.debug.immediateflips)
271         back_buffer_flip();
272 }
273 
buffer_write(cell_t * buffer,cell_t * cell,COORD pos)274 void buffer_write(cell_t * buffer, cell_t * cell, COORD pos)
275 {
276     nhassert(pos.X >= 0 && pos.X < console.width);
277     nhassert(pos.Y >= 0 && pos.Y < console.height);
278 
279     cell_t * dst = buffer + (console.width * pos.Y) + pos.X;
280     *dst = *cell;
281 
282     if (iflags.debug.immediateflips && buffer == console.back_buffer)
283         back_buffer_flip();
284 }
285 
286 /*
287  * Called after returning from ! or ^Z
288  */
289 void
gettty()290 gettty()
291 {
292 #ifndef TEXTCOLOR
293     int k;
294 #endif
295     erase_char = '\b';
296     kill_char = 21; /* cntl-U */
297     iflags.cbreak = TRUE;
298 #ifdef TEXTCOLOR
299     init_ttycolor();
300 #else
301     for (k = 0; k < CLR_MAX; ++k)
302         ttycolors[k] = NO_COLOR;
303 #endif
304 }
305 
306 /* reset terminal to original state */
307 void
settty(s)308 settty(s)
309 const char *s;
310 {
311     cmov(ttyDisplay->curx, ttyDisplay->cury);
312     end_screen();
313     if (s)
314         raw_print(s);
315     restore_original_console_font();
316     if (orig_QuickEdit) {
317         DWORD cmode;
318 
319         GetConsoleMode(console.hConIn, &cmode);
320         cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
321         SetConsoleMode(console.hConIn, cmode);
322     }
323 }
324 
325 /* called by init_nhwindows() and resume_nhwindows() */
326 void
setftty()327 setftty()
328 {
329 #ifdef CHANGE_COLOR
330     if (altered_palette)
331         adjust_palette();
332 #endif
333     start_screen();
334 }
335 
336 void
tty_startup(wid,hgt)337 tty_startup(wid, hgt)
338 int *wid, *hgt;
339 {
340     *wid = console.width;
341     *hgt = console.height;
342     set_option_mod_status("mouse_support", SET_IN_GAME);
343 }
344 
345 void
tty_number_pad(state)346 tty_number_pad(state)
347 int state;
348 {
349     // do nothing
350 }
351 
352 void
tty_start_screen()353 tty_start_screen()
354 {
355     if (iflags.num_pad)
356         tty_number_pad(1); /* make keypad send digits */
357 }
358 
359 void
tty_end_screen()360 tty_end_screen()
361 {
362     clear_screen();
363     really_move_cursor();
364     buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
365     back_buffer_flip();
366     FlushConsoleInputBuffer(console.hConIn);
367 }
368 
369 static BOOL
CtrlHandler(ctrltype)370 CtrlHandler(ctrltype)
371 DWORD ctrltype;
372 {
373     switch (ctrltype) {
374     /*	case CTRL_C_EVENT: */
375     case CTRL_BREAK_EVENT:
376         clear_screen();
377     case CTRL_CLOSE_EVENT:
378     case CTRL_LOGOFF_EVENT:
379     case CTRL_SHUTDOWN_EVENT:
380         getreturn_enabled = FALSE;
381 #ifndef NOSAVEONHANGUP
382         hangup(0);
383 #endif
384 #if defined(SAFERHANGUP)
385         CloseHandle(console.hConIn); /* trigger WAIT_FAILED */
386         return TRUE;
387 #endif
388     default:
389         return FALSE;
390     }
391 }
392 
393 /* called by pcmain() and process_options() */
394 void
nttty_open(mode)395 nttty_open(mode)
396 int mode; // unused
397 {
398     DWORD cmode;
399 
400     /* Initialize the function pointer that points to
401      * the kbhit() equivalent, in this TTY case nttty_kbhit()
402      */
403     nt_kbhit = nttty_kbhit;
404 
405     if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) {
406         /* Unable to set control handler */
407         cmode = 0; /* just to have a statement to break on for debugger */
408     }
409 
410     LI = console.height;
411     CO = console.width;
412 
413     really_move_cursor();
414 }
415 
416 void
nttty_exit()417 nttty_exit()
418 {
419     /* go back to using the safe routines */
420     safe_routines();
421 }
422 
423 int
process_keystroke(ir,valid,numberpad,portdebug)424 process_keystroke(ir, valid, numberpad, portdebug)
425 INPUT_RECORD *ir;
426 boolean *valid;
427 boolean numberpad;
428 int portdebug;
429 {
430     int ch;
431 
432 #ifdef QWERTZ_SUPPORT
433     if (Cmd.swap_yz)
434         numberpad |= 0x10;
435 #endif
436     ch = keyboard_handler.pProcessKeystroke(
437                     console.hConIn, ir, valid, numberpad, portdebug);
438 #ifdef QWERTZ_SUPPORT
439     numberpad &= ~0x10;
440 #endif
441     /* check for override */
442     if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
443         ch = key_overrides[ch];
444     return ch;
445 }
446 
447 int
nttty_kbhit()448 nttty_kbhit()
449 {
450     return keyboard_handler.pNHkbhit(console.hConIn, &ir);
451 }
452 
453 int
tgetch()454 tgetch()
455 {
456     int mod;
457     coord cc;
458     DWORD count;
459     boolean numpad = iflags.num_pad;
460 
461     really_move_cursor();
462     if (iflags.debug_fuzzer)
463         return randomkey();
464 #ifdef QWERTZ_SUPPORT
465     if (Cmd.swap_yz)
466         numpad |= 0x10;
467 #endif
468 
469     return (program_state.done_hup)
470                ? '\033'
471                : keyboard_handler.pCheckInput(
472                    console.hConIn, &ir, &count, numpad, 0, &mod, &cc);
473 }
474 
475 int
ntposkey(x,y,mod)476 ntposkey(x, y, mod)
477 int *x, *y, *mod;
478 {
479     int ch;
480     coord cc;
481     DWORD count;
482     boolean numpad = iflags.num_pad;
483 
484     really_move_cursor();
485     if (iflags.debug_fuzzer)
486         return randomkey();
487 #ifdef QWERTZ_SUPPORT
488     if (Cmd.swap_yz)
489         numpad |= 0x10;
490 #endif
491     ch = (program_state.done_hup)
492              ? '\033'
493              : keyboard_handler.pCheckInput(
494                    console.hConIn, &ir, &count, numpad, 1, mod, &cc);
495 #ifdef QWERTZ_SUPPORT
496     numpad &= ~0x10;
497 #endif
498     if (!ch) {
499         *x = cc.x;
500         *y = cc.y;
501     }
502     return ch;
503 }
504 
set_console_cursor(int x,int y)505 static void set_console_cursor(int x, int y)
506 {
507     nhassert(x >= 0 && x < console.width);
508     nhassert(y >= 0 && y < console.height);
509 
510     console.cursor.X = max(0, min(console.width - 1, x));
511     console.cursor.Y = max(0, min(console.height - 1, y));
512 }
513 
514 static void
really_move_cursor()515 really_move_cursor()
516 {
517 #ifdef PORT_DEBUG
518     char oldtitle[BUFSZ], newtitle[BUFSZ];
519     if (display_cursor_info && wizard) {
520         oldtitle[0] = '\0';
521         if (GetConsoleTitle(oldtitle, BUFSZ)) {
522             oldtitle[39] = '\0';
523         }
524         Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle,
525                 ttyDisplay->curx, ttyDisplay->cury,
526                 console.cursor.X, console.cursor.Y);
527         (void) SetConsoleTitle(newtitle);
528     }
529 #endif
530     if (ttyDisplay)
531         set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
532 
533     back_buffer_flip();
534     SetConsoleCursorPosition(console.hConOut, console.cursor);
535 }
536 
537 void
cmov(x,y)538 cmov(x, y)
539 register int x, y;
540 {
541     ttyDisplay->cury = y;
542     ttyDisplay->curx = x;
543 
544     set_console_cursor(x, y);
545 }
546 
547 void
nocmov(x,y)548 nocmov(x, y)
549 int x, y;
550 {
551     ttyDisplay->curx = x;
552     ttyDisplay->cury = y;
553 
554     set_console_cursor(x, y);
555 }
556 
557 /* same signature as 'putchar()' with potential failure result ignored */
558 int
xputc(ch)559 xputc(ch)
560 int ch;
561 {
562     set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
563     xputc_core((char) ch);
564     return 0;
565 }
566 
567 void
xputs(s)568 xputs(s)
569 const char *s;
570 {
571     int k;
572     int slen = (int) strlen(s);
573 
574     if (ttyDisplay)
575         set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
576 
577     if (s) {
578         for (k = 0; k < slen && s[k]; ++k)
579             xputc_core(s[k]);
580     }
581 }
582 
583 /* xputc_core() and g_putch() are the only
584  * two routines that actually place output
585  * on the display.
586  */
587 void
xputc_core(ch)588 xputc_core(ch)
589 char ch;
590 {
591     nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
592     nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
593 
594     boolean inverse = FALSE;
595     cell_t cell;
596 
597     switch (ch) {
598     case '\n':
599         if (console.cursor.Y < console.height - 1)
600             console.cursor.Y++;
601     /* fall through */
602     case '\r':
603         console.cursor.X = 1;
604         break;
605     case '\b':
606         if (console.cursor.X > 1) {
607             console.cursor.X--;
608         } else if(console.cursor.Y > 0) {
609             console.cursor.X = console.width - 1;
610             console.cursor.Y--;
611         }
612         break;
613     default:
614 
615         inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
616         console.attr = (inverse) ?
617                         ttycolors_inv[console.current_nhcolor] :
618                         ttycolors[console.current_nhcolor];
619         if (console.current_nhattr[ATR_BOLD])
620                 console.attr |= (inverse) ?
621                                 BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
622 
623         cell.attribute = console.attr;
624         cell.character = (console.has_unicode ? console.cpMap[ch] : ch);
625 
626         buffer_write(console.back_buffer, &cell, console.cursor);
627 
628         if (console.cursor.X == console.width - 1) {
629             if (console.cursor.Y < console.height - 1) {
630                 console.cursor.X = 1;
631                 console.cursor.Y++;
632             }
633         } else {
634             console.cursor.X++;
635         }
636     }
637 
638     nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
639     nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
640 }
641 
642 /*
643  * Overrides wintty.c function of the same name
644  * for win32. It is used for glyphs only, not text.
645  */
646 
647 void
g_putch(in_ch)648 g_putch(in_ch)
649 int in_ch;
650 {
651     boolean inverse = FALSE;
652     unsigned char ch = (unsigned char) in_ch;
653 
654     set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
655 
656     inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
657     console.attr = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse) ?
658                     ttycolors_inv[console.current_nhcolor] :
659                     ttycolors[console.current_nhcolor];
660     if (console.current_nhattr[ATR_BOLD])
661         console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
662 
663     cell_t cell;
664 
665     cell.attribute = console.attr;
666     cell.character = (console.has_unicode ? cp437[ch] : ch);
667 
668     buffer_write(console.back_buffer, &cell, console.cursor);
669 }
670 
671 void
cl_end()672 cl_end()
673 {
674     set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
675     buffer_clear_to_end_of_line(console.back_buffer, console.cursor.X,
676                                 console.cursor.Y);
677     tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
678 }
679 
680 void
raw_clear_screen()681 raw_clear_screen()
682 {
683     if (WINDOWPORT("tty")) {
684         cell_t * back = console.back_buffer;
685         cell_t * front = console.front_buffer;
686         COORD pos;
687         DWORD unused;
688 
689         for (pos.Y = 0; pos.Y < console.height; pos.Y++) {
690             for (pos.X = 0; pos.X < console.width; pos.X++) {
691                  WriteConsoleOutputAttribute(console.hConOut, &back->attribute,
692                                              1, pos, &unused);
693                  front->attribute = back->attribute;
694                  if (console.has_unicode) {
695                      WriteConsoleOutputCharacterW(console.hConOut,
696                              &back->character, 1, pos, &unused);
697                  } else {
698                      char ch = (char)back->character;
699                      WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos,
700                                                          &unused);
701                  }
702                  *front = *back;
703                  back++;
704                  front++;
705             }
706         }
707     }
708 }
709 
710 void
clear_screen()711 clear_screen()
712 {
713     buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
714     home();
715 }
716 
717 void
home()718 home()
719 {
720     ttyDisplay->curx = ttyDisplay->cury = 0;
721     set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
722 }
723 
724 void
backsp()725 backsp()
726 {
727     set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
728     xputc_core('\b');
729 }
730 
731 void
cl_eos()732 cl_eos()
733 {
734     buffer_fill_to_end(console.back_buffer, &clear_cell, ttyDisplay->curx,
735                         ttyDisplay->cury);
736     tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
737 }
738 
739 void
tty_nhbell()740 tty_nhbell()
741 {
742     if (flags.silent || iflags.debug_fuzzer)
743         return;
744     Beep(8000, 500);
745 }
746 
747 volatile int junk; /* prevent optimizer from eliminating loop below */
748 
749 void
tty_delay_output()750 tty_delay_output()
751 {
752     /* delay 50 ms - uses ANSI C clock() function now */
753     clock_t goal;
754     int k;
755 
756     goal = 50 + clock();
757     back_buffer_flip();
758     if (iflags.debug_fuzzer)
759         return;
760 
761     while (goal > clock()) {
762         k = junk; /* Do nothing */
763     }
764 }
765 
766 /*
767  * CLR_BLACK		0
768  * CLR_RED		1
769  * CLR_GREEN		2
770  * CLR_BROWN		3	low-intensity yellow
771  * CLR_BLUE		4
772  * CLR_MAGENTA 		5
773  * CLR_CYAN		6
774  * CLR_GRAY		7	low-intensity white
775  * NO_COLOR		8
776  * CLR_ORANGE		9
777  * CLR_BRIGHT_GREEN	10
778  * CLR_YELLOW		11
779  * CLR_BRIGHT_BLUE	12
780  * CLR_BRIGHT_MAGENTA  	13
781  * CLR_BRIGHT_CYAN	14
782  * CLR_WHITE		15
783  * CLR_MAX		16
784  * BRIGHT		8
785  */
786 
787 static void
init_ttycolor()788 init_ttycolor()
789 {
790 #ifdef TEXTCOLOR
791     ttycolors[CLR_BLACK]        = FOREGROUND_INTENSITY; /* fix by Quietust */
792     ttycolors[CLR_RED]          = FOREGROUND_RED;
793     ttycolors[CLR_GREEN]        = FOREGROUND_GREEN;
794     ttycolors[CLR_BROWN]        = FOREGROUND_GREEN | FOREGROUND_RED;
795     ttycolors[CLR_BLUE]         = FOREGROUND_BLUE;
796     ttycolors[CLR_MAGENTA]      = FOREGROUND_BLUE | FOREGROUND_RED;
797     ttycolors[CLR_CYAN]         = FOREGROUND_GREEN | FOREGROUND_BLUE;
798     ttycolors[CLR_GRAY]         = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
799     ttycolors[NO_COLOR]         = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
800     ttycolors[CLR_ORANGE]       = FOREGROUND_RED | FOREGROUND_INTENSITY;
801     ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
802     ttycolors[CLR_YELLOW]       = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
803     ttycolors[CLR_BRIGHT_BLUE]  = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
804     ttycolors[CLR_BRIGHT_MAGENTA]=FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
805     ttycolors[CLR_BRIGHT_CYAN]  = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
806     ttycolors[CLR_WHITE]        = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED
807                                     | FOREGROUND_INTENSITY;
808 
809     ttycolors_inv[CLR_BLACK]       = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
810                                         | BACKGROUND_INTENSITY;
811     ttycolors_inv[CLR_RED]         = BACKGROUND_RED | BACKGROUND_INTENSITY;
812     ttycolors_inv[CLR_GREEN]       = BACKGROUND_GREEN;
813     ttycolors_inv[CLR_BROWN]       = BACKGROUND_GREEN | BACKGROUND_RED;
814     ttycolors_inv[CLR_BLUE]        = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
815     ttycolors_inv[CLR_MAGENTA]     = BACKGROUND_BLUE | BACKGROUND_RED;
816     ttycolors_inv[CLR_CYAN]        = BACKGROUND_GREEN | BACKGROUND_BLUE;
817     ttycolors_inv[CLR_GRAY]        = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE;
818     ttycolors_inv[NO_COLOR]        = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
819     ttycolors_inv[CLR_ORANGE]      = BACKGROUND_RED | BACKGROUND_INTENSITY;
820     ttycolors_inv[CLR_BRIGHT_GREEN]= BACKGROUND_GREEN | BACKGROUND_INTENSITY;
821     ttycolors_inv[CLR_YELLOW]      = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
822     ttycolors_inv[CLR_BRIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
823     ttycolors_inv[CLR_BRIGHT_MAGENTA] =BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
824     ttycolors_inv[CLR_BRIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
825     ttycolors_inv[CLR_WHITE]       = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
826                                        | BACKGROUND_INTENSITY;
827 #else
828     int k;
829     ttycolors[0] = FOREGROUND_INTENSITY;
830     ttycolors_inv[0] = BACKGROUND_INTENSITY;
831     for (k = 1; k < SIZE(ttycolors); ++k) {
832         ttycolors[k] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
833         ttycolors_inv[k] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
834     }
835 #endif
836     init_ttycolor_completed = TRUE;
837 }
838 
839 #if 0
840 int
841 has_color(int color)        /* this function is commented out */
842 {
843 #ifdef TEXTCOLOR
844     if ((color >= 0) && (color < CLR_MAX))
845         return 1;
846 #else
847     if ((color == CLR_BLACK) || (color == CLR_WHITE) || (color == NO_COLOR))
848         return 1;
849 #endif
850     else
851         return 0;
852 }
853 #endif
854 
855 int
term_attr_fixup(int attrmask)856 term_attr_fixup(int attrmask)
857 {
858     return attrmask;
859 }
860 
861 void
term_start_attr(int attrib)862 term_start_attr(int attrib)
863 {
864     console.current_nhattr[attrib] = TRUE;
865     if (attrib) console.current_nhattr[ATR_NONE] = FALSE;
866 }
867 
868 void
term_end_attr(int attrib)869 term_end_attr(int attrib)
870 {
871     int k;
872 
873     switch (attrib) {
874     case ATR_INVERSE:
875     case ATR_ULINE:
876     case ATR_BLINK:
877     case ATR_BOLD:
878         break;
879     }
880     console.current_nhattr[attrib] = FALSE;
881     console.current_nhattr[ATR_NONE] = TRUE;
882     /* re-evaluate all attr now for performance at output time */
883     for (k=ATR_NONE; k <= ATR_INVERSE; ++k) {
884         if (console.current_nhattr[k])
885             console.current_nhattr[ATR_NONE] = FALSE;
886     }
887 }
888 
889 void
term_end_raw_bold(void)890 term_end_raw_bold(void)
891 {
892     term_end_attr(ATR_BOLD);
893 }
894 
895 void
term_start_raw_bold(void)896 term_start_raw_bold(void)
897 {
898     term_start_attr(ATR_BOLD);
899 }
900 
901 void
term_start_color(int color)902 term_start_color(int color)
903 {
904 #ifdef TEXTCOLOR
905     if (color >= 0 && color < CLR_MAX) {
906         console.current_nhcolor = color;
907     } else
908 #endif
909     console.current_nhcolor = NO_COLOR;
910 }
911 
912 void
term_end_color(void)913 term_end_color(void)
914 {
915 #ifdef TEXTCOLOR
916     console.foreground = DEFTEXTCOLOR;
917 #endif
918     console.attr = (console.foreground | console.background);
919     console.current_nhcolor = NO_COLOR;
920 }
921 
922 void
standoutbeg()923 standoutbeg()
924 {
925     term_start_attr(ATR_BOLD);
926 }
927 
928 void
standoutend()929 standoutend()
930 {
931     term_end_attr(ATR_BOLD);
932 }
933 
934 #ifndef NO_MOUSE_ALLOWED
935 void
toggle_mouse_support()936 toggle_mouse_support()
937 {
938     static int qeinit = 0;
939     DWORD cmode;
940 
941     GetConsoleMode(console.hConIn, &cmode);
942     if (!qeinit) {
943         qeinit = 1;
944         orig_QuickEdit = ((cmode & ENABLE_QUICK_EDIT_MODE) != 0);
945     }
946     switch(iflags.wc_mouse_support) {
947         case 2:
948                 cmode |= ENABLE_MOUSE_INPUT;
949                 break;
950         case 1:
951                 cmode |= ENABLE_MOUSE_INPUT;
952                 cmode &= ~ENABLE_QUICK_EDIT_MODE;
953                 cmode |= ENABLE_EXTENDED_FLAGS;
954                 break;
955         case 0:
956                 /*FALLTHRU*/
957         default:
958                 cmode &= ~ENABLE_MOUSE_INPUT;
959                 if (orig_QuickEdit)
960                     cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
961     }
962     SetConsoleMode(console.hConIn, cmode);
963 }
964 #endif
965 
966 /* handle tty options updates here */
967 void
nttty_preference_update(pref)968 nttty_preference_update(pref)
969 const char *pref;
970 {
971     if (stricmp(pref, "mouse_support") == 0) {
972 #ifndef NO_MOUSE_ALLOWED
973         toggle_mouse_support();
974 #endif
975     }
976     if (stricmp(pref, "symset") == 0)
977         check_and_set_font();
978     return;
979 }
980 
981 #ifdef PORT_DEBUG
982 void
win32con_debug_keystrokes()983 win32con_debug_keystrokes()
984 {
985     DWORD count;
986     boolean valid = 0;
987     int ch;
988     xputs("\n");
989     while (!valid || ch != 27) {
990         nocmov(ttyDisplay->curx, ttyDisplay->cury);
991         ReadConsoleInput(console.hConIn, &ir, 1, &count);
992         if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
993             ch = process_keystroke(&ir, &valid, iflags.num_pad, 1);
994     }
995     (void) doredraw();
996 }
997 void
win32con_handler_info()998 win32con_handler_info()
999 {
1000     char *buf;
1001     int ci;
1002     if (!keyboard_handler.pSourceAuthor && !keyboard_handler.pSourceWhere)
1003         pline("Keyboard handler source info and author unavailable.");
1004     else {
1005         if (keyboard_handler.pKeyHandlerName &&
1006             keyboard_handler.pKeyHandlerName(&buf, 1)) {
1007             xputs("\n");
1008             xputs("Keystroke handler loaded: \n    ");
1009             xputs(buf);
1010         }
1011         if (keyboard_handler.pSourceAuthor &&
1012             keyboard_handler.pSourceAuthor(&buf)) {
1013             xputs("\n");
1014             xputs("Keystroke handler Author: \n    ");
1015             xputs(buf);
1016         }
1017         if (keyboard_handler.pSourceWhere &&
1018             keyboard_handler.pSourceWhere(&buf)) {
1019             xputs("\n");
1020             xputs("Keystroke handler source code available at:\n    ");
1021             xputs(buf);
1022         }
1023         xputs("\nPress any key to resume.");
1024         ci = nhgetch();
1025         (void) doredraw();
1026     }
1027 }
1028 
1029 void
win32con_toggle_cursor_info()1030 win32con_toggle_cursor_info()
1031 {
1032     display_cursor_info = !display_cursor_info;
1033 }
1034 #endif
1035 
1036 void
map_subkeyvalue(op)1037 map_subkeyvalue(op)
1038 register char *op;
1039 {
1040     char digits[] = "0123456789";
1041     int length, i, idx, val;
1042     char *kp;
1043 
1044     idx = -1;
1045     val = -1;
1046     kp = index(op, '/');
1047     if (kp) {
1048         *kp = '\0';
1049         kp++;
1050         length = strlen(kp);
1051         if (length < 1 || length > 3)
1052             return;
1053         for (i = 0; i < length; i++)
1054             if (!index(digits, kp[i]))
1055                 return;
1056         val = atoi(kp);
1057         length = strlen(op);
1058         if (length < 1 || length > 3)
1059             return;
1060         for (i = 0; i < length; i++)
1061             if (!index(digits, op[i]))
1062                 return;
1063         idx = atoi(op);
1064     }
1065     if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1)
1066         return;
1067     key_overrides[idx] = val;
1068 }
1069 
unload_keyboard_handler()1070 void unload_keyboard_handler()
1071 {
1072     nhassert(keyboard_handler.hLibrary != NULL);
1073 
1074     FreeLibrary(keyboard_handler.hLibrary);
1075     memset(&keyboard_handler, 0, sizeof(keyboard_handler_t));
1076 }
1077 
1078 boolean
load_keyboard_handler(const char * inName)1079 load_keyboard_handler(const char * inName)
1080 {
1081     char path[MAX_ALTKEYHANDLER + 4];
1082     strcpy(path, inName);
1083     strcat(path, ".dll");
1084 
1085     HANDLE hLibrary = LoadLibrary(path);
1086 
1087     if (hLibrary == NULL)
1088         return FALSE;
1089 
1090     PROCESS_KEYSTROKE pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
1091         hLibrary, TEXT("ProcessKeystroke"));
1092     NHKBHIT pNHkbhit = (NHKBHIT) GetProcAddress(
1093         hLibrary, TEXT("NHkbhit"));
1094     CHECKINPUT pCheckInput =
1095         (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
1096 
1097     if (!pProcessKeystroke || !pNHkbhit || !pCheckInput)
1098     {
1099         return FALSE;
1100     } else {
1101         if (keyboard_handler.hLibrary != NULL)
1102             unload_keyboard_handler();
1103 
1104         keyboard_handler.hLibrary = hLibrary;
1105 
1106         keyboard_handler.pProcessKeystroke = pProcessKeystroke;
1107         keyboard_handler.pNHkbhit = pNHkbhit;
1108         keyboard_handler.pCheckInput = pCheckInput;
1109 
1110         keyboard_handler.pSourceWhere =
1111             (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
1112         keyboard_handler.pSourceAuthor =
1113             (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
1114         keyboard_handler.pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
1115             hLibrary, TEXT("KeyHandlerName"));
1116     }
1117 
1118     return TRUE;
1119 }
1120 
set_altkeyhandler(const char * inName)1121 void set_altkeyhandler(const char * inName)
1122 {
1123     if (strlen(inName) >= MAX_ALTKEYHANDLER) {
1124         config_error_add("altkeyhandler name '%s' is too long", inName);
1125         return;
1126     }
1127 
1128     char name[MAX_ALTKEYHANDLER];
1129     strcpy(name, inName);
1130 
1131     /* We support caller mistakenly giving name with '.dll' extension */
1132     char * ext = strchr(name, '.');
1133     if (ext != NULL) *ext = '\0';
1134 
1135     if (load_keyboard_handler(name))
1136         strcpy(iflags.altkeyhandler, name);
1137     else {
1138         config_error_add("unable to load altkeyhandler '%s'", name);
1139         return;
1140     }
1141 
1142     return;
1143 }
1144 
1145 
1146 /* fatal error */
1147 /*VARARGS1*/
1148 void nttty_error
VA_DECL(const char *,s)1149 VA_DECL(const char *, s)
1150 {
1151     char buf[BUFSZ];
1152     VA_START(s);
1153     VA_INIT(s, const char *);
1154     /* error() may get called before tty is initialized */
1155     if (iflags.window_inited)
1156         end_screen();
1157     buf[0] = '\n';
1158     (void) vsnprintf(&buf[1], sizeof buf - 1, s, VA_ARGS);
1159     msmsg(buf);
1160     really_move_cursor();
1161     VA_END();
1162     exit(EXIT_FAILURE);
1163 }
1164 
1165 void
synch_cursor()1166 synch_cursor()
1167 {
1168     really_move_cursor();
1169 }
1170 
1171 #ifdef CHANGE_COLOR
1172 void
tty_change_color(color_number,rgb,reverse)1173 tty_change_color(color_number, rgb, reverse)
1174 int color_number, reverse;
1175 long rgb;
1176 {
1177     /* Map NetHack color index to NT Console palette index */
1178     int idx, win32_color_number[] = {
1179         0,  /* CLR_BLACK           0 */
1180         4,  /* CLR_RED             1 */
1181         2,  /* CLR_GREEN           2 */
1182         6,  /* CLR_BROWN           3 */
1183         1,  /* CLR_BLUE            4 */
1184         5,  /* CLR_MAGENTA         5 */
1185         3,  /* CLR_CYAN            6 */
1186         7,  /* CLR_GRAY            7 */
1187         8,  /* NO_COLOR            8 */
1188         12, /* CLR_ORANGE          9 */
1189         10, /* CLR_BRIGHT_GREEN   10 */
1190         14, /* CLR_YELLOW         11 */
1191         9,  /* CLR_BRIGHT_BLUE    12 */
1192         13, /* CLR_BRIGHT_MAGENTA 13 */
1193         11, /* CLR_BRIGHT_CYAN    14 */
1194         15  /* CLR_WHITE          15 */
1195     };
1196     int k;
1197     if (color_number < 0) { /* indicates OPTIONS=palette with no value */
1198         /* copy the NetHack palette into UserDefinedColors */
1199         for (k = 0; k < CLR_MAX; k++)
1200             UserDefinedColors[k] = NetHackColors[k];
1201     } else if (color_number >= 0 && color_number < CLR_MAX) {
1202         if (!altered_palette) {
1203             /* make sure a full suite is available */
1204             for (k = 0; k < CLR_MAX; k++)
1205                 UserDefinedColors[k] = DefaultColors[k];
1206         }
1207         idx = win32_color_number[color_number];
1208         UserDefinedColors[idx] = rgb;
1209     }
1210     altered_palette = TRUE;
1211 }
1212 
1213 char *
tty_get_color_string()1214 tty_get_color_string()
1215 {
1216     return "";
1217 }
1218 
1219 int
match_color_name(c)1220 match_color_name(c)
1221 const char *c;
1222 {
1223     const struct others {
1224         int idx;
1225         const char *colorname;
1226     } othernames[] = {
1227         { CLR_MAGENTA, "purple" },
1228         { CLR_BRIGHT_MAGENTA, "bright purple" },
1229         { NO_COLOR, "dark gray" },
1230         { NO_COLOR, "dark grey" },
1231         { CLR_GRAY, "grey" },
1232     };
1233 
1234     int cnt;
1235     for (cnt = 0; cnt < CLR_MAX; ++cnt) {
1236         if (!strcmpi(c, c_obj_colors[cnt]))
1237             return cnt;
1238     }
1239     for (cnt = 0; cnt < SIZE(othernames); ++cnt) {
1240         if (!strcmpi(c, othernames[cnt].colorname))
1241             return othernames[cnt].idx;
1242     }
1243     return -1;
1244 }
1245 
1246 /*
1247  * Returns 0 if badoption syntax
1248  */
1249 int
alternative_palette(op)1250 alternative_palette(op)
1251 char *op;
1252 {
1253     /*
1254      *	palette:color-R-G-B
1255      *	OPTIONS=palette:green-4-3-1, palette:0-0-0-0
1256      */
1257     int fieldcnt, color_number, rgb, red, green, blue;
1258     char *fields[4], *cp;
1259 
1260     if (!op) {
1261         change_color(-1, 0, 0); /* indicates palette option with
1262                                    no value meaning "load an entire
1263                                    hard-coded NetHack palette." */
1264         return 1;
1265     }
1266 
1267     cp = fields[0] = op;
1268     for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1269         cp = index(cp, '-');
1270         if (!cp)
1271             return 0;
1272         fields[fieldcnt] = cp;
1273         cp++;
1274     }
1275     for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1276         *(fields[fieldcnt]) = '\0';
1277         ++fields[fieldcnt];
1278     }
1279     rgb = 0;
1280     for (fieldcnt = 0; fieldcnt < 4; ++fieldcnt) {
1281         if (fieldcnt == 0 && isalpha(*(fields[0]))) {
1282             color_number = match_color_name(fields[0]);
1283             if (color_number == -1)
1284                 return 0;
1285         } else {
1286             int dcount = 0, cval = 0;
1287             cp = fields[fieldcnt];
1288             if (*cp == '\\' && index("0123456789xXoO", cp[1])) {
1289                 const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
1290 
1291                 cp++;
1292                 if (*cp == 'x' || *cp == 'X')
1293                     for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
1294                         cval = (int) ((cval * 16) + (dp - hex) / 2);
1295                 else if (*cp == 'o' || *cp == 'O')
1296                     for (++cp; (index("01234567", *cp)) && (dcount++ < 3);
1297                          cp++)
1298                         cval = (cval * 8) + (*cp - '0');
1299                 else
1300                     return 0;
1301             } else {
1302                 for (; *cp && (index("0123456789", *cp)) && (dcount++ < 3);
1303                      cp++)
1304                     cval = (cval * 10) + (*cp - '0');
1305             }
1306             switch (fieldcnt) {
1307             case 0:
1308                 color_number = cval;
1309                 break;
1310             case 1:
1311                 red = cval;
1312                 break;
1313             case 2:
1314                 green = cval;
1315                 break;
1316             case 3:
1317                 blue = cval;
1318                 break;
1319             }
1320         }
1321     }
1322     rgb = RGB(red, green, blue);
1323     if (color_number >= 0 && color_number < CLR_MAX)
1324         change_color(color_number, rgb, 0);
1325     return 1;
1326 }
1327 
1328 /*
1329  *  This uses an undocumented method to set console attributes
1330  *  at runtime including console palette
1331  *
1332  * 	VOID WINAPI SetConsolePalette(COLORREF palette[16])
1333  *
1334  *  Author: James Brown at www.catch22.net
1335  *
1336  *  Set palette of current console.
1337  *  Palette should be of the form:
1338  *
1339  * 	COLORREF DefaultColors[CLR_MAX] =
1340  * 	{
1341  *		0x00000000, 0x00800000, 0x00008000, 0x00808000,
1342  *		0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
1343  *		0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
1344  *		0x000000ff, 0x00ff00ff,	0x0000ffff, 0x00ffffff
1345  *	 };
1346  */
1347 
1348 #pragma pack(push, 1)
1349 
1350 /*
1351  *	Structure to send console via WM_SETCONSOLEINFO
1352  */
1353 typedef struct _CONSOLE_INFO {
1354     ULONG Length;
1355     COORD ScreenBufferSize;
1356     COORD WindowSize;
1357     ULONG WindowPosX;
1358     ULONG WindowPosY;
1359 
1360     COORD FontSize;
1361     ULONG FontFamily;
1362     ULONG FontWeight;
1363     WCHAR FaceName[32];
1364 
1365     ULONG CursorSize;
1366     ULONG FullScreen;
1367     ULONG QuickEdit;
1368     ULONG AutoPosition;
1369     ULONG InsertMode;
1370 
1371     USHORT ScreenColors;
1372     USHORT PopupColors;
1373     ULONG HistoryNoDup;
1374     ULONG HistoryBufferSize;
1375     ULONG NumberOfHistoryBuffers;
1376 
1377     COLORREF ColorTable[16];
1378 
1379     ULONG CodePage;
1380     HWND Hwnd;
1381 
1382     WCHAR ConsoleTitle[0x100];
1383 } CONSOLE_INFO;
1384 
1385 #pragma pack(pop)
1386 
1387 BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci);
1388 static void GetConsoleSizeInfo(CONSOLE_INFO *pci);
1389 VOID WINAPI SetConsolePalette(COLORREF crPalette[16]);
1390 
1391 void
adjust_palette(VOID_ARGS)1392 adjust_palette(VOID_ARGS)
1393 {
1394     SetConsolePalette(UserDefinedColors);
1395     altered_palette = 0;
1396 }
1397 
1398 /*
1399 /* only in Win2k+  (use FindWindow for NT4) */
1400 /* HWND WINAPI GetConsoleWindow(); */
1401 
1402 /*  Undocumented console message */
1403 #define WM_SETCONSOLEINFO (WM_USER + 201)
1404 
1405 VOID WINAPI
SetConsolePalette(COLORREF palette[16])1406 SetConsolePalette(COLORREF palette[16])
1407 {
1408     CONSOLE_INFO ci = { sizeof(ci) };
1409     int i;
1410     HWND hwndConsole = GetConsoleHandle();
1411 
1412     /* get current size/position settings rather than using defaults.. */
1413     GetConsoleSizeInfo(&ci);
1414 
1415     /* set these to zero to keep current settings */
1416     ci.FontSize.X = 0; /* def = 8  */
1417     ci.FontSize.Y = 0; /* def = 12 */
1418     ci.FontFamily = 0; /* def = 0x30 = FF_MODERN|FIXED_PITCH */
1419     ci.FontWeight = 0; /* 0x400;   */
1420     /* lstrcpyW(ci.FaceName, L"Terminal"); */
1421     ci.FaceName[0] = L'\0';
1422 
1423     ci.CursorSize = 25;
1424     ci.FullScreen = FALSE;
1425     ci.QuickEdit = TRUE;
1426     ci.AutoPosition = 0x10000;
1427     ci.InsertMode = TRUE;
1428     ci.ScreenColors = MAKEWORD(0x7, 0x0);
1429     ci.PopupColors = MAKEWORD(0x5, 0xf);
1430 
1431     ci.HistoryNoDup = FALSE;
1432     ci.HistoryBufferSize = 50;
1433     ci.NumberOfHistoryBuffers = 4;
1434 
1435     // colour table
1436     for (i = 0; i < 16; i++)
1437         ci.ColorTable[i] = palette[i];
1438 
1439     ci.CodePage = GetConsoleOutputCP();
1440     ci.Hwnd = hwndConsole;
1441 
1442     lstrcpyW(ci.ConsoleTitle, L"");
1443 
1444     SetConsoleInfo(hwndConsole, &ci);
1445 }
1446 
1447 /*
1448  *  Wrapper around WM_SETCONSOLEINFO. We need to create the
1449  *  necessary section (file-mapping) object in the context of the
1450  *  process which owns the console, before posting the message
1451  */
1452 BOOL
SetConsoleInfo(HWND hwndConsole,CONSOLE_INFO * pci)1453 SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci)
1454 {
1455     DWORD dwConsoleOwnerPid;
1456     HANDLE hProcess;
1457     HANDLE hSection, hDupSection;
1458     PVOID ptrView = 0;
1459     HANDLE hThread;
1460 
1461     /*
1462      *	Open the process which "owns" the console
1463      */
1464     GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid);
1465     hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
1466 
1467     /*
1468      * Create a SECTION object backed by page-file, then map a view of
1469      * this section into the owner process so we can write the contents
1470      * of the CONSOLE_INFO buffer into it
1471      */
1472     hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
1473                                  pci->Length, 0);
1474 
1475     /*
1476      *	Copy our console structure into the section-object
1477      */
1478     ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
1479                             pci->Length);
1480     memcpy(ptrView, pci, pci->Length);
1481     UnmapViewOfFile(ptrView);
1482 
1483     /*
1484      *	Map the memory into owner process
1485      */
1486     DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection, 0,
1487                     FALSE, DUPLICATE_SAME_ACCESS);
1488 
1489     /*  Send console window the "update" message */
1490     SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM) hDupSection, 0);
1491 
1492     /*
1493      * clean up
1494      */
1495     hThread = CreateRemoteThread(hProcess, 0, 0,
1496                                  (LPTHREAD_START_ROUTINE) CloseHandle,
1497                                  hDupSection, 0, 0);
1498 
1499     CloseHandle(hThread);
1500     CloseHandle(hSection);
1501     CloseHandle(hProcess);
1502 
1503     return TRUE;
1504 }
1505 
1506 /*
1507  *  Fill the CONSOLE_INFO structure with information
1508  *  about the current console window
1509  */
1510 static void
GetConsoleSizeInfo(CONSOLE_INFO * pci)1511 GetConsoleSizeInfo(CONSOLE_INFO *pci)
1512 {
1513     CONSOLE_SCREEN_BUFFER_INFO csbi;
1514 
1515     HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
1516 
1517     GetConsoleScreenBufferInfo(hConsoleOut, &csbi);
1518 
1519     pci->ScreenBufferSize = csbi.dwSize;
1520     pci->WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
1521     pci->WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
1522     pci->WindowPosX = csbi.srWindow.Left;
1523     pci->WindowPosY = csbi.srWindow.Top;
1524 }
1525 
1526 static HWND
GetConsoleHandle(void)1527 GetConsoleHandle(void)
1528 {
1529     HMODULE hMod = GetModuleHandle("kernel32.dll");
1530     GETCONSOLEWINDOW pfnGetConsoleWindow =
1531         (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
1532     if (pfnGetConsoleWindow)
1533         return pfnGetConsoleWindow();
1534     else
1535         return GetConsoleHwnd();
1536 }
1537 
1538 static HWND
GetConsoleHwnd(void)1539 GetConsoleHwnd(void)
1540 {
1541     int iterations = 0;
1542     HWND hwndFound = 0;
1543     char OldTitle[1024], NewTitle[1024], TestTitle[1024];
1544 
1545     /* Get current window title */
1546     GetConsoleTitle(OldTitle, sizeof OldTitle);
1547 
1548     (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
1549                    GetCurrentProcessId());
1550     SetConsoleTitle(NewTitle);
1551 
1552     GetConsoleTitle(TestTitle, sizeof TestTitle);
1553     while (strcmp(TestTitle, NewTitle) != 0) {
1554         iterations++;
1555         /* sleep(0); */
1556         GetConsoleTitle(TestTitle, sizeof TestTitle);
1557     }
1558     hwndFound = FindWindow(NULL, NewTitle);
1559     SetConsoleTitle(OldTitle);
1560     /*       printf("%d iterations\n", iterations); */
1561     return hwndFound;
1562 }
1563 #endif /*CHANGE_COLOR*/
1564 
EnumFontCallback(const LOGFONTW * lf,const TEXTMETRICW * tm,DWORD fontType,LPARAM lParam)1565 static int CALLBACK EnumFontCallback(
1566     const LOGFONTW * lf, const TEXTMETRICW * tm, DWORD fontType, LPARAM lParam)
1567 {
1568     LOGFONTW * lf_ptr = (LOGFONTW *) lParam;
1569     *lf_ptr = *lf;
1570     return 0;
1571 }
1572 
1573 /* check_and_set_font ensures that the current font will render the symbols
1574  * that are currently being used correctly.  If they will not be rendered
1575  * correctly, then it will change the font to a known good font.
1576  */
1577 void
check_and_set_font()1578 check_and_set_font()
1579 {
1580     if (!check_font_widths()) {
1581         raw_print("WARNING: glyphs too wide in console font."
1582                   "  Changing code page to 437 and font to Consolas\n");
1583         set_known_good_console_font();
1584     }
1585 }
1586 
1587 /* check_font_widths returns TRUE if all glyphs in current console font
1588  * fit within the width of a single console cell.
1589  */
1590 boolean
check_font_widths()1591 check_font_widths()
1592 {
1593     CONSOLE_FONT_INFOEX console_font_info;
1594     console_font_info.cbSize = sizeof(console_font_info);
1595     BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
1596                                             &console_font_info);
1597 
1598     /* get console window and DC
1599      * NOTE: the DC from the console window does not have the correct
1600      *       font selected at this point.
1601      */
1602     HWND hWnd = GetConsoleWindow();
1603     HDC hDC = GetDC(hWnd);
1604 
1605     LOGFONTW logical_font;
1606     logical_font.lfCharSet = DEFAULT_CHARSET;
1607     wcscpy(logical_font.lfFaceName, console_font_info.FaceName);
1608     logical_font.lfPitchAndFamily = 0;
1609 
1610     /* getting matching console font */
1611     LOGFONTW matching_log_font = { 0 };
1612     EnumFontFamiliesExW(hDC, &logical_font, EnumFontCallback,
1613                                         (LPARAM) &matching_log_font, 0);
1614 
1615     if (matching_log_font.lfHeight == 0) {
1616         raw_print("Unable to enumerate system fonts\n");
1617         return FALSE;
1618     }
1619 
1620     /* create font matching console font */
1621     LOGFONTW console_font_log_font = matching_log_font;
1622     console_font_log_font.lfWeight = console_font_info.FontWeight;
1623     console_font_log_font.lfHeight = console_font_info.dwFontSize.Y;
1624     console_font_log_font.lfWidth = console_font_info.dwFontSize.X;
1625     HFONT console_font = CreateFontIndirectW(&console_font_log_font);
1626 
1627     if (console_font == NULL) {
1628         raw_print("Unable to create console font\n");
1629         return FALSE;
1630     }
1631 
1632     /* select font */
1633     HGDIOBJ saved_font = SelectObject(hDC, console_font);
1634 
1635     /* determine whether it is a true type font */
1636     TEXTMETRICA tm;
1637     success = GetTextMetricsA(hDC, &tm);
1638 
1639     if (!success) {
1640         raw_print("Unable to get console font text metrics\n");
1641         goto clean_up;
1642     }
1643 
1644     boolean isTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
1645 
1646     /* determine which glyphs are used */
1647     boolean used[256];
1648     memset(used, 0, sizeof(used));
1649     for (int i = 0; i < SYM_MAX; i++) {
1650         used[primary_syms[i]] = TRUE;
1651         used[rogue_syms[i]] = TRUE;
1652     }
1653 
1654     int wcUsedCount = 0;
1655     wchar_t wcUsed[256];
1656     for (int i = 0; i < sizeof(used); i++)
1657         if (used[i])
1658             wcUsed[wcUsedCount++] = cp437[i];
1659 
1660     /* measure the set of used glyphs to ensure they fit */
1661     boolean all_glyphs_fit = TRUE;
1662 
1663     for (int i = 0; i < wcUsedCount; i++) {
1664         int width;
1665         if (isTrueType) {
1666             ABC abc;
1667             success = GetCharABCWidthsW(hDC, wcUsed[i], wcUsed[i], &abc);
1668             width = abc.abcA + abc.abcB + abc.abcC;
1669         } else {
1670             success = GetCharWidthW(hDC, wcUsed[i], wcUsed[i], &width);
1671         }
1672 
1673         if (success && width > console_font_info.dwFontSize.X) {
1674             all_glyphs_fit = FALSE;
1675             break;
1676         }
1677     }
1678 
1679 clean_up:
1680 
1681     SelectObject(hDC, saved_font);
1682     DeleteObject(console_font);
1683 
1684     return all_glyphs_fit;
1685 }
1686 
1687 /* set_known_good_console_font sets the code page and font used by the console
1688  * to settings know to work well with NetHack.  It also saves the original
1689  * settings so that they can be restored prior to NetHack exit.
1690  */
1691 void
set_known_good_console_font()1692 set_known_good_console_font()
1693 {
1694     CONSOLE_FONT_INFOEX console_font_info;
1695     console_font_info.cbSize = sizeof(console_font_info);
1696     BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
1697                                             &console_font_info);
1698 
1699     console.font_changed = TRUE;
1700     console.original_font_info = console_font_info;
1701     console.original_code_page = GetConsoleOutputCP();
1702 
1703     wcscpy_s(console_font_info.FaceName,
1704         sizeof(console_font_info.FaceName)
1705             / sizeof(console_font_info.FaceName[0]),
1706         L"Consolas");
1707 
1708     success = SetConsoleOutputCP(437);
1709     nhassert(success);
1710 
1711     success = SetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info);
1712     nhassert(success);
1713 }
1714 
1715 /* restore_original_console_font will restore the console font and code page
1716  * settings to what they were when NetHack was launched.
1717  */
1718 void
restore_original_console_font()1719 restore_original_console_font()
1720 {
1721     if (console.font_changed) {
1722         BOOL success;
1723         raw_print("Restoring original font and code page\n");
1724         success = SetConsoleOutputCP(console.original_code_page);
1725         if (!success)
1726             raw_print("Unable to restore original code page\n");
1727 
1728         success = SetCurrentConsoleFontEx(console.hConOut, FALSE,
1729                                             &console.original_font_info);
1730         if (!success)
1731             raw_print("Unable to restore original font\n");
1732 
1733         console.font_changed = FALSE;
1734     }
1735 }
1736 
1737 /* set_cp_map() creates a mapping of every possible character of a code
1738  * page to its corresponding WCHAR.  This is necessary due to the high
1739  * cost of making calls to MultiByteToWideChar() for every character we
1740  * wish to print to the console.
1741  */
1742 
set_cp_map()1743 void set_cp_map()
1744 {
1745     if (console.has_unicode) {
1746         UINT codePage = GetConsoleOutputCP();
1747 
1748         if (codePage == 437) {
1749             memcpy(console.cpMap, cp437, sizeof(console.cpMap));
1750         } else {
1751             for (int i = 0; i < 256; i++) {
1752                 char c = (char)i;
1753                 int count = MultiByteToWideChar(codePage, 0, &c, 1,
1754                                                 &console.cpMap[i], 1);
1755                 nhassert(count == 1);
1756 
1757                 // If a character was mapped to unicode control codes,
1758                 // remap to the appropriate unicode character per our
1759                 // code page 437 mappings.
1760                 if (console.cpMap[i] < 32)
1761                     console.cpMap[i] = cp437[console.cpMap[i]];
1762             }
1763         }
1764 
1765     }
1766 }
1767 
1768 #if 0
1769 /* early_raw_print() is used during early game intialization prior to the
1770  * setting up of the windowing system.  This allows early errors and panics
1771  * to have there messages displayed.
1772  *
1773  * early_raw_print() eventually gets replaced by tty_raw_print().
1774  *
1775  */
1776 
1777 void early_raw_print(const char *s)
1778 {
1779     if (console.hConOut == NULL)
1780         return;
1781 
1782     nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
1783     nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
1784 
1785     WORD attribute = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
1786     DWORD unused;
1787 
1788     while (*s != '\0') {
1789         switch (*s) {
1790         case '\n':
1791             if (console.cursor.Y < console.height - 1)
1792                 console.cursor.Y++;
1793         /* fall through */
1794         case '\r':
1795             console.cursor.X = 1;
1796             break;
1797         case '\b':
1798             if (console.cursor.X > 1) {
1799                 console.cursor.X--;
1800             } else if(console.cursor.Y > 0) {
1801                 console.cursor.X = console.width - 1;
1802                 console.cursor.Y--;
1803             }
1804             break;
1805         default:
1806             WriteConsoleOutputAttribute(console.hConOut, &attribute,
1807                                             1, console.cursor, &unused);
1808             WriteConsoleOutputCharacterA(console.hConOut, s,
1809                                             1, console.cursor, &unused);
1810             if (console.cursor.X == console.width - 1) {
1811                 if (console.cursor.Y < console.height - 1) {
1812                     console.cursor.X = 1;
1813                     console.cursor.Y++;
1814                 }
1815             } else {
1816                 console.cursor.X++;
1817             }
1818         }
1819         s++;
1820     }
1821 
1822     nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
1823     nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
1824 
1825     SetConsoleCursorPosition(console.hConOut, console.cursor);
1826 
1827 }
1828 #endif
1829 
1830 /* nethack_enter_nttty() is the first thing that is called from main
1831  * once the tty port is confirmed.
1832  *
1833  * We initialize all console state to support rendering to the console
1834  * through out flipping support at this time.  This allows us to support
1835  * raw_print prior to our returning.
1836  *
1837  * During this early initialization, we also determine the width and
1838  * height of the console that will be used.  This width and height will
1839  * not later change.
1840  *
1841  * We also check and set the console font to a font that we know will work
1842  * well with nethack.
1843  *
1844  * The intent of this early initialization is to get all state that is
1845  * not dependent upon game options initialized allowing us to simplify
1846  * any additional initialization that might be needed when we are actually
1847  * asked to open.
1848  *
1849  * Other then the call below which clears the entire console buffer, no
1850  * other code outputs directly to the console other then the code that
1851  * handles flipping the back buffer.
1852  *
1853  */
1854 
nethack_enter_nttty()1855 void nethack_enter_nttty()
1856 {
1857 #if 0
1858     /* set up state needed by early_raw_print() */
1859     windowprocs.win_raw_print = early_raw_print;
1860 #endif
1861     console.hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
1862     nhassert(console.hConOut != NULL); // NOTE: this assert will not print
1863 
1864     GetConsoleScreenBufferInfo(console.hConOut, &console.origcsbi);
1865 
1866     /* Testing of widths != COLNO has not turned up any problems.  Need
1867      * to do a bit more testing and then we are likely to enable having
1868      * console width match window width.
1869      */
1870 #if 0
1871     console.width = console.origcsbi.srWindow.Right -
1872                      console.origcsbi.srWindow.Left + 1;
1873     console.Width = max(console.Width, COLNO);
1874 #else
1875     console.width = COLNO;
1876 #endif
1877 
1878     console.height = console.origcsbi.srWindow.Bottom -
1879                      console.origcsbi.srWindow.Top + 1;
1880     console.height = max(console.height, ROWNO + 3);
1881 
1882     console.buffer_size = console.width * console.height;
1883 
1884 
1885     /* clear the entire console buffer */
1886     int size = console.origcsbi.dwSize.X * console.origcsbi.dwSize.Y;
1887     DWORD unused;
1888     set_console_cursor(0, 0);
1889     FillConsoleOutputAttribute(
1890         console.hConOut, CONSOLE_CLEAR_ATTRIBUTE,
1891         size, console.cursor, &unused);
1892 
1893     FillConsoleOutputCharacter(
1894         console.hConOut, CONSOLE_CLEAR_CHARACTER,
1895         size, console.cursor, &unused);
1896 
1897     set_console_cursor(1, 0);
1898     SetConsoleCursorPosition(console.hConOut, console.cursor);
1899 
1900     /* At this point early_raw_print will work */
1901 
1902     console.hConIn = GetStdHandle(STD_INPUT_HANDLE);
1903     nhassert(console.hConIn  != NULL);
1904 
1905     /* grow the size of the console buffer if it is not wide enough */
1906     if (console.origcsbi.dwSize.X < console.width) {
1907         COORD size = {
1908             size.Y = console.origcsbi.dwSize.Y,
1909             size.X = console.width
1910         };
1911 
1912         SetConsoleScreenBufferSize(console.hConOut, size);
1913     }
1914 
1915     /* setup front and back buffers */
1916     int buffer_size_bytes = sizeof(cell_t) * console.buffer_size;
1917 
1918     console.front_buffer = (cell_t *)malloc(buffer_size_bytes);
1919     buffer_fill_to_end(console.front_buffer, &undefined_cell, 0, 0);
1920 
1921     console.back_buffer = (cell_t *)malloc(buffer_size_bytes);
1922     buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
1923 
1924     /* determine whether OS version has unicode support */
1925     console.has_unicode = ((GetVersion() & 0x80000000) == 0);
1926 
1927     /* check the font before we capture the code page map */
1928     check_and_set_font();
1929     set_cp_map();
1930 
1931     /* Set console mode */
1932     DWORD cmode, mask;
1933     GetConsoleMode(console.hConIn, &cmode);
1934 #ifdef NO_MOUSE_ALLOWED
1935     mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT
1936            | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;
1937 #else
1938     mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
1939            | ENABLE_WINDOW_INPUT;
1940 #endif
1941     /* Turn OFF the settings specified in the mask */
1942     cmode &= ~mask;
1943 #ifndef NO_MOUSE_ALLOWED
1944     cmode |= ENABLE_MOUSE_INPUT;
1945 #endif
1946     SetConsoleMode(console.hConIn, cmode);
1947 
1948     /* load default keyboard handler */
1949     HKL keyboard_layout = GetKeyboardLayout(0);
1950     DWORD primary_language = (UINT_PTR) keyboard_layout & 0x3f;
1951 
1952     /* This was overriding the handler that had already
1953        been loaded during options parsing. Needs to
1954        check first */
1955     if (!iflags.altkeyhandler[0]) {
1956         if (primary_language == LANG_ENGLISH) {
1957             if (!load_keyboard_handler("nhdefkey"))
1958                 error("Unable to load nhdefkey.dll");
1959         } else {
1960             if (!load_keyboard_handler("nhraykey"))
1961                 error("Unable to load nhraykey.dll");
1962         }
1963     }
1964 }
1965 #endif /* TTY_GRAPHICS */
1966 
1967 /* this is used as a printf() replacement when the window
1968  * system isn't initialized yet
1969  */
1970 void msmsg
VA_DECL(const char *,fmt)1971 VA_DECL(const char *, fmt)
1972 {
1973     char buf[ROWNO * COLNO]; /* worst case scenario */
1974     VA_START(fmt);
1975     VA_INIT(fmt, const char *);
1976     (void) vsnprintf(buf, sizeof buf, fmt, VA_ARGS);
1977     if (redirect_stdout)
1978         fprintf(stdout, "%s", buf);
1979     else {
1980 #ifdef TTY_GRAPHICS
1981         if(!init_ttycolor_completed)
1982             init_ttycolor();
1983         /* if we have generated too many messages ... ask the user to
1984          * confirm and then clear.
1985          */
1986         if (console.cursor.Y > console.height - 4) {
1987             xputs("Hit <Enter> to continue.");
1988             while (pgetchar() != '\n')
1989                 ;
1990             raw_clear_screen();
1991             set_console_cursor(1, 0);
1992         }
1993         xputs(buf);
1994         if (ttyDisplay)
1995             curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y);
1996 #else
1997         fprintf(stdout, "%s", buf);
1998 #endif
1999     }
2000     VA_END();
2001     return;
2002 }
2003 
2004 #endif /* WIN32 */
2005