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. */
5 /* tty.c - (Windows NT) version */
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
16 #define NEED_VARARGS /* Uses ... */
19 #include <sys\types.h>
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));
29 * The following WIN32 Console API routines are used in this file.
32 * GetConsoleScreenBufferInfo
34 * SetConsoleCursorPosition
35 * SetConsoleTextAttribute
36 * SetConsoleCtrlHandler
39 * WriteConsoleOutputCharacter
40 * FillConsoleOutputAttribute
44 /* Win32 Console handles for input and output */
48 /* Win32 Screen buffer,coordinate,console I/O information */
49 CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi;
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.
61 extern int redirect_stdout;
62 static BOOL FDECL(CtrlHandler, (DWORD));
64 /* Flag for whether unicode is supported */
65 static boolean has_unicode;
68 static boolean display_cursor_info = FALSE;
71 extern boolean getreturn_enabled; /* from sys/share/pcsys.c */
73 /* dynamic keystroke handling .DLL support */
74 typedef int(__stdcall *PROCESS_KEYSTROKE)(HANDLE, INPUT_RECORD *, boolean *,
77 typedef int(__stdcall *NHKBHIT)(HANDLE, INPUT_RECORD *);
79 typedef int(__stdcall *CHECKINPUT)(HANDLE, INPUT_RECORD *, DWORD *, BOOLEAN_P,
82 typedef int(__stdcall *SOURCEWHERE)(char **);
84 typedef int(__stdcall *SOURCEAUTHOR)(char **);
86 typedef int(__stdcall *KEYHANDLERNAME)(char **, int);
89 PROCESS_KEYSTROKE pProcessKeystroke;
91 CHECKINPUT pCheckInput;
92 SOURCEWHERE pSourceWhere;
93 SOURCEAUTHOR pSourceAuthor;
94 KEYHANDLERNAME pKeyHandlerName;
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
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
119 int ttycolors[CLR_MAX];
121 static void NDECL(init_ttycolor);
123 static void NDECL(really_move_cursor);
125 #define MAX_OVERRIDES 256
126 unsigned char key_overrides[MAX_OVERRIDES];
128 static char nullstr[] = "";
129 char erase_char, kill_char;
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 };
140 * Called after returning from ! or ^Z
149 kill_char = 21; /* cntl-U */
150 iflags.cbreak = TRUE;
154 for (k = 0; k < CLR_MAX; ++k)
159 /* reset terminal to original state */
164 cmov(ttyDisplay->curx, ttyDisplay->cury);
170 /* called by init_nhwindows() and resume_nhwindows() */
179 has_unicode = ((GetVersion() & 0x80000000) == 0);
183 tty_startup(wid, hgt)
186 int twid = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1;
191 *hgt = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1;
192 set_option_mod_status("mouse_support", SET_IN_GAME);
196 tty_number_pad(state)
205 tty_number_pad(1); /* make keypad send digits */
212 really_move_cursor();
213 if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
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);
225 FlushConsoleInputBuffer(hConIn);
229 CtrlHandler(ctrltype)
233 /* case CTRL_C_EVENT: */
234 case CTRL_BREAK_EVENT:
236 case CTRL_CLOSE_EVENT:
237 case CTRL_LOGOFF_EVENT:
238 case CTRL_SHUTDOWN_EVENT:
239 getreturn_enabled = FALSE;
240 #ifndef NOSAVEONHANGUP
243 #if defined(SAFERHANGUP)
244 CloseHandle(hConIn); /* trigger WAIT_FAILED */
252 /* called by init_tty in wintty.c for WIN32 port only */
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
269 = GetStdHandle(STD_OUTPUT_HANDLE);
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))
277 HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
278 HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
280 if (!hStdOut && !hStdIn) {
283 AttachConsole(GetCurrentProcessId());
284 /* rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */
285 freopen("CON", "w", stdout);
286 freopen("CON", "r", stdin);
294 load_keyboard_handler();
295 /* Initialize the function pointer that points to
296 * the kbhit() equivalent, in this TTY case nttty_kbhit()
298 nt_kbhit = nttty_kbhit;
300 /* Obtain handles for the standard Console I/O devices */
301 hConIn = GetStdHandle(STD_INPUT_HANDLE);
302 hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
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);
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;
319 mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
320 | ENABLE_WINDOW_INPUT;
322 /* Turn OFF the settings specified in the mask */
324 #ifndef NO_MOUSE_ALLOWED
325 cmode |= ENABLE_MOUSE_INPUT;
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 */
333 cursor.X = cursor.Y = 0;
334 really_move_cursor();
338 process_keystroke(ir, valid, numberpad, portdebug)
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];
354 return pNHkbhit(hConIn, &ir);
360 GetConsoleScreenBufferInfo(hConOut, &csbi);
362 LI = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1);
363 CO = csbi.srWindow.Right - (csbi.srWindow.Left + 1);
365 if ((LI < 25) || (CO < 80)) {
374 SetConsoleScreenBufferSize(hConOut, newcoord);
384 really_move_cursor();
385 return (program_state.done_hup)
387 : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 0, &mod,
398 really_move_cursor();
399 ch = (program_state.done_hup)
401 : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc);
413 char oldtitle[BUFSZ], newtitle[BUFSZ];
414 if (display_cursor_info && wizard) {
416 if (GetConsoleTitle(oldtitle, BUFSZ)) {
419 Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle,
420 ttyDisplay->curx, ttyDisplay->cury, cursor.X, cursor.Y);
421 (void) SetConsoleTitle(newtitle);
425 cursor.X = ttyDisplay->curx;
426 cursor.Y = ttyDisplay->cury;
428 SetConsoleCursorPosition(hConOut, cursor);
435 ttyDisplay->cury = y;
436 ttyDisplay->curx = x;
447 ttyDisplay->curx = x;
448 ttyDisplay->cury = y;
466 WriteConsoleOutputAttribute(hConOut, &attr, 1, cursor, &acount);
468 /* Avoid bug in ANSI API on WinNT */
471 rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, &ch, 1, c2, 2);
472 WriteConsoleOutputCharacterW(hConOut, c2, rc, cursor, &ccount);
474 WriteConsoleOutputCharacterA(hConOut, &ch, 1, cursor, &ccount);
484 cursor.X = ttyDisplay->curx;
485 cursor.Y = ttyDisplay->cury;
491 xputc2_core(ch1, ch2)
495 unsigned char buf[2];
501 attrs[0] = attrs[1] = attr;
503 WriteConsoleOutputAttribute(hConOut,(WORD *)(&attrs),2,
505 WriteConsoleOutputCharacter(hConOut,buf,2,
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;
521 xputc2_core(ch1, ch2);
530 int slen = strlen(s);
533 cursor.X = ttyDisplay->curx;
534 cursor.Y = ttyDisplay->cury;
538 for (k = 0; k < slen && s[k]; ++k)
544 * Overrides wintty.c function of the same name
545 * for win32. It is used for glyphs only, not text.
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
586 unsigned char ch = (unsigned char) in_ch;
588 cursor.X = ttyDisplay->curx;
589 cursor.Y = ttyDisplay->cury;
590 WriteConsoleOutputAttribute(hConOut, &attr, 1, cursor, &acount);
592 WriteConsoleOutputCharacterW(hConOut, &cp437[ch], 1, cursor, &ccount);
594 WriteConsoleOutputCharacterA(hConOut, &ch, 1, cursor, &ccount);
601 cursor.X = ttyDisplay->curx;
602 cursor.Y = ttyDisplay->cury;
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);
612 if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
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);
636 cursor.X = cursor.Y = 0;
637 ttyDisplay->curx = ttyDisplay->cury = 0;
643 cursor.X = ttyDisplay->curx;
644 cursor.Y = ttyDisplay->cury;
651 int cy = ttyDisplay->cury + 1;
652 if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
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,
665 tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
676 volatile int junk; /* prevent optimizer from eliminating loop below */
681 /* delay 50 ms - uses ANSI C clock() function now */
686 while (goal > clock()) {
687 k = junk; /* Do nothing */
696 * CLR_BROWN 3 low-intensity yellow
700 * CLR_GRAY 7 low-intensity white
703 * CLR_BRIGHT_GREEN 10
706 * CLR_BRIGHT_MAGENTA 13
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;
738 #endif /* TEXTCOLOR */
746 if (color == CLR_BLACK)
748 else if (color == CLR_WHITE)
756 term_start_attr(int attrib)
760 if (iflags.wc_inverse) {
761 /* Suggestion by Lee Berger */
763 & (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED))
764 == (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED))
766 ~(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
768 (BACKGROUND_RED | BACKGROUND_BLUE | BACKGROUND_GREEN);
775 foreground |= FOREGROUND_INTENSITY;
778 foreground &= ~FOREGROUND_INTENSITY;
781 attr = (foreground | background);
785 term_end_attr(int attrib)
790 & (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED)) == 0)
792 (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED);
798 foreground &= ~FOREGROUND_INTENSITY;
801 attr = (foreground | background);
805 term_end_raw_bold(void)
807 term_end_attr(ATR_BOLD);
811 term_start_raw_bold(void)
813 term_start_attr(ATR_BOLD);
817 term_start_color(int color)
820 if (color >= 0 && color < CLR_MAX) {
822 (background != 0 && (color == CLR_GRAY || color == CLR_WHITE))
827 foreground = DEFTEXTCOLOR;
829 attr = (foreground | background);
836 foreground = DEFTEXTCOLOR;
838 attr = (foreground | background);
844 term_start_attr(ATR_BOLD);
850 term_end_attr(ATR_BOLD);
853 #ifndef NO_MOUSE_ALLOWED
855 toggle_mouse_support()
858 GetConsoleMode(hConIn, &cmode);
859 if (iflags.wc_mouse_support)
860 cmode |= ENABLE_MOUSE_INPUT;
862 cmode &= ~ENABLE_MOUSE_INPUT;
863 SetConsoleMode(hConIn, cmode);
867 /* handle tty options updates here */
869 nttty_preference_update(pref)
872 if (stricmp(pref, "mouse_support") == 0) {
873 #ifndef NO_MOUSE_ALLOWED
874 toggle_mouse_support();
882 win32con_debug_keystrokes()
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);
897 win32con_handler_info()
901 if (!pSourceAuthor && !pSourceWhere)
902 pline("Keyboard handler source info and author unavailable.");
904 if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) {
906 xputs("Keystroke handler loaded: \n ");
909 if (pSourceAuthor && pSourceAuthor(&buf)) {
911 xputs("Keystroke handler Author: \n ");
914 if (pSourceWhere && pSourceWhere(&buf)) {
916 xputs("Keystroke handler source code available at:\n ");
919 xputs("\nPress any key to resume.");
926 win32con_toggle_cursor_info()
928 display_cursor_info = !display_cursor_info;
936 char digits[] = "0123456789";
937 int length, i, idx, val;
947 if (length < 1 || length > 3)
949 for (i = 0; i < length; i++)
950 if (!index(digits, kp[i]))
954 if (length < 1 || length > 3)
956 for (i = 0; i < length; i++)
957 if (!index(digits, op[i]))
961 if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1)
963 key_overrides[idx] = val;
967 load_keyboard_handler()
969 char suffx[] = ".dll";
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;
984 if ((truncspot = strstri(iflags.altkeyhandler, suffx)) != 0)
986 (void) strncpy(kh, iflags.altkeyhandler,
987 (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
988 kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
990 Strcpy(iflags.altkeyhandler, kh);
991 hLibrary = LoadLibrary(kh);
993 pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
994 hLibrary, TEXT("ProcessKeystroke"));
995 pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit"));
997 (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
999 (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
1001 (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
1002 pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
1003 hLibrary, TEXT("KeyHandlerName"));
1006 if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
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;
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);
1023 pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
1024 hLibrary, TEXT("ProcessKeystroke"));
1026 (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
1027 pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit"));
1029 (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
1031 (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
1032 pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
1033 hLibrary, TEXT("KeyHandlerName"));
1036 if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
1038 raw_printf("\nNetHack was unable to load keystroke handler.\n");
1040 FreeLibrary(hLibrary);
1041 hLibrary = (HANDLE) 0;
1042 raw_printf("\nNetHack keystroke handler is invalid.\n");
1048 /* this is used as a printf() replacement when the window
1049 * system isn't initialized yet
1052 VA_DECL(const char *, fmt)
1054 char buf[ROWNO * COLNO]; /* worst case scenario */
1056 VA_INIT(fmt, const char *);
1057 Vsprintf(buf, fmt, VA_ARGS);
1058 if (redirect_stdout)
1059 fprintf(stdout, "%s", buf);
1065 cursor.X = ttyDisplay->curx;
1066 cursor.Y = ttyDisplay->cury;
1071 jbuffer(*(str++), NULL, xputc_core, xputc2_core);
1076 curs(BASE_WINDOW, cursor.X + 1, cursor.Y);
1085 VA_DECL(const char *, s)
1089 VA_INIT(s, const char *);
1090 /* error() may get called before tty is initialized */
1091 if (iflags.window_inited)
1094 (void) vsprintf(&buf[1], s, VA_ARGS);
1096 really_move_cursor();
1104 really_move_cursor();
1109 tty_change_color(color_number, rgb, reverse)
1110 int color_number, reverse;
1113 /* Map NetHack color index to NT Console palette index */
1114 int idx, win32_color_number[] = {
1115 0, /* CLR_BLACK 0 */
1117 2, /* CLR_GREEN 2 */
1118 6, /* CLR_BROWN 3 */
1120 5, /* CLR_MAGENTA 5 */
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 */
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];
1143 idx = win32_color_number[color_number];
1144 UserDefinedColors[idx] = rgb;
1146 altered_palette = TRUE;
1150 tty_get_color_string()
1159 const struct others {
1161 const char *colorname;
1163 { CLR_MAGENTA, "purple" },
1164 { CLR_BRIGHT_MAGENTA, "bright purple" },
1165 { NO_COLOR, "dark gray" },
1166 { NO_COLOR, "dark grey" },
1167 { CLR_GRAY, "grey" },
1171 for (cnt = 0; cnt < CLR_MAX; ++cnt) {
1172 if (!strcmpi(c, c_obj_colors[cnt]))
1175 for (cnt = 0; cnt < SIZE(othernames); ++cnt) {
1176 if (!strcmpi(c, othernames[cnt].colorname))
1177 return othernames[cnt].idx;
1183 * Returns 0 if badoption syntax
1186 alternative_palette(op)
1190 * palette:color-R-G-B
1191 * OPTIONS=palette:green-4-3-1, palette:0-0-0-0
1193 int fieldcnt, color_number, rgb, red, green, blue;
1194 char *fields[4], *cp;
1197 change_color(-1, 0, 0); /* indicates palette option with
1198 no value meaning "load an entire
1199 hard-coded NetHack palette." */
1203 cp = fields[0] = op;
1204 for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1205 cp = index(cp, '-');
1208 fields[fieldcnt] = cp;
1211 for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1212 *(fields[fieldcnt]) = '\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)
1222 int dcount = 0, cval = 0;
1223 cp = fields[fieldcnt];
1224 if (*cp == '\\' && index("0123456789xXoO", cp[1])) {
1225 const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
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);
1234 cval = (cval * 8) + (*cp - '0');
1238 for (; *cp && (index("0123456789", *cp)) && (dcount++ < 3);
1240 cval = (cval * 10) + (*cp - '0');
1244 color_number = cval;
1258 rgb = RGB(red, green, blue);
1259 if (color_number >= 0 && color_number < CLR_MAX)
1260 change_color(color_number, rgb, 0);
1265 * This uses an undocumented method to set console attributes
1266 * at runtime including console palette
1268 * VOID WINAPI SetConsolePalette(COLORREF palette[16])
1270 * Author: James Brown at www.catch22.net
1272 * Set palette of current console.
1273 * Palette should be of the form:
1275 * COLORREF DefaultColors[CLR_MAX] =
1277 * 0x00000000, 0x00800000, 0x00008000, 0x00808000,
1278 * 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
1279 * 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
1280 * 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
1284 #pragma pack(push, 1)
1287 * Structure to send console via WM_SETCONSOLEINFO
1289 typedef struct _CONSOLE_INFO {
1291 COORD ScreenBufferSize;
1307 USHORT ScreenColors;
1310 ULONG HistoryBufferSize;
1311 ULONG NumberOfHistoryBuffers;
1313 COLORREF ColorTable[16];
1318 WCHAR ConsoleTitle[0x100];
1323 BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci);
1324 static void GetConsoleSizeInfo(CONSOLE_INFO *pci);
1325 VOID WINAPI SetConsolePalette(COLORREF crPalette[16]);
1328 adjust_palette(VOID_ARGS)
1330 SetConsolePalette(UserDefinedColors);
1331 altered_palette = 0;
1335 /* only in Win2k+ (use FindWindow for NT4) */
1336 /* HWND WINAPI GetConsoleWindow(); */
1338 /* Undocumented console message */
1339 #define WM_SETCONSOLEINFO (WM_USER + 201)
1342 SetConsolePalette(COLORREF palette[16])
1344 CONSOLE_INFO ci = { sizeof(ci) };
1346 HWND hwndConsole = GetConsoleHandle();
1348 /* get current size/position settings rather than using defaults.. */
1349 GetConsoleSizeInfo(&ci);
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';
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);
1367 ci.HistoryNoDup = FALSE;
1368 ci.HistoryBufferSize = 50;
1369 ci.NumberOfHistoryBuffers = 4;
1372 for (i = 0; i < 16; i++)
1373 ci.ColorTable[i] = palette[i];
1375 ci.CodePage = GetConsoleOutputCP();
1376 ci.Hwnd = hwndConsole;
1378 lstrcpyW(ci.ConsoleTitle, L"");
1380 SetConsoleInfo(hwndConsole, &ci);
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
1389 SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci)
1391 DWORD dwConsoleOwnerPid;
1393 HANDLE hSection, hDupSection;
1398 * Open the process which "owns" the console
1400 GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid);
1401 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
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
1408 hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
1412 * Copy our console structure into the section-object
1414 ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
1416 memcpy(ptrView, pci, pci->Length);
1417 UnmapViewOfFile(ptrView);
1420 * Map the memory into owner process
1422 DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection, 0,
1423 FALSE, DUPLICATE_SAME_ACCESS);
1425 /* Send console window the "update" message */
1426 SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM) hDupSection, 0);
1431 hThread = CreateRemoteThread(hProcess, 0, 0,
1432 (LPTHREAD_START_ROUTINE) CloseHandle,
1435 CloseHandle(hThread);
1436 CloseHandle(hSection);
1437 CloseHandle(hProcess);
1443 * Fill the CONSOLE_INFO structure with information
1444 * about the current console window
1447 GetConsoleSizeInfo(CONSOLE_INFO *pci)
1449 CONSOLE_SCREEN_BUFFER_INFO csbi;
1451 HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
1453 GetConsoleScreenBufferInfo(hConsoleOut, &csbi);
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;
1463 GetConsoleHandle(void)
1465 HMODULE hMod = GetModuleHandle("kernel32.dll");
1466 GETCONSOLEWINDOW pfnGetConsoleWindow =
1467 (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
1468 if (pfnGetConsoleWindow)
1469 return pfnGetConsoleWindow();
1471 return GetConsoleHwnd();
1475 GetConsoleHwnd(void)
1479 char OldTitle[1024], NewTitle[1024], TestTitle[1024];
1481 /* Get current window title */
1482 GetConsoleTitle(OldTitle, sizeof OldTitle);
1484 (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
1485 GetCurrentProcessId());
1486 SetConsoleTitle(NewTitle);
1488 GetConsoleTitle(TestTitle, sizeof TestTitle);
1489 while (strcmp(TestTitle, NewTitle) != 0) {
1492 GetConsoleTitle(TestTitle, sizeof TestTitle);
1494 hwndFound = FindWindow(NULL, NewTitle);
1495 SetConsoleTitle(OldTitle);
1496 /* printf("%d iterations\n", iterations); */
1499 #endif /*CHANGE_COLOR*/