OSDN Git Service

eliminate warnings about xputc_core[2]
[jnethack/source.git] / sys / winnt / nttty.c
1 /* NetHack 3.6  nttty.c $NHDT-Date: 1520825872 2018/03/12 03:37:52 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */
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  *
13  */
14
15 #ifdef WIN32
16 #define NEED_VARARGS /* Uses ... */
17 #include "hack.h"
18 #include "wintty.h"
19 #include <sys\types.h>
20 #include <sys\stat.h>
21 #include "win32api.h"
22
23 /*
24  * The following WIN32 Console API routines are used in this file.
25  *
26  * CreateFile
27  * GetConsoleScreenBufferInfo
28  * GetStdHandle
29  * SetConsoleCursorPosition
30  * SetConsoleTextAttribute
31  * SetConsoleCtrlHandler
32  * PeekConsoleInput
33  * ReadConsoleInput
34  * WriteConsoleOutputCharacter
35  * FillConsoleOutputAttribute
36  * GetConsoleOutputCP
37  */
38
39 static BOOL FDECL(CtrlHandler, (DWORD));
40 static void FDECL(xputc_core, (char));
41 #if 1 /*JP*/
42 static void FDECL(xputc2_core, (unsigned int, unsigned int));
43 #endif
44 void FDECL(cmov, (int, int));
45 void FDECL(nocmov, (int, int));
46 int FDECL(process_keystroke,
47           (INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug));
48 static void NDECL(init_ttycolor);
49 static void NDECL(really_move_cursor);
50 static void NDECL(check_and_set_font);
51 static boolean NDECL(check_font_widths);
52 static void NDECL(set_known_good_console_font);
53 static void NDECL(restore_original_console_font);
54
55 /* Win32 Console handles for input and output */
56 HANDLE hConIn;
57 HANDLE hConOut;
58
59 /* Win32 Screen buffer,coordinate,console I/O information */
60 CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi;
61 COORD ntcoord;
62 INPUT_RECORD ir;
63
64 /* Support for changing console font if existing glyph widths are too wide */
65 boolean console_font_changed;
66 CONSOLE_FONT_INFOEX original_console_font_info;
67 UINT original_console_code_page;
68
69 extern boolean getreturn_enabled; /* from sys/share/pcsys.c */
70 extern int redirect_stdout;
71
72 /* Flag for whether NetHack was launched via the GUI, not the command line.
73  * The reason we care at all, is so that we can get
74  * a final RETURN at the end of the game when launched from the GUI
75  * to prevent the scoreboard (or panic message :-|) from vanishing
76  * immediately after it is displayed, yet not bother when started
77  * from the command line.
78  */
79 int GUILaunched;
80 /* Flag for whether unicode is supported */
81 static boolean has_unicode;
82 static boolean init_ttycolor_completed;
83 #ifdef PORT_DEBUG
84 static boolean display_cursor_info = FALSE;
85 #endif
86 #ifdef CHANGE_COLOR
87 static void NDECL(adjust_palette);
88 static int FDECL(match_color_name, (const char *));
89 typedef HWND(WINAPI *GETCONSOLEWINDOW)();
90 static HWND GetConsoleHandle(void);
91 static HWND GetConsoleHwnd(void);
92 static boolean altered_palette;
93 static COLORREF UserDefinedColors[CLR_MAX];
94 static COLORREF NetHackColors[CLR_MAX] = {
95     0x00000000, 0x00c80000, 0x0000c850, 0x00b4b432, 0x000000d2, 0x00800080,
96     0x000064b4, 0x00c0c0c0, 0x00646464, 0x00f06464, 0x0000ff00, 0x00ffff00,
97     0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
98 };
99 static COLORREF DefaultColors[CLR_MAX] = {
100     0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080,
101     0x00008080, 0x00c0c0c0, 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
102     0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
103 };
104 #endif
105 struct console_t {
106     WORD background;
107     WORD foreground;
108     WORD attr;
109     int current_nhcolor;
110     int current_nhattr[ATR_INVERSE+1];
111     COORD cursor;
112 } console = {
113     0,
114     (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
115     (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
116     NO_COLOR,
117     {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE},
118     {0, 0}
119 };
120 static DWORD ccount, acount;
121 #ifndef CLR_MAX
122 #define CLR_MAX 16
123 #endif
124
125 int ttycolors[CLR_MAX];
126 int ttycolors_inv[CLR_MAX];
127
128 #define MAX_OVERRIDES 256
129 unsigned char key_overrides[MAX_OVERRIDES];
130 static char nullstr[] = "";
131 char erase_char, kill_char;
132 #define DEFTEXTCOLOR ttycolors[7]
133
134 /* dynamic keystroke handling .DLL support */
135 typedef int(__stdcall *PROCESS_KEYSTROKE)(HANDLE, INPUT_RECORD *, boolean *,
136                                           BOOLEAN_P, int);
137
138 typedef int(__stdcall *NHKBHIT)(HANDLE, INPUT_RECORD *);
139
140 typedef int(__stdcall *CHECKINPUT)(HANDLE, INPUT_RECORD *, DWORD *, BOOLEAN_P,
141                                    int, int *, coord *);
142
143 typedef int(__stdcall *SOURCEWHERE)(char **);
144
145 typedef int(__stdcall *SOURCEAUTHOR)(char **);
146
147 typedef int(__stdcall *KEYHANDLERNAME)(char **, int);
148
149 HANDLE hLibrary;
150 PROCESS_KEYSTROKE pProcessKeystroke;
151 NHKBHIT pNHkbhit;
152 CHECKINPUT pCheckInput;
153 SOURCEWHERE pSourceWhere;
154 SOURCEAUTHOR pSourceAuthor;
155 KEYHANDLERNAME pKeyHandlerName;
156
157 /*
158  * Called after returning from ! or ^Z
159  */
160 void
161 gettty()
162 {
163     console_font_changed = FALSE;
164
165     check_and_set_font();
166
167 #ifndef TEXTCOLOR
168     int k;
169 #endif
170     erase_char = '\b';
171     kill_char = 21; /* cntl-U */
172     iflags.cbreak = TRUE;
173 #ifdef TEXTCOLOR
174     init_ttycolor();
175 #else
176     for (k = 0; k < CLR_MAX; ++k)
177         ttycolors[k] = NO_COLOR;
178 #endif
179 }
180
181 /* reset terminal to original state */
182 void
183 settty(s)
184 const char *s;
185 {
186     cmov(ttyDisplay->curx, ttyDisplay->cury);
187     end_screen();
188     if (s)
189         raw_print(s);
190
191     restore_original_console_font();
192 }
193
194 /* called by init_nhwindows() and resume_nhwindows() */
195 void
196 setftty()
197 {
198 #ifdef CHANGE_COLOR
199     if (altered_palette)
200         adjust_palette();
201 #endif
202     start_screen();
203     has_unicode = ((GetVersion() & 0x80000000) == 0);
204 }
205
206 void
207 tty_startup(wid, hgt)
208 int *wid, *hgt;
209 {
210     int twid = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1;
211
212     if (twid > 80)
213         twid = 80;
214     *wid = twid;
215     *hgt = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1;
216     set_option_mod_status("mouse_support", SET_IN_GAME);
217 }
218
219 void
220 tty_number_pad(state)
221 int state;
222 {
223 }
224
225 void
226 tty_start_screen()
227 {
228     if (iflags.num_pad)
229         tty_number_pad(1); /* make keypad send digits */
230 }
231
232 void
233 tty_end_screen()
234 {
235     clear_screen();
236     really_move_cursor();
237     if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
238         DWORD ccnt;
239         COORD newcoord;
240
241         newcoord.X = 0;
242         newcoord.Y = 0;
243         FillConsoleOutputAttribute(
244             hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
245             csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt);
246         FillConsoleOutputCharacter(
247             hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt);
248     }
249     FlushConsoleInputBuffer(hConIn);
250 }
251
252 static BOOL
253 CtrlHandler(ctrltype)
254 DWORD ctrltype;
255 {
256     switch (ctrltype) {
257     /*  case CTRL_C_EVENT: */
258     case CTRL_BREAK_EVENT:
259         clear_screen();
260     case CTRL_CLOSE_EVENT:
261     case CTRL_LOGOFF_EVENT:
262     case CTRL_SHUTDOWN_EVENT:
263         getreturn_enabled = FALSE;
264 #ifndef NOSAVEONHANGUP
265         hangup(0);
266 #endif
267 #if defined(SAFERHANGUP)
268         CloseHandle(hConIn); /* trigger WAIT_FAILED */
269         return TRUE;
270 #endif
271     default:
272         return FALSE;
273     }
274 }
275
276 /* called by init_tty in wintty.c for WIN32 port only */
277 void
278 nttty_open(mode)
279 int mode;
280 {
281     HANDLE hStdOut;
282     DWORD cmode;
283     long mask;
284
285     GUILaunched = 0;
286
287     try :
288         /* The following lines of code were suggested by
289          * Bob Landau of Microsoft WIN32 Developer support,
290          * as the only current means of determining whether
291          * we were launched from the command prompt, or from
292          * the NT program manager. M. Allison
293          */
294     hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
295
296     if (hStdOut) {
297         GetConsoleScreenBufferInfo(hStdOut, &origcsbi);
298     } else if (mode) {
299         HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
300         HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
301
302         if (!hStdOut && !hStdIn) {
303             /* Bool rval; */
304             AllocConsole();
305             AttachConsole(GetCurrentProcessId());
306             /*  rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */
307             freopen("CON", "w", stdout);
308             freopen("CON", "r", stdin);
309         }
310         mode = 0;
311         goto try;
312     } else {
313         return;
314     }
315
316     /* Obtain handles for the standard Console I/O devices */
317     hConIn = GetStdHandle(STD_INPUT_HANDLE);
318     hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
319
320     load_keyboard_handler();
321     /* Initialize the function pointer that points to
322     * the kbhit() equivalent, in this TTY case nttty_kbhit()
323     */
324     nt_kbhit = nttty_kbhit;
325
326     GetConsoleMode(hConIn, &cmode);
327 #ifdef NO_MOUSE_ALLOWED
328     mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT
329            | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;
330 #else
331     mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
332            | ENABLE_WINDOW_INPUT;
333 #endif
334     /* Turn OFF the settings specified in the mask */
335     cmode &= ~mask;
336 #ifndef NO_MOUSE_ALLOWED
337     cmode |= ENABLE_MOUSE_INPUT;
338 #endif
339     SetConsoleMode(hConIn, cmode);
340     if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) {
341         /* Unable to set control handler */
342         cmode = 0; /* just to have a statement to break on for debugger */
343     }
344     get_scr_size();
345     console.cursor.X = console.cursor.Y = 0;
346     really_move_cursor();
347 }
348
349 int
350 process_keystroke(ir, valid, numberpad, portdebug)
351 INPUT_RECORD *ir;
352 boolean *valid;
353 boolean numberpad;
354 int portdebug;
355 {
356     int ch = pProcessKeystroke(hConIn, ir, valid, numberpad, portdebug);
357     /* check for override */
358     if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
359         ch = key_overrides[ch];
360     return ch;
361 }
362
363 int
364 nttty_kbhit()
365 {
366     return pNHkbhit(hConIn, &ir);
367 }
368
369 void
370 get_scr_size()
371 {
372     int lines, cols;
373     
374     GetConsoleScreenBufferInfo(hConOut, &csbi);
375     
376     lines = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1);
377     cols = csbi.srWindow.Right - (csbi.srWindow.Left + 1);
378
379     LI = lines;
380     CO = min(cols, 80);
381     
382     if ((LI < 25) || (CO < 80)) {
383         COORD newcoord;
384
385         LI = 25;
386         CO = 80;
387
388         newcoord.Y = LI;
389         newcoord.X = CO;
390
391         SetConsoleScreenBufferSize(hConOut, newcoord);
392     }
393 }
394
395 int
396 tgetch()
397 {
398     int mod;
399     coord cc;
400     DWORD count;
401     really_move_cursor();
402     return (program_state.done_hup)
403                ? '\033'
404                : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 0, &mod,
405                              &cc);
406 }
407
408 int
409 ntposkey(x, y, mod)
410 int *x, *y, *mod;
411 {
412     int ch;
413     coord cc;
414     DWORD count;
415     really_move_cursor();
416     ch = (program_state.done_hup)
417              ? '\033'
418              : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc);
419     if (!ch) {
420         *x = cc.x;
421         *y = cc.y;
422     }
423     return ch;
424 }
425
426 static void
427 really_move_cursor()
428 {
429 #ifdef PORT_DEBUG
430     char oldtitle[BUFSZ], newtitle[BUFSZ];
431     if (display_cursor_info && wizard) {
432         oldtitle[0] = '\0';
433         if (GetConsoleTitle(oldtitle, BUFSZ)) {
434             oldtitle[39] = '\0';
435         }
436         Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle,
437                 ttyDisplay->curx, ttyDisplay->cury, console.cursor.X, console.cursor.Y);
438         (void) SetConsoleTitle(newtitle);
439     }
440 #endif
441     if (ttyDisplay) {
442         console.cursor.X = ttyDisplay->curx;
443         console.cursor.Y = ttyDisplay->cury;
444     }
445     SetConsoleCursorPosition(hConOut, console.cursor);
446 }
447
448 void
449 cmov(x, y)
450 register int x, y;
451 {
452     ttyDisplay->cury = y;
453     ttyDisplay->curx = x;
454     console.cursor.X = x;
455     console.cursor.Y = y;
456 }
457
458 void
459 nocmov(x, y)
460 int x, y;
461 {
462     console.cursor.X = x;
463     console.cursor.Y = y;
464     ttyDisplay->curx = x;
465     ttyDisplay->cury = y;
466 }
467
468 void
469 xputc(ch)
470 char ch;
471 {
472     console.cursor.X = ttyDisplay->curx;
473     console.cursor.Y = ttyDisplay->cury;
474     xputc_core(ch);
475 }
476
477 #if 1 /*JP*/
478 void
479 xputc2_core(ch1, ch2)
480 unsigned int ch1;
481 unsigned int ch2;
482 {
483     unsigned char buf[2];
484     WORD attrs[2];
485     boolean inverse = FALSE;
486
487     buf[0] = ch1;
488     buf[1] = ch2;
489
490     /* xputc_core()\82©\82ç\82Ì\83R\83s\81[ */
491     inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
492     console.attr = (inverse) ?
493                     ttycolors_inv[console.current_nhcolor] :
494                     ttycolors[console.current_nhcolor];
495     if (console.current_nhattr[ATR_BOLD])
496             console.attr |= (inverse) ?
497                             BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
498
499     attrs[0] = attrs[1] = console.attr;
500
501     WriteConsoleOutputAttribute(hConOut, attrs, 2,
502                                 console.cursor, &acount);
503     WriteConsoleOutputCharacter(hConOut, buf, 2,
504                                 console.cursor, &ccount);
505     console.cursor.X += 2;
506 }
507
508 void
509 xputc2(ch1, ch2)
510 int ch1;
511 int ch2;
512 {
513     /* wintty.c \82Å\82Í 1 \83o\83C\83g\96\88\82É curx \82ð\89Á\8eZ\82·\82é\82ª\81A\82±\82±\82Í
514        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Å
515       \82µ\82Ü\82Á\82Ä\82¢\82é\81B\8f]\82Á\82Ä 1 \82ð\88ø\82­\81B */
516     console.cursor.X = ttyDisplay->curx - 1;
517     console.cursor.Y = ttyDisplay->cury;
518
519     xputc2_core(ch1, ch2);
520 }
521 #endif
522
523 void
524 xputs(s)
525 const char *s;
526 {
527     int k;
528     int slen = strlen(s);
529
530     if (ttyDisplay) {
531         console.cursor.X = ttyDisplay->curx;
532         console.cursor.Y = ttyDisplay->cury;
533     }
534
535     if (s) {
536         for (k = 0; k < slen && s[k]; ++k)
537             xputc_core(s[k]);
538     }
539 }
540
541 /* xputc_core() and g_putch() are the only
542  * two routines that actually place output
543  * on the display.
544  */
545 void
546 xputc_core(ch)
547 char ch;
548 {
549     boolean inverse = FALSE;
550     switch (ch) {
551     case '\n':
552         console.cursor.Y++;
553     /* fall through */
554     case '\r':
555         console.cursor.X = 1;
556         break;
557     case '\b':
558         console.cursor.X--;
559         break;
560     default:
561         inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
562         console.attr = (inverse) ?
563                         ttycolors_inv[console.current_nhcolor] :
564                         ttycolors[console.current_nhcolor];
565         if (console.current_nhattr[ATR_BOLD])
566                 console.attr |= (inverse) ?
567                                 BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
568         WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount);
569         if (has_unicode) {
570             /* Avoid bug in ANSI API on WinNT */
571             WCHAR c2[2];
572             int rc;
573             rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, &ch, 1, c2, 2);
574             WriteConsoleOutputCharacterW(hConOut, c2, rc, console.cursor, &ccount);
575         } else {
576             WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount);
577         }
578         console.cursor.X++;
579     }
580 }
581
582 /*
583  * Overrides wintty.c function of the same name
584  * for win32. It is used for glyphs only, not text.
585  */
586
587 /* CP437 to Unicode mapping according to the Unicode Consortium */
588 static const WCHAR cp437[] = {
589     0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
590     0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
591     0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
592     0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
593     0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
594     0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
595     0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
596     0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
597     0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
598     0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
599     0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
600     0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
601     0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
602     0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
603     0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
604     0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
605     0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
606     0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
607     0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
608     0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
609     0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
610     0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
611     0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
612     0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
613     0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
614     0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
615     0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
616     0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
617     0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
618     0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
619     0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
620     0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
621 };
622
623 void
624 g_putch(in_ch)
625 int in_ch;
626 {
627     boolean inverse = FALSE;
628     unsigned char ch = (unsigned char) in_ch;
629
630     console.cursor.X = ttyDisplay->curx;
631     console.cursor.Y = ttyDisplay->cury;
632
633     inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
634     console.attr = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse) ?
635                     ttycolors_inv[console.current_nhcolor] :
636                     ttycolors[console.current_nhcolor];
637     if (console.current_nhattr[ATR_BOLD])
638         console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
639     WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount);
640
641     if (has_unicode)
642         WriteConsoleOutputCharacterW(hConOut, &cp437[ch], 1, console.cursor, &ccount);
643     else
644         WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount);
645 }
646
647 void
648 cl_end()
649 {
650     int cx;
651     console.cursor.X = ttyDisplay->curx;
652     console.cursor.Y = ttyDisplay->cury;
653     cx = CO - console.cursor.X;
654     FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, console.cursor, &acount);
655     FillConsoleOutputCharacter(hConOut, ' ', cx, console.cursor, &ccount);
656     tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
657 }
658
659 void
660 raw_clear_screen()
661 {
662     if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
663         DWORD ccnt;
664         COORD newcoord;
665
666         newcoord.X = 0;
667         newcoord.Y = 0;
668         FillConsoleOutputAttribute(
669             hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
670             csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt);
671         FillConsoleOutputCharacter(
672             hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt);
673     }
674 }
675
676 void
677 clear_screen()
678 {
679     raw_clear_screen();
680     home();
681 }
682
683 void
684 home()
685 {
686     console.cursor.X = console.cursor.Y = 0;
687     ttyDisplay->curx = ttyDisplay->cury = 0;
688 }
689
690 void
691 backsp()
692 {
693     console.cursor.X = ttyDisplay->curx;
694     console.cursor.Y = ttyDisplay->cury;
695     xputc_core('\b');
696 }
697
698 void
699 cl_eos()
700 {
701     int cy = ttyDisplay->cury + 1;
702     if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
703         DWORD ccnt;
704         COORD newcoord;
705
706         newcoord.X = ttyDisplay->curx;
707         newcoord.Y = ttyDisplay->cury;
708         FillConsoleOutputAttribute(
709             hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
710             csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt);
711         FillConsoleOutputCharacter(hConOut, ' ',
712                                    csbi.dwSize.X * csbi.dwSize.Y - cy,
713                                    newcoord, &ccnt);
714     }
715     tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
716 }
717
718 void
719 tty_nhbell()
720 {
721     if (flags.silent)
722         return;
723     Beep(8000, 500);
724 }
725
726 volatile int junk; /* prevent optimizer from eliminating loop below */
727
728 void
729 tty_delay_output()
730 {
731     /* delay 50 ms - uses ANSI C clock() function now */
732     clock_t goal;
733     int k;
734
735     goal = 50 + clock();
736     while (goal > clock()) {
737         k = junk; /* Do nothing */
738     }
739 }
740
741 #ifdef TEXTCOLOR
742 /*
743  * CLR_BLACK            0
744  * CLR_RED              1
745  * CLR_GREEN            2
746  * CLR_BROWN            3       low-intensity yellow
747  * CLR_BLUE             4
748  * CLR_MAGENTA          5
749  * CLR_CYAN             6
750  * CLR_GRAY             7       low-intensity white
751  * NO_COLOR             8
752  * CLR_ORANGE           9
753  * CLR_BRIGHT_GREEN     10
754  * CLR_YELLOW           11
755  * CLR_BRIGHT_BLUE      12
756  * CLR_BRIGHT_MAGENTA   13
757  * CLR_BRIGHT_CYAN      14
758  * CLR_WHITE            15
759  * CLR_MAX              16
760  * BRIGHT               8
761  */
762
763 static void
764 init_ttycolor()
765 {
766 #ifdef TEXTCOLOR
767     ttycolors[CLR_BLACK]        = FOREGROUND_INTENSITY; /* fix by Quietust */
768     ttycolors[CLR_RED]          = FOREGROUND_RED;
769     ttycolors[CLR_GREEN]        = FOREGROUND_GREEN;
770     ttycolors[CLR_BROWN]        = FOREGROUND_GREEN | FOREGROUND_RED;
771     ttycolors[CLR_BLUE]         = FOREGROUND_BLUE;
772     ttycolors[CLR_MAGENTA]      = FOREGROUND_BLUE | FOREGROUND_RED;
773     ttycolors[CLR_CYAN]         = FOREGROUND_GREEN | FOREGROUND_BLUE;
774     ttycolors[CLR_GRAY]         = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
775     ttycolors[NO_COLOR]         = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
776     ttycolors[CLR_ORANGE]       = FOREGROUND_RED | FOREGROUND_INTENSITY;
777     ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
778     ttycolors[CLR_YELLOW]       = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
779     ttycolors[CLR_BRIGHT_BLUE]  = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
780     ttycolors[CLR_BRIGHT_MAGENTA]=FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
781     ttycolors[CLR_BRIGHT_CYAN]  = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
782     ttycolors[CLR_WHITE]        = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED
783                                     | FOREGROUND_INTENSITY;
784
785     ttycolors_inv[CLR_BLACK]       = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
786                                         | BACKGROUND_INTENSITY;
787     ttycolors_inv[CLR_RED]         = BACKGROUND_RED | BACKGROUND_INTENSITY;
788     ttycolors_inv[CLR_GREEN]       = BACKGROUND_GREEN;
789     ttycolors_inv[CLR_BROWN]       = BACKGROUND_GREEN | BACKGROUND_RED;
790     ttycolors_inv[CLR_BLUE]        = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
791     ttycolors_inv[CLR_MAGENTA]     = BACKGROUND_BLUE | BACKGROUND_RED;
792     ttycolors_inv[CLR_CYAN]        = BACKGROUND_GREEN | BACKGROUND_BLUE;
793     ttycolors_inv[CLR_GRAY]        = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE;
794     ttycolors_inv[NO_COLOR]        = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
795     ttycolors_inv[CLR_ORANGE]      = BACKGROUND_RED | BACKGROUND_INTENSITY;
796     ttycolors_inv[CLR_BRIGHT_GREEN]= BACKGROUND_GREEN | BACKGROUND_INTENSITY;
797     ttycolors_inv[CLR_YELLOW]      = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
798     ttycolors_inv[CLR_BRIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
799     ttycolors_inv[CLR_BRIGHT_MAGENTA] =BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
800     ttycolors_inv[CLR_BRIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
801     ttycolors_inv[CLR_WHITE]       = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
802                                        | BACKGROUND_INTENSITY;
803 #else
804     int k;
805     ttycolors[0] = FOREGROUND_INTENSITY;
806     ttycolors_inv[0] = BACKGROUND_INTENSITY;
807     for (k = 1; k < SIZE(ttycolors); ++k) {
808         ttycolors[k] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
809         ttycolors_inv[k] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
810     }
811 #endif
812     init_ttycolor_completed = TRUE;
813 }
814 #endif /* TEXTCOLOR */
815
816 int
817 has_color(int color)
818 {
819 #ifdef TEXTCOLOR
820     if ((color >= 0) && (color < CLR_MAX))
821         return 1;
822 #else
823     if ((color == CLR_BLACK) || (color == CLR_WHITE) || (color == NO_COLOR))
824         return 1;
825 #endif
826     else
827         return 0;
828 }
829
830 void
831 term_start_attr(int attrib)
832 {
833     console.current_nhattr[attrib] = TRUE;
834     if (attrib) console.current_nhattr[ATR_NONE] = FALSE;
835 }
836
837 void
838 term_end_attr(int attrib)
839 {
840     int k;
841
842     switch (attrib) {
843     case ATR_INVERSE:
844     case ATR_ULINE:
845     case ATR_BLINK:
846     case ATR_BOLD:
847         break;
848     }
849     console.current_nhattr[attrib] = FALSE;
850     console.current_nhattr[ATR_NONE] = TRUE;
851     /* re-evaluate all attr now for performance at output time */
852     for (k=ATR_NONE; k <= ATR_INVERSE; ++k) {
853         if (console.current_nhattr[k])
854             console.current_nhattr[ATR_NONE] = FALSE;
855     }
856 }
857
858 void
859 term_end_raw_bold(void)
860 {
861     term_end_attr(ATR_BOLD);
862 }
863
864 void
865 term_start_raw_bold(void)
866 {
867     term_start_attr(ATR_BOLD);
868 }
869
870 void
871 term_start_color(int color)
872 {
873 #ifdef TEXTCOLOR
874     if (color >= 0 && color < CLR_MAX) {
875         console.current_nhcolor = color;
876     } else
877 #endif
878     console.current_nhcolor = NO_COLOR;
879 }
880
881 void
882 term_end_color(void)
883 {
884 #ifdef TEXTCOLOR
885     console.foreground = DEFTEXTCOLOR;
886 #endif
887     console.attr = (console.foreground | console.background);
888     console.current_nhcolor = NO_COLOR;
889 }
890
891 void
892 standoutbeg()
893 {
894     term_start_attr(ATR_BOLD);
895 }
896
897 void
898 standoutend()
899 {
900     term_end_attr(ATR_BOLD);
901 }
902
903 #ifndef NO_MOUSE_ALLOWED
904 void
905 toggle_mouse_support()
906 {
907     DWORD cmode;
908     GetConsoleMode(hConIn, &cmode);
909     if (iflags.wc_mouse_support)
910         cmode |= ENABLE_MOUSE_INPUT;
911     else
912         cmode &= ~ENABLE_MOUSE_INPUT;
913     SetConsoleMode(hConIn, cmode);
914 }
915 #endif
916
917 /* handle tty options updates here */
918 void
919 nttty_preference_update(pref)
920 const char *pref;
921 {
922     if (stricmp(pref, "mouse_support") == 0) {
923 #ifndef NO_MOUSE_ALLOWED
924         toggle_mouse_support();
925 #endif
926     }
927     if (stricmp(pref, "symset") == 0)
928         check_and_set_font();
929     return;
930 }
931
932 #ifdef PORT_DEBUG
933 void
934 win32con_debug_keystrokes()
935 {
936     DWORD count;
937     boolean valid = 0;
938     int ch;
939     xputs("\n");
940     while (!valid || ch != 27) {
941         nocmov(ttyDisplay->curx, ttyDisplay->cury);
942         ReadConsoleInput(hConIn, &ir, 1, &count);
943         if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
944             ch = process_keystroke(&ir, &valid, iflags.num_pad, 1);
945     }
946     (void) doredraw();
947 }
948 void
949 win32con_handler_info()
950 {
951     char *buf;
952     int ci;
953     if (!pSourceAuthor && !pSourceWhere)
954         pline("Keyboard handler source info and author unavailable.");
955     else {
956         if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) {
957             xputs("\n");
958             xputs("Keystroke handler loaded: \n    ");
959             xputs(buf);
960         }
961         if (pSourceAuthor && pSourceAuthor(&buf)) {
962             xputs("\n");
963             xputs("Keystroke handler Author: \n    ");
964             xputs(buf);
965         }
966         if (pSourceWhere && pSourceWhere(&buf)) {
967             xputs("\n");
968             xputs("Keystroke handler source code available at:\n    ");
969             xputs(buf);
970         }
971         xputs("\nPress any key to resume.");
972         ci = nhgetch();
973         (void) doredraw();
974     }
975 }
976
977 void
978 win32con_toggle_cursor_info()
979 {
980     display_cursor_info = !display_cursor_info;
981 }
982 #endif
983
984 void
985 map_subkeyvalue(op)
986 register char *op;
987 {
988     char digits[] = "0123456789";
989     int length, i, idx, val;
990     char *kp;
991
992     idx = -1;
993     val = -1;
994     kp = index(op, '/');
995     if (kp) {
996         *kp = '\0';
997         kp++;
998         length = strlen(kp);
999         if (length < 1 || length > 3)
1000             return;
1001         for (i = 0; i < length; i++)
1002             if (!index(digits, kp[i]))
1003                 return;
1004         val = atoi(kp);
1005         length = strlen(op);
1006         if (length < 1 || length > 3)
1007             return;
1008         for (i = 0; i < length; i++)
1009             if (!index(digits, op[i]))
1010                 return;
1011         idx = atoi(op);
1012     }
1013     if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1)
1014         return;
1015     key_overrides[idx] = val;
1016 }
1017
1018 void
1019 load_keyboard_handler()
1020 {
1021     char suffx[] = ".dll";
1022     char *truncspot;
1023 #define MAX_DLLNAME 25
1024     char kh[MAX_ALTKEYHANDLER];
1025     if (iflags.altkeyhandler[0]) {
1026         if (hLibrary) { /* already one loaded apparently */
1027             FreeLibrary(hLibrary);
1028             hLibrary = (HANDLE) 0;
1029             pNHkbhit = (NHKBHIT) 0;
1030             pCheckInput = (CHECKINPUT) 0;
1031             pSourceWhere = (SOURCEWHERE) 0;
1032             pSourceAuthor = (SOURCEAUTHOR) 0;
1033             pKeyHandlerName = (KEYHANDLERNAME) 0;
1034             pProcessKeystroke = (PROCESS_KEYSTROKE) 0;
1035         }
1036         if ((truncspot = strstri(iflags.altkeyhandler, suffx)) != 0)
1037             *truncspot = '\0';
1038         (void) strncpy(kh, iflags.altkeyhandler,
1039                        (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
1040         kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
1041         Strcat(kh, suffx);
1042         Strcpy(iflags.altkeyhandler, kh);
1043         hLibrary = LoadLibrary(kh);
1044         if (hLibrary) {
1045             pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
1046                 hLibrary, TEXT("ProcessKeystroke"));
1047             pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit"));
1048             pCheckInput =
1049                 (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
1050             pSourceWhere =
1051                 (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
1052             pSourceAuthor =
1053                 (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
1054             pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
1055                 hLibrary, TEXT("KeyHandlerName"));
1056         }
1057     }
1058     if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
1059         if (hLibrary) {
1060             FreeLibrary(hLibrary);
1061             hLibrary = (HANDLE) 0;
1062             pNHkbhit = (NHKBHIT) 0;
1063             pCheckInput = (CHECKINPUT) 0;
1064             pSourceWhere = (SOURCEWHERE) 0;
1065             pSourceAuthor = (SOURCEAUTHOR) 0;
1066             pKeyHandlerName = (KEYHANDLERNAME) 0;
1067             pProcessKeystroke = (PROCESS_KEYSTROKE) 0;
1068         }
1069         (void) strncpy(kh, "nhdefkey.dll",
1070                        (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
1071         kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
1072         Strcpy(iflags.altkeyhandler, kh);
1073         hLibrary = LoadLibrary(kh);
1074         if (hLibrary) {
1075             pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
1076                 hLibrary, TEXT("ProcessKeystroke"));
1077             pCheckInput =
1078                 (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
1079             pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit"));
1080             pSourceWhere =
1081                 (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
1082             pSourceAuthor =
1083                 (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
1084             pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
1085                 hLibrary, TEXT("KeyHandlerName"));
1086         }
1087     }
1088     if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
1089         if (!hLibrary)
1090             raw_printf("\nNetHack was unable to load keystroke handler.\n");
1091         else {
1092             FreeLibrary(hLibrary);
1093             hLibrary = (HANDLE) 0;
1094             raw_printf("\nNetHack keystroke handler is invalid.\n");
1095         }
1096         exit(EXIT_FAILURE);
1097     }
1098 }
1099
1100 /* this is used as a printf() replacement when the window
1101  * system isn't initialized yet
1102  */
1103 void msmsg
1104 VA_DECL(const char *, fmt)
1105 {
1106     char buf[ROWNO * COLNO]; /* worst case scenario */
1107     VA_START(fmt);
1108     VA_INIT(fmt, const char *);
1109     Vsprintf(buf, fmt, VA_ARGS);
1110     if (redirect_stdout)
1111         fprintf(stdout, "%s", buf);
1112     else {
1113         if(!init_ttycolor_completed)
1114             init_ttycolor();
1115
1116 #if 0 /*JP*/
1117         xputs(buf);
1118 #else
1119         if(ttyDisplay){
1120             console.cursor.X = ttyDisplay->curx;
1121             console.cursor.Y = ttyDisplay->cury;
1122         }
1123         {
1124             char *str = buf;
1125             while(*str){
1126                 jbuffer(*(str++), NULL, (void (__cdecl *)(unsigned int))xputc_core, xputc2_core);
1127             }
1128         }
1129 #endif
1130         if (ttyDisplay)
1131             curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y);
1132     }
1133     VA_END();
1134     return;
1135 }
1136
1137 /* fatal error */
1138 /*VARARGS1*/
1139 void nttty_error
1140 VA_DECL(const char *, s)
1141 {
1142     char buf[BUFSZ];
1143     VA_START(s);
1144     VA_INIT(s, const char *);
1145     /* error() may get called before tty is initialized */
1146     if (iflags.window_inited)
1147         end_screen();
1148     buf[0] = '\n';
1149     (void) vsprintf(&buf[1], s, VA_ARGS);
1150     msmsg(buf);
1151     really_move_cursor();
1152     VA_END();
1153     exit(EXIT_FAILURE);
1154 }
1155
1156 void
1157 synch_cursor()
1158 {
1159     really_move_cursor();
1160 }
1161
1162 #ifdef CHANGE_COLOR
1163 void
1164 tty_change_color(color_number, rgb, reverse)
1165 int color_number, reverse;
1166 long rgb;
1167 {
1168     /* Map NetHack color index to NT Console palette index */
1169     int idx, win32_color_number[] = {
1170         0,  /* CLR_BLACK           0 */
1171         4,  /* CLR_RED             1 */
1172         2,  /* CLR_GREEN           2 */
1173         6,  /* CLR_BROWN           3 */
1174         1,  /* CLR_BLUE            4 */
1175         5,  /* CLR_MAGENTA         5 */
1176         3,  /* CLR_CYAN            6 */
1177         7,  /* CLR_GRAY            7 */
1178         8,  /* NO_COLOR            8 */
1179         12, /* CLR_ORANGE          9 */
1180         10, /* CLR_BRIGHT_GREEN   10 */
1181         14, /* CLR_YELLOW         11 */
1182         9,  /* CLR_BRIGHT_BLUE    12 */
1183         13, /* CLR_BRIGHT_MAGENTA 13 */
1184         11, /* CLR_BRIGHT_CYAN    14 */
1185         15  /* CLR_WHITE          15 */
1186     };
1187     int k;
1188     if (color_number < 0) { /* indicates OPTIONS=palette with no value */
1189         /* copy the NetHack palette into UserDefinedColors */
1190         for (k = 0; k < CLR_MAX; k++)
1191             UserDefinedColors[k] = NetHackColors[k];
1192     } else if (color_number >= 0 && color_number < CLR_MAX) {
1193         if (!altered_palette) {
1194             /* make sure a full suite is available */
1195             for (k = 0; k < CLR_MAX; k++)
1196                 UserDefinedColors[k] = DefaultColors[k];
1197         }
1198         idx = win32_color_number[color_number];
1199         UserDefinedColors[idx] = rgb;
1200     }
1201     altered_palette = TRUE;
1202 }
1203
1204 char *
1205 tty_get_color_string()
1206 {
1207     return "";
1208 }
1209
1210 int
1211 match_color_name(c)
1212 const char *c;
1213 {
1214     const struct others {
1215         int idx;
1216         const char *colorname;
1217     } othernames[] = {
1218         { CLR_MAGENTA, "purple" },
1219         { CLR_BRIGHT_MAGENTA, "bright purple" },
1220         { NO_COLOR, "dark gray" },
1221         { NO_COLOR, "dark grey" },
1222         { CLR_GRAY, "grey" },
1223     };
1224
1225     int cnt;
1226     for (cnt = 0; cnt < CLR_MAX; ++cnt) {
1227         if (!strcmpi(c, c_obj_colors[cnt]))
1228             return cnt;
1229     }
1230     for (cnt = 0; cnt < SIZE(othernames); ++cnt) {
1231         if (!strcmpi(c, othernames[cnt].colorname))
1232             return othernames[cnt].idx;
1233     }
1234     return -1;
1235 }
1236
1237 /*
1238  * Returns 0 if badoption syntax
1239  */
1240 int
1241 alternative_palette(op)
1242 char *op;
1243 {
1244     /*
1245      *  palette:color-R-G-B
1246      *  OPTIONS=palette:green-4-3-1, palette:0-0-0-0
1247      */
1248     int fieldcnt, color_number, rgb, red, green, blue;
1249     char *fields[4], *cp;
1250
1251     if (!op) {
1252         change_color(-1, 0, 0); /* indicates palette option with
1253                                    no value meaning "load an entire
1254                                    hard-coded NetHack palette." */
1255         return 1;
1256     }
1257
1258     cp = fields[0] = op;
1259     for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1260         cp = index(cp, '-');
1261         if (!cp)
1262             return 0;
1263         fields[fieldcnt] = cp;
1264         cp++;
1265     }
1266     for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1267         *(fields[fieldcnt]) = '\0';
1268         ++fields[fieldcnt];
1269     }
1270     rgb = 0;
1271     for (fieldcnt = 0; fieldcnt < 4; ++fieldcnt) {
1272         if (fieldcnt == 0 && isalpha(*(fields[0]))) {
1273             color_number = match_color_name(fields[0]);
1274             if (color_number == -1)
1275                 return 0;
1276         } else {
1277             int dcount = 0, cval = 0;
1278             cp = fields[fieldcnt];
1279             if (*cp == '\\' && index("0123456789xXoO", cp[1])) {
1280                 const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
1281
1282                 cp++;
1283                 if (*cp == 'x' || *cp == 'X')
1284                     for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
1285                         cval = (int) ((cval * 16) + (dp - hex) / 2);
1286                 else if (*cp == 'o' || *cp == 'O')
1287                     for (++cp; (index("01234567", *cp)) && (dcount++ < 3);
1288                          cp++)
1289                         cval = (cval * 8) + (*cp - '0');
1290                 else
1291                     return 0;
1292             } else {
1293                 for (; *cp && (index("0123456789", *cp)) && (dcount++ < 3);
1294                      cp++)
1295                     cval = (cval * 10) + (*cp - '0');
1296             }
1297             switch (fieldcnt) {
1298             case 0:
1299                 color_number = cval;
1300                 break;
1301             case 1:
1302                 red = cval;
1303                 break;
1304             case 2:
1305                 green = cval;
1306                 break;
1307             case 3:
1308                 blue = cval;
1309                 break;
1310             }
1311         }
1312     }
1313     rgb = RGB(red, green, blue);
1314     if (color_number >= 0 && color_number < CLR_MAX)
1315         change_color(color_number, rgb, 0);
1316     return 1;
1317 }
1318
1319 /*
1320  *  This uses an undocumented method to set console attributes
1321  *  at runtime including console palette
1322  *
1323  *      VOID WINAPI SetConsolePalette(COLORREF palette[16])
1324  *
1325  *  Author: James Brown at www.catch22.net
1326  *
1327  *  Set palette of current console.
1328  *  Palette should be of the form:
1329  *
1330  *      COLORREF DefaultColors[CLR_MAX] =
1331  *      {
1332  *              0x00000000, 0x00800000, 0x00008000, 0x00808000,
1333  *              0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
1334  *              0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
1335  *              0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
1336  *       };
1337  */
1338
1339 #pragma pack(push, 1)
1340
1341 /*
1342  *      Structure to send console via WM_SETCONSOLEINFO
1343  */
1344 typedef struct _CONSOLE_INFO {
1345     ULONG Length;
1346     COORD ScreenBufferSize;
1347     COORD WindowSize;
1348     ULONG WindowPosX;
1349     ULONG WindowPosY;
1350
1351     COORD FontSize;
1352     ULONG FontFamily;
1353     ULONG FontWeight;
1354     WCHAR FaceName[32];
1355
1356     ULONG CursorSize;
1357     ULONG FullScreen;
1358     ULONG QuickEdit;
1359     ULONG AutoPosition;
1360     ULONG InsertMode;
1361
1362     USHORT ScreenColors;
1363     USHORT PopupColors;
1364     ULONG HistoryNoDup;
1365     ULONG HistoryBufferSize;
1366     ULONG NumberOfHistoryBuffers;
1367
1368     COLORREF ColorTable[16];
1369
1370     ULONG CodePage;
1371     HWND Hwnd;
1372
1373     WCHAR ConsoleTitle[0x100];
1374 } CONSOLE_INFO;
1375
1376 #pragma pack(pop)
1377
1378 BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci);
1379 static void GetConsoleSizeInfo(CONSOLE_INFO *pci);
1380 VOID WINAPI SetConsolePalette(COLORREF crPalette[16]);
1381
1382 void
1383 adjust_palette(VOID_ARGS)
1384 {
1385     SetConsolePalette(UserDefinedColors);
1386     altered_palette = 0;
1387 }
1388
1389 /*
1390 /* only in Win2k+  (use FindWindow for NT4) */
1391 /* HWND WINAPI GetConsoleWindow(); */
1392
1393 /*  Undocumented console message */
1394 #define WM_SETCONSOLEINFO (WM_USER + 201)
1395
1396 VOID WINAPI
1397 SetConsolePalette(COLORREF palette[16])
1398 {
1399     CONSOLE_INFO ci = { sizeof(ci) };
1400     int i;
1401     HWND hwndConsole = GetConsoleHandle();
1402
1403     /* get current size/position settings rather than using defaults.. */
1404     GetConsoleSizeInfo(&ci);
1405
1406     /* set these to zero to keep current settings */
1407     ci.FontSize.X = 0; /* def = 8  */
1408     ci.FontSize.Y = 0; /* def = 12 */
1409     ci.FontFamily = 0; /* def = 0x30 = FF_MODERN|FIXED_PITCH */
1410     ci.FontWeight = 0; /* 0x400;   */
1411     /* lstrcpyW(ci.FaceName, L"Terminal"); */
1412     ci.FaceName[0] = L'\0';
1413
1414     ci.CursorSize = 25;
1415     ci.FullScreen = FALSE;
1416     ci.QuickEdit = TRUE;
1417     ci.AutoPosition = 0x10000;
1418     ci.InsertMode = TRUE;
1419     ci.ScreenColors = MAKEWORD(0x7, 0x0);
1420     ci.PopupColors = MAKEWORD(0x5, 0xf);
1421
1422     ci.HistoryNoDup = FALSE;
1423     ci.HistoryBufferSize = 50;
1424     ci.NumberOfHistoryBuffers = 4;
1425
1426     // colour table
1427     for (i = 0; i < 16; i++)
1428         ci.ColorTable[i] = palette[i];
1429
1430     ci.CodePage = GetConsoleOutputCP();
1431     ci.Hwnd = hwndConsole;
1432
1433     lstrcpyW(ci.ConsoleTitle, L"");
1434
1435     SetConsoleInfo(hwndConsole, &ci);
1436 }
1437
1438 /*
1439  *  Wrapper around WM_SETCONSOLEINFO. We need to create the
1440  *  necessary section (file-mapping) object in the context of the
1441  *  process which owns the console, before posting the message
1442  */
1443 BOOL
1444 SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci)
1445 {
1446     DWORD dwConsoleOwnerPid;
1447     HANDLE hProcess;
1448     HANDLE hSection, hDupSection;
1449     PVOID ptrView = 0;
1450     HANDLE hThread;
1451
1452     /*
1453      *  Open the process which "owns" the console
1454      */
1455     GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid);
1456     hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
1457
1458     /*
1459      * Create a SECTION object backed by page-file, then map a view of
1460      * this section into the owner process so we can write the contents
1461      * of the CONSOLE_INFO buffer into it
1462      */
1463     hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
1464                                  pci->Length, 0);
1465
1466     /*
1467      *  Copy our console structure into the section-object
1468      */
1469     ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
1470                             pci->Length);
1471     memcpy(ptrView, pci, pci->Length);
1472     UnmapViewOfFile(ptrView);
1473
1474     /*
1475      *  Map the memory into owner process
1476      */
1477     DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection, 0,
1478                     FALSE, DUPLICATE_SAME_ACCESS);
1479
1480     /*  Send console window the "update" message */
1481     SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM) hDupSection, 0);
1482
1483     /*
1484      * clean up
1485      */
1486     hThread = CreateRemoteThread(hProcess, 0, 0,
1487                                  (LPTHREAD_START_ROUTINE) CloseHandle,
1488                                  hDupSection, 0, 0);
1489
1490     CloseHandle(hThread);
1491     CloseHandle(hSection);
1492     CloseHandle(hProcess);
1493
1494     return TRUE;
1495 }
1496
1497 /*
1498  *  Fill the CONSOLE_INFO structure with information
1499  *  about the current console window
1500  */
1501 static void
1502 GetConsoleSizeInfo(CONSOLE_INFO *pci)
1503 {
1504     CONSOLE_SCREEN_BUFFER_INFO csbi;
1505
1506     HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
1507
1508     GetConsoleScreenBufferInfo(hConsoleOut, &csbi);
1509
1510     pci->ScreenBufferSize = csbi.dwSize;
1511     pci->WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
1512     pci->WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
1513     pci->WindowPosX = csbi.srWindow.Left;
1514     pci->WindowPosY = csbi.srWindow.Top;
1515 }
1516
1517 static HWND
1518 GetConsoleHandle(void)
1519 {
1520     HMODULE hMod = GetModuleHandle("kernel32.dll");
1521     GETCONSOLEWINDOW pfnGetConsoleWindow =
1522         (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
1523     if (pfnGetConsoleWindow)
1524         return pfnGetConsoleWindow();
1525     else
1526         return GetConsoleHwnd();
1527 }
1528
1529 static HWND
1530 GetConsoleHwnd(void)
1531 {
1532     int iterations = 0;
1533     HWND hwndFound = 0;
1534     char OldTitle[1024], NewTitle[1024], TestTitle[1024];
1535
1536     /* Get current window title */
1537     GetConsoleTitle(OldTitle, sizeof OldTitle);
1538
1539     (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
1540                    GetCurrentProcessId());
1541     SetConsoleTitle(NewTitle);
1542
1543     GetConsoleTitle(TestTitle, sizeof TestTitle);
1544     while (strcmp(TestTitle, NewTitle) != 0) {
1545         iterations++;
1546         /* sleep(0); */
1547         GetConsoleTitle(TestTitle, sizeof TestTitle);
1548     }
1549     hwndFound = FindWindow(NULL, NewTitle);
1550     SetConsoleTitle(OldTitle);
1551     /*       printf("%d iterations\n", iterations); */
1552     return hwndFound;
1553 }
1554 #endif /*CHANGE_COLOR*/
1555
1556 static int CALLBACK EnumFontCallback(
1557     const LOGFONTW * lf, const TEXTMETRICW * tm, DWORD fontType, LPARAM lParam)
1558 {
1559     LOGFONTW * lf_ptr = (LOGFONTW *) lParam;
1560     *lf_ptr = *lf;
1561     return 0;
1562 }
1563
1564 /* check_and_set_font ensures that the current font will render the symbols
1565  * that are currently being used correctly.  If they will not be rendered
1566  * correctly, then it will change the font to a known good font.
1567  */
1568 void
1569 check_and_set_font()
1570 {
1571 #if 0 /*JP*//* \83R\81[\83h\83y\81[\83W\82Í\95Ï\8dX\82µ\82È\82¢\81B932\82ð\89¼\92è\82·\82é\81B*/
1572     if (!check_font_widths()) {
1573         raw_print("WARNING: glyphs too wide in console font."
1574                   "  Changing code page to 437 and font to Consolas\n");
1575         set_known_good_console_font();
1576     }
1577 #endif
1578 }
1579
1580 /* check_font_widths returns TRUE if all glyphs in current console font
1581  * fit within the width of a single console cell.
1582  */
1583 boolean
1584 check_font_widths()
1585 {
1586     CONSOLE_FONT_INFOEX console_font_info;
1587     console_font_info.cbSize = sizeof(console_font_info);
1588     BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE,
1589                                             &console_font_info);
1590
1591     /* get console window and DC
1592      * NOTE: the DC from the console window does not have the correct
1593      *       font selected at this point.
1594      */
1595     HWND hWnd = GetConsoleWindow();
1596     HDC hDC = GetDC(hWnd);
1597
1598     LOGFONTW logical_font;
1599     logical_font.lfCharSet = DEFAULT_CHARSET;
1600     wcscpy(logical_font.lfFaceName, console_font_info.FaceName);
1601     logical_font.lfPitchAndFamily = 0;
1602
1603     /* getting matching console font */
1604     LOGFONTW matching_log_font = { 0 };
1605     EnumFontFamiliesExW(hDC, &logical_font, EnumFontCallback,
1606                                         (LPARAM) &matching_log_font, 0);
1607
1608     if (matching_log_font.lfHeight == 0) {
1609         raw_print("Unable to enumerate system fonts\n");
1610         return FALSE;
1611     }
1612
1613     /* create font matching console font */
1614     LOGFONTW console_font_log_font = matching_log_font;
1615     console_font_log_font.lfWeight = console_font_info.FontWeight;
1616     console_font_log_font.lfHeight = console_font_info.dwFontSize.Y;
1617     console_font_log_font.lfWidth = 0;
1618     HFONT console_font = CreateFontIndirectW(&console_font_log_font);
1619
1620     if (console_font == NULL) {
1621         raw_print("Unable to create console font\n");
1622         return FALSE;
1623     }
1624
1625     /* select font */
1626     HGDIOBJ saved_font = SelectObject(hDC, console_font);
1627
1628     /* determine whether it is a true type font */
1629     TEXTMETRICA tm;
1630     success = GetTextMetricsA(hDC, &tm);
1631
1632     if (!success) {
1633         raw_print("Unable to get console font text metrics\n");
1634         goto clean_up;
1635     }
1636
1637     boolean isTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
1638
1639     /* determine which glyphs are used */
1640     boolean used[256];
1641     memset(used, 0, sizeof(used));
1642     for (int i = 0; i < SYM_MAX; i++) {
1643         used[l_syms[i]] = TRUE;
1644         used[r_syms[i]] = TRUE;
1645     }
1646
1647     int wcUsedCount = 0;
1648     wchar_t wcUsed[256];
1649     for (int i = 0; i < sizeof(used); i++)
1650         if (used[i])
1651             wcUsed[wcUsedCount++] = cp437[i];
1652
1653     /* measure the set of used glyphs to ensure they fit */
1654     boolean all_glyphs_fit = TRUE;
1655
1656     for (int i = 0; i < wcUsedCount; i++) {
1657         int width;
1658         if (isTrueType) {
1659             ABC abc;
1660             success = GetCharABCWidthsW(hDC, wcUsed[i], wcUsed[i], &abc);
1661             width = abc.abcA + abc.abcB + abc.abcC;
1662         } else {
1663             success = GetCharWidthW(hDC, wcUsed[i], wcUsed[i], &width);
1664         }
1665
1666         if (success && width > console_font_info.dwFontSize.X) {
1667             all_glyphs_fit = FALSE;
1668             break;
1669         }
1670     }
1671
1672 clean_up:
1673
1674     SelectObject(hDC, saved_font);
1675     DeleteObject(console_font);
1676
1677     return all_glyphs_fit;
1678 }
1679
1680 /* set_known_good_console_font sets the code page and font used by the console
1681  * to settings know to work well with NetHack.  It also saves the original
1682  * settings so that they can be restored prior to NetHack exit.
1683  */
1684 void
1685 set_known_good_console_font()
1686 {
1687     CONSOLE_FONT_INFOEX console_font_info;
1688     console_font_info.cbSize = sizeof(console_font_info);
1689     BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE,
1690                                             &console_font_info);
1691
1692     console_font_changed = TRUE;
1693     original_console_font_info = console_font_info;
1694     original_console_code_page = GetConsoleOutputCP();
1695
1696     wcscpy_s(console_font_info.FaceName,
1697         sizeof(console_font_info.FaceName)
1698             / sizeof(console_font_info.FaceName[0]),
1699         L"Consolas");
1700
1701     success = SetConsoleOutputCP(437);
1702     if (!success)
1703         raw_print("Unable to set console code page to 437\n");
1704
1705     success = SetCurrentConsoleFontEx(hConOut, FALSE, &console_font_info);
1706     if (!success)
1707         raw_print("Unable to set console font to Consolas\n");
1708 }
1709
1710 /* restore_original_console_font will restore the console font and code page
1711  * settings to what they were when NetHack was launched.
1712  */
1713 void
1714 restore_original_console_font()
1715 {
1716     if (console_font_changed) {
1717         BOOL success;
1718         raw_print("Restoring original font and code page\n");
1719         success = SetConsoleOutputCP(original_console_code_page);
1720         if (!success)
1721             raw_print("Unable to restore original code page\n");
1722
1723         success = SetCurrentConsoleFontEx(hConOut, FALSE,
1724                                             &original_console_font_info);
1725         if (!success)
1726             raw_print("Unable to restore original font\n");
1727
1728         console_font_changed = FALSE;
1729     }
1730 }
1731
1732 #endif /* WIN32 */