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
18 #define NEED_VARARGS /* Uses ... */
23 #include <sys\types.h>
26 extern boolean getreturn_enabled; /* from sys/share/pcsys.c */
27 extern int redirect_stdout;
31 * Console Buffer Flipping Support
33 * To minimize the number of calls into the WriteConsoleOutputXXX methods,
34 * we implement a notion of a console back buffer which keeps the next frame
35 * of console output as it is being composed. When ready to show the new
36 * frame, we compare this next frame to what is currently being output and
37 * only call WriteConsoleOutputXXX for those console values that need to
42 #define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \
44 #define CONSOLE_CLEAR_CHARACTER (' ')
46 #define CONSOLE_UNDEFINED_ATTRIBUTE (0)
47 #define CONSOLE_UNDEFINED_CHARACTER ('\0')
58 cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE };
59 cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
60 CONSOLE_UNDEFINED_ATTRIBUTE };
62 cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE, 0 };
63 cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
64 CONSOLE_UNDEFINED_ATTRIBUTE, 0 };
68 * The following WIN32 Console API routines are used in this file.
71 * GetConsoleScreenBufferInfo
73 * SetConsoleCursorPosition
74 * SetConsoleTextAttribute
75 * SetConsoleCtrlHandler
78 * WriteConsoleOutputCharacter
79 * FillConsoleOutputAttribute
83 static BOOL FDECL(CtrlHandler, (DWORD));
84 static void FDECL(xputc_core, (char));
86 static void FDECL(xputc2_core, (unsigned int, unsigned int));
88 void FDECL(cmov, (int, int));
89 void FDECL(nocmov, (int, int));
90 int FDECL(process_keystroke,
91 (INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug));
92 static void NDECL(init_ttycolor);
93 static void NDECL(really_move_cursor);
94 static void NDECL(check_and_set_font);
95 static boolean NDECL(check_font_widths);
96 static void NDECL(set_known_good_console_font);
97 static void NDECL(restore_original_console_font);
98 extern void NDECL(safe_routines);
100 /* Win32 Screen buffer,coordinate,console I/O information */
103 static boolean orig_QuickEdit;
105 /* Support for changing console font if existing glyph widths are too wide */
107 /* Flag for whether NetHack was launched via the GUI, not the command line.
108 * The reason we care at all, is so that we can get
109 * a final RETURN at the end of the game when launched from the GUI
110 * to prevent the scoreboard (or panic message :-|) from vanishing
111 * immediately after it is displayed, yet not bother when started
112 * from the command line.
114 int GUILaunched = FALSE;
115 /* Flag for whether unicode is supported */
116 static boolean init_ttycolor_completed;
118 static boolean display_cursor_info = FALSE;
121 static void NDECL(adjust_palette);
122 static int FDECL(match_color_name, (const char *));
123 typedef HWND(WINAPI *GETCONSOLEWINDOW)();
124 static HWND GetConsoleHandle(void);
125 static HWND GetConsoleHwnd(void);
126 static boolean altered_palette;
127 static COLORREF UserDefinedColors[CLR_MAX];
128 static COLORREF NetHackColors[CLR_MAX] = {
129 0x00000000, 0x00c80000, 0x0000c850, 0x00b4b432, 0x000000d2, 0x00800080,
130 0x000064b4, 0x00c0c0c0, 0x00646464, 0x00f06464, 0x0000ff00, 0x00ffff00,
131 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
133 static COLORREF DefaultColors[CLR_MAX] = {
134 0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080,
135 0x00008080, 0x00c0c0c0, 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
136 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
144 int current_nhattr[ATR_INVERSE+1];
148 CONSOLE_SCREEN_BUFFER_INFO origcsbi;
153 cell_t * front_buffer;
154 cell_t * back_buffer;
156 boolean font_changed;
157 CONSOLE_FONT_INFOEX original_font_info;
158 UINT original_code_page;
161 (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
162 (FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
164 {FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE},
181 static DWORD ccount, acount;
186 int ttycolors[CLR_MAX];
187 int ttycolors_inv[CLR_MAX];
189 #define MAX_OVERRIDES 256
190 unsigned char key_overrides[MAX_OVERRIDES];
191 static char nullstr[] = "";
192 char erase_char, kill_char;
193 #define DEFTEXTCOLOR ttycolors[7]
195 /* dynamic keystroke handling .DLL support */
196 typedef int(__stdcall *PROCESS_KEYSTROKE)(HANDLE, INPUT_RECORD *, boolean *,
199 typedef int(__stdcall *NHKBHIT)(HANDLE, INPUT_RECORD *);
201 typedef int(__stdcall *CHECKINPUT)(HANDLE, INPUT_RECORD *, DWORD *, BOOLEAN_P,
202 int, int *, coord *);
204 typedef int(__stdcall *SOURCEWHERE)(char **);
206 typedef int(__stdcall *SOURCEAUTHOR)(char **);
208 typedef int(__stdcall *KEYHANDLERNAME)(char **, int);
211 char * name; // name without DLL extension
213 PROCESS_KEYSTROKE pProcessKeystroke;
215 CHECKINPUT pCheckInput;
216 SOURCEWHERE pSourceWhere;
217 SOURCEAUTHOR pSourceAuthor;
218 KEYHANDLERNAME pKeyHandlerName;
219 } keyboard_handler_t;
221 keyboard_handler_t keyboard_handler;
224 /* Console buffer flipping support */
226 static void back_buffer_flip()
228 cell_t * back = console.back_buffer;
229 cell_t * front = console.front_buffer;
233 for (pos.Y = 0; pos.Y < console.height; pos.Y++) {
234 for (pos.X = 0; pos.X < console.width; pos.X++) {
236 if (back->iskanji == 1) {
237 cell_t * back2 = back + 1;
238 cell_t * front2 = front + 1;
239 if (back->attribute != front->attribute ||
240 back2->attribute != front2->attribute) {
242 attrs[0] = attrs[1] = back->attribute;
243 WriteConsoleOutputAttribute(console.hConOut, attrs,
245 front->attribute = back->attribute;
246 front2->attribute = back2->attribute;
248 if (back->character != front->character ||
249 back2->character != front2->character) {
250 unsigned char buf[2];
251 buf[0] = (unsigned char)(back->character);
252 buf[1] = (unsigned char)(back2->character);
253 WriteConsoleOutputCharacter(console.hConOut, buf, 2, pos,
255 front->character = back->character;
256 front2->character = back2->character;
264 if (back->attribute != front->attribute) {
265 WriteConsoleOutputAttribute(console.hConOut, &back->attribute,
267 front->attribute = back->attribute;
269 if (back->character != front->character) {
270 if (console.has_unicode) {
271 WriteConsoleOutputCharacterW(console.hConOut,
272 &back->character, 1, pos, &unused);
274 char ch = (char)back->character;
275 WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos,
286 void buffer_fill_to_end(cell_t * buffer, cell_t * fill, int x, int y)
288 nhassert(x >= 0 && x < console.width);
289 nhassert(y >= 0 && ((y < console.height) || (y == console.height &&
292 cell_t * dst = buffer + console.width * y + x;
293 cell_t * sentinel = buffer + console.buffer_size;
294 while (dst != sentinel)
297 if (iflags.debug.immediateflips && buffer == console.back_buffer)
301 static void buffer_clear_to_end_of_line(cell_t * buffer, int x, int y)
303 nhassert(x >= 0 && x < console.width);
304 nhassert(y >= 0 && ((y < console.height) || (y == console.height &&
306 cell_t * dst = buffer + console.width * y + x;
307 cell_t *sentinel = buffer + console.width * (y + 1);
309 while (dst != sentinel)
312 if (iflags.debug.immediateflips)
316 void buffer_write(cell_t * buffer, cell_t * cell, COORD pos)
318 nhassert(pos.X >= 0 && pos.X < console.width);
319 nhassert(pos.Y >= 0 && pos.Y < console.height);
321 cell_t * dst = buffer + (console.width * pos.Y) + pos.X;
324 if (iflags.debug.immediateflips && buffer == console.back_buffer)
329 * Called after returning from ! or ^Z
338 kill_char = 21; /* cntl-U */
339 iflags.cbreak = TRUE;
343 for (k = 0; k < CLR_MAX; ++k)
344 ttycolors[k] = NO_COLOR;
348 /* reset terminal to original state */
353 cmov(ttyDisplay->curx, ttyDisplay->cury);
357 restore_original_console_font();
358 if (orig_QuickEdit) {
361 GetConsoleMode(console.hConIn, &cmode);
362 cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
363 SetConsoleMode(console.hConIn, cmode);
367 /* called by init_nhwindows() and resume_nhwindows() */
379 tty_startup(wid, hgt)
382 *wid = console.width;
383 *hgt = console.height;
384 set_option_mod_status("mouse_support", SET_IN_GAME);
388 tty_number_pad(state)
398 tty_number_pad(1); /* make keypad send digits */
405 really_move_cursor();
406 buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
408 FlushConsoleInputBuffer(console.hConIn);
412 CtrlHandler(ctrltype)
416 /* case CTRL_C_EVENT: */
417 case CTRL_BREAK_EVENT:
419 case CTRL_CLOSE_EVENT:
420 case CTRL_LOGOFF_EVENT:
421 case CTRL_SHUTDOWN_EVENT:
422 getreturn_enabled = FALSE;
423 #ifndef NOSAVEONHANGUP
426 #if defined(SAFERHANGUP)
427 CloseHandle(console.hConIn); /* trigger WAIT_FAILED */
435 /* called by pcmain() and process_options() */
442 /* Initialize the function pointer that points to
443 * the kbhit() equivalent, in this TTY case nttty_kbhit()
445 nt_kbhit = nttty_kbhit;
447 if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) {
448 /* Unable to set control handler */
449 cmode = 0; /* just to have a statement to break on for debugger */
455 really_move_cursor();
461 /* go back to using the safe routines */
466 process_keystroke(ir, valid, numberpad, portdebug)
472 int ch = keyboard_handler.pProcessKeystroke(
473 console.hConIn, ir, valid, numberpad, portdebug);
474 /* check for override */
475 if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
476 ch = key_overrides[ch];
483 return keyboard_handler.pNHkbhit(console.hConIn, &ir);
492 really_move_cursor();
493 if (iflags.debug_fuzzer)
495 return (program_state.done_hup)
497 : keyboard_handler.pCheckInput(
498 console.hConIn, &ir, &count, iflags.num_pad, 0, &mod, &cc);
508 really_move_cursor();
509 if (iflags.debug_fuzzer)
511 ch = (program_state.done_hup)
513 : keyboard_handler.pCheckInput(
514 console.hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc);
522 static void set_console_cursor(int x, int y)
524 nhassert(x >= 0 && x < console.width);
525 nhassert(y >= 0 && y < console.height);
527 console.cursor.X = max(0, min(console.width - 1, x));
528 console.cursor.Y = max(0, min(console.height - 1, y));
535 char oldtitle[BUFSZ], newtitle[BUFSZ];
536 if (display_cursor_info && wizard) {
538 if (GetConsoleTitle(oldtitle, BUFSZ)) {
541 Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle,
542 ttyDisplay->curx, ttyDisplay->cury,
543 console.cursor.X, console.cursor.Y);
544 (void) SetConsoleTitle(newtitle);
548 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
551 SetConsoleCursorPosition(console.hConOut, console.cursor);
558 ttyDisplay->cury = y;
559 ttyDisplay->curx = x;
561 set_console_cursor(x, y);
568 ttyDisplay->curx = x;
569 ttyDisplay->cury = y;
571 set_console_cursor(x, y);
578 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
584 xputc2_core(ch1, ch2)
588 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
589 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
591 boolean inverse = FALSE;
594 /* xputc_core()
\82©
\82ç
\82Ì
\83R
\83s
\81[ */
595 inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
596 console.attr = (inverse) ?
597 ttycolors_inv[console.current_nhcolor] :
598 ttycolors[console.current_nhcolor];
599 if (console.current_nhattr[ATR_BOLD])
600 console.attr |= (inverse) ?
601 BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
603 cell.attribute = console.attr;
605 /*
\89E
\92[
\82É1
\83o
\83C
\83g
\95ª
\82µ
\82©
\8bó
\82«
\82ª
\82È
\82¢
\8fê
\8d\87 */
606 if (console.cursor.X == console.width - 2) {
607 /*
\8bó
\94\92\95\
\8e¦ */
608 cell.character = ' ';
610 buffer_write(console.back_buffer, &cell, console.cursor);
612 if (console.cursor.Y < console.height - 1) {
613 /*
\8e\9f\82Ì
\8ds
\82É */
614 console.cursor.X = 1;
617 /*
\8aù
\82É
\89º
\92[
\82Ì
\8fê
\8d\87\82Í
\82È
\82É
\82à
\82µ
\82È
\82¢ */
622 cell.character = ch1;
624 buffer_write(console.back_buffer, &cell, console.cursor);
627 cell.character = ch2;
629 buffer_write(console.back_buffer, &cell, console.cursor);
631 if (console.cursor.X == console.width - 1) {
632 if (console.cursor.Y < console.height - 1) {
633 console.cursor.X = 1;
640 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
641 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
649 /* wintty.c
\82Å
\82Í 1
\83o
\83C
\83g
\96\88\82É curx
\82ð
\89Á
\8eZ
\82·
\82é
\82ª
\81A
\82±
\82±
\82Í
650 2
\83o
\83C
\83g
\82½
\82Ü
\82Á
\82Ä
\82©
\82ç
\8cÄ
\82Ñ
\8fo
\82³
\82ê
\82é
\82Ì
\82Å
\81A1
\95¶
\8e\9a\95ª
\90æ
\82É
\90i
\82ñ
\82Å
651 \82µ
\82Ü
\82Á
\82Ä
\82¢
\82é
\81B
\8f]
\82Á
\82Ä 1
\82ð
\88ø
\82
\81B */
652 console.cursor.X = ttyDisplay->curx - 1;
653 console.cursor.Y = ttyDisplay->cury;
655 xputc2_core(ch1, ch2);
664 int slen = strlen(s);
667 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
670 for (k = 0; k < slen && s[k]; ++k)
675 /* xputc_core() and g_putch() are the only
676 * two routines that actually place output
683 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
684 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
686 boolean inverse = FALSE;
691 if (console.cursor.Y < console.height - 1)
695 console.cursor.X = 1;
698 if (console.cursor.X > 1) {
700 } else if(console.cursor.Y > 0) {
701 console.cursor.X = console.width - 1;
707 inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
708 console.attr = (inverse) ?
709 ttycolors_inv[console.current_nhcolor] :
710 ttycolors[console.current_nhcolor];
711 if (console.current_nhattr[ATR_BOLD])
712 console.attr |= (inverse) ?
713 BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
715 cell.attribute = console.attr;
716 cell.character = (console.has_unicode ? console.cpMap[ch] : ch);
717 #if 1 /*JP*//*
\8fí
\82É1
\83o
\83C
\83g
\95¶
\8e\9a*/
721 buffer_write(console.back_buffer, &cell, console.cursor);
723 if (console.cursor.X == console.width - 1) {
724 if (console.cursor.Y < console.height - 1) {
725 console.cursor.X = 1;
733 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
734 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
738 * Overrides wintty.c function of the same name
739 * for win32. It is used for glyphs only, not text.
746 boolean inverse = FALSE;
747 unsigned char ch = (unsigned char) in_ch;
749 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
751 inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
752 console.attr = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse) ?
753 ttycolors_inv[console.current_nhcolor] :
754 ttycolors[console.current_nhcolor];
755 if (console.current_nhattr[ATR_BOLD])
756 console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
760 cell.attribute = console.attr;
761 cell.character = (console.has_unicode ? cp437[ch] : ch);
762 #if 1 /*JP*//*
\8fí
\82É1
\83o
\83C
\83g
\95¶
\8e\9a*/
766 buffer_write(console.back_buffer, &cell, console.cursor);
772 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
773 buffer_clear_to_end_of_line(console.back_buffer, console.cursor.X,
775 tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
781 buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
794 ttyDisplay->curx = ttyDisplay->cury = 0;
795 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
801 set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
808 buffer_fill_to_end(console.back_buffer, &clear_cell, ttyDisplay->curx,
810 tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
816 if (flags.silent || iflags.debug_fuzzer)
821 volatile int junk; /* prevent optimizer from eliminating loop below */
826 /* delay 50 ms - uses ANSI C clock() function now */
832 if (iflags.debug_fuzzer)
835 while (goal > clock()) {
836 k = junk; /* Do nothing */
845 * CLR_BROWN 3 low-intensity yellow
849 * CLR_GRAY 7 low-intensity white
852 * CLR_BRIGHT_GREEN 10
855 * CLR_BRIGHT_MAGENTA 13
866 ttycolors[CLR_BLACK] = FOREGROUND_INTENSITY; /* fix by Quietust */
867 ttycolors[CLR_RED] = FOREGROUND_RED;
868 ttycolors[CLR_GREEN] = FOREGROUND_GREEN;
869 ttycolors[CLR_BROWN] = FOREGROUND_GREEN | FOREGROUND_RED;
870 ttycolors[CLR_BLUE] = FOREGROUND_BLUE;
871 ttycolors[CLR_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED;
872 ttycolors[CLR_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE;
873 ttycolors[CLR_GRAY] = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
874 ttycolors[NO_COLOR] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
875 ttycolors[CLR_ORANGE] = FOREGROUND_RED | FOREGROUND_INTENSITY;
876 ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
877 ttycolors[CLR_YELLOW] = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
878 ttycolors[CLR_BRIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
879 ttycolors[CLR_BRIGHT_MAGENTA]=FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
880 ttycolors[CLR_BRIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
881 ttycolors[CLR_WHITE] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED
882 | FOREGROUND_INTENSITY;
884 ttycolors_inv[CLR_BLACK] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
885 | BACKGROUND_INTENSITY;
886 ttycolors_inv[CLR_RED] = BACKGROUND_RED | BACKGROUND_INTENSITY;
887 ttycolors_inv[CLR_GREEN] = BACKGROUND_GREEN;
888 ttycolors_inv[CLR_BROWN] = BACKGROUND_GREEN | BACKGROUND_RED;
889 ttycolors_inv[CLR_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
890 ttycolors_inv[CLR_MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED;
891 ttycolors_inv[CLR_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE;
892 ttycolors_inv[CLR_GRAY] = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE;
893 ttycolors_inv[NO_COLOR] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
894 ttycolors_inv[CLR_ORANGE] = BACKGROUND_RED | BACKGROUND_INTENSITY;
895 ttycolors_inv[CLR_BRIGHT_GREEN]= BACKGROUND_GREEN | BACKGROUND_INTENSITY;
896 ttycolors_inv[CLR_YELLOW] = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
897 ttycolors_inv[CLR_BRIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
898 ttycolors_inv[CLR_BRIGHT_MAGENTA] =BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
899 ttycolors_inv[CLR_BRIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
900 ttycolors_inv[CLR_WHITE] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
901 | BACKGROUND_INTENSITY;
904 ttycolors[0] = FOREGROUND_INTENSITY;
905 ttycolors_inv[0] = BACKGROUND_INTENSITY;
906 for (k = 1; k < SIZE(ttycolors); ++k) {
907 ttycolors[k] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
908 ttycolors_inv[k] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
911 init_ttycolor_completed = TRUE;
913 #endif /* TEXTCOLOR */
919 if ((color >= 0) && (color < CLR_MAX))
922 if ((color == CLR_BLACK) || (color == CLR_WHITE) || (color == NO_COLOR))
930 term_attr_fixup(int attrmask)
936 term_start_attr(int attrib)
938 console.current_nhattr[attrib] = TRUE;
939 if (attrib) console.current_nhattr[ATR_NONE] = FALSE;
943 term_end_attr(int attrib)
954 console.current_nhattr[attrib] = FALSE;
955 console.current_nhattr[ATR_NONE] = TRUE;
956 /* re-evaluate all attr now for performance at output time */
957 for (k=ATR_NONE; k <= ATR_INVERSE; ++k) {
958 if (console.current_nhattr[k])
959 console.current_nhattr[ATR_NONE] = FALSE;
964 term_end_raw_bold(void)
966 term_end_attr(ATR_BOLD);
970 term_start_raw_bold(void)
972 term_start_attr(ATR_BOLD);
976 term_start_color(int color)
979 if (color >= 0 && color < CLR_MAX) {
980 console.current_nhcolor = color;
983 console.current_nhcolor = NO_COLOR;
990 console.foreground = DEFTEXTCOLOR;
992 console.attr = (console.foreground | console.background);
993 console.current_nhcolor = NO_COLOR;
999 term_start_attr(ATR_BOLD);
1005 term_end_attr(ATR_BOLD);
1008 #ifndef NO_MOUSE_ALLOWED
1010 toggle_mouse_support()
1012 static int qeinit = 0;
1015 GetConsoleMode(console.hConIn, &cmode);
1018 orig_QuickEdit = ((cmode & ENABLE_QUICK_EDIT_MODE) != 0);
1020 switch(iflags.wc_mouse_support) {
1022 cmode |= ENABLE_MOUSE_INPUT;
1025 cmode |= ENABLE_MOUSE_INPUT;
1026 cmode &= ~ENABLE_QUICK_EDIT_MODE;
1027 cmode |= ENABLE_EXTENDED_FLAGS;
1032 cmode &= ~ENABLE_MOUSE_INPUT;
1034 cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
1036 SetConsoleMode(console.hConIn, cmode);
1040 /* handle tty options updates here */
1042 nttty_preference_update(pref)
1045 if (stricmp(pref, "mouse_support") == 0) {
1046 #ifndef NO_MOUSE_ALLOWED
1047 toggle_mouse_support();
1050 if (stricmp(pref, "symset") == 0)
1051 check_and_set_font();
1057 win32con_debug_keystrokes()
1063 while (!valid || ch != 27) {
1064 nocmov(ttyDisplay->curx, ttyDisplay->cury);
1065 ReadConsoleInput(console.hConIn, &ir, 1, &count);
1066 if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
1067 ch = process_keystroke(&ir, &valid, iflags.num_pad, 1);
1072 win32con_handler_info()
1076 if (!keyboard_handler.pSourceAuthor && !keyboard_handler.pSourceWhere)
1077 pline("Keyboard handler source info and author unavailable.");
1079 if (keyboard_handler.pKeyHandlerName &&
1080 keyboard_handler.pKeyHandlerName(&buf, 1)) {
1082 xputs("Keystroke handler loaded: \n ");
1085 if (keyboard_handler.pSourceAuthor &&
1086 keyboard_handler.pSourceAuthor(&buf)) {
1088 xputs("Keystroke handler Author: \n ");
1091 if (keyboard_handler.pSourceWhere &&
1092 keyboard_handler.pSourceWhere(&buf)) {
1094 xputs("Keystroke handler source code available at:\n ");
1097 xputs("\nPress any key to resume.");
1104 win32con_toggle_cursor_info()
1106 display_cursor_info = !display_cursor_info;
1114 char digits[] = "0123456789";
1115 int length, i, idx, val;
1120 kp = index(op, '/');
1124 length = strlen(kp);
1125 if (length < 1 || length > 3)
1127 for (i = 0; i < length; i++)
1128 if (!index(digits, kp[i]))
1131 length = strlen(op);
1132 if (length < 1 || length > 3)
1134 for (i = 0; i < length; i++)
1135 if (!index(digits, op[i]))
1139 if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1)
1141 key_overrides[idx] = val;
1144 void unload_keyboard_handler()
1146 nhassert(keyboard_handler.hLibrary != NULL);
1148 FreeLibrary(keyboard_handler.hLibrary);
1149 memset(&keyboard_handler, 0, sizeof(keyboard_handler_t));
1153 load_keyboard_handler(const char * inName)
1155 char path[MAX_ALTKEYHANDLER + 4];
1156 strcpy(path, inName);
1157 strcat(path, ".dll");
1159 HANDLE hLibrary = LoadLibrary(path);
1161 if (hLibrary == NULL)
1164 PROCESS_KEYSTROKE pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
1165 hLibrary, TEXT("ProcessKeystroke"));
1166 NHKBHIT pNHkbhit = (NHKBHIT) GetProcAddress(
1167 hLibrary, TEXT("NHkbhit"));
1168 CHECKINPUT pCheckInput =
1169 (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
1171 if (!pProcessKeystroke || !pNHkbhit || !pCheckInput)
1175 if (keyboard_handler.hLibrary != NULL)
1176 unload_keyboard_handler();
1178 keyboard_handler.hLibrary = hLibrary;
1180 keyboard_handler.pProcessKeystroke = pProcessKeystroke;
1181 keyboard_handler.pNHkbhit = pNHkbhit;
1182 keyboard_handler.pCheckInput = pCheckInput;
1184 keyboard_handler.pSourceWhere =
1185 (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
1186 keyboard_handler.pSourceAuthor =
1187 (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
1188 keyboard_handler.pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
1189 hLibrary, TEXT("KeyHandlerName"));
1195 void set_altkeyhandler(const char * inName)
1197 if (strlen(inName) >= MAX_ALTKEYHANDLER) {
1198 config_error_add("altkeyhandler name '%s' is too long", inName);
1202 char name[MAX_ALTKEYHANDLER];
1203 strcpy(name, inName);
1205 /* We support caller mistakenly giving name with '.dll' extension */
1206 char * ext = strchr(name, '.');
1207 if (ext != NULL) *ext = '\0';
1209 if (load_keyboard_handler(name))
1210 strcpy(iflags.altkeyhandler, name);
1212 config_error_add("unable to load altkeyhandler '%s'", name);
1223 VA_DECL(const char *, s)
1227 VA_INIT(s, const char *);
1228 /* error() may get called before tty is initialized */
1229 if (iflags.window_inited)
1232 (void) vsprintf(&buf[1], s, VA_ARGS);
1234 really_move_cursor();
1242 really_move_cursor();
1247 tty_change_color(color_number, rgb, reverse)
1248 int color_number, reverse;
1251 /* Map NetHack color index to NT Console palette index */
1252 int idx, win32_color_number[] = {
1253 0, /* CLR_BLACK 0 */
1255 2, /* CLR_GREEN 2 */
1256 6, /* CLR_BROWN 3 */
1258 5, /* CLR_MAGENTA 5 */
1262 12, /* CLR_ORANGE 9 */
1263 10, /* CLR_BRIGHT_GREEN 10 */
1264 14, /* CLR_YELLOW 11 */
1265 9, /* CLR_BRIGHT_BLUE 12 */
1266 13, /* CLR_BRIGHT_MAGENTA 13 */
1267 11, /* CLR_BRIGHT_CYAN 14 */
1268 15 /* CLR_WHITE 15 */
1271 if (color_number < 0) { /* indicates OPTIONS=palette with no value */
1272 /* copy the NetHack palette into UserDefinedColors */
1273 for (k = 0; k < CLR_MAX; k++)
1274 UserDefinedColors[k] = NetHackColors[k];
1275 } else if (color_number >= 0 && color_number < CLR_MAX) {
1276 if (!altered_palette) {
1277 /* make sure a full suite is available */
1278 for (k = 0; k < CLR_MAX; k++)
1279 UserDefinedColors[k] = DefaultColors[k];
1281 idx = win32_color_number[color_number];
1282 UserDefinedColors[idx] = rgb;
1284 altered_palette = TRUE;
1288 tty_get_color_string()
1297 const struct others {
1299 const char *colorname;
1301 { CLR_MAGENTA, "purple" },
1302 { CLR_BRIGHT_MAGENTA, "bright purple" },
1303 { NO_COLOR, "dark gray" },
1304 { NO_COLOR, "dark grey" },
1305 { CLR_GRAY, "grey" },
1309 for (cnt = 0; cnt < CLR_MAX; ++cnt) {
1310 if (!strcmpi(c, c_obj_colors[cnt]))
1313 for (cnt = 0; cnt < SIZE(othernames); ++cnt) {
1314 if (!strcmpi(c, othernames[cnt].colorname))
1315 return othernames[cnt].idx;
1321 * Returns 0 if badoption syntax
1324 alternative_palette(op)
1328 * palette:color-R-G-B
1329 * OPTIONS=palette:green-4-3-1, palette:0-0-0-0
1331 int fieldcnt, color_number, rgb, red, green, blue;
1332 char *fields[4], *cp;
1335 change_color(-1, 0, 0); /* indicates palette option with
1336 no value meaning "load an entire
1337 hard-coded NetHack palette." */
1341 cp = fields[0] = op;
1342 for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1343 cp = index(cp, '-');
1346 fields[fieldcnt] = cp;
1349 for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
1350 *(fields[fieldcnt]) = '\0';
1354 for (fieldcnt = 0; fieldcnt < 4; ++fieldcnt) {
1355 if (fieldcnt == 0 && isalpha(*(fields[0]))) {
1356 color_number = match_color_name(fields[0]);
1357 if (color_number == -1)
1360 int dcount = 0, cval = 0;
1361 cp = fields[fieldcnt];
1362 if (*cp == '\\' && index("0123456789xXoO", cp[1])) {
1363 const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
1366 if (*cp == 'x' || *cp == 'X')
1367 for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
1368 cval = (int) ((cval * 16) + (dp - hex) / 2);
1369 else if (*cp == 'o' || *cp == 'O')
1370 for (++cp; (index("01234567", *cp)) && (dcount++ < 3);
1372 cval = (cval * 8) + (*cp - '0');
1376 for (; *cp && (index("0123456789", *cp)) && (dcount++ < 3);
1378 cval = (cval * 10) + (*cp - '0');
1382 color_number = cval;
1396 rgb = RGB(red, green, blue);
1397 if (color_number >= 0 && color_number < CLR_MAX)
1398 change_color(color_number, rgb, 0);
1403 * This uses an undocumented method to set console attributes
1404 * at runtime including console palette
1406 * VOID WINAPI SetConsolePalette(COLORREF palette[16])
1408 * Author: James Brown at www.catch22.net
1410 * Set palette of current console.
1411 * Palette should be of the form:
1413 * COLORREF DefaultColors[CLR_MAX] =
1415 * 0x00000000, 0x00800000, 0x00008000, 0x00808000,
1416 * 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
1417 * 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
1418 * 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
1422 #pragma pack(push, 1)
1425 * Structure to send console via WM_SETCONSOLEINFO
1427 typedef struct _CONSOLE_INFO {
1429 COORD ScreenBufferSize;
1445 USHORT ScreenColors;
1448 ULONG HistoryBufferSize;
1449 ULONG NumberOfHistoryBuffers;
1451 COLORREF ColorTable[16];
1456 WCHAR ConsoleTitle[0x100];
1461 BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci);
1462 static void GetConsoleSizeInfo(CONSOLE_INFO *pci);
1463 VOID WINAPI SetConsolePalette(COLORREF crPalette[16]);
1466 adjust_palette(VOID_ARGS)
1468 SetConsolePalette(UserDefinedColors);
1469 altered_palette = 0;
1473 /* only in Win2k+ (use FindWindow for NT4) */
1474 /* HWND WINAPI GetConsoleWindow(); */
1476 /* Undocumented console message */
1477 #define WM_SETCONSOLEINFO (WM_USER + 201)
1480 SetConsolePalette(COLORREF palette[16])
1482 CONSOLE_INFO ci = { sizeof(ci) };
1484 HWND hwndConsole = GetConsoleHandle();
1486 /* get current size/position settings rather than using defaults.. */
1487 GetConsoleSizeInfo(&ci);
1489 /* set these to zero to keep current settings */
1490 ci.FontSize.X = 0; /* def = 8 */
1491 ci.FontSize.Y = 0; /* def = 12 */
1492 ci.FontFamily = 0; /* def = 0x30 = FF_MODERN|FIXED_PITCH */
1493 ci.FontWeight = 0; /* 0x400; */
1494 /* lstrcpyW(ci.FaceName, L"Terminal"); */
1495 ci.FaceName[0] = L'\0';
1498 ci.FullScreen = FALSE;
1499 ci.QuickEdit = TRUE;
1500 ci.AutoPosition = 0x10000;
1501 ci.InsertMode = TRUE;
1502 ci.ScreenColors = MAKEWORD(0x7, 0x0);
1503 ci.PopupColors = MAKEWORD(0x5, 0xf);
1505 ci.HistoryNoDup = FALSE;
1506 ci.HistoryBufferSize = 50;
1507 ci.NumberOfHistoryBuffers = 4;
1510 for (i = 0; i < 16; i++)
1511 ci.ColorTable[i] = palette[i];
1513 ci.CodePage = GetConsoleOutputCP();
1514 ci.Hwnd = hwndConsole;
1516 lstrcpyW(ci.ConsoleTitle, L"");
1518 SetConsoleInfo(hwndConsole, &ci);
1522 * Wrapper around WM_SETCONSOLEINFO. We need to create the
1523 * necessary section (file-mapping) object in the context of the
1524 * process which owns the console, before posting the message
1527 SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci)
1529 DWORD dwConsoleOwnerPid;
1531 HANDLE hSection, hDupSection;
1536 * Open the process which "owns" the console
1538 GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid);
1539 hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
1542 * Create a SECTION object backed by page-file, then map a view of
1543 * this section into the owner process so we can write the contents
1544 * of the CONSOLE_INFO buffer into it
1546 hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
1550 * Copy our console structure into the section-object
1552 ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
1554 memcpy(ptrView, pci, pci->Length);
1555 UnmapViewOfFile(ptrView);
1558 * Map the memory into owner process
1560 DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection, 0,
1561 FALSE, DUPLICATE_SAME_ACCESS);
1563 /* Send console window the "update" message */
1564 SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM) hDupSection, 0);
1569 hThread = CreateRemoteThread(hProcess, 0, 0,
1570 (LPTHREAD_START_ROUTINE) CloseHandle,
1573 CloseHandle(hThread);
1574 CloseHandle(hSection);
1575 CloseHandle(hProcess);
1581 * Fill the CONSOLE_INFO structure with information
1582 * about the current console window
1585 GetConsoleSizeInfo(CONSOLE_INFO *pci)
1587 CONSOLE_SCREEN_BUFFER_INFO csbi;
1589 HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
1591 GetConsoleScreenBufferInfo(hConsoleOut, &csbi);
1593 pci->ScreenBufferSize = csbi.dwSize;
1594 pci->WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
1595 pci->WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
1596 pci->WindowPosX = csbi.srWindow.Left;
1597 pci->WindowPosY = csbi.srWindow.Top;
1601 GetConsoleHandle(void)
1603 HMODULE hMod = GetModuleHandle("kernel32.dll");
1604 GETCONSOLEWINDOW pfnGetConsoleWindow =
1605 (GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
1606 if (pfnGetConsoleWindow)
1607 return pfnGetConsoleWindow();
1609 return GetConsoleHwnd();
1613 GetConsoleHwnd(void)
1617 char OldTitle[1024], NewTitle[1024], TestTitle[1024];
1619 /* Get current window title */
1620 GetConsoleTitle(OldTitle, sizeof OldTitle);
1622 (void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
1623 GetCurrentProcessId());
1624 SetConsoleTitle(NewTitle);
1626 GetConsoleTitle(TestTitle, sizeof TestTitle);
1627 while (strcmp(TestTitle, NewTitle) != 0) {
1630 GetConsoleTitle(TestTitle, sizeof TestTitle);
1632 hwndFound = FindWindow(NULL, NewTitle);
1633 SetConsoleTitle(OldTitle);
1634 /* printf("%d iterations\n", iterations); */
1637 #endif /*CHANGE_COLOR*/
1639 static int CALLBACK EnumFontCallback(
1640 const LOGFONTW * lf, const TEXTMETRICW * tm, DWORD fontType, LPARAM lParam)
1642 LOGFONTW * lf_ptr = (LOGFONTW *) lParam;
1647 /* check_and_set_font ensures that the current font will render the symbols
1648 * that are currently being used correctly. If they will not be rendered
1649 * correctly, then it will change the font to a known good font.
1652 check_and_set_font()
1654 #if 0 /*JP*//*
\83R
\81[
\83h
\83y
\81[
\83W
\82Í
\95Ï
\8dX
\82µ
\82È
\82¢
\81B932
\82ð
\89¼
\92è
\82·
\82é
\81B*/
1655 if (!check_font_widths()) {
1656 raw_print("WARNING: glyphs too wide in console font."
1657 " Changing code page to 437 and font to Consolas\n");
1658 set_known_good_console_font();
1663 /* check_font_widths returns TRUE if all glyphs in current console font
1664 * fit within the width of a single console cell.
1669 CONSOLE_FONT_INFOEX console_font_info;
1670 console_font_info.cbSize = sizeof(console_font_info);
1671 BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
1672 &console_font_info);
1674 /* get console window and DC
1675 * NOTE: the DC from the console window does not have the correct
1676 * font selected at this point.
1678 HWND hWnd = GetConsoleWindow();
1679 HDC hDC = GetDC(hWnd);
1681 LOGFONTW logical_font;
1682 logical_font.lfCharSet = DEFAULT_CHARSET;
1683 wcscpy(logical_font.lfFaceName, console_font_info.FaceName);
1684 logical_font.lfPitchAndFamily = 0;
1686 /* getting matching console font */
1687 LOGFONTW matching_log_font = { 0 };
1688 EnumFontFamiliesExW(hDC, &logical_font, EnumFontCallback,
1689 (LPARAM) &matching_log_font, 0);
1691 if (matching_log_font.lfHeight == 0) {
1692 raw_print("Unable to enumerate system fonts\n");
1696 /* create font matching console font */
1697 LOGFONTW console_font_log_font = matching_log_font;
1698 console_font_log_font.lfWeight = console_font_info.FontWeight;
1699 console_font_log_font.lfHeight = console_font_info.dwFontSize.Y;
1700 console_font_log_font.lfWidth = console_font_info.dwFontSize.X;
1701 HFONT console_font = CreateFontIndirectW(&console_font_log_font);
1703 if (console_font == NULL) {
1704 raw_print("Unable to create console font\n");
1709 HGDIOBJ saved_font = SelectObject(hDC, console_font);
1711 /* determine whether it is a true type font */
1713 success = GetTextMetricsA(hDC, &tm);
1716 raw_print("Unable to get console font text metrics\n");
1720 boolean isTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
1722 /* determine which glyphs are used */
1724 memset(used, 0, sizeof(used));
1725 for (int i = 0; i < SYM_MAX; i++) {
1726 used[l_syms[i]] = TRUE;
1727 used[r_syms[i]] = TRUE;
1730 int wcUsedCount = 0;
1731 wchar_t wcUsed[256];
1732 for (int i = 0; i < sizeof(used); i++)
1734 wcUsed[wcUsedCount++] = cp437[i];
1736 /* measure the set of used glyphs to ensure they fit */
1737 boolean all_glyphs_fit = TRUE;
1739 for (int i = 0; i < wcUsedCount; i++) {
1743 success = GetCharABCWidthsW(hDC, wcUsed[i], wcUsed[i], &abc);
1744 width = abc.abcA + abc.abcB + abc.abcC;
1746 success = GetCharWidthW(hDC, wcUsed[i], wcUsed[i], &width);
1749 if (success && width > console_font_info.dwFontSize.X) {
1750 all_glyphs_fit = FALSE;
1757 SelectObject(hDC, saved_font);
1758 DeleteObject(console_font);
1760 return all_glyphs_fit;
1763 /* set_known_good_console_font sets the code page and font used by the console
1764 * to settings know to work well with NetHack. It also saves the original
1765 * settings so that they can be restored prior to NetHack exit.
1768 set_known_good_console_font()
1770 CONSOLE_FONT_INFOEX console_font_info;
1771 console_font_info.cbSize = sizeof(console_font_info);
1772 BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
1773 &console_font_info);
1775 console.font_changed = TRUE;
1776 console.original_font_info = console_font_info;
1777 console.original_code_page = GetConsoleOutputCP();
1779 wcscpy_s(console_font_info.FaceName,
1780 sizeof(console_font_info.FaceName)
1781 / sizeof(console_font_info.FaceName[0]),
1784 success = SetConsoleOutputCP(437);
1787 success = SetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info);
1791 /* restore_original_console_font will restore the console font and code page
1792 * settings to what they were when NetHack was launched.
1795 restore_original_console_font()
1797 if (console.font_changed) {
1799 raw_print("Restoring original font and code page\n");
1800 success = SetConsoleOutputCP(console.original_code_page);
1802 raw_print("Unable to restore original code page\n");
1804 success = SetCurrentConsoleFontEx(console.hConOut, FALSE,
1805 &console.original_font_info);
1807 raw_print("Unable to restore original font\n");
1809 console.font_changed = FALSE;
1813 /* set_cp_map() creates a mapping of every possible character of a code
1814 * page to its corresponding WCHAR. This is necessary due to the high
1815 * cost of making calls to MultiByteToWideChar() for every character we
1816 * wish to print to the console.
1821 if (console.has_unicode) {
1822 UINT codePage = GetConsoleOutputCP();
1824 if (codePage == 437) {
1825 memcpy(console.cpMap, cp437, sizeof(console.cpMap));
1827 for (int i = 0; i < 256; i++) {
1829 int count = MultiByteToWideChar(codePage, 0, &c, 1,
1830 &console.cpMap[i], 1);
1831 nhassert(count == 1);
1833 // If a character was mapped to unicode control codes,
1834 // remap to the appropriate unicode character per our
1835 // code page 437 mappings.
1836 if (console.cpMap[i] < 32)
1837 console.cpMap[i] = cp437[console.cpMap[i]];
1845 /* early_raw_print() is used during early game intialization prior to the
1846 * setting up of the windowing system. This allows early errors and panics
1847 * to have there messages displayed.
1849 * early_raw_print() eventually gets replaced by tty_raw_print().
1853 void early_raw_print(const char *s)
1855 if (console.hConOut == NULL)
1858 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
1859 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
1861 WORD attribute = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
1864 while (*s != '\0') {
1867 if (console.cursor.Y < console.height - 1)
1871 console.cursor.X = 1;
1874 if (console.cursor.X > 1) {
1876 } else if(console.cursor.Y > 0) {
1877 console.cursor.X = console.width - 1;
1882 WriteConsoleOutputAttribute(console.hConOut, &attribute,
1883 1, console.cursor, &unused);
1884 WriteConsoleOutputCharacterA(console.hConOut, s,
1885 1, console.cursor, &unused);
1886 if (console.cursor.X == console.width - 1) {
1887 if (console.cursor.Y < console.height - 1) {
1888 console.cursor.X = 1;
1898 nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
1899 nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
1901 SetConsoleCursorPosition(console.hConOut, console.cursor);
1906 /* nethack_enter_nttty() is the first thing that is called from main
1907 * once the tty port is confirmed.
1909 * We initialize all console state to support rendering to the console
1910 * through out flipping support at this time. This allows us to support
1911 * raw_print prior to our returning.
1913 * During this early initialization, we also determine the width and
1914 * height of the console that will be used. This width and height will
1917 * We also check and set the console font to a font that we know will work
1918 * well with nethack.
1920 * The intent of this early initialization is to get all state that is
1921 * not dependent upon game options initialized allowing us to simplify
1922 * any additional initialization that might be needed when we are actually
1925 * Other then the call below which clears the entire console buffer, no
1926 * other code outputs directly to the console other then the code that
1927 * handles flipping the back buffer.
1931 void nethack_enter_nttty()
1934 /* set up state needed by early_raw_print() */
1935 windowprocs.win_raw_print = early_raw_print;
1937 console.hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
1938 nhassert(console.hConOut != NULL); // NOTE: this assert will not print
1940 GetConsoleScreenBufferInfo(console.hConOut, &console.origcsbi);
1942 /* Testing of widths != COLNO has not turned up any problems. Need
1943 * to do a bit more testing and then we are likely to enable having
1944 * console width match window width.
1947 console.width = console.origcsbi.srWindow.Right -
1948 console.origcsbi.srWindow.Left + 1;
1949 console.Width = max(console.Width, COLNO);
1951 console.width = COLNO;
1954 console.height = console.origcsbi.srWindow.Bottom -
1955 console.origcsbi.srWindow.Top + 1;
1956 console.height = max(console.height, ROWNO + 3);
1958 console.buffer_size = console.width * console.height;
1961 /* clear the entire console buffer */
1962 int size = console.origcsbi.dwSize.X * console.origcsbi.dwSize.Y;
1964 set_console_cursor(0, 0);
1965 FillConsoleOutputAttribute(
1966 console.hConOut, CONSOLE_CLEAR_ATTRIBUTE,
1967 size, console.cursor, &unused);
1969 FillConsoleOutputCharacter(
1970 console.hConOut, CONSOLE_CLEAR_CHARACTER,
1971 size, console.cursor, &unused);
1973 set_console_cursor(1, 0);
1974 SetConsoleCursorPosition(console.hConOut, console.cursor);
1976 /* At this point early_raw_print will work */
1978 console.hConIn = GetStdHandle(STD_INPUT_HANDLE);
1979 nhassert(console.hConIn != NULL);
1981 /* grow the size of the console buffer if it is not wide enough */
1982 if (console.origcsbi.dwSize.X < console.width) {
1984 size.Y = console.origcsbi.dwSize.Y,
1985 size.X = console.width
1988 SetConsoleScreenBufferSize(console.hConOut, size);
1991 /* setup front and back buffers */
1992 int buffer_size_bytes = sizeof(cell_t) * console.buffer_size;
1994 console.front_buffer = (cell_t *)malloc(buffer_size_bytes);
1995 buffer_fill_to_end(console.front_buffer, &undefined_cell, 0, 0);
1997 console.back_buffer = (cell_t *)malloc(buffer_size_bytes);
1998 buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
2000 /* determine whether OS version has unicode support */
2001 console.has_unicode = ((GetVersion() & 0x80000000) == 0);
2003 /* check the font before we capture the code page map */
2004 check_and_set_font();
2007 /* Set console mode */
2009 GetConsoleMode(console.hConIn, &cmode);
2010 #ifdef NO_MOUSE_ALLOWED
2011 mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT
2012 | ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;
2014 mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
2015 | ENABLE_WINDOW_INPUT;
2017 /* Turn OFF the settings specified in the mask */
2019 #ifndef NO_MOUSE_ALLOWED
2020 cmode |= ENABLE_MOUSE_INPUT;
2022 SetConsoleMode(console.hConIn, cmode);
2024 /* load default keyboard handler */
2025 HKL keyboard_layout = GetKeyboardLayout(0);
2026 DWORD primary_language = (UINT_PTR) keyboard_layout & 0x3f;
2028 if (primary_language == LANG_ENGLISH) {
2029 if (!load_keyboard_handler("nhdefkey"))
2030 error("Unable to load nhdefkey.dll");
2032 if (!load_keyboard_handler("nhraykey"))
2033 error("Unable to load nhraykey.dll");
2036 #endif /* TTY_GRAPHICS */
2038 /* this is used as a printf() replacement when the window
2039 * system isn't initialized yet
2042 VA_DECL(const char *, fmt)
2044 char buf[ROWNO * COLNO]; /* worst case scenario */
2046 VA_INIT(fmt, const char *);
2047 Vsprintf(buf, fmt, VA_ARGS);
2048 if (redirect_stdout)
2049 fprintf(stdout, "%s", buf);
2052 if(!init_ttycolor_completed)
2054 /* if we have generated too many messages ... ask the user to
2055 * confirm and then clear.
2057 if (console.cursor.Y > console.height - 4) {
2058 xputs("Hit <Enter> to continue.");
2059 while (pgetchar() != '\n')
2062 set_console_cursor(1, 0);
2068 console.cursor.X = ttyDisplay->curx;
2069 console.cursor.Y = ttyDisplay->cury;
2074 jbuffer(*(str++), NULL, (void (__cdecl *)(unsigned int))xputc_core, xputc2_core);
2079 curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y);
2081 fprintf(stdout, "%s", buf);