1 /* NetHack 3.6 nttty.c $NHDT-Date: 1554215932 2019/04/02 14:38:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.99 $ */
2 /* Copyright (c) NetHack PC Development Team 1993 */
3 /* NetHack may be freely redistributed. See license for details. */
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
12 * Use of back buffer to improve performance B. House 2018/05/06
17 #define NEED_VARARGS /* Uses ... */
22 #include <sys\types.h>
25 extern boolean getreturn_enabled; /* from sys/share/pcsys.c */
26 extern int redirect_stdout;
30 * Console Buffer Flipping Support
32 * To minimize the number of calls into the WriteConsoleOutputXXX methods,
33 * we implement a notion of a console back buffer which keeps the next frame
34 * of console output as it is being composed. When ready to show the new
35 * frame, we compare this next frame to what is currently being output and
36 * only call WriteConsoleOutputXXX for those console values that need to
41 #define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \
43 #define CONSOLE_CLEAR_CHARACTER (' ')
45 #define CONSOLE_UNDEFINED_ATTRIBUTE (0)
46 #define CONSOLE_UNDEFINED_CHARACTER ('\0')
57 cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE };
58 cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
59 CONSOLE_UNDEFINED_ATTRIBUTE };
61 cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE, 0 };
62 cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
63 CONSOLE_UNDEFINED_ATTRIBUTE, 0 };
67 * The following WIN32 Console API routines are used in this file.
70 * GetConsoleScreenBufferInfo
72 * SetConsoleCursorPosition
73 * SetConsoleTextAttribute
74 * SetConsoleCtrlHandler
77 * WriteConsoleOutputCharacter
78 * FillConsoleOutputAttribute
82 static BOOL FDECL(CtrlHandler, (DWORD));
83 static void FDECL(xputc_core, (char));
85 static void FDECL(xputc2_core, (unsigned int, unsigned int));
87 void FDECL(cmov, (int, int));
88 void FDECL(nocmov, (int, int));
89 int FDECL(process_keystroke,
90 (INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug));
91 static void NDECL(init_ttycolor);
92 static void NDECL(really_move_cursor);
93 static void NDECL(check_and_set_font);
95 static boolean NDECL(check_font_widths);
97 static void NDECL(set_known_good_console_font);
98 static void NDECL(restore_original_console_font);
99 extern void NDECL(safe_routines);
101 /* Win32 Screen buffer,coordinate,console I/O information */
104 static boolean orig_QuickEdit;
106 /* Support for changing console font if existing glyph widths are too wide */
108 /* Flag for whether NetHack was launched via the GUI, not the command line.
109 * The reason we care at all, is so that we can get
110 * a final RETURN at the end of the game when launched from the GUI
111 * to prevent the scoreboard (or panic message :-|) from vanishing
112 * immediately after it is displayed, yet not bother when started
113 * from the command line.
115 int GUILaunched = FALSE;
116 /* Flag for whether unicode is supported */
117 static boolean init_ttycolor_completed;
119 static boolean display_cursor_info = FALSE;
122 static void NDECL(adjust_palette);
123 static int FDECL(match_color_name, (const char *));
124 typedef HWND(WINAPI *GETCONSOLEWINDOW)();
125 static HWND GetConsoleHandle(void);
126 static HWND GetConsoleHwnd(void);
127 static boolean altered_palette;
128 static COLORREF UserDefinedColors[CLR_MAX];
129 static COLORREF NetHackColors[CLR_MAX] = {
130 0x00000000, 0x00c80000, 0x0000c850, 0x00b4b432, 0x000000d2, 0x00800080,
131 0x000064b4, 0x00c0c0c0, 0x00646464, 0x00f06464, 0x0000ff00, 0x00ffff00,
132 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
134 static COLORREF DefaultColors[CLR_MAX] = {
135 0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080,
136 0x00008080, 0x00c0c0c0, 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
137 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
145 int current_nhattr[ATR_INVERSE+1];
149 CONSOLE_SCREEN_BUFFER_INFO origcsbi;
154 cell_t * front_buffer;
155 cell_t * back_buffer;
157 boolean font_changed;
158 CONSOLE_FONT_INFOEX original_font_info;
159 UINT original_code_page;
162 (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
163 (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
165 {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE},
182 static DWORD ccount, acount;
187 int ttycolors[CLR_MAX];
188 int ttycolors_inv[CLR_MAX];
190 #define MAX_OVERRIDES 256
191 unsigned char key_overrides[MAX_OVERRIDES];
192 static char nullstr[] = "";
193 char erase_char, kill_char;
194 #define DEFTEXTCOLOR ttycolors[7]
196 /* dynamic keystroke handling .DLL support */
197 typedef int(__stdcall *PROCESS_KEYSTROKE)(HANDLE, INPUT_RECORD *, boolean *,
200 typedef int(__stdcall *NHKBHIT)(HANDLE, INPUT_RECORD *);
202 typedef int(__stdcall *CHECKINPUT)(HANDLE, INPUT_RECORD *, DWORD *, BOOLEAN_P,
203 int, int *, coord *);
205 typedef int(__stdcall *SOURCEWHERE)(char **);
207 typedef int(__stdcall *SOURCEAUTHOR)(char **);
209 typedef int(__stdcall *KEYHANDLERNAME)(char **, int);
212 char * name; // name without DLL extension
214 PROCESS_KEYSTROKE pProcessKeystroke;
216 CHECKINPUT pCheckInput;
217 SOURCEWHERE pSourceWhere;
218 SOURCEAUTHOR pSourceAuthor;
219 KEYHANDLERNAME pKeyHandlerName;
220 } keyboard_handler_t;
222 keyboard_handler_t keyboard_handler;
225 /* Console buffer flipping support */
227 static void back_buffer_flip()
229 cell_t * back = console.back_buffer;
230 cell_t * front = console.front_buffer;
234 for (pos.Y = 0; pos.Y < console.height; pos.Y++) {
235 for (pos.X = 0; pos.X < console.width; pos.X++) {
237 if (back->iskanji == 1) {
238 cell_t * back2 = back + 1;
239 cell_t * front2 = front + 1;
240 if (back->attribute != front->attribute ||
241 back2->attribute != front2->attribute) {
243 attrs[0] = attrs[1] = back->attribute;
244 WriteConsoleOutputAttribute(console.hConOut, attrs,
246 front->attribute = back->attribute;
247 front2->attribute = back2->attribute;
249 if (back->character != front->character ||
250 back2->character != front2->character) {
251 unsigned char buf[2];
252 buf[0] = (unsigned char)(back->character);
253 buf[1] = (unsigned char)(back2->character);
254 WriteConsoleOutputCharacter(console.hConOut, buf, 2, pos,
256 front->character = back->character;
257 front2->character = back2->character;
265 if (back->attribute != front->attribute) {
266 WriteConsoleOutputAttribute(console.hConOut, &back->attribute,
268 front->attribute = back->attribute;
270 if (back->character != front->character) {
271 if (console.has_unicode) {
272 WriteConsoleOutputCharacterW(console.hConOut,
273 &back->character, 1, pos, &unused);
275 char ch = (char)back->character;
276 WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos,
287 void buffer_fill_to_end(cell_t * buffer, cell_t * fill, int x, int y)
289 nhassert(x >= 0 && x < console.width);
290 nhassert(y >= 0 && ((y < console.height) || (y == console.height &&
293 cell_t * dst = buffer + console.width * y + x;
294 cell_t * sentinel = buffer + console.buffer_size;
295 while (dst != sentinel)
298 if (iflags.debug.immediateflips && buffer == console.back_buffer)
302 static void buffer_clear_to_end_of_line(cell_t * buffer, int x, int y)
304 nhassert(x >= 0 && x < console.width);
305 nhassert(y >= 0 && ((y < console.height) || (y == console.height &&
307 cell_t * dst = buffer + console.width * y + x;
308 cell_t *sentinel = buffer + console.width * (y + 1);
310 while (dst != sentinel)
313 if (iflags.debug.immediateflips)
317 void buffer_write(cell_t * buffer, cell_t * cell, COORD pos)
319 nhassert(pos.X >= 0 && pos.X < console.width);
320 nhassert(pos.Y >= 0 && pos.Y < console.height);
322 cell_t * dst = buffer + (console.width * pos.Y) + pos.X;
325 if (iflags.debug.immediateflips && buffer == console.back_buffer)
330 * Called after returning from ! or ^Z
339 kill_char = 21; /* cntl-U */
340 iflags.cbreak = TRUE;
344 for (k = 0; k < CLR_MAX; ++k)
345 ttycolors[k] = NO_COLOR;
349 /* reset terminal to original state */
354 cmov(ttyDisplay->curx, ttyDisplay->cury);
358 restore_original_console_font();
359 if (orig_QuickEdit) {
362 GetConsoleMode(console.hConIn, &cmode);
363 cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
364 SetConsoleMode(console.hConIn, cmode);
368 /* called by init_nhwindows() and resume_nhwindows() */
380 tty_startup(wid, hgt)
383 *wid = console.width;
384 *hgt = console.height;
385 set_option_mod_status("mouse_support", SET_IN_GAME);
389 tty_number_pad(state)
399 tty_number_pad(1); /* make keypad send digits */
406 really_move_cursor();
407 buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
409 FlushConsoleInputBuffer(console.hConIn);
413 CtrlHandler(ctrltype)
417 /* case CTRL_C_EVENT: */
418 case CTRL_BREAK_EVENT:
420 case CTRL_CLOSE_EVENT:
421 case CTRL_LOGOFF_EVENT:
422 case CTRL_SHUTDOWN_EVENT:
423 getreturn_enabled = FALSE;
424 #ifndef NOSAVEONHANGUP
427 #if defined(SAFERHANGUP)
428 CloseHandle(console.hConIn); /* trigger WAIT_FAILED */
436 /* called by pcmain() and process_options() */
443 /* Initialize the function pointer that points to
444 * the kbhit() equivalent, in this TTY case nttty_kbhit()
446 nt_kbhit = nttty_kbhit;
448 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) {
449 /* Unable to set control handler */
450 cmode = 0; /* just to have a statement to break on for debugger */
456 really_move_cursor();
462 /* go back to using the safe routines */
467 process_keystroke(ir, valid, numberpad, portdebug)
475 #ifdef QWERTZ_SUPPORT
479 ch = keyboard_handler.pProcessKeystroke(
480 console.hConIn, ir, valid, numberpad, portdebug);
481 #ifdef QWERTZ_SUPPORT
484 /* check for override */
485 if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
486 ch = key_overrides[ch];
493 return keyboard_handler.pNHkbhit(console.hConIn, &ir);
502 boolean numpad = iflags.num_pad;
504 really_move_cursor();
505 if (iflags.debug_fuzzer)
507 #ifdef QWERTZ_SUPPORT
512 return (program_state.done_hup)
514 : keyboard_handler.pCheckInput(
515 console.hConIn, &ir, &count, numpad, 0, &mod, &cc);
525 boolean numpad = iflags.num_pad;
527 really_move_cursor();
528 if (iflags.debug_fuzzer)
530 #ifdef QWERTZ_SUPPORT
534 ch = (program_state.done_hup)
536 : keyboard_handler.pCheckInput(
537 console.hConIn, &ir, &count, numpad, 1, mod, &cc);
538 #ifdef QWERTZ_SUPPORT
548 static void set_console_cursor(int x, int y)
550 nhassert(x >= 0 && x < console.width);
551 nhassert(y >= 0 && y < console.height);
553 console.cursor.X = max(0, min(console.width - 1, x));
554 console.cursor.Y = max(0, min(console.height - 1, y));
561 char oldtitle[BUFSZ], newtitle[BUFSZ];
562 if (display_cursor_info && wizard) {
564 if (GetConsoleTitle(oldtitle, BUFSZ)) {
567 Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle,
568 ttyDisplay->curx, ttyDisplay->cury,
569 console.cursor.X, console.cursor.Y);
570 (void) SetConsoleTitle(newtitle);
574 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
577 SetConsoleCursorPosition(console.hConOut, console.cursor);
584 ttyDisplay->cury = y;
585 ttyDisplay->curx = x;
587 set_console_cursor(x, y);
594 ttyDisplay->curx = x;
595 ttyDisplay->cury = y;
597 set_console_cursor(x, y);
600 /* same signature as 'putchar()' with potential failure result ignored */
605 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
606 xputc_core((char) ch);
612 xputc2_core(ch1, ch2)
616 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
617 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
619 boolean inverse = FALSE;
622 /* xputc_core()
\82©
\82ç
\82Ì
\83R
\83s
\81[ */
623 inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
624 console.attr = (inverse) ?
625 ttycolors_inv[console.current_nhcolor] :
626 ttycolors[console.current_nhcolor];
627 if (console.current_nhattr[ATR_BOLD])
628 console.attr |= (inverse) ?
629 BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
631 cell.attribute = console.attr;
633 /*
\89E
\92[
\82É1
\83o
\83C
\83g
\95ª
\82µ
\82©
\8bó
\82«
\82ª
\82È
\82¢
\8fê
\8d\87 */
634 if (console.cursor.X == console.width - 2) {
635 /*
\8bó
\94\92\95\
\8e¦ */
636 cell.character = ' ';
638 buffer_write(console.back_buffer, &cell, console.cursor);
640 if (console.cursor.Y < console.height - 1) {
641 /*
\8e\9f\82Ì
\8ds
\82É */
642 console.cursor.X = 1;
645 /*
\8aù
\82É
\89º
\92[
\82Ì
\8fê
\8d\87\82Í
\82È
\82É
\82à
\82µ
\82È
\82¢ */
650 cell.character = ch1;
652 buffer_write(console.back_buffer, &cell, console.cursor);
655 cell.character = ch2;
657 buffer_write(console.back_buffer, &cell, console.cursor);
659 if (console.cursor.X == console.width - 1) {
660 if (console.cursor.Y < console.height - 1) {
661 console.cursor.X = 1;
668 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
669 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
677 /* wintty.c
\82Å
\82Í 1
\83o
\83C
\83g
\96\88\82É curx
\82ð
\89Á
\8eZ
\82·
\82é
\82ª
\81A
\82±
\82±
\82Í
678 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Å
679 \82µ
\82Ü
\82Á
\82Ä
\82¢
\82é
\81B
\8f]
\82Á
\82Ä 1
\82ð
\88ø
\82
\81B */
680 console.cursor.X = ttyDisplay->curx - 1;
681 console.cursor.Y = ttyDisplay->cury;
683 xputc2_core(ch1, ch2);
692 int slen = (int) strlen(s);
695 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
698 for (k = 0; k < slen && s[k]; ++k)
703 /* xputc_core() and g_putch() are the only
704 * two routines that actually place output
711 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
712 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
714 boolean inverse = FALSE;
719 if (console.cursor.Y < console.height - 1)
723 console.cursor.X = 1;
726 if (console.cursor.X > 1) {
728 } else if(console.cursor.Y > 0) {
729 console.cursor.X = console.width - 1;
735 inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
736 console.attr = (inverse) ?
737 ttycolors_inv[console.current_nhcolor] :
738 ttycolors[console.current_nhcolor];
739 if (console.current_nhattr[ATR_BOLD])
740 console.attr |= (inverse) ?
741 BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
743 cell.attribute = console.attr;
745 cell.character = (console.has_unicode ? console.cpMap[ch] : ch);
749 #if 1 /*JP*//*
\8fí
\82É1
\83o
\83C
\83g
\95¶
\8e\9a*/
753 buffer_write(console.back_buffer, &cell, console.cursor);
755 if (console.cursor.X == console.width - 1) {
756 if (console.cursor.Y < console.height - 1) {
757 console.cursor.X = 1;
765 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
766 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
770 * Overrides wintty.c function of the same name
771 * for win32. It is used for glyphs only, not text.
778 boolean inverse = FALSE;
779 unsigned char ch = (unsigned char) in_ch;
781 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
783 inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
784 console.attr = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse) ?
785 ttycolors_inv[console.current_nhcolor] :
786 ttycolors[console.current_nhcolor];
787 if (console.current_nhattr[ATR_BOLD])
788 console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
792 cell.attribute = console.attr;
794 cell.character = (console.has_unicode ? cp437[ch] : ch);
798 #if 1 /*JP*//*
\8fí
\82É1
\83o
\83C
\83g
\95¶
\8e\9a*/
802 buffer_write(console.back_buffer, &cell, console.cursor);
808 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
809 buffer_clear_to_end_of_line(console.back_buffer, console.cursor.X,
811 tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
817 if (WINDOWPORT("tty")) {
818 cell_t * back = console.back_buffer;
819 cell_t * front = console.front_buffer;
823 for (pos.Y = 0; pos.Y < console.height; pos.Y++) {
824 for (pos.X = 0; pos.X < console.width; pos.X++) {
825 WriteConsoleOutputAttribute(console.hConOut, &back->attribute,
827 front->attribute = back->attribute;
828 if (console.has_unicode) {
829 WriteConsoleOutputCharacterW(console.hConOut,
830 &back->character, 1, pos, &unused);
832 char ch = (char)back->character;
833 WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos,
847 buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
854 ttyDisplay->curx = ttyDisplay->cury = 0;
855 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
861 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
868 buffer_fill_to_end(console.back_buffer, &clear_cell, ttyDisplay->curx,
870 tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
876 if (flags.silent || iflags.debug_fuzzer)
881 volatile int junk; /* prevent optimizer from eliminating loop below */
886 /* delay 50 ms - uses ANSI C clock() function now */
892 if (iflags.debug_fuzzer)
895 while (goal > clock()) {
896 k = junk; /* Do nothing */
904 * CLR_BROWN 3 low-intensity yellow
908 * CLR_GRAY 7 low-intensity white
911 * CLR_BRIGHT_GREEN 10
914 * CLR_BRIGHT_MAGENTA 13
925 ttycolors[CLR_BLACK] = FOREGROUND_INTENSITY; /* fix by Quietust */
926 ttycolors[CLR_RED] = FOREGROUND_RED;
927 ttycolors[CLR_GREEN] = FOREGROUND_GREEN;
928 ttycolors[CLR_BROWN] = FOREGROUND_GREEN | FOREGROUND_RED;
929 ttycolors[CLR_BLUE] = FOREGROUND_BLUE;
930 ttycolors[CLR_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED;
931 ttycolors[CLR_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE;
932 ttycolors[CLR_GRAY] = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
933 ttycolors[NO_COLOR] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
934 ttycolors[CLR_ORANGE] = FOREGROUND_RED | FOREGROUND_INTENSITY;
935 ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
936 ttycolors[CLR_YELLOW] = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
937 ttycolors[CLR_BRIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
938 ttycolors[CLR_BRIGHT_MAGENTA]=FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
939 ttycolors[CLR_BRIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
940 ttycolors[CLR_WHITE] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED
941 | FOREGROUND_INTENSITY;
943 ttycolors_inv[CLR_BLACK] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
944 | BACKGROUND_INTENSITY;
945 ttycolors_inv[CLR_RED] = BACKGROUND_RED | BACKGROUND_INTENSITY;
946 ttycolors_inv[CLR_GREEN] = BACKGROUND_GREEN;
947 ttycolors_inv[CLR_BROWN] = BACKGROUND_GREEN | BACKGROUND_RED;
948 ttycolors_inv[CLR_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
949 ttycolors_inv[CLR_MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED;
950 ttycolors_inv[CLR_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE;
951 ttycolors_inv[CLR_GRAY] = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE;
952 ttycolors_inv[NO_COLOR] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
953 ttycolors_inv[CLR_ORANGE] = BACKGROUND_RED | BACKGROUND_INTENSITY;
954 ttycolors_inv[CLR_BRIGHT_GREEN]= BACKGROUND_GREEN | BACKGROUND_INTENSITY;
955 ttycolors_inv[CLR_YELLOW] = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
956 ttycolors_inv[CLR_BRIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
957 ttycolors_inv[CLR_BRIGHT_MAGENTA] =BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
958 ttycolors_inv[CLR_BRIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
959 ttycolors_inv[CLR_WHITE] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
960 | BACKGROUND_INTENSITY;
963 ttycolors[0] = FOREGROUND_INTENSITY;
964 ttycolors_inv[0] = BACKGROUND_INTENSITY;
965 for (k = 1; k < SIZE(ttycolors); ++k) {
966 ttycolors[k] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
967 ttycolors_inv[k] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
970 init_ttycolor_completed = TRUE;
975 has_color(int color) /* this function is commented out */
978 if ((color >= 0) && (color < CLR_MAX))
981 if ((color == CLR_BLACK) || (color == CLR_WHITE) || (color == NO_COLOR))
990 term_attr_fixup(int attrmask)
996 term_start_attr(int attrib)
998 console.current_nhattr[attrib] = TRUE;
999 if (attrib) console.current_nhattr[ATR_NONE] = FALSE;
1003 term_end_attr(int attrib)
1014 console.current_nhattr[attrib] = FALSE;
1015 console.current_nhattr[ATR_NONE] = TRUE;
1016 /* re-evaluate all attr now for performance at output time */
1017 for (k=ATR_NONE; k <= ATR_INVERSE; ++k) {
1018 if (console.current_nhattr[k])
1019 console.current_nhattr[ATR_NONE] = FALSE;
1024 term_end_raw_bold(void)
1026 term_end_attr(ATR_BOLD);
1030 term_start_raw_bold(void)
1032 term_start_attr(ATR_BOLD);
1036 term_start_color(int color)
1039 if (color >= 0 && color < CLR_MAX) {
1040 console.current_nhcolor = color;
1043 console.current_nhcolor = NO_COLOR;
1047 term_end_color(void)
1050 console.foreground = DEFTEXTCOLOR;
1052 console.attr = (console.foreground | console.background);
1053 console.current_nhcolor = NO_COLOR;
1059 term_start_attr(ATR_BOLD);
1065 term_end_attr(ATR_BOLD);
1068 #ifndef NO_MOUSE_ALLOWED
1070 toggle_mouse_support()
1072 static int qeinit = 0;
1075 GetConsoleMode(console.hConIn, &cmode);
1078 orig_QuickEdit = ((cmode & ENABLE_QUICK_EDIT_MODE) != 0);
1080 switch(iflags.wc_mouse_support) {
1082 cmode |= ENABLE_MOUSE_INPUT;
1085 cmode |= ENABLE_MOUSE_INPUT;
1086 cmode &= ~ENABLE_QUICK_EDIT_MODE;
1087 cmode |= ENABLE_EXTENDED_FLAGS;
1092 cmode &= ~ENABLE_MOUSE_INPUT;
1094 cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
1096 SetConsoleMode(console.hConIn, cmode);
1100 /* handle tty options updates here */
1102 nttty_preference_update(pref)
1105 if (stricmp(pref, "mouse_support") == 0) {
1106 #ifndef NO_MOUSE_ALLOWED
1107 toggle_mouse_support();
1110 if (stricmp(pref, "symset") == 0)
1111 check_and_set_font();
1117 win32con_debug_keystrokes()
1123 while (!valid || ch != 27) {
1124 nocmov(ttyDisplay->curx, ttyDisplay->cury);
1125 ReadConsoleInput(console.hConIn, &ir, 1, &count);
1126 if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
1127 ch = process_keystroke(&ir, &valid, iflags.num_pad, 1);
1132 win32con_handler_info()
1136 if (!keyboard_handler.pSourceAuthor && !keyboard_handler.pSourceWhere)
1137 pline("Keyboard handler source info and author unavailable.");
1139 if (keyboard_handler.pKeyHandlerName &&
1140 keyboard_handler.pKeyHandlerName(&buf, 1)) {
1142 xputs("Keystroke handler loaded: \n ");
1145 if (keyboard_handler.pSourceAuthor &&
1146 keyboard_handler.pSourceAuthor(&buf)) {
1148 xputs("Keystroke handler Author: \n ");
1151 if (keyboard_handler.pSourceWhere &&
1152 keyboard_handler.pSourceWhere(&buf)) {
1154 xputs("Keystroke handler source code available at:\n ");
1157 xputs("\nPress any key to resume.");
1164 win32con_toggle_cursor_info()
1166 display_cursor_info = !display_cursor_info;
1174 char digits[] = "0123456789";
1175 int length, i, idx, val;
1180 kp = index(op, '/');
1184 length = strlen(kp);
1185 if (length < 1 || length > 3)
1187 for (i = 0; i < length; i++)
1188 if (!index(digits, kp[i]))
1191 length = strlen(op);
1192 if (length < 1 || length > 3)
1194 for (i = 0; i < length; i++)
1195 if (!index(digits, op[i]))
1199 if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1)
1201 key_overrides[idx] = val;
1204 void unload_keyboard_handler()
1206 nhassert(keyboard_handler.hLibrary != NULL);
1208 FreeLibrary(keyboard_handler.hLibrary);
1209 memset(&keyboard_handler, 0, sizeof(keyboard_handler_t));
1213 load_keyboard_handler(const char * inName)
1215 char path[MAX_ALTKEYHANDLER + 4];
1216 strcpy(path, inName);
1217 strcat(path, ".dll");
1219 HANDLE hLibrary = LoadLibrary(path);
1221 if (hLibrary == NULL)
1224 PROCESS_KEYSTROKE pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
1225 hLibrary, TEXT("ProcessKeystroke"));
1226 NHKBHIT pNHkbhit = (NHKBHIT) GetProcAddress(
1227 hLibrary, TEXT("NHkbhit"));
1228 CHECKINPUT pCheckInput =
1229 (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
1231 if (!pProcessKeystroke || !pNHkbhit || !pCheckInput)
1235 if (keyboard_handler.hLibrary != NULL)
1236 unload_keyboard_handler();
1238 keyboard_handler.hLibrary = hLibrary;
1240 keyboard_handler.pProcessKeystroke = pProcessKeystroke;
1241 keyboard_handler.pNHkbhit = pNHkbhit;
1242 keyboard_handler.pCheckInput = pCheckInput;
1244 keyboard_handler.pSourceWhere =
1245 (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
1246 keyboard_handler.pSourceAuthor =
1247 (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
1248 keyboard_handler.pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
1249 hLibrary, TEXT("KeyHandlerName"));
1255 void set_altkeyhandler(const char * inName)
1257 if (strlen(inName) >= MAX_ALTKEYHANDLER) {
1258 config_error_add("altkeyhandler name '%s' is too long", inName);
1262 char name[MAX_ALTKEYHANDLER];
1263 strcpy(name, inName);
1265 /* We support caller mistakenly giving name with '.dll' extension */
1266 char * ext = strchr(name, '.');
1267 if (ext != NULL) *ext = '\0';
1269 if (load_keyboard_handler(name))
1270 strcpy(iflags.altkeyhandler, name);
1272 config_error_add("unable to load altkeyhandler '%s'", name);
1283 VA_DECL(const char *, s)
1287 VA_INIT(s, const char *);
1288 /* error() may get called before tty is initialized */
1289 if (iflags.window_inited)
1292 (void) vsnprintf(&buf[1], sizeof buf - 1, s, VA_ARGS);
1294 really_move_cursor();
1302 really_move_cursor();
1307 tty_change_color(color_number, rgb, reverse)
1308 int color_number, reverse;
1311 /* Map NetHack color index to NT Console palette index */
1312 int idx, win32_color_number[] = {
1313 0, /* CLR_BLACK 0 */
1315 2, /* CLR_GREEN 2 */
1316 6, /* CLR_BROWN 3 */
1318 5, /* CLR_MAGENTA 5 */
1322 12, /* CLR_ORANGE 9 */
1323 10, /* CLR_BRIGHT_GREEN 10 */
1324 14, /* CLR_YELLOW 11 */
1325 9, /* CLR_BRIGHT_BLUE 12 */
1326 13, /* CLR_BRIGHT_MAGENTA 13 */
1327 11, /* CLR_BRIGHT_CYAN 14 */
1328 15 /* CLR_WHITE 15 */
1331 if (color_number < 0) { /* indicates OPTIONS=palette with no value */
1332 /* copy the NetHack palette into UserDefinedColors */
1333 for (k = 0; k < CLR_MAX; k++)
1334 UserDefinedColors[k] = NetHackColors[k];
1335 } else if (color_number >= 0 && color_number < CLR_MAX) {
1336 if (!altered_palette) {
1337 /* make sure a full suite is available */
1338 for (k = 0; k < CLR_MAX; k++)
1339 UserDefinedColors[k] = DefaultColors[k];
1341 idx = win32_color_number[color_number];
1342 UserDefinedColors[idx] = rgb;
1344 altered_palette = TRUE;
1348 tty_get_color_string()
1357 const struct others {
1359 const char *colorname;
1361 { CLR_MAGENTA, "purple" },
1362 { CLR_BRIGHT_MAGENTA, "bright purple" },
1363 { NO_COLOR, "dark gray" },
1364 { NO_COLOR, "dark grey" },
1365 { CLR_GRAY, "grey" },
1369 for (cnt = 0; cnt < CLR_MAX; ++cnt) {
1370 if (!strcmpi(c, c_obj_colors[cnt]))
1373 for (cnt = 0; cnt < SIZE(othernames); ++cnt) {
1374 if (!strcmpi(c, othernames[cnt].colorname))
1375 return othernames[cnt].idx;
1381 * Returns 0 if badoption syntax
1384 alternative_palette(op)
1388 * palette:color-R-G-B
1389 * OPTIONS=palette:green-4-3-1, palette:0-0-0-0
1391 int fieldcnt, color_number, rgb, red, green, blue;
1392 char *fields[4], *cp;
1395 change_color(-1, 0, 0); /* indicates palette option with
1396 no value meaning "load an entire
1397 hard-coded NetHack palette." */
1401 cp = fields[0] = op;
1402 for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1403 cp = index(cp, '-');
1406 fields[fieldcnt] = cp;
1409 for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1410 *(fields[fieldcnt]) = '\0';
1414 for (fieldcnt = 0; fieldcnt < 4; ++fieldcnt) {
1415 if (fieldcnt == 0 && isalpha(*(fields[0]))) {
1416 color_number = match_color_name(fields[0]);
1417 if (color_number == -1)
1420 int dcount = 0, cval = 0;
1421 cp = fields[fieldcnt];
1422 if (*cp == '\\' && index("0123456789xXoO", cp[1])) {
1423 const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
1426 if (*cp == 'x' || *cp == 'X')
1427 for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
1428 cval = (int) ((cval * 16) + (dp - hex) / 2);
1429 else if (*cp == 'o' || *cp == 'O')
1430 for (++cp; (index("01234567", *cp)) && (dcount++ < 3);
1432 cval = (cval * 8) + (*cp - '0');
1436 for (; *cp && (index("0123456789", *cp)) && (dcount++ < 3);
1438 cval = (cval * 10) + (*cp - '0');
1442 color_number = cval;
1456 rgb = RGB(red, green, blue);
1457 if (color_number >= 0 && color_number < CLR_MAX)
1458 change_color(color_number, rgb, 0);
1463 * This uses an undocumented method to set console attributes
1464 * at runtime including console palette
1466 * VOID WINAPI SetConsolePalette(COLORREF palette[16])
1468 * Author: James Brown at www.catch22.net
1470 * Set palette of current console.
1471 * Palette should be of the form:
1473 * COLORREF DefaultColors[CLR_MAX] =
1475 * 0x00000000, 0x00800000, 0x00008000, 0x00808000,
1476 * 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
1477 * 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
1478 * 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
1482 #pragma pack(push, 1)
1485 * Structure to send console via WM_SETCONSOLEINFO
1487 typedef struct _CONSOLE_INFO {
1489 COORD ScreenBufferSize;
1505 USHORT ScreenColors;
1508 ULONG HistoryBufferSize;
1509 ULONG NumberOfHistoryBuffers;
1511 COLORREF ColorTable[16];
1516 WCHAR ConsoleTitle[0x100];
1521 BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci);
1522 static void GetConsoleSizeInfo(CONSOLE_INFO *pci);
1523 VOID WINAPI SetConsolePalette(COLORREF crPalette[16]);
1526 adjust_palette(VOID_ARGS)
1528 SetConsolePalette(UserDefinedColors);
1529 altered_palette = 0;
1533 /* only in Win2k+ (use FindWindow for NT4) */
1534 /* HWND WINAPI GetConsoleWindow(); */
1536 /* Undocumented console message */
1537 #define WM_SETCONSOLEINFO (WM_USER + 201)
1540 SetConsolePalette(COLORREF palette[16])
1542 CONSOLE_INFO ci = { sizeof(ci) };
1544 HWND hwndConsole = GetConsoleHandle();
1546 /* get current size/position settings rather than using defaults.. */
1547 GetConsoleSizeInfo(&ci);
1549 /* set these to zero to keep current settings */
1550 ci.FontSize.X = 0; /* def = 8 */
1551 ci.FontSize.Y = 0; /* def = 12 */
1552 ci.FontFamily = 0; /* def = 0x30 = FF_MODERN|FIXED_PITCH */
1553 ci.FontWeight = 0; /* 0x400; */
1554 /* lstrcpyW(ci.FaceName, L"Terminal"); */
1555 ci.FaceName[0] = L'\0';
1558 ci.FullScreen = FALSE;
1559 ci.QuickEdit = TRUE;
1560 ci.AutoPosition = 0x10000;
1561 ci.InsertMode = TRUE;
1562 ci.ScreenColors = MAKEWORD(0x7, 0x0);
1563 ci.PopupColors = MAKEWORD(0x5, 0xf);
1565 ci.HistoryNoDup = FALSE;
1566 ci.HistoryBufferSize = 50;
1567 ci.NumberOfHistoryBuffers = 4;
1570 for (i = 0; i < 16; i++)
1571 ci.ColorTable[i] = palette[i];
1573 ci.CodePage = GetConsoleOutputCP();
1574 ci.Hwnd = hwndConsole;
1576 lstrcpyW(ci.ConsoleTitle, L"");
1578 SetConsoleInfo(hwndConsole, &ci);
1582 * Wrapper around WM_SETCONSOLEINFO. We need to create the
1583 * necessary section (file-mapping) object in the context of the
1584 * process which owns the console, before posting the message
1587 SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci)
1589 DWORD dwConsoleOwnerPid;
1591 HANDLE hSection, hDupSection;
1596 * Open the process which "owns" the console
1598 GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid);
1599 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
1602 * Create a SECTION object backed by page-file, then map a view of
1603 * this section into the owner process so we can write the contents
1604 * of the CONSOLE_INFO buffer into it
1606 hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
1610 * Copy our console structure into the section-object
1612 ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
1614 memcpy(ptrView, pci, pci->Length);
1615 UnmapViewOfFile(ptrView);
1618 * Map the memory into owner process
1620 DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection, 0,
1621 FALSE, DUPLICATE_SAME_ACCESS);
1623 /* Send console window the "update" message */
1624 SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM) hDupSection, 0);
1629 hThread = CreateRemoteThread(hProcess, 0, 0,
1630 (LPTHREAD_START_ROUTINE) CloseHandle,
1633 CloseHandle(hThread);
1634 CloseHandle(hSection);
1635 CloseHandle(hProcess);
1641 * Fill the CONSOLE_INFO structure with information
1642 * about the current console window
1645 GetConsoleSizeInfo(CONSOLE_INFO *pci)
1647 CONSOLE_SCREEN_BUFFER_INFO csbi;
1649 HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
1651 GetConsoleScreenBufferInfo(hConsoleOut, &csbi);
1653 pci->ScreenBufferSize = csbi.dwSize;
1654 pci->WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
1655 pci->WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
1656 pci->WindowPosX = csbi.srWindow.Left;
1657 pci->WindowPosY = csbi.srWindow.Top;
1661 GetConsoleHandle(void)
1663 HMODULE hMod = GetModuleHandle("kernel32.dll");
1664 GETCONSOLEWINDOW pfnGetConsoleWindow =
1665 (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
1666 if (pfnGetConsoleWindow)
1667 return pfnGetConsoleWindow();
1669 return GetConsoleHwnd();
1673 GetConsoleHwnd(void)
1677 char OldTitle[1024], NewTitle[1024], TestTitle[1024];
1679 /* Get current window title */
1680 GetConsoleTitle(OldTitle, sizeof OldTitle);
1682 (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
1683 GetCurrentProcessId());
1684 SetConsoleTitle(NewTitle);
1686 GetConsoleTitle(TestTitle, sizeof TestTitle);
1687 while (strcmp(TestTitle, NewTitle) != 0) {
1690 GetConsoleTitle(TestTitle, sizeof TestTitle);
1692 hwndFound = FindWindow(NULL, NewTitle);
1693 SetConsoleTitle(OldTitle);
1694 /* printf("%d iterations\n", iterations); */
1697 #endif /*CHANGE_COLOR*/
1699 static int CALLBACK EnumFontCallback(
1700 const LOGFONTW * lf, const TEXTMETRICW * tm, DWORD fontType, LPARAM lParam)
1702 LOGFONTW * lf_ptr = (LOGFONTW *) lParam;
1707 /* check_and_set_font ensures that the current font will render the symbols
1708 * that are currently being used correctly. If they will not be rendered
1709 * correctly, then it will change the font to a known good font.
1712 check_and_set_font()
1714 #if 0 /*JP*//*
\83R
\81[
\83h
\83y
\81[
\83W
\82Í
\95Ï
\8dX
\82µ
\82È
\82¢
\81B932
\82ð
\89¼
\92è
\82·
\82é
\81B*/
1715 if (!check_font_widths()) {
1716 raw_print("WARNING: glyphs too wide in console font."
1717 " Changing code page to 437 and font to Consolas\n");
1718 set_known_good_console_font();
1724 /* check_font_widths returns TRUE if all glyphs in current console font
1725 * fit within the width of a single console cell.
1730 CONSOLE_FONT_INFOEX console_font_info;
1731 console_font_info.cbSize = sizeof(console_font_info);
1732 BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
1733 &console_font_info);
1735 /* get console window and DC
1736 * NOTE: the DC from the console window does not have the correct
1737 * font selected at this point.
1739 HWND hWnd = GetConsoleWindow();
1740 HDC hDC = GetDC(hWnd);
1742 LOGFONTW logical_font;
1743 logical_font.lfCharSet = DEFAULT_CHARSET;
1744 wcscpy(logical_font.lfFaceName, console_font_info.FaceName);
1745 logical_font.lfPitchAndFamily = 0;
1747 /* getting matching console font */
1748 LOGFONTW matching_log_font = { 0 };
1749 EnumFontFamiliesExW(hDC, &logical_font, EnumFontCallback,
1750 (LPARAM) &matching_log_font, 0);
1752 if (matching_log_font.lfHeight == 0) {
1753 raw_print("Unable to enumerate system fonts\n");
1757 /* create font matching console font */
1758 LOGFONTW console_font_log_font = matching_log_font;
1759 console_font_log_font.lfWeight = console_font_info.FontWeight;
1760 console_font_log_font.lfHeight = console_font_info.dwFontSize.Y;
1761 console_font_log_font.lfWidth = console_font_info.dwFontSize.X;
1762 HFONT console_font = CreateFontIndirectW(&console_font_log_font);
1764 if (console_font == NULL) {
1765 raw_print("Unable to create console font\n");
1770 HGDIOBJ saved_font = SelectObject(hDC, console_font);
1772 /* determine whether it is a true type font */
1774 success = GetTextMetricsA(hDC, &tm);
1777 raw_print("Unable to get console font text metrics\n");
1781 boolean isTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
1783 /* determine which glyphs are used */
1785 memset(used, 0, sizeof(used));
1786 for (int i = 0; i < SYM_MAX; i++) {
1787 used[primary_syms[i]] = TRUE;
1788 used[rogue_syms[i]] = TRUE;
1791 int wcUsedCount = 0;
1792 wchar_t wcUsed[256];
1793 for (int i = 0; i < sizeof(used); i++)
1795 wcUsed[wcUsedCount++] = cp437[i];
1797 /* measure the set of used glyphs to ensure they fit */
1798 boolean all_glyphs_fit = TRUE;
1800 for (int i = 0; i < wcUsedCount; i++) {
1804 success = GetCharABCWidthsW(hDC, wcUsed[i], wcUsed[i], &abc);
1805 width = abc.abcA + abc.abcB + abc.abcC;
1807 success = GetCharWidthW(hDC, wcUsed[i], wcUsed[i], &width);
1810 if (success && width > console_font_info.dwFontSize.X) {
1811 all_glyphs_fit = FALSE;
1818 SelectObject(hDC, saved_font);
1819 DeleteObject(console_font);
1821 return all_glyphs_fit;
1825 /* set_known_good_console_font sets the code page and font used by the console
1826 * to settings know to work well with NetHack. It also saves the original
1827 * settings so that they can be restored prior to NetHack exit.
1830 set_known_good_console_font()
1832 CONSOLE_FONT_INFOEX console_font_info;
1833 console_font_info.cbSize = sizeof(console_font_info);
1834 BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
1835 &console_font_info);
1837 console.font_changed = TRUE;
1838 console.original_font_info = console_font_info;
1839 console.original_code_page = GetConsoleOutputCP();
1841 wcscpy_s(console_font_info.FaceName,
1842 sizeof(console_font_info.FaceName)
1843 / sizeof(console_font_info.FaceName[0]),
1846 success = SetConsoleOutputCP(437);
1849 success = SetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info);
1853 /* restore_original_console_font will restore the console font and code page
1854 * settings to what they were when NetHack was launched.
1857 restore_original_console_font()
1859 if (console.font_changed) {
1861 raw_print("Restoring original font and code page\n");
1862 success = SetConsoleOutputCP(console.original_code_page);
1864 raw_print("Unable to restore original code page\n");
1866 success = SetCurrentConsoleFontEx(console.hConOut, FALSE,
1867 &console.original_font_info);
1869 raw_print("Unable to restore original font\n");
1871 console.font_changed = FALSE;
1876 /* set_cp_map() creates a mapping of every possible character of a code
1877 * page to its corresponding WCHAR. This is necessary due to the high
1878 * cost of making calls to MultiByteToWideChar() for every character we
1879 * wish to print to the console.
1884 if (console.has_unicode) {
1885 UINT codePage = GetConsoleOutputCP();
1887 if (codePage == 437) {
1888 memcpy(console.cpMap, cp437, sizeof(console.cpMap));
1890 for (int i = 0; i < 256; i++) {
1892 int count = MultiByteToWideChar(codePage, 0, &c, 1,
1893 &console.cpMap[i], 1);
1894 nhassert(count == 1);
1896 // If a character was mapped to unicode control codes,
1897 // remap to the appropriate unicode character per our
1898 // code page 437 mappings.
1899 if (console.cpMap[i] < 32)
1900 console.cpMap[i] = cp437[console.cpMap[i]];
1909 /* early_raw_print() is used during early game intialization prior to the
1910 * setting up of the windowing system. This allows early errors and panics
1911 * to have there messages displayed.
1913 * early_raw_print() eventually gets replaced by tty_raw_print().
1917 void early_raw_print(const char *s)
1919 if (console.hConOut == NULL)
1922 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
1923 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
1925 WORD attribute = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
1928 while (*s != '\0') {
1931 if (console.cursor.Y < console.height - 1)
1935 console.cursor.X = 1;
1938 if (console.cursor.X > 1) {
1940 } else if(console.cursor.Y > 0) {
1941 console.cursor.X = console.width - 1;
1946 WriteConsoleOutputAttribute(console.hConOut, &attribute,
1947 1, console.cursor, &unused);
1948 WriteConsoleOutputCharacterA(console.hConOut, s,
1949 1, console.cursor, &unused);
1950 if (console.cursor.X == console.width - 1) {
1951 if (console.cursor.Y < console.height - 1) {
1952 console.cursor.X = 1;
1962 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
1963 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
1965 SetConsoleCursorPosition(console.hConOut, console.cursor);
1970 /* nethack_enter_nttty() is the first thing that is called from main
1971 * once the tty port is confirmed.
1973 * We initialize all console state to support rendering to the console
1974 * through out flipping support at this time. This allows us to support
1975 * raw_print prior to our returning.
1977 * During this early initialization, we also determine the width and
1978 * height of the console that will be used. This width and height will
1981 * We also check and set the console font to a font that we know will work
1982 * well with nethack.
1984 * The intent of this early initialization is to get all state that is
1985 * not dependent upon game options initialized allowing us to simplify
1986 * any additional initialization that might be needed when we are actually
1989 * Other then the call below which clears the entire console buffer, no
1990 * other code outputs directly to the console other then the code that
1991 * handles flipping the back buffer.
1995 void nethack_enter_nttty()
1998 /* set up state needed by early_raw_print() */
1999 windowprocs.win_raw_print = early_raw_print;
2001 console.hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
2002 nhassert(console.hConOut != NULL); // NOTE: this assert will not print
2004 GetConsoleScreenBufferInfo(console.hConOut, &console.origcsbi);
2006 /* Testing of widths != COLNO has not turned up any problems. Need
2007 * to do a bit more testing and then we are likely to enable having
2008 * console width match window width.
2011 console.width = console.origcsbi.srWindow.Right -
2012 console.origcsbi.srWindow.Left + 1;
2013 console.Width = max(console.Width, COLNO);
2015 console.width = COLNO;
2018 console.height = console.origcsbi.srWindow.Bottom -
2019 console.origcsbi.srWindow.Top + 1;
2020 console.height = max(console.height, ROWNO + 3);
2022 console.buffer_size = console.width * console.height;
2025 /* clear the entire console buffer */
2026 int size = console.origcsbi.dwSize.X * console.origcsbi.dwSize.Y;
2028 set_console_cursor(0, 0);
2029 FillConsoleOutputAttribute(
2030 console.hConOut, CONSOLE_CLEAR_ATTRIBUTE,
2031 size, console.cursor, &unused);
2033 FillConsoleOutputCharacter(
2034 console.hConOut, CONSOLE_CLEAR_CHARACTER,
2035 size, console.cursor, &unused);
2037 set_console_cursor(1, 0);
2038 SetConsoleCursorPosition(console.hConOut, console.cursor);
2040 /* At this point early_raw_print will work */
2042 console.hConIn = GetStdHandle(STD_INPUT_HANDLE);
2043 nhassert(console.hConIn != NULL);
2045 /* grow the size of the console buffer if it is not wide enough */
2046 if (console.origcsbi.dwSize.X < console.width) {
2048 size.Y = console.origcsbi.dwSize.Y,
2049 size.X = console.width
2052 SetConsoleScreenBufferSize(console.hConOut, size);
2055 /* setup front and back buffers */
2056 int buffer_size_bytes = sizeof(cell_t) * console.buffer_size;
2058 console.front_buffer = (cell_t *)malloc(buffer_size_bytes);
2059 buffer_fill_to_end(console.front_buffer, &undefined_cell, 0, 0);
2061 console.back_buffer = (cell_t *)malloc(buffer_size_bytes);
2062 buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
2064 /* determine whether OS version has unicode support */
2065 console.has_unicode = ((GetVersion() & 0x80000000) == 0);
2067 /* check the font before we capture the code page map */
2068 check_and_set_font();
2073 /* Set console mode */
2075 GetConsoleMode(console.hConIn, &cmode);
2076 #ifdef NO_MOUSE_ALLOWED
2077 mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT
2078 | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;
2080 mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
2081 | ENABLE_WINDOW_INPUT;
2083 /* Turn OFF the settings specified in the mask */
2085 #ifndef NO_MOUSE_ALLOWED
2086 cmode |= ENABLE_MOUSE_INPUT;
2088 SetConsoleMode(console.hConIn, cmode);
2090 /* load default keyboard handler */
2091 HKL keyboard_layout = GetKeyboardLayout(0);
2092 DWORD primary_language = (UINT_PTR) keyboard_layout & 0x3f;
2094 /* This was overriding the handler that had already
2095 been loaded during options parsing. Needs to
2097 #if 0 /*JP*//*
\93ú
\96{
\8cê
\82Å
\82Ínhdefkey
\82µ
\82©
\8eg
\82í
\82È
\82¢ */
2098 if (!iflags.altkeyhandler[0]) {
2099 if (primary_language == LANG_ENGLISH) {
2100 if (!load_keyboard_handler("nhdefkey"))
2101 error("Unable to load nhdefkey.dll");
2103 if (!load_keyboard_handler("nhraykey"))
2104 error("Unable to load nhraykey.dll");
2108 if (!load_keyboard_handler("nhdefkey"))
2109 error("nhdefkey.dll
\82ð
\93Ç
\82Ý
\8d\9e\82ß
\82Ü
\82¹
\82ñ");
2112 #endif /* TTY_GRAPHICS */
2114 /* this is used as a printf() replacement when the window
2115 * system isn't initialized yet
2118 VA_DECL(const char *, fmt)
2120 char buf[ROWNO * COLNO]; /* worst case scenario */
2122 VA_INIT(fmt, const char *);
2123 (void) vsnprintf(buf, sizeof buf, fmt, VA_ARGS);
2124 if (redirect_stdout)
2125 fprintf(stdout, "%s", buf);
2128 if(!init_ttycolor_completed)
2130 /* if we have generated too many messages ... ask the user to
2131 * confirm and then clear.
2133 if (console.cursor.Y > console.height - 4) {
2134 xputs("Hit <Enter> to continue.");
2135 while (pgetchar() != '\n')
2138 set_console_cursor(1, 0);
2144 console.cursor.X = ttyDisplay->curx;
2145 console.cursor.Y = ttyDisplay->cury;
2150 jbuffer(*(str++), NULL, (void (__cdecl *)(unsigned int))xputc_core, xputc2_core);
2155 curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y);
2157 fprintf(stdout, "%s", buf);