OSDN Git Service

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