OSDN Git Service

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