Files
nethack/sys/windows/consoletty.c
nhmall e5f7ba9fe5 Windows virtual terminal sequences
Microsoft has been making a recommendation that programs should switch
from using the classic low-level console API calls to virtual terminal
sequences for a couple of years.

References:
"Our recommendation is to replace the classic Windows Console API with virtual
terminal sequences. This article will outline the difference between the two
and discuss the reasons for our recommendation."
From:
Classic Console APIs versus Virtual Terminal Sequences
https://docs.microsoft.com/en-us/windows/console/classic-vs-vt

The online documentation for WriteConsoleOutputCharacter() and
WriteConsoleOutputAttribute() have this disclaimer on them:
"This document describes console platform functionality that is no longer a
part of our ecosystem roadmap. We do not recommend using this content in new
products, but we will continue to support existing usages for the indefinite
future. Our preferred modern solution focuses on virtual terminal sequences
for maximum compatibility in cross-platform scenarios. You can find more
information about this design decision in our classic console vs. virtual
terminal document."

Since NetHack started out as a terminal program, before there was a
Windows "classic" console API introduced with Windows NT, it seemed only
fitting that the Windows console port should evolve in the virtual terminal
direction.

This is a first stab at it. The performance won't be as instantaneous as
the low-level console API's. That's likely partly because of this consoletty.c
initial implementation, but it may also partly be because under the hood in
the OS, there's recognitions/translations/conversions going on. Microsoft
states it will continue to evolve the Windows Terminal and console, and
hopefully it will improve. Hopefully it isn't too slow to play. It still
attempts to take advantage of the back buffer stuff that Barton House
introduced to minimize screen updates. At this point, it can still be
recompiled without the virtual terminal support by defining NO_VT when
compiling consoletty.c, or by commenting out the definition of
VIRTUAL_TERMINAL_SEQUENCES at the top of sys/windows/consoletty.c

That's the informational news, and the negative news out of the way.

There's some good news too. Because the virtual terminal sequences
support include 24-bit color support, the Windows console under virtual
terminal sequence can provide a more pleasant set of colors to the NetHack
console interface. To that end, some color changes have been implemented
in consoletty.c now.

It makes the console port ready to accept and display 24-bit color from
the NetHack core, if that should ever happen, as well.

As usual with a first implementation, there may be some bugs. Reports
are welcome.
2021-10-11 09:48:48 -04:00

2882 lines
87 KiB
C

/* NetHack 3.7 consoletty.c $NHDT-Date: 1596498316 2020/08/03 23:45:16 $ $NHDT-Branch: NetHack-3.7 $:$NHDT-Revision: 1.117 $ */
/* Copyright (c) NetHack PC Development Team 1993 */
/* NetHack may be freely redistributed. See license for details. */
/* tty.c - (Windows console) version */
/*
* Initial Creation M. Allison 1993/01/31
* Switch to low level console output routines M. Allison 2003/10/01
* Restrict cursor movement until input pending M. Lehotay 2003/10/02
* Call Unicode version of output API on NT R. Chason 2005/10/28
* Use of back buffer to improve performance B. House 2018/05/06
*
*/
#ifndef NO_VT
#define VIRTUAL_TERMINAL_SEQUENCES
#endif
#ifdef WIN32
#define NEED_VARARGS /* Uses ... */
#include "win32api.h"
#include "winos.h"
#include "hack.h"
#include "wintty.h"
#include <sys\types.h>
#include <sys\stat.h>
#ifdef VIRTUAL_TERMINAL_SEQUENCES
#include <locale.h>
#ifndef INTEGER_H
#include "integer.h"
#endif
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
extern boolean getreturn_enabled; /* from sys/share/pcsys.c */
extern int redirect_stdout;
#ifdef TTY_GRAPHICS
/*
* Console Buffer Flipping Support
*
* To minimize the number of calls into the WriteConsoleOutputXXX methods,
* we implement a notion of a console back buffer which keeps the next frame
* of console output as it is being composed. When ready to show the new
* frame, we compare this next frame to what is currently being output and
* only call WriteConsoleOutputXXX for those console values that need to
* change.
*
*/
#ifndef VIRTUAL_TERMINAL_SEQUENCES
#define CONSOLE_CLEAR_ATTRIBUTE \
(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define CONSOLE_UNDEFINED_ATTRIBUTE (0)
#else /* VIRTUAL_TERMINAL_SEQUENCES */
#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)
#define CONSOLE_CLEAR_CHARACTER (' ')
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
#define CONSOLE_UNDEFINED_CHARACTER ('\0')
#ifdef VIRTUAL_TERMINAL_SEQUENCES
enum console_attributes {
atr_bold = 1,
atr_dim = 2,
atr_uline = 4,
atr_blink = 8,
atr_inverse = 16
};
#define MAX_UTF8_SEQUENCE 7
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
typedef struct {
#ifndef VIRTUAL_TERMINAL_SEQUENCES
WCHAR character;
WORD attribute;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
uint8 utf8str[MAX_UTF8_SEQUENCE];
WCHAR wcharacter;
WORD attr;
long color24;
const char *colorseq;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
} cell_t;
#ifndef VIRTUAL_TERMINAL_SEQUENCES
cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE };
cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
CONSOLE_UNDEFINED_ATTRIBUTE };
#else /* VIRTUAL_TERMINAL_SEQUENCES */
cell_t clear_cell = { { CONSOLE_CLEAR_CHARACTER, 0, 0, 0, 0, 0, 0 },
CONSOLE_CLEAR_CHARACTER, 0, 0L, "\x1b[0m" };
cell_t undefined_cell = { { CONSOLE_UNDEFINED_CHARACTER, 0, 0, 0, 0, 0, 0 },
CONSOLE_UNDEFINED_CHARACTER, 0, 0L, (const char *) 0 };
static const uint8 empty_utf8str[MAX_UTF8_SEQUENCE] = { 0 };
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
/*
* The following WIN32 Console API routines are used in this file.
*
* CreateFile
* GetConsoleScreenBufferInfo
* GetStdHandle
* SetConsoleCursorPosition
* SetConsoleTextAttribute
* SetConsoleCtrlHandler
* PeekConsoleInput
* ReadConsoleInput
* GetConsoleOutputCP
#ifndef VIRTUAL_TERMINAL_SEQUENCES
* WriteConsoleOutputCharacter
* FillConsoleOutputAttribute
#endif
*/
static BOOL CtrlHandler(DWORD);
#ifndef VIRTUAL_TERMINAL_SEQUENCES
static void xputc_core(char);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
static void xputc_core(int);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
void cmov(int, int);
void nocmov(int, int);
int process_keystroke(INPUT_RECORD *, boolean *, boolean numberpad,
int portdebug);
static void init_ttycolor(void);
static void really_move_cursor(void);
static void check_and_set_font(void);
static boolean check_font_widths(void);
static void set_known_good_console_font(void);
static void restore_original_console_font(void);
extern void safe_routines(void);
#ifdef VIRTUAL_TERMINAL_SEQUENCES
void tty_ibmgraphics_fixup(void);
extern void (*utf8graphics_mode_callback)(void); /* symbols.c */
extern void (*ibmgraphics_mode_callback)(void); /* symbols.c */
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
/* Win32 Screen buffer,coordinate,console I/O information */
COORD ntcoord;
INPUT_RECORD ir;
static boolean orig_QuickEdit;
/* Support for changing console font if existing glyph widths are too wide */
/* Flag for whether NetHack was launched via the GUI, not the command line.
* The reason we care at all, is so that we can get
* a final RETURN at the end of the game when launched from the GUI
* to prevent the scoreboard (or panic message :-|) from vanishing
* immediately after it is displayed, yet not bother when started
* from the command line.
*/
int GUILaunched = FALSE;
/* Flag for whether unicode is supported */
static boolean init_ttycolor_completed;
#ifdef PORT_DEBUG
static boolean display_cursor_info = FALSE;
#endif
#ifdef CHANGE_COLOR
static void adjust_palette(void);
static int match_color_name(const char *);
typedef HWND(WINAPI *GETCONSOLEWINDOW)();
static HWND GetConsoleHandle(void);
static HWND GetConsoleHwnd(void);
static boolean altered_palette;
static COLORREF UserDefinedColors[CLR_MAX];
static COLORREF NetHackColors[CLR_MAX] = {
0x00000000, 0x00c80000, 0x0000c850, 0x00b4b432, 0x000000d2, 0x00800080,
0x000064b4, 0x00c0c0c0, 0x00646464, 0x00f06464, 0x0000ff00, 0x00ffff00,
0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
};
static COLORREF DefaultColors[CLR_MAX] = {
0x00000000, 0x00800000, 0x00008000, 0x00808000, 0x00000080, 0x00800080,
0x00008080, 0x00c0c0c0, 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
};
#endif
struct console_t {
WORD background;
WORD foreground;
WORD attr;
int current_nhcolor;
int current_nhattr[ATR_INVERSE+1];
COORD cursor;
HANDLE hConOut;
HANDLE hConIn;
CONSOLE_SCREEN_BUFFER_INFO orig_csbi;
int width;
int height;
boolean has_unicode;
int buffer_size;
cell_t * front_buffer;
cell_t * back_buffer;
WCHAR cpMap[256];
boolean font_changed;
CONSOLE_FONT_INFOEX orig_font_info;
#ifndef VIRTUAL_TERMINAL_SEQUENCES
UINT original_code_page;
} console = {
0,
(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
NO_COLOR,
#else /* VIRTUAL_TERMINAL_SEQUENCES */
UINT orig_code_page;
char *orig_localestr;
DWORD orig_in_cmode;
DWORD orig_out_cmode;
CONSOLE_FONT_INFOEX font_info;
UINT code_page;
char *localestr;
DWORD in_cmode;
DWORD out_cmode;
long color24;
} console = {
(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED), /* background */
(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED), /* foreground */
0, /* attr */
0, /* current_nhcolor */
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
{FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE},
#ifndef VIRTUAL_TERMINAL_SEQUENCES
{0, 0},
NULL,
NULL,
{ 0 },
0,
0,
FALSE,
0,
NULL,
NULL,
{ 0 },
FALSE,
{ 0 },
0
#else /* VIRTUAL_TERMINAL_SEQUENCES */
{ 0, 0 }, /* cursor */
NULL, /* hConOut*/
NULL, /* hConIn */
{ 0 }, /* cbsi */
0, /* width */
0, /* height */
FALSE, /* has_unicode */
0, /* buffer_size */
{ 0 }, /* front_buffer */
{ 0 }, /* back_buffer */
{ 0 }, /* cpMap */
FALSE, /* font_changed */
{ 0 }, /* orig_font_info */
0U, /* orig_code_page */
NULL, /* orig_localestr */
0, /* orig_in_cmode */
0, /* orig_out_cmode */
{ 0 }, /* font_info */
0U, /* code_page */
NULL, /* localestr */
0, /* in_cmode */
0, /* out_cmode */
0L /* color24 */
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
};
static DWORD ccount, acount;
#ifndef CLR_MAX
#define CLR_MAX 16
#endif
int ttycolors[CLR_MAX];
int ttycolors_inv[CLR_MAX];
#define MAX_OVERRIDES 256
unsigned char key_overrides[MAX_OVERRIDES];
static char nullstr[] = "";
char erase_char, kill_char;
#define DEFTEXTCOLOR ttycolors[7]
/* dynamic keystroke handling .DLL support */
typedef int(__stdcall *PROCESS_KEYSTROKE)(HANDLE, INPUT_RECORD *, boolean *,
boolean, int);
typedef int(__stdcall *NHKBHIT)(HANDLE, INPUT_RECORD *);
typedef int(__stdcall *CHECKINPUT)(HANDLE, INPUT_RECORD *, DWORD *, boolean,
int, int *, coord *);
typedef int(__stdcall *SOURCEWHERE)(char **);
typedef int(__stdcall *SOURCEAUTHOR)(char **);
typedef int(__stdcall *KEYHANDLERNAME)(char **, int);
typedef struct {
char * name; // name without DLL extension
HANDLE hLibrary;
PROCESS_KEYSTROKE pProcessKeystroke;
NHKBHIT pNHkbhit;
CHECKINPUT pCheckInput;
SOURCEWHERE pSourceWhere;
SOURCEAUTHOR pSourceAuthor;
KEYHANDLERNAME pKeyHandlerName;
} keyboard_handler_t;
keyboard_handler_t keyboard_handler;
#ifdef VIRTUAL_TERMINAL_SEQUENCES
long customcolors[CLR_MAX];
const char *esc_seq_colors[CLR_MAX];
struct rgbvalues {
int idx;
const char *name;
const char *hexval;
long r, gn, b;
} rgbtable[] = {
{ 0, "maroon", "#800000", 128, 0, 0 },
{ 1, "dark red", "#8B0000", 139, 0, 0 },
{ 2, "brown", "#A52A2A", 165, 42, 42 },
{ 3, "firebrick", "#B22222", 178, 34, 34 },
{ 4, "crimson", "#DC143C", 220, 20, 60 },
{ 5, "red", "#FF0000", 255, 0, 0 },
{ 6, "tomato", "#FF6347", 255, 99, 71 },
{ 7, "coral", "#FF7F50", 255, 127, 80 },
{ 8, "indian red", "#CD5C5C", 205, 92, 92 },
{ 9, "light coral", "#F08080", 240, 128, 128 },
{ 10, "dark salmon", "#E9967A", 233, 150, 122 },
{ 11, "salmon", "#FA8072", 250, 128, 114 },
{ 12, "light salmon", "#FFA07A", 255, 160, 122 },
{ 13, "orange red", "#FF4500", 255, 69, 0 },
{ 14, "dark orange", "#FF8C00", 255, 140, 0 },
{ 15, "orange", "#FFA500", 255, 165, 0 },
{ 16, "gold", "#FFD700", 255, 215, 0 },
{ 17, "dark golden rod", "#B8860B", 184, 134, 11 },
{ 18, "golden rod", "#DAA520", 218, 165, 32 },
{ 19, "pale golden rod", "#EEE8AA", 238, 232, 170 },
{ 20, "dark khaki", "#BDB76B", 189, 183, 107 },
{ 21, "khaki", "#F0E68C", 240, 230, 140 },
{ 22, "olive", "#808000", 128, 128, 0 },
{ 23, "yellow", "#FFFF00", 255, 255, 0 },
{ 24, "yellow green", "#9ACD32", 154, 205, 50 },
{ 25, "dark olive green", "#556B2F", 85, 107, 47 },
{ 26, "olive drab", "#6B8E23", 107, 142, 35 },
{ 27, "lawn green", "#7CFC00", 124, 252, 0 },
{ 28, "chart reuse", "#7FFF00", 127, 255, 0 },
{ 29, "green yellow", "#ADFF2F", 173, 255, 47 },
{ 30, "dark green", "#006400", 0, 100, 0 },
{ 31, "green", "#008000", 0, 128, 0 },
{ 32, "forest green", "#228B22", 34, 139, 34 },
{ 33, "lime", "#00FF00", 0, 255, 0 },
{ 34, "lime green", "#32CD32", 50, 205, 50 },
{ 35, "light green", "#90EE90", 144, 238, 144 },
{ 36, "pale green", "#98FB98", 152, 251, 152 },
{ 37, "dark sea green", "#8FBC8F", 143, 188, 143 },
{ 38, "medium spring green", "#00FA9A", 0, 250, 154 },
{ 39, "spring green", "#00FF7F", 0, 255, 127 },
{ 40, "sea green", "#2E8B57", 46, 139, 87 },
{ 41, "medium aqua marine", "#66CDAA", 102, 205, 170 },
{ 42, "medium sea green", "#3CB371", 60, 179, 113 },
{ 43, "light sea green", "#20B2AA", 32, 178, 170 },
{ 44, "dark slate gray", "#2F4F4F", 47, 79, 79 },
{ 45, "teal", "#008080", 0, 128, 128 },
{ 46, "dark cyan", "#008B8B", 0, 139, 139 },
{ 47, "aqua", "#00FFFF", 0, 255, 255 },
{ 48, "cyan", "#00FFFF", 0, 255, 255 },
{ 49, "light cyan", "#E0FFFF", 224, 255, 255 },
{ 50, "dark turquoise", "#00CED1", 0, 206, 209 },
{ 51, "turquoise", "#40E0D0", 64, 224, 208 },
{ 52, "medium turquoise", "#48D1CC", 72, 209, 204 },
{ 53, "pale turquoise", "#AFEEEE", 175, 238, 238 },
{ 54, "aqua marine", "#7FFFD4", 127, 255, 212 },
{ 55, "powder blue", "#B0E0E6", 176, 224, 230 },
{ 56, "cadet blue", "#5F9EA0", 95, 158, 160 },
{ 57, "steel blue", "#4682B4", 70, 130, 180 },
{ 58, "corn flower blue", "#6495ED", 100, 149, 237 },
{ 59, "deep sky blue", "#00BFFF", 0, 191, 255 },
{ 60, "dodger blue", "#1E90FF", 30, 144, 255 },
{ 61, "light blue", "#ADD8E6", 173, 216, 230 },
{ 62, "sky blue", "#87CEEB", 135, 206, 235 },
{ 63, "light sky blue", "#87CEFA", 135, 206, 250 },
{ 64, "midnight blue", "#191970", 25, 25, 112 },
{ 65, "navy", "#000080", 0, 0, 128 },
{ 66, "dark blue", "#00008B", 0, 0, 139 },
{ 67, "medium blue", "#0000CD", 0, 0, 205 },
{ 68, "blue", "#0000FF", 0, 0, 255 },
{ 69, "royal blue", "#4169E1", 65, 105, 225 },
{ 70, "blue violet", "#8A2BE2", 138, 43, 226 },
{ 71, "indigo", "#4B0082", 75, 0, 130 },
{ 72, "dark slate blue", "#483D8B", 72, 61, 139 },
{ 73, "slate blue", "#6A5ACD", 106, 90, 205 },
{ 74, "medium slate blue", "#7B68EE", 123, 104, 238 },
{ 75, "medium purple", "#9370DB", 147, 112, 219 },
{ 76, "dark magenta", "#8B008B", 139, 0, 139 },
{ 77, "dark violet", "#9400D3", 148, 0, 211 },
{ 78, "dark orchid", "#9932CC", 153, 50, 204 },
{ 79, "medium orchid", "#BA55D3", 186, 85, 211 },
{ 80, "purple", "#800080", 128, 0, 128 },
{ 81, "thistle", "#D8BFD8", 216, 191, 216 },
{ 82, "plum", "#DDA0DD", 221, 160, 221 },
{ 83, "violet", "#EE82EE", 238, 130, 238 },
{ 84, "magenta / fuchsia", "#FF00FF", 255, 0, 255 },
{ 85, "orchid", "#DA70D6", 218, 112, 214 },
{ 86, "medium violet red", "#C71585", 199, 21, 133 },
{ 87, "pale violet red", "#DB7093", 219, 112, 147 },
{ 88, "deep pink", "#FF1493", 255, 20, 147 },
{ 89, "hot pink", "#FF69B4", 255, 105, 180 },
{ 90, "light pink", "#FFB6C1", 255, 182, 193 },
{ 91, "pink", "#FFC0CB", 255, 192, 203 },
{ 92, "antique white", "#FAEBD7", 250, 235, 215 },
{ 93, "beige", "#F5F5DC", 245, 245, 220 },
{ 94, "bisque", "#FFE4C4", 255, 228, 196 },
{ 95, "blanched almond", "#FFEBCD", 255, 235, 205 },
{ 96, "wheat", "#F5DEB3", 245, 222, 179 },
{ 97, "corn silk", "#FFF8DC", 255, 248, 220 },
{ 98, "lemon chiffon", "#FFFACD", 255, 250, 205 },
{ 99, "light golden rod yellow", "#FAFAD2", 250, 250, 210 },
{ 100, "light yellow", "#FFFFE0", 255, 255, 224 },
{ 101, "saddle brown", "#8B4513", 139, 69, 19 },
{ 102, "sienna", "#A0522D", 160, 82, 45 },
{ 103, "chocolate", "#D2691E", 210, 105, 30 },
{ 104, "peru", "#CD853F", 205, 133, 63 },
{ 105, "sandy brown", "#F4A460", 244, 164, 96 },
{ 106, "burly wood", "#DEB887", 222, 184, 135 },
{ 107, "tan", "#D2B48C", 210, 180, 140 },
{ 108, "rosy brown", "#BC8F8F", 188, 143, 143 },
{ 109, "moccasin", "#FFE4B5", 255, 228, 181 },
{ 110, "navajo white", "#FFDEAD", 255, 222, 173 },
{ 111, "peach puff", "#FFDAB9", 255, 218, 185 },
{ 112, "misty rose", "#FFE4E1", 255, 228, 225 },
{ 113, "lavender blush", "#FFF0F5", 255, 240, 245 },
{ 114, "linen", "#FAF0E6", 250, 240, 230 },
{ 115, "old lace", "#FDF5E6", 253, 245, 230 },
{ 116, "papaya whip", "#FFEFD5", 255, 239, 213 },
{ 117, "sea shell", "#FFF5EE", 255, 245, 238 },
{ 118, "mint cream", "#F5FFFA", 245, 255, 250 },
{ 119, "slate gray", "#708090", 112, 128, 144 },
{ 120, "light slate gray", "#778899", 119, 136, 153 },
{ 121, "light steel blue", "#B0C4DE", 176, 196, 222 },
{ 122, "lavender", "#E6E6FA", 230, 230, 250 },
{ 123, "floral white", "#FFFAF0", 255, 250, 240 },
{ 124, "alice blue", "#F0F8FF", 240, 248, 255 },
{ 125, "ghost white", "#F8F8FF", 248, 248, 255 },
{ 126, "honeydew", "#F0FFF0", 240, 255, 240 },
{ 127, "ivory", "#FFFFF0", 255, 255, 240 },
{ 128, "azure", "#F0FFFF", 240, 255, 255 },
{ 129, "snow", "#FFFAFA", 255, 250, 250 },
{ 130, "black", "#000000", 0, 0, 0 },
{ 131, "dim gray / dim grey", "#696969", 105, 105, 105 },
{ 132, "gray / grey", "#808080", 128, 128, 128 },
{ 133, "dark gray / dark grey", "#A9A9A9", 169, 169, 169 },
{ 134, "silver", "#C0C0C0", 192, 192, 192 },
{ 135, "light gray / light grey", "#D3D3D3", 211, 211, 211 },
{ 136, "gainsboro", "#DCDCDC", 220, 220, 220 },
{ 137, "white smoke", "#F5F5F5", 245, 245, 245 },
{ 138, "white", "#FFFFFF", 255, 255, 255 },
};
long
rgbtable_to_long(struct rgbvalues *tbl)
{
long rgblong = (tbl->r << 0) | (tbl->gn << 8) | (tbl->b << 16);
return rgblong;
}
static void
init_custom_colors(void)
{
customcolors[CLR_BLACK] = rgbtable_to_long(&rgbtable[131]);
customcolors[CLR_RED] = rgbtable_to_long(&rgbtable[5]);
customcolors[CLR_GREEN] = rgbtable_to_long(&rgbtable[31]);
customcolors[CLR_BROWN] = rgbtable_to_long(&rgbtable[104]);
customcolors[CLR_BLUE] = rgbtable_to_long(&rgbtable[58]);
customcolors[CLR_MAGENTA] = rgbtable_to_long(&rgbtable[76]);
customcolors[CLR_CYAN] = rgbtable_to_long(&rgbtable[48]);
customcolors[CLR_GRAY] = rgbtable_to_long(&rgbtable[73]);
customcolors[NO_COLOR] = rgbtable_to_long(&rgbtable[137]);
customcolors[CLR_ORANGE] = rgbtable_to_long(&rgbtable[15]);
customcolors[CLR_BRIGHT_GREEN] = rgbtable_to_long(&rgbtable[34]);
customcolors[CLR_YELLOW] = rgbtable_to_long(&rgbtable[18]);
customcolors[CLR_BRIGHT_BLUE] = rgbtable_to_long(&rgbtable[69]);
customcolors[CLR_BRIGHT_MAGENTA] = rgbtable_to_long(&rgbtable[84]);
customcolors[CLR_BRIGHT_CYAN] = rgbtable_to_long(&rgbtable[49]);
customcolors[CLR_WHITE] = rgbtable_to_long(&rgbtable[138]);
/* esc_seq_colors[CLR_BLACK] = "\x1b[30m"; */
esc_seq_colors[CLR_BLACK] = "\x1b[38;2;47;79;79m";
esc_seq_colors[CLR_RED] = "\x1b[31m";
esc_seq_colors[CLR_GREEN] = "\x1b[32m";
esc_seq_colors[CLR_YELLOW] = "\x1b[38;2;255;255;0m";
esc_seq_colors[CLR_BLUE] = "\x1b[38;2;100;149;237m";
esc_seq_colors[CLR_MAGENTA] = "\x1b[35m";
esc_seq_colors[CLR_CYAN] = "\x1b[36m";
esc_seq_colors[CLR_WHITE] = "\x1b[37m";
esc_seq_colors[CLR_BROWN] = "\x1b[38;2;205;133;63m";
// esc_seq_colors[CLR_GRAY] = "\x1b[31m\x1b[32m\x1b[34m";
esc_seq_colors[CLR_GRAY] = "\x1b[90m";
esc_seq_colors[NO_COLOR] = "\x1b[39m";
esc_seq_colors[CLR_ORANGE] = "\x1b[38;2;255;140;0m";
esc_seq_colors[CLR_BRIGHT_GREEN] = "\x1b[39m";
esc_seq_colors[CLR_BRIGHT_BLUE] = "\x1b[34m\x1b[94m";
esc_seq_colors[CLR_BRIGHT_MAGENTA] = "\x1b[35m\x1b[95m";
esc_seq_colors[CLR_BRIGHT_CYAN] = "\x1b[36m\x1b[96m";
}
void emit_start_bold(void);
void emit_stop_bold(void);
void emit_start_dim(void);
void emit_stop_dim(void);
void emit_start_blink(void);
void emit_stop_blink(void);
void emit_start_underline(void);
void emit_stop_underline(void);
void emit_start_inverse(void);
void emit_stop_inverse(void);
void emit_start_24bitcolor(long color24bit);
void emit_default_color(void);
void emit_return_to_default(void);
void emit_hide_cursor(void);
void emit_show_curor(void);
void
emit_hide_cursor(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[?25l";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_show_cursor(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[?25h";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_start_bold(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[4m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_stop_bold(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[24m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
#if 0
emit_start_dim(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[4m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_stop_dim(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[24m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
#endif
void
emit_start_blink(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[5m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_stop_blink(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[25m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_start_underline(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[4m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_stop_underline(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[24m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_start_inverse(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[7m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
void
emit_stop_inverse(void)
{
DWORD unused, reserved;
static const char escseq[] = "\x1b[27m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
#define tcfmtstr "\x1b[38;2;%d;%d;%dm"
#if 0
#define tcfmtstr "\x1b[38:2:%d:%d:%dm"
#endif
void
emit_start_24bitcolor(long color24bit)
{
DWORD unused, reserved;
static char tcolorbuf[QBUFSZ];
long mcolor24bit =
(color24bit & 0xFFFFFF); /* color 0 has bit 0x1000000 set */
Snprintf(tcolorbuf, sizeof tcolorbuf, tcfmtstr,
((mcolor24bit >> 0) & 0xFF), /* red */
((mcolor24bit >> 8) & 0xFF), /* green */
((mcolor24bit >> 16) & 0xFF)); /* blue */
WriteConsoleA(console.hConOut, (LPCSTR) tcolorbuf,
(int) strlen(tcolorbuf), &unused, &reserved);
}
void
emit_default_color(void)
{
DWORD unused, reserved;
static char escseq[] = "\x1b[39m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
#ifdef VIRTUAL_TERMINAL_SEQUENCES
void
emit_return_to_default(void)
{
DWORD unused, reserved;
static char escseq[] = "\x1b[0m";
WriteConsoleA(console.hConOut, (LPCSTR) escseq, (int) strlen(escseq),
&unused, &reserved);
}
static boolean newattr_on = TRUE;
static boolean color24_on = TRUE;
/* for debugging */
WORD what_is_there_now;
BOOL success;
DWORD error_result;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
/* Console buffer flipping support */
#ifdef VIRTUAL_TERMINAL_SEQUENCES
enum do_flags { do_utf8_content = 1, do_wide_content = 2, do_colorseq = 4, do_color24 = 8, do_newattr = 16 };
enum did_flags { did_utf8_content = 1, did_wide_content = 2, did_colorseq = 4, did_color24 = 8, did_newattr = 16 };
#endif
static void back_buffer_flip(void)
{
cell_t *back = console.back_buffer;
cell_t *front = console.front_buffer;
COORD pos;
DWORD unused;
#ifdef VIRTUAL_TERMINAL_SEQUENCES
DWORD reserved;
unsigned do_anything, did_anything;
emit_hide_cursor();
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
for (pos.Y = 0; pos.Y < console.height; pos.Y++) {
for (pos.X = 0; pos.X < console.width; pos.X++) {
#ifndef VIRTUAL_TERMINAL_SEQUENCES
if (back->attribute != front->attribute) {
WriteConsoleOutputAttribute(console.hConOut, &back->attribute,
1, pos, &unused);
front->attribute = back->attribute;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
boolean pos_set = FALSE;
do_anything = did_anything = 0U;
if (back->color24 != front->color24)
do_anything |= do_color24;
if (back->colorseq != front->colorseq)
do_anything |= do_colorseq;
if (back->attr != front->attr)
do_anything |= do_newattr;
if (strcmp((const char *) back->utf8str,
(const char *) front->utf8str))
do_anything |= do_utf8_content;
#ifndef VIRTUAL_TERMINAL_SEQUENCES
if (back->character != front->character) {
if (console.has_unicode) {
WriteConsoleOutputCharacterW(console.hConOut,
&back->character, 1, pos, &unused);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
if (do_anything) {
SetConsoleCursorPosition(console.hConOut, pos);
pos_set = TRUE;
{
did_anything |= did_newattr;
if (back->attr) {
if (back->attr & atr_bold)
emit_start_bold();
// if (back->attr & atr_dim)
// emit_start_dim();
if (back->attr & atr_uline)
emit_start_underline();
// if (back->attr & atr_blink)
// emit_start_blink();
if (back->attr & atr_inverse)
emit_start_inverse();
// front->attr = back->attr; /* will happen below due
// to did_newattr */
} else {
emit_return_to_default();
}
}
if (color24_on && back->color24) {
did_anything |= did_color24;
if (back->color24) {
emit_start_24bitcolor(back->color24);
}
} else if (back->colorseq) {
did_anything |= did_colorseq;
WriteConsoleA(console.hConOut, back->colorseq,
(int) strlen(back->colorseq), &unused,
&reserved);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
} else {
#ifndef VIRTUAL_TERMINAL_SEQUENCES
char ch = (char)back->character;
WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos,
&unused);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
did_anything |= did_colorseq;
emit_default_color();
}
if (did_anything
|| (do_anything & (do_wide_content | do_utf8_content))) {
WriteConsoleW(console.hConOut, &back->wcharacter, 1,
&unused, &reserved);
did_anything |= did_wide_content;
}
}
if (did_anything) {
if (!pos_set) {
SetConsoleCursorPosition(console.hConOut, pos);
pos_set = TRUE;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
#ifdef VIRTUAL_TERMINAL_SEQUENCES
emit_return_to_default();
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
*front = *back;
}
back++;
front++;
}
}
#ifdef VIRTUAL_TERMINAL_SEQUENCES
emit_show_cursor();
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
void buffer_fill_to_end(cell_t * buffer, cell_t * fill, int x, int y)
{
nhassert(x >= 0 && x < console.width);
nhassert(y >= 0 && ((y < console.height) || (y == console.height &&
x == 0)));
cell_t * dst = buffer + console.width * y + x;
cell_t * sentinel = buffer + console.buffer_size;
while (dst != sentinel)
*dst++ = *fill;
if (iflags.debug.immediateflips && buffer == console.back_buffer)
back_buffer_flip();
}
static void buffer_clear_to_end_of_line(cell_t * buffer, int x, int y)
{
nhassert(x >= 0 && x < console.width);
nhassert(y >= 0 && ((y < console.height) || (y == console.height &&
x == 0)));
cell_t * dst = buffer + console.width * y + x;
cell_t *sentinel = buffer + console.width * (y + 1);
while (dst != sentinel)
*dst++ = clear_cell;
if (iflags.debug.immediateflips)
back_buffer_flip();
}
void buffer_write(cell_t * buffer, cell_t * cell, COORD pos)
{
nhassert(pos.X >= 0 && pos.X < console.width);
nhassert(pos.Y >= 0 && pos.Y < console.height);
cell_t * dst = buffer + (console.width * pos.Y) + pos.X;
*dst = *cell;
if (iflags.debug.immediateflips && buffer == console.back_buffer)
back_buffer_flip();
}
/*
* Called after returning from ! or ^Z
*/
void
gettty()
{
#ifndef TEXTCOLOR
int k;
#endif
erase_char = '\b';
kill_char = 21; /* cntl-U */
iflags.cbreak = TRUE;
#ifdef TEXTCOLOR
init_ttycolor();
#else
for (k = 0; k < CLR_MAX; ++k)
ttycolors[k] = NO_COLOR;
#endif
}
/* reset terminal to original state */
void
settty(const char* s)
{
cmov(ttyDisplay->curx, ttyDisplay->cury);
end_screen();
if (s)
raw_print(s);
restore_original_console_font();
if (orig_QuickEdit) {
#ifndef VIRTUAL_TERMINAL_SEQUENCES
DWORD cmode;
GetConsoleMode(console.hConIn, &cmode);
cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
SetConsoleMode(console.hConIn, cmode);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
GetConsoleMode(console.hConIn, &console.in_cmode);
console.in_cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
SetConsoleMode(console.hConIn, console.in_cmode);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
}
/* called by init_nhwindows() and resume_nhwindows() */
void
setftty()
{
#ifdef CHANGE_COLOR
if (altered_palette)
adjust_palette();
#endif
start_screen();
}
void
tty_startup(int *wid, int *hgt)
{
*wid = console.width;
*hgt = console.height;
set_option_mod_status("mouse_support", set_in_game);
}
void
tty_number_pad(int state)
{
// do nothing
}
void
tty_start_screen()
{
if (iflags.num_pad)
tty_number_pad(1); /* make keypad send digits */
#ifdef VIRTUAL_TERMINAL_SEQUENCES
ibmgraphics_mode_callback = tty_ibmgraphics_fixup;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
void
tty_end_screen()
{
clear_screen();
really_move_cursor();
buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
back_buffer_flip();
FlushConsoleInputBuffer(console.hConIn);
}
static BOOL
CtrlHandler(DWORD ctrltype)
{
switch (ctrltype) {
/* case CTRL_C_EVENT: */
case CTRL_BREAK_EVENT:
clear_screen();
case CTRL_CLOSE_EVENT:
case CTRL_LOGOFF_EVENT:
case CTRL_SHUTDOWN_EVENT:
getreturn_enabled = FALSE;
#ifndef NOSAVEONHANGUP
hangup(0);
#endif
#if defined(SAFERHANGUP)
CloseHandle(console.hConIn); /* trigger WAIT_FAILED */
return TRUE;
#endif
default:
return FALSE;
}
}
/* called by pcmain() and process_options() */
void
consoletty_open(int mode)
{
int debugvar;
/* Initialize the function pointer that points to
* the kbhit() equivalent, in this TTY case consoletty_kbhit()
*/
nt_kbhit = consoletty_kbhit;
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) {
/* Unable to set control handler */
debugvar = 0; /* just to have a statement to break on for debugger */
}
LI = console.height;
CO = console.width;
really_move_cursor();
}
void
consoletty_exit()
{
/* go back to using the safe routines */
safe_routines();
}
int
process_keystroke(
INPUT_RECORD *ir,
boolean *valid,
boolean numberpad,
int portdebug)
{
int ch;
#ifdef QWERTZ_SUPPORT
if (g.Cmd.swap_yz)
numberpad |= 0x10;
#endif
ch = keyboard_handler.pProcessKeystroke(
console.hConIn, ir, valid, numberpad, portdebug);
#ifdef QWERTZ_SUPPORT
numberpad &= ~0x10;
#endif
/* check for override */
if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
ch = key_overrides[ch];
return ch;
}
int
consoletty_kbhit()
{
return keyboard_handler.pNHkbhit(console.hConIn, &ir);
}
int
tgetch()
{
int mod;
coord cc;
DWORD count;
boolean numpad = iflags.num_pad;
really_move_cursor();
if (iflags.debug_fuzzer)
return randomkey();
#ifdef QWERTZ_SUPPORT
if (g.Cmd.swap_yz)
numpad |= 0x10;
#endif
return (g.program_state.done_hup)
? '\033'
: keyboard_handler.pCheckInput(
console.hConIn, &ir, &count, numpad, 0, &mod, &cc);
}
int
console_poskey(int *x, int *y, int *mod)
{
int ch;
coord cc = { 0, 0 };
DWORD count;
boolean numpad = iflags.num_pad;
really_move_cursor();
if (iflags.debug_fuzzer) {
int poskey = randomkey();
if (poskey == 0) {
*x = rn2(console.width);
*y = rn2(console.height);
}
return poskey;
}
#ifdef QWERTZ_SUPPORT
if (g.Cmd.swap_yz)
numpad |= 0x10;
#endif
ch = (g.program_state.done_hup)
? '\033'
: keyboard_handler.pCheckInput(
console.hConIn, &ir, &count, numpad, 1, mod, &cc);
#ifdef QWERTZ_SUPPORT
numpad &= ~0x10;
#endif
if (!ch) {
*x = cc.x;
*y = cc.y;
}
return ch;
}
static void set_console_cursor(int x, int y)
{
nhassert(x >= 0 && x < console.width);
nhassert(y >= 0 && y < console.height);
console.cursor.X = max(0, min(console.width - 1, x));
console.cursor.Y = max(0, min(console.height - 1, y));
}
static void
really_move_cursor()
{
#ifdef PORT_DEBUG
char oldtitle[BUFSZ], newtitle[BUFSZ];
if (display_cursor_info && wizard) {
oldtitle[0] = '\0';
if (GetConsoleTitle(oldtitle, BUFSZ)) {
oldtitle[39] = '\0';
}
Sprintf(newtitle, "%-55s tty=(%02d,%02d) consoletty=(%02d,%02d)", oldtitle,
ttyDisplay->curx, ttyDisplay->cury,
console.cursor.X, console.cursor.Y);
(void) SetConsoleTitle(newtitle);
}
#endif
if (ttyDisplay)
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
back_buffer_flip();
SetConsoleCursorPosition(console.hConOut, console.cursor);
}
void
cmov(int x, int y)
{
ttyDisplay->cury = y;
ttyDisplay->curx = x;
set_console_cursor(x, y);
}
void
nocmov(int x, int y)
{
ttyDisplay->curx = x;
ttyDisplay->cury = y;
set_console_cursor(x, y);
}
#ifndef VIRTUAL_TERMINAL_SEQUENCES
/* same signature as 'putchar()' with potential failure result ignored */
int
xputc(int ch)
{
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
xputc_core((char) ch);
return 0;
}
#endif /* ! VIRTUAL_TERMINAL_SEQUENCES */
void
xputs(const char* s)
{
int k;
int slen = (int) strlen(s);
if (ttyDisplay)
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
if (s) {
for (k = 0; k < slen && s[k]; ++k)
#ifndef VIRTUAL_TERMINAL_SEQUENCES
xputc_core(s[k]);
#else
xputc_core((int) s[k]);
#endif
}
}
/* xputc_core() and g_putch() are the only routines that actually place output.
same signature as 'putchar()' with potential failure result ignored */
int
xputc(int ch)
{
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
xputc_core(ch);
return 0;
}
void
#ifndef VIRTUAL_TERMINAL_SEQUENCES
xputc_core(char ch)
#else /* VIRTUAL_TERMINAL_SEQUENCES */
xputc_core(int ch)
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
{
#ifdef VIRTUAL_TERMINAL_SEQUENCES
int ccount = 1; /* default non-zero, but char conversion results will alter */
WCHAR wch[2];
#else
boolean inverse = FALSE;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
cell_t cell;
switch (ch) {
case '\n':
if (console.cursor.Y < console.height - 1)
console.cursor.Y++;
/* fall through */
case '\r':
console.cursor.X = 1;
break;
case '\b':
if (console.cursor.X > 1) {
console.cursor.X--;
} else if(console.cursor.Y > 0) {
console.cursor.X = console.width - 1;
console.cursor.Y--;
}
break;
default:
#ifndef VIRTUAL_TERMINAL_SEQUENCES
inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
console.attr = (inverse) ?
ttycolors_inv[console.current_nhcolor] :
ttycolors[console.current_nhcolor];
if (console.current_nhattr[ATR_BOLD])
console.attr |= (inverse) ?
BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
cell.attribute = console.attr;
cell.character = (console.has_unicode ? console.cpMap[ch] : ch);
buffer_write(console.back_buffer, &cell, console.cursor);
if (console.cursor.X == console.width - 1) {
if (console.cursor.Y < console.height - 1) {
console.cursor.X = 1;
console.cursor.Y++;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
/* this causes way too much performance degradation */
/* cell.color24 = customcolors[console.current_nhcolor]; */
cell.colorseq = esc_seq_colors[console.current_nhcolor];
cell.attr = console.attr;
//if (console.color24)
// __debugbreak();
cell.color24 = 0L;
wch[1] = 0;
if (console.has_unicode) {
wch[0] = (ch >= 0 && ch < SIZE(console.cpMap)) ? console.cpMap[ch]
: ch;
/* store the wide version here also, so we don't slow
down back_buffer_flip() with conversions */
cell.wcharacter = wch[0];
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
} else {
#ifndef VIRTUAL_TERMINAL_SEQUENCES
console.cursor.X++;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
/* we can just use the UTF-8 utf8str field, since ascii is a
single-byte representation of a small subset of unicode */
cell.utf8str[0] = ch;
cell.utf8str[1] = 0;
}
if (ccount) {
buffer_write(console.back_buffer, &cell, console.cursor);
if (console.cursor.X == console.width - 1) {
if (console.cursor.Y < console.height - 1) {
console.cursor.X = 1;
console.cursor.Y++;
}
} else {
console.cursor.X++;
}
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
}
nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
}
/*
* Overrides wintty.c function of the same name
* for win32. It is used for glyphs only, not text.
*/
void
g_putch(int in_ch)
{
#ifndef VIRTUAL_TERMINAL_SEQUENCES
boolean inverse = FALSE;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
int ccount = 0;
WCHAR wch[2];
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
unsigned char ch = (unsigned char) in_ch;
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
#ifndef VIRTUAL_TERMINAL_SEQUENCES
inverse = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse);
console.attr = (console.current_nhattr[ATR_INVERSE] && iflags.wc_inverse) ?
ttycolors_inv[console.current_nhcolor] :
ttycolors[console.current_nhcolor];
if (console.current_nhattr[ATR_BOLD])
console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
#endif /* ! VIRTUAL_TERMINAL_SEQUENCES */
cell_t cell;
#ifndef VIRTUAL_TERMINAL_SEQUENCES
cell.attribute = console.attr;
cell.character = (console.has_unicode ? cp437[ch] : ch);
#else
cell.attr = console.attr;
cell.colorseq = esc_seq_colors[console.current_nhcolor];
cell.color24 = console.color24 ? console.color24 : 0L;
wch[1] = 0;
if (console.has_unicode) {
wch[0] = (ch >= 0 && ch < SIZE(console.cpMap)) ? console.cpMap[ch] : ch;
/* store the wide version here also, so we don't slow
down back_buffer_flip() with conversions */
cell.wcharacter = wch[0];
} else {
/* we can just use the UTF-8 utf8str field, since ascii is a
single-byte representation of a small subset of unicode */
cell.utf8str[0] = ch;
cell.utf8str[1] = 0;
ccount = 2;
}
#endif
buffer_write(console.back_buffer, &cell, console.cursor);
}
#ifdef VIRTUAL_TERMINAL_SEQUENCES
void
term_start_24bitcolor(long color24bit)
{
console.color24 = color24bit; /* color 0 has bit 0x1000000 set */
}
void
term_end_24bitcolor(void)
{
console.color24 = 0L;
}
#endif VIRTUAL_TERMINAL_SEQUENCES
void
cl_end(void)
{
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
buffer_clear_to_end_of_line(console.back_buffer, console.cursor.X,
console.cursor.Y);
tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
}
void
raw_clear_screen(void)
{
if (WINDOWPORT("tty")) {
cell_t * back = console.back_buffer;
cell_t * front = console.front_buffer;
COORD pos;
DWORD unused;
#ifdef VIRTUAL_TERMINAL_SEQUENCES
DWORD reserved;
#endif
#ifdef VIRTUAL_TERMINAL_SEQUENCES
pos.Y = 0;
pos.X = 0;
SetConsoleCursorPosition(console.hConOut, pos);
emit_return_to_default();
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
for (pos.Y = 0; pos.Y < console.height; pos.Y++) {
for (pos.X = 0; pos.X < console.width; pos.X++) {
#ifndef VIRTUAL_TERMINAL_SEQUENCES
WriteConsoleOutputAttribute(console.hConOut, &back->attribute,
1, pos, &unused);
front->attribute = back->attribute;
if (console.has_unicode) {
WriteConsoleOutputCharacterW(console.hConOut,
&back->character, 1, pos, &unused);
} else {
char ch = (char)back->character;
WriteConsoleOutputCharacterA(console.hConOut, &ch, 1, pos,
&unused);
}
#else /* VIRTUAL_TERMINAL_SEQUENCES */
*back = clear_cell;
if (console.has_unicode)
WriteConsoleW(console.hConOut, &back->wcharacter, 1,
&unused, &reserved);
else
WriteConsoleA(console.hConOut, (LPCSTR) back->utf8str,
(int) strlen((char *) back->utf8str), &unused, &reserved);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
*front = *back;
back++;
front++;
}
}
}
}
void
clear_screen(void)
{
buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
home();
}
void
home(void)
{
ttyDisplay->curx = ttyDisplay->cury = 0;
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
}
void
backsp(void)
{
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
xputc_core('\b');
}
void
cl_eos(void)
{
buffer_fill_to_end(console.back_buffer, &clear_cell, ttyDisplay->curx,
ttyDisplay->cury);
tty_curs(BASE_WINDOW, (int) ttyDisplay->curx + 1, (int) ttyDisplay->cury);
}
void
tty_nhbell(void)
{
if (flags.silent || iflags.debug_fuzzer)
return;
Beep(8000, 500);
}
volatile int junk; /* prevent optimizer from eliminating loop below */
void
tty_delay_output(void)
{
/* delay 50 ms - uses ANSI C clock() function now */
clock_t goal;
int k;
goal = 50 + clock();
back_buffer_flip();
if (iflags.debug_fuzzer)
return;
while (goal > clock()) {
k = junk; /* Do nothing */
}
}
/*
* CLR_BLACK 0
* CLR_RED 1
* CLR_GREEN 2
* CLR_BROWN 3 low-intensity yellow
* CLR_BLUE 4
* CLR_MAGENTA 5
* CLR_CYAN 6
* CLR_GRAY 7 low-intensity white
* NO_COLOR 8
* CLR_ORANGE 9
* CLR_BRIGHT_GREEN 10
* CLR_YELLOW 11
* CLR_BRIGHT_BLUE 12
* CLR_BRIGHT_MAGENTA 13
* CLR_BRIGHT_CYAN 14
* CLR_WHITE 15
* CLR_MAX 16
* BRIGHT 8
*/
static void
init_ttycolor(void)
{
#ifdef TEXTCOLOR
ttycolors[CLR_BLACK] = FOREGROUND_INTENSITY; /* fix by Quietust */
ttycolors[CLR_RED] = FOREGROUND_RED;
ttycolors[CLR_GREEN] = FOREGROUND_GREEN;
ttycolors[CLR_BROWN] = FOREGROUND_GREEN | FOREGROUND_RED;
ttycolors[CLR_BLUE] = FOREGROUND_BLUE;
ttycolors[CLR_MAGENTA] = FOREGROUND_BLUE | FOREGROUND_RED;
ttycolors[CLR_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE;
ttycolors[CLR_GRAY] = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
ttycolors[NO_COLOR] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
ttycolors[CLR_ORANGE] = FOREGROUND_RED | FOREGROUND_INTENSITY;
ttycolors[CLR_BRIGHT_GREEN] = FOREGROUND_GREEN | FOREGROUND_INTENSITY;
ttycolors[CLR_YELLOW] = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_INTENSITY;
ttycolors[CLR_BRIGHT_BLUE] = FOREGROUND_BLUE | FOREGROUND_INTENSITY;
ttycolors[CLR_BRIGHT_MAGENTA]=FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_INTENSITY;
ttycolors[CLR_BRIGHT_CYAN] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_INTENSITY;
ttycolors[CLR_WHITE] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED
| FOREGROUND_INTENSITY;
ttycolors_inv[CLR_BLACK] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
| BACKGROUND_INTENSITY;
ttycolors_inv[CLR_RED] = BACKGROUND_RED | BACKGROUND_INTENSITY;
ttycolors_inv[CLR_GREEN] = BACKGROUND_GREEN;
ttycolors_inv[CLR_BROWN] = BACKGROUND_GREEN | BACKGROUND_RED;
ttycolors_inv[CLR_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
ttycolors_inv[CLR_MAGENTA] = BACKGROUND_BLUE | BACKGROUND_RED;
ttycolors_inv[CLR_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE;
ttycolors_inv[CLR_GRAY] = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_BLUE;
ttycolors_inv[NO_COLOR] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
ttycolors_inv[CLR_ORANGE] = BACKGROUND_RED | BACKGROUND_INTENSITY;
ttycolors_inv[CLR_BRIGHT_GREEN]= BACKGROUND_GREEN | BACKGROUND_INTENSITY;
ttycolors_inv[CLR_YELLOW] = BACKGROUND_GREEN | BACKGROUND_RED | BACKGROUND_INTENSITY;
ttycolors_inv[CLR_BRIGHT_BLUE] = BACKGROUND_BLUE | BACKGROUND_INTENSITY;
ttycolors_inv[CLR_BRIGHT_MAGENTA] =BACKGROUND_BLUE | BACKGROUND_RED | BACKGROUND_INTENSITY;
ttycolors_inv[CLR_BRIGHT_CYAN] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_INTENSITY;
ttycolors_inv[CLR_WHITE] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED
| BACKGROUND_INTENSITY;
#else
int k;
ttycolors[0] = FOREGROUND_INTENSITY;
ttycolors_inv[0] = BACKGROUND_INTENSITY;
for (k = 1; k < SIZE(ttycolors); ++k) {
ttycolors[k] = FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED;
ttycolors_inv[k] = BACKGROUND_GREEN | BACKGROUND_BLUE | BACKGROUND_RED;
}
#endif
init_ttycolor_completed = TRUE;
}
int
term_attr_fixup(int attrmask)
{
return attrmask;
}
void
term_start_attr(int attrib)
{
#ifdef VIRTUAL_TERMINAL_SEQUENCES
switch (attrib) {
case ATR_INVERSE:
console.attr |= atr_inverse;
break;
case ATR_ULINE:
console.attr |= atr_uline;
break;
case ATR_BLINK:
console.attr |= atr_blink;
break;
case ATR_BOLD:
console.attr |= atr_bold;
break;
}
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
console.current_nhattr[attrib] = TRUE;
if (attrib) console.current_nhattr[ATR_NONE] = FALSE;
}
void
term_end_attr(int attrib)
{
int k;
switch (attrib) {
case ATR_INVERSE:
#ifdef VIRTUAL_TERMINAL_SEQUENCES
console.attr &= ~atr_inverse;
break;
#endif
case ATR_ULINE:
#ifdef VIRTUAL_TERMINAL_SEQUENCES
console.attr &= ~atr_uline;
break;
#endif
case ATR_BLINK:
#ifdef VIRTUAL_TERMINAL_SEQUENCES
console.attr &= ~atr_blink;
break;
#endif
case ATR_BOLD:
#ifdef VIRTUAL_TERMINAL_SEQUENCES
console.attr &= ~atr_bold;
#endif
break;
}
console.current_nhattr[attrib] = FALSE;
console.current_nhattr[ATR_NONE] = TRUE;
/* re-evaluate all attr now for performance at output time */
for (k=ATR_NONE; k <= ATR_INVERSE; ++k) {
if (console.current_nhattr[k])
console.current_nhattr[ATR_NONE] = FALSE;
}
}
void
term_end_raw_bold(void)
{
term_end_attr(ATR_BOLD);
}
void
term_start_raw_bold(void)
{
term_start_attr(ATR_BOLD);
}
void
term_start_color(int color)
{
#ifdef TEXTCOLOR
if (color >= 0 && color < CLR_MAX) {
console.current_nhcolor = color;
} else
#endif
console.current_nhcolor = NO_COLOR;
}
void
term_end_color(void)
{
#ifdef TEXTCOLOR
console.foreground = DEFTEXTCOLOR;
#endif
#ifndef VIRTUAL_TERMINAL_SEQUENCES
console.attr = (console.foreground | console.background);
#endif /* ! VIRTUAL_TERMINAL_SEQUENCES */
console.current_nhcolor = NO_COLOR;
}
void
standoutbeg(void)
{
term_start_attr(ATR_BOLD);
}
void
standoutend(void)
{
term_end_attr(ATR_BOLD);
}
#ifndef NO_MOUSE_ALLOWED
void
toggle_mouse_support(void)
{
static int qeinit = 0;
#ifndef VIRTUAL_TERMINAL_SEQUENCES
DWORD cmode;
#endif /* ! VIRTUAL_TERMINAL_SEQUENCES */
#ifndef VIRTUAL_TERMINAL_SEQUENCES
GetConsoleMode(console.hConIn, &cmode);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
GetConsoleMode(console.hConIn, &console.in_cmode);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
if (!qeinit) {
qeinit = 1;
#ifndef VIRTUAL_TERMINAL_SEQUENCES
orig_QuickEdit = ((cmode & ENABLE_QUICK_EDIT_MODE) != 0);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
orig_QuickEdit = ((console.in_cmode & ENABLE_QUICK_EDIT_MODE) != 0);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
switch(iflags.wc_mouse_support) {
case 2:
#ifndef VIRTUAL_TERMINAL_SEQUENCES
cmode |= ENABLE_MOUSE_INPUT;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
console.in_cmode |= ENABLE_MOUSE_INPUT;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
break;
case 1:
#ifndef VIRTUAL_TERMINAL_SEQUENCES
cmode |= ENABLE_MOUSE_INPUT;
cmode &= ~ENABLE_QUICK_EDIT_MODE;
cmode |= ENABLE_EXTENDED_FLAGS;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
console.in_cmode |= ENABLE_MOUSE_INPUT;
console.in_cmode &= ~ENABLE_QUICK_EDIT_MODE;
console.in_cmode |= ENABLE_EXTENDED_FLAGS;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
break;
case 0:
/*FALLTHRU*/
default:
#ifndef VIRTUAL_TERMINAL_SEQUENCES
cmode &= ~ENABLE_MOUSE_INPUT;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
console.in_cmode &= ~ENABLE_MOUSE_INPUT;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
if (orig_QuickEdit)
#ifndef VIRTUAL_TERMINAL_SEQUENCES
cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
console.in_cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
#ifndef VIRTUAL_TERMINAL_SEQUENCES
SetConsoleMode(console.hConIn, cmode);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
SetConsoleMode(console.hConIn, console.in_cmode);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
#endif
/* handle tty options updates here */
void
consoletty_preference_update(const char* pref)
{
if (stricmp(pref, "mouse_support") == 0) {
#ifndef NO_MOUSE_ALLOWED
toggle_mouse_support();
#endif
}
#endif
if (stricmp(pref, "symset") == 0) {
if (SYMHANDLING(H_IBM)) {
tty_ibmgraphics_fixup();
}
check_and_set_font();
}
return;
}
/*
* This is called when making the switch to a symset
* with an IBM handler to allow any operating system
* specific changes to be carried out.
*/
void
tty_ibmgraphics_fixup(void)
{
#ifdef VIRTUAL_TERMINAL_SEQUENCES
char buf[BUFSZ], *bp, *localestr;
if (!console.hConOut)
console.hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
/* the locale */
Snprintf(buf, sizeof buf, "%s", console.orig_localestr);
if ((bp = strstri(buf, ".utf8")) != 0)
*bp = '\0';
localestr = setlocale(LC_ALL, buf);
if (localestr) {
if (console.localestr)
free(console.localestr);
console.localestr = strdup(localestr);
}
set_known_good_console_font();
/* the console mode */
GetConsoleMode(console.hConOut, &console.out_cmode);
if ((console.out_cmode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0) {
console.out_cmode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(console.hConOut, console.out_cmode);
GetConsoleMode(console.hConOut, &console.out_cmode);
}
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
#ifdef PORT_DEBUG
void
win32con_debug_keystrokes(void)
{
DWORD count;
boolean valid = 0;
int ch = 0;
xputs("\n");
while (!valid || ch != 27) {
nocmov(ttyDisplay->curx, ttyDisplay->cury);
ReadConsoleInput(console.hConIn, &ir, 1, &count);
if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
ch = process_keystroke(&ir, &valid, iflags.num_pad, 1);
}
(void) doredraw();
}
void
win32con_handler_info(void)
{
char *buf;
int ci;
if (!keyboard_handler.pSourceAuthor && !keyboard_handler.pSourceWhere)
pline("Keyboard handler source info and author unavailable.");
else {
if (keyboard_handler.pKeyHandlerName &&
keyboard_handler.pKeyHandlerName(&buf, 1)) {
xputs("\n");
xputs("Keystroke handler loaded: \n ");
xputs(buf);
}
if (keyboard_handler.pSourceAuthor &&
keyboard_handler.pSourceAuthor(&buf)) {
xputs("\n");
xputs("Keystroke handler Author: \n ");
xputs(buf);
}
if (keyboard_handler.pSourceWhere &&
keyboard_handler.pSourceWhere(&buf)) {
xputs("\n");
xputs("Keystroke handler source code available at:\n ");
xputs(buf);
}
xputs("\nPress any key to resume.");
ci = nhgetch();
(void) doredraw();
}
}
void
win32con_toggle_cursor_info(void)
{
display_cursor_info = !display_cursor_info;
}
#endif
void
map_subkeyvalue(char* op)
{
char digits[] = "0123456789";
int length, i, idx, val;
char *kp;
idx = -1;
val = -1;
kp = index(op, '/');
if (kp) {
*kp = '\0';
kp++;
length = strlen(kp);
if (length < 1 || length > 3)
return;
for (i = 0; i < length; i++)
if (!index(digits, kp[i]))
return;
val = atoi(kp);
length = strlen(op);
if (length < 1 || length > 3)
return;
for (i = 0; i < length; i++)
if (!index(digits, op[i]))
return;
idx = atoi(op);
}
if (idx >= MAX_OVERRIDES || idx < 0 || val >= MAX_OVERRIDES || val < 1)
return;
key_overrides[idx] = val;
}
void unload_keyboard_handler(void)
{
nhassert(keyboard_handler.hLibrary != NULL);
FreeLibrary(keyboard_handler.hLibrary);
memset(&keyboard_handler, 0, sizeof(keyboard_handler_t));
}
boolean
load_keyboard_handler(const char * inName)
{
char path[MAX_ALTKEYHANDLER + 4];
strcpy(path, inName);
strcat(path, ".dll");
HANDLE hLibrary = LoadLibrary(path);
if (hLibrary == NULL)
return FALSE;
PROCESS_KEYSTROKE pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
hLibrary, TEXT("ProcessKeystroke"));
NHKBHIT pNHkbhit = (NHKBHIT) GetProcAddress(
hLibrary, TEXT("NHkbhit"));
CHECKINPUT pCheckInput =
(CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
if (!pProcessKeystroke || !pNHkbhit || !pCheckInput)
{
return FALSE;
} else {
if (keyboard_handler.hLibrary != NULL)
unload_keyboard_handler();
keyboard_handler.hLibrary = hLibrary;
keyboard_handler.pProcessKeystroke = pProcessKeystroke;
keyboard_handler.pNHkbhit = pNHkbhit;
keyboard_handler.pCheckInput = pCheckInput;
keyboard_handler.pSourceWhere =
(SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
keyboard_handler.pSourceAuthor =
(SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
keyboard_handler.pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
hLibrary, TEXT("KeyHandlerName"));
}
return TRUE;
}
void set_altkeyhandler(const char * inName)
{
if (strlen(inName) >= MAX_ALTKEYHANDLER) {
config_error_add("altkeyhandler name '%s' is too long", inName);
return;
}
char name[MAX_ALTKEYHANDLER];
strcpy(name, inName);
/* We support caller mistakenly giving name with '.dll' extension */
char * ext = strchr(name, '.');
if (ext != NULL) *ext = '\0';
if (load_keyboard_handler(name))
strcpy(iflags.altkeyhandler, name);
else {
config_error_add("unable to load altkeyhandler '%s'", name);
return;
}
return;
}
/* fatal error */
/*VARARGS1*/
void consoletty_error
VA_DECL(const char *, s)
{
char buf[BUFSZ];
VA_START(s);
VA_INIT(s, const char *);
/* error() may get called before tty is initialized */
if (iflags.window_inited)
end_screen();
buf[0] = '\n';
(void) vsnprintf(&buf[1], sizeof buf - 1, s, VA_ARGS);
msmsg(buf);
really_move_cursor();
VA_END();
exit(EXIT_FAILURE);
}
void
synch_cursor(void)
{
really_move_cursor();
}
#ifdef CHANGE_COLOR
void
tty_change_color(color_number, rgb, reverse)
int color_number, reverse;
long rgb;
{
/* Map NetHack color index to NT Console palette index */
int idx, win32_color_number[] = {
0, /* CLR_BLACK 0 */
4, /* CLR_RED 1 */
2, /* CLR_GREEN 2 */
6, /* CLR_BROWN 3 */
1, /* CLR_BLUE 4 */
5, /* CLR_MAGENTA 5 */
3, /* CLR_CYAN 6 */
7, /* CLR_GRAY 7 */
8, /* NO_COLOR 8 */
12, /* CLR_ORANGE 9 */
10, /* CLR_BRIGHT_GREEN 10 */
14, /* CLR_YELLOW 11 */
9, /* CLR_BRIGHT_BLUE 12 */
13, /* CLR_BRIGHT_MAGENTA 13 */
11, /* CLR_BRIGHT_CYAN 14 */
15 /* CLR_WHITE 15 */
};
int k;
if (color_number < 0) { /* indicates OPTIONS=palette with no value */
/* copy the NetHack palette into UserDefinedColors */
for (k = 0; k < CLR_MAX; k++)
UserDefinedColors[k] = NetHackColors[k];
} else if (color_number >= 0 && color_number < CLR_MAX) {
if (!altered_palette) {
/* make sure a full suite is available */
for (k = 0; k < CLR_MAX; k++)
UserDefinedColors[k] = DefaultColors[k];
}
idx = win32_color_number[color_number];
UserDefinedColors[idx] = rgb;
}
altered_palette = TRUE;
}
char *
tty_get_color_string()
{
return "";
}
int
match_color_name(c)
const char *c;
{
const struct others {
int idx;
const char *colorname;
} othernames[] = {
{ CLR_MAGENTA, "purple" },
{ CLR_BRIGHT_MAGENTA, "bright purple" },
{ NO_COLOR, "dark gray" },
{ NO_COLOR, "dark grey" },
{ CLR_GRAY, "grey" },
};
int cnt;
for (cnt = 0; cnt < CLR_MAX; ++cnt) {
if (!strcmpi(c, c_obj_colors[cnt]))
return cnt;
}
for (cnt = 0; cnt < SIZE(othernames); ++cnt) {
if (!strcmpi(c, othernames[cnt].colorname))
return othernames[cnt].idx;
}
return -1;
}
/*
* Returns 0 if badoption syntax
*/
int
alternative_palette(op)
char *op;
{
/*
* palette:color-R-G-B
* OPTIONS=palette:green-4-3-1, palette:0-0-0-0
*/
int fieldcnt, color_number, rgb, red, green, blue;
char *fields[4], *cp;
if (!op) {
change_color(-1, 0, 0); /* indicates palette option with
no value meaning "load an entire
hard-coded NetHack palette." */
return 1;
}
cp = fields[0] = op;
for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
cp = index(cp, '-');
if (!cp)
return 0;
fields[fieldcnt] = cp;
cp++;
}
for (fieldcnt = 1; fieldcnt < 4; ++fieldcnt) {
*(fields[fieldcnt]) = '\0';
++fields[fieldcnt];
}
rgb = 0;
for (fieldcnt = 0; fieldcnt < 4; ++fieldcnt) {
if (fieldcnt == 0 && isalpha(*(fields[0]))) {
color_number = match_color_name(fields[0]);
if (color_number == -1)
return 0;
} else {
int dcount = 0, cval = 0;
cp = fields[fieldcnt];
if (*cp == '\\' && index("0123456789xXoO", cp[1])) {
const char *dp, *hex = "00112233445566778899aAbBcCdDeEfF";
cp++;
if (*cp == 'x' || *cp == 'X')
for (++cp; (dp = index(hex, *cp)) && (dcount++ < 2); cp++)
cval = (int) ((cval * 16) + (dp - hex) / 2);
else if (*cp == 'o' || *cp == 'O')
for (++cp; (index("01234567", *cp)) && (dcount++ < 3);
cp++)
cval = (cval * 8) + (*cp - '0');
else
return 0;
} else {
for (; *cp && (index("0123456789", *cp)) && (dcount++ < 3);
cp++)
cval = (cval * 10) + (*cp - '0');
}
switch (fieldcnt) {
case 0:
color_number = cval;
break;
case 1:
red = cval;
break;
case 2:
green = cval;
break;
case 3:
blue = cval;
break;
}
}
}
rgb = RGB(red, green, blue);
if (color_number >= 0 && color_number < CLR_MAX)
change_color(color_number, rgb, 0);
return 1;
}
/*
* This uses an undocumented method to set console attributes
* at runtime including console palette
*
* VOID WINAPI SetConsolePalette(COLORREF palette[16])
*
* Author: James Brown at www.catch22.net
*
* Set palette of current console.
* Palette should be of the form:
*
* COLORREF DefaultColors[CLR_MAX] =
* {
* 0x00000000, 0x00800000, 0x00008000, 0x00808000,
* 0x00000080, 0x00800080, 0x00008080, 0x00c0c0c0,
* 0x00808080, 0x00ff0000, 0x0000ff00, 0x00ffff00,
* 0x000000ff, 0x00ff00ff, 0x0000ffff, 0x00ffffff
* };
*/
#pragma pack(push, 1)
/*
* Structure to send console via WM_SETCONSOLEINFO
*/
typedef struct _CONSOLE_INFO {
ULONG Length;
COORD ScreenBufferSize;
COORD WindowSize;
ULONG WindowPosX;
ULONG WindowPosY;
COORD FontSize;
ULONG FontFamily;
ULONG FontWeight;
WCHAR FaceName[32];
ULONG CursorSize;
ULONG FullScreen;
ULONG QuickEdit;
ULONG AutoPosition;
ULONG InsertMode;
USHORT ScreenColors;
USHORT PopupColors;
ULONG HistoryNoDup;
ULONG HistoryBufferSize;
ULONG NumberOfHistoryBuffers;
COLORREF ColorTable[16];
ULONG CodePage;
HWND Hwnd;
WCHAR ConsoleTitle[0x100];
} CONSOLE_INFO;
#pragma pack(pop)
BOOL SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci);
static void GetConsoleSizeInfo(CONSOLE_INFO *pci);
VOID WINAPI SetConsolePalette(COLORREF crPalette[16]);
void
adjust_palette(void)
{
SetConsolePalette(UserDefinedColors);
altered_palette = 0;
}
/*
/* only in Win2k+ (use FindWindow for NT4) */
/* HWND WINAPI GetConsoleWindow(); */
/* Undocumented console message */
#define WM_SETCONSOLEINFO (WM_USER + 201)
VOID WINAPI
SetConsolePalette(COLORREF palette[16])
{
CONSOLE_INFO ci = { sizeof(ci) };
int i;
HWND hwndConsole = GetConsoleHandle();
/* get current size/position settings rather than using defaults.. */
GetConsoleSizeInfo(&ci);
/* set these to zero to keep current settings */
ci.FontSize.X = 0; /* def = 8 */
ci.FontSize.Y = 0; /* def = 12 */
ci.FontFamily = 0; /* def = 0x30 = FF_MODERN|FIXED_PITCH */
ci.FontWeight = 0; /* 0x400; */
/* lstrcpyW(ci.FaceName, L"Terminal"); */
ci.FaceName[0] = L'\0';
ci.CursorSize = 25;
ci.FullScreen = FALSE;
ci.QuickEdit = TRUE;
ci.AutoPosition = 0x10000;
ci.InsertMode = TRUE;
ci.ScreenColors = MAKEWORD(0x7, 0x0);
ci.PopupColors = MAKEWORD(0x5, 0xf);
ci.HistoryNoDup = FALSE;
ci.HistoryBufferSize = 50;
ci.NumberOfHistoryBuffers = 4;
// colour table
for (i = 0; i < 16; i++)
ci.ColorTable[i] = palette[i];
ci.CodePage = GetConsoleOutputCP();
ci.Hwnd = hwndConsole;
lstrcpyW(ci.ConsoleTitle, L"");
SetConsoleInfo(hwndConsole, &ci);
}
/*
* Wrapper around WM_SETCONSOLEINFO. We need to create the
* necessary section (file-mapping) object in the context of the
* process which owns the console, before posting the message
*/
BOOL
SetConsoleInfo(HWND hwndConsole, CONSOLE_INFO *pci)
{
DWORD dwConsoleOwnerPid;
HANDLE hProcess;
HANDLE hSection, hDupSection;
PVOID ptrView = 0;
HANDLE hThread;
/*
* Open the process which "owns" the console
*/
GetWindowThreadProcessId(hwndConsole, &dwConsoleOwnerPid);
hProcess = OpenProcess(PROCESS_ALL_ACCESS, FALSE, dwConsoleOwnerPid);
/*
* Create a SECTION object backed by page-file, then map a view of
* this section into the owner process so we can write the contents
* of the CONSOLE_INFO buffer into it
*/
hSection = CreateFileMapping(INVALID_HANDLE_VALUE, 0, PAGE_READWRITE, 0,
pci->Length, 0);
/*
* Copy our console structure into the section-object
*/
ptrView = MapViewOfFile(hSection, FILE_MAP_WRITE | FILE_MAP_READ, 0, 0,
pci->Length);
memcpy(ptrView, pci, pci->Length);
UnmapViewOfFile(ptrView);
/*
* Map the memory into owner process
*/
DuplicateHandle(GetCurrentProcess(), hSection, hProcess, &hDupSection, 0,
FALSE, DUPLICATE_SAME_ACCESS);
/* Send console window the "update" message */
SendMessage(hwndConsole, WM_SETCONSOLEINFO, (WPARAM) hDupSection, 0);
/*
* clean up
*/
hThread = CreateRemoteThread(hProcess, 0, 0,
(LPTHREAD_START_ROUTINE) CloseHandle,
hDupSection, 0, 0);
CloseHandle(hThread);
CloseHandle(hSection);
CloseHandle(hProcess);
return TRUE;
}
/*
* Fill the CONSOLE_INFO structure with information
* about the current console window
*/
static void
GetConsoleSizeInfo(CONSOLE_INFO *pci)
{
CONSOLE_SCREEN_BUFFER_INFO csbi;
HANDLE hConsoleOut = GetStdHandle(STD_OUTPUT_HANDLE);
GetConsoleScreenBufferInfo(hConsoleOut, &csbi);
pci->ScreenBufferSize = csbi.dwSize;
pci->WindowSize.X = csbi.srWindow.Right - csbi.srWindow.Left + 1;
pci->WindowSize.Y = csbi.srWindow.Bottom - csbi.srWindow.Top + 1;
pci->WindowPosX = csbi.srWindow.Left;
pci->WindowPosY = csbi.srWindow.Top;
}
static HWND
GetConsoleHandle(void)
{
HMODULE hMod = GetModuleHandle("kernel32.dll");
GETCONSOLEWINDOW pfnGetConsoleWindow =
(GETCONSOLEWINDOW) GetProcAddress(hMod, "GetConsoleWindow");
if (pfnGetConsoleWindow)
return pfnGetConsoleWindow();
else
return GetConsoleHwnd();
}
static HWND
GetConsoleHwnd(void)
{
int iterations = 0;
HWND hwndFound = 0;
char OldTitle[1024], NewTitle[1024], TestTitle[1024];
/* Get current window title */
GetConsoleTitle(OldTitle, sizeof OldTitle);
(void) sprintf(NewTitle, "NETHACK%d/%d", GetTickCount(),
GetCurrentProcessId());
SetConsoleTitle(NewTitle);
GetConsoleTitle(TestTitle, sizeof TestTitle);
while (strcmp(TestTitle, NewTitle) != 0) {
iterations++;
/* sleep(0); */
GetConsoleTitle(TestTitle, sizeof TestTitle);
}
hwndFound = FindWindow(NULL, NewTitle);
SetConsoleTitle(OldTitle);
/* printf("%d iterations\n", iterations); */
return hwndFound;
}
#endif /*CHANGE_COLOR*/
static int CALLBACK EnumFontCallback(
const LOGFONTW * lf, const TEXTMETRICW * tm, DWORD fontType, LPARAM lParam)
{
LOGFONTW * lf_ptr = (LOGFONTW *) lParam;
*lf_ptr = *lf;
return 0;
}
/* check_and_set_font ensures that the current font will render the symbols
* that are currently being used correctly. If they will not be rendered
* correctly, then it will change the font to a known good font.
*/
void
check_and_set_font()
{
if (!check_font_widths()) {
raw_print("WARNING: glyphs too wide in console font."
" Changing code page to 437 and font to Consolas\n");
set_known_good_console_font();
}
}
/* check_font_widths returns TRUE if all glyphs in current console font
* fit within the width of a single console cell.
*/
boolean
#ifndef VIRTUAL_TERMINAL_SEQUENCES
check_font_widths()
#else /* VIRTUAL_TERMINAL_SEQUENCES */
check_font_widths(void)
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
{
CONSOLE_FONT_INFOEX console_font_info;
console_font_info.cbSize = sizeof(console_font_info);
BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
&console_font_info);
/* get console window and DC
* NOTE: the DC from the console window does not have the correct
* font selected at this point.
*/
HWND hWnd = GetConsoleWindow();
HDC hDC = GetDC(hWnd);
LOGFONTW logical_font;
logical_font.lfCharSet = DEFAULT_CHARSET;
wcscpy(logical_font.lfFaceName, console_font_info.FaceName);
logical_font.lfPitchAndFamily = 0;
/* getting matching console font */
LOGFONTW matching_log_font = { 0 };
EnumFontFamiliesExW(hDC, &logical_font, EnumFontCallback,
(LPARAM) &matching_log_font, 0);
if (matching_log_font.lfHeight == 0) {
raw_print("Unable to enumerate system fonts\n");
return FALSE;
}
/* create font matching console font */
LOGFONTW console_font_log_font = matching_log_font;
console_font_log_font.lfWeight = console_font_info.FontWeight;
console_font_log_font.lfHeight = console_font_info.dwFontSize.Y;
console_font_log_font.lfWidth = console_font_info.dwFontSize.X;
HFONT console_font = CreateFontIndirectW(&console_font_log_font);
if (console_font == NULL) {
raw_print("Unable to create console font\n");
return FALSE;
}
/* select font */
HGDIOBJ saved_font = SelectObject(hDC, console_font);
/* measure the set of used glyphs to ensure they fit */
boolean all_glyphs_fit = FALSE;
/* determine whether it is a true type font */
TEXTMETRICA tm;
success = GetTextMetricsA(hDC, &tm);
if (!success) {
raw_print("Unable to get console font text metrics\n");
goto clean_up;
}
boolean isTrueType = (tm.tmPitchAndFamily & TMPF_TRUETYPE) != 0;
/* determine which glyphs are used */
boolean used[256];
memset(used, 0, sizeof(used));
for (int i = 0; i < SYM_MAX; i++) {
used[g.primary_syms[i]] = TRUE;
used[g.rogue_syms[i]] = TRUE;
}
int wcUsedCount = 0;
wchar_t wcUsed[256];
for (int i = 0; i < sizeof(used); i++)
if (used[i])
wcUsed[wcUsedCount++] = cp437[i];
all_glyphs_fit = TRUE;
for (int i = 0; i < wcUsedCount; i++) {
int width;
if (isTrueType) {
ABC abc;
success = GetCharABCWidthsW(hDC, wcUsed[i], wcUsed[i], &abc);
width = abc.abcA + abc.abcB + abc.abcC;
} else {
success = GetCharWidthW(hDC, wcUsed[i], wcUsed[i], &width);
}
if (success && width > console_font_info.dwFontSize.X) {
all_glyphs_fit = FALSE;
break;
}
}
clean_up:
SelectObject(hDC, saved_font);
DeleteObject(console_font);
return all_glyphs_fit;
}
/* set_known_good_console_font sets the code page and font used by the console
* to settings know to work well with NetHack. It also saves the original
* settings so that they can be restored prior to NetHack exit.
*/
void
set_known_good_console_font(void)
{
CONSOLE_FONT_INFOEX console_font_info;
console_font_info.cbSize = sizeof(console_font_info);
BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
&console_font_info);
success = SetConsoleOutputCP(437);
nhassert(success);
console.font_changed = TRUE;
#ifndef VIRTUAL_TERMINAL_SEQUENCES
console.orig_font_info = console_font_info;
console.original_code_page = GetConsoleOutputCP();
#else /* VIRTUAL_TERMINAL_SEQUENCES */
console.code_page = GetConsoleOutputCP();
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
wcscpy_s(console_font_info.FaceName,
sizeof(console_font_info.FaceName)
/ sizeof(console_font_info.FaceName[0]),
L"Consolas");
#ifndef VIRTUAL_TERMINAL_SEQUENCES
success = SetConsoleOutputCP(437);
nhassert(success);
#endif /* ! VIRTUAL_TERMINAL_SEQUENCES */
success = SetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info);
nhassert(success);
#ifdef VIRTUAL_TERMINAL_SEQUENCES
if (success)
console.font_info = console_font_info;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
/* restore_original_console_font will restore the console font and code page
* settings to what they were when NetHack was launched.
*/
void
restore_original_console_font(void)
{
#ifdef VIRTUAL_TERMINAL_SEQUENCES
char *tmplocalestr;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
if (console.font_changed) {
BOOL success;
#ifndef VIRTUAL_TERMINAL_SEQUENCES
raw_print("Restoring original font and code page\n");
success = SetConsoleOutputCP(console.original_code_page);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
raw_print("Restoring original font, code page and locale\n");
tmplocalestr = setlocale(LC_ALL, console.orig_localestr);
if (tmplocalestr) {
if (console.localestr)
free(console.localestr);
console.localestr = strdup(tmplocalestr);
}
success = SetConsoleOutputCP(console.orig_code_page);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
if (!success)
raw_print("Unable to restore original code page\n");
success = SetCurrentConsoleFontEx(console.hConOut, FALSE,
&console.orig_font_info);
if (!success)
raw_print("Unable to restore original font\n");
console.font_changed = FALSE;
}
}
/* set_cp_map() creates a mapping of every possible character of a code
* page to its corresponding WCHAR. This is necessary due to the high
* cost of making calls to MultiByteToWideChar() for every character we
* wish to print to the console.
*/
void set_cp_map(void)
{
if (console.has_unicode) {
#ifndef VIRTUAL_TERMINAL_SEQUENCES
UINT codePage = GetConsoleOutputCP();
#else
console.code_page = GetConsoleOutputCP();
#endif
#ifndef VIRTUAL_TERMINAL_SEQUENCES
if (codePage == 437) {
#else
if (console.code_page == 437) {
#endif
memcpy(console.cpMap, cp437, sizeof(console.cpMap));
} else {
for (int i = 0; i < 256; i++) {
char c = (char)i;
int count = MultiByteToWideChar(
#ifndef VIRTUAL_TERMINAL_SEQUENCES
codePage,
#else
console.code_page,
#endif
0, &c, 1, &console.cpMap[i], 1);
nhassert(count == 1);
// If a character was mapped to unicode control codes,
// remap to the appropriate unicode character per our
// code page 437 mappings.
if (console.cpMap[i] < 32)
console.cpMap[i] = cp437[console.cpMap[i]];
}
}
}
}
#if 0
/* early_raw_print() is used during early game intialization prior to the
* setting up of the windowing system. This allows early errors and panics
* to have there messages displayed.
*
* early_raw_print() eventually gets replaced by tty_raw_print().
*
*/
void early_raw_print(const char *s)
{
if (console.hConOut == NULL)
return;
nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
WORD attribute = FOREGROUND_GREEN | FOREGROUND_RED | FOREGROUND_BLUE;
DWORD unused;
while (*s != '\0') {
switch (*s) {
case '\n':
if (console.cursor.Y < console.height - 1)
console.cursor.Y++;
/* fall through */
case '\r':
console.cursor.X = 1;
break;
case '\b':
if (console.cursor.X > 1) {
console.cursor.X--;
} else if(console.cursor.Y > 0) {
console.cursor.X = console.width - 1;
console.cursor.Y--;
}
break;
default:
WriteConsoleOutputAttribute(console.hConOut, &attribute,
1, console.cursor, &unused);
WriteConsoleOutputCharacterA(console.hConOut, s,
1, console.cursor, &unused);
if (console.cursor.X == console.width - 1) {
if (console.cursor.Y < console.height - 1) {
console.cursor.X = 1;
console.cursor.Y++;
}
} else {
console.cursor.X++;
}
}
s++;
}
nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
SetConsoleCursorPosition(console.hConOut, console.cursor);
}
#endif
/* nethack_enter_consoletty() is the first thing that is called from main
* once the tty port is confirmed.
*
* We initialize all console state to support rendering to the console
* through out flipping support at this time. This allows us to support
* raw_print prior to our returning.
*
* During this early initialization, we also determine the width and
* height of the console that will be used. This width and height will
* not later change.
*
* We also check and set the console font to a font that we know will work
* well with nethack.
*
* The intent of this early initialization is to get all state that is
* not dependent upon game options initialized allowing us to simplify
* any additional initialization that might be needed when we are actually
* asked to open.
*
* Other then the call below which clears the entire console buffer, no
* other code outputs directly to the console other then the code that
* handles flipping the back buffer.
*
*/
void nethack_enter_consoletty(void)
{
#ifdef VIRTUAL_TERMINAL_SEQUENCES
char buf[BUFSZ], *bp, *localestr;
BOOL success;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
#if 0
/* set up state needed by early_raw_print() */
windowprocs.win_raw_print = early_raw_print;
#endif
console.hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
nhassert(console.hConOut != NULL); // NOTE: this assert will not print
GetConsoleScreenBufferInfo(console.hConOut, &console.orig_csbi);
/* Testing of widths != COLNO has not turned up any problems. Need
* to do a bit more testing and then we are likely to enable having
* console width match window width.
*/
#if 0
console.width = console.orig_csbi.srWindow.Right -
console.orig_csbi.srWindow.Left + 1;
console.Width = max(console.Width, COLNO);
#else
console.width = COLNO;
#endif
console.height = console.orig_csbi.srWindow.Bottom -
console.orig_csbi.srWindow.Top + 1;
console.height = max(console.height, ROWNO + 3);
console.buffer_size = console.width * console.height;
/* clear the entire console buffer */
int size = console.orig_csbi.dwSize.X * console.orig_csbi.dwSize.Y;
DWORD unused;
set_console_cursor(0, 0);
FillConsoleOutputAttribute(
console.hConOut, CONSOLE_CLEAR_ATTRIBUTE,
size, console.cursor, &unused);
FillConsoleOutputCharacter(
console.hConOut, CONSOLE_CLEAR_CHARACTER,
size, console.cursor, &unused);
set_console_cursor(1, 0);
SetConsoleCursorPosition(console.hConOut, console.cursor);
/* At this point early_raw_print will work */
console.hConIn = GetStdHandle(STD_INPUT_HANDLE);
nhassert(console.hConIn != NULL);
/* grow the size of the console buffer if it is not wide enough */
if (console.orig_csbi.dwSize.X < console.width) {
COORD screen_size = {0};
screen_size.Y = console.orig_csbi.dwSize.Y,
screen_size.X = console.width;
SetConsoleScreenBufferSize(console.hConOut, screen_size);
}
/* setup front and back buffers */
int buffer_size_bytes = sizeof(cell_t) * console.buffer_size;
console.front_buffer = (cell_t *)malloc(buffer_size_bytes);
buffer_fill_to_end(console.front_buffer, &undefined_cell, 0, 0);
console.back_buffer = (cell_t *)malloc(buffer_size_bytes);
buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
/* determine whether OS version has unicode support */
console.has_unicode = ((GetVersion() & 0x80000000) == 0);
#ifdef VIRTUAL_TERMINAL_SEQUENCES
/* store the original code page*/
console.orig_code_page = GetConsoleOutputCP();
/* store the original locale */
console.orig_localestr = dupstr(setlocale(LC_ALL, ""));
/* store the original font */
console.orig_font_info.cbSize = sizeof(console.orig_font_info);
success = GetCurrentConsoleFontEx(console.hConOut,
FALSE, &console.orig_font_info);
console.font_info = console.orig_font_info;
/* adjust the locale */
Snprintf(buf, sizeof buf, "%s", console.orig_localestr);
if ((bp = strstri(buf, ".utf8")) != 0)
*bp = '\0';
localestr = setlocale(LC_ALL, buf);
if (localestr) {
if (console.localestr)
free(console.localestr);
console.localestr = strdup(localestr);
}
console.code_page = console.orig_code_page;
if (console.has_unicode) {
if (console.code_page != 437)
success = SetConsoleOutputCP(437);
} else if (console.code_page != 1252) {
success = SetConsoleOutputCP(1252);
}
console.code_page = GetConsoleOutputCP();
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
/* check the font before we capture the code page map */
check_and_set_font();
set_cp_map();
#ifndef VIRTUAL_TERMINAL_SEQUENCES
/* Set console mode */
DWORD cmode, mask;
GetConsoleMode(console.hConIn, &cmode);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
/* input console mode */
DWORD disablemask;
GetConsoleMode(console.hConIn, &console.orig_in_cmode);
GetConsoleMode(console.hConOut, &console.orig_out_cmode);
console.in_cmode = console.orig_in_cmode;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
#ifdef NO_MOUSE_ALLOWED
#ifndef VIRTUAL_TERMINAL_SEQUENCES
mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT
#else
disablemask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT
#endif
| ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;
#else
#ifndef VIRTUAL_TERMINAL_SEQUENCES
mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
#else
disablemask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
#endif
| ENABLE_WINDOW_INPUT;
#endif
/* Turn OFF the settings specified in the mask */
#ifndef VIRTUAL_TERMINAL_SEQUENCES
cmode &= ~mask;
#else
console.in_cmode &= ~disablemask;
#endif
#ifndef NO_MOUSE_ALLOWED
#ifndef VIRTUAL_TERMINAL_SEQUENCES
cmode |= ENABLE_MOUSE_INPUT;
#else /* VIRTUAL_TERMINAL_SEQUENCES */
console.in_cmode |= ENABLE_MOUSE_INPUT;
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
#endif /* NO_MOUSE_ALLOWED */
#ifndef VIRTUAL_TERMINAL_SEQUENCES
SetConsoleMode(console.hConIn, cmode);
#else /* VIRTUAL_TERMINAL_SEQUENCES */
SetConsoleMode(console.hConIn, console.in_cmode);
console.out_cmode = console.orig_out_cmode;
if ((console.out_cmode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0) {
/* recognize escape sequences */
console.out_cmode |= ENABLE_VIRTUAL_TERMINAL_PROCESSING;
SetConsoleMode(console.hConOut, console.out_cmode);
}
GetConsoleMode(console.hConOut, &console.out_cmode);
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
/* load default keyboard handler */
HKL keyboard_layout = GetKeyboardLayout(0);
DWORD primary_language = (UINT_PTR) keyboard_layout & 0x3f;
/* This was overriding the handler that had already
been loaded during options parsing. Needs to
check first */
if (!iflags.altkeyhandler[0]) {
if (primary_language == LANG_ENGLISH) {
if (!load_keyboard_handler("nhdefkey"))
error("Unable to load nhdefkey.dll");
} else {
if (!load_keyboard_handler("nhraykey"))
error("Unable to load nhraykey.dll");
}
}
#ifdef VIRTUAL_TERMINAL_SEQUENCES
init_custom_colors();
#endif /* VIRTUAL_TERMINAL_SEQUENCES */
}
#endif /* TTY_GRAPHICS */
/* this is used as a printf() replacement when the window
* system isn't initialized yet
*/
void msmsg
VA_DECL(const char *, fmt)
{
char buf[ROWNO * COLNO]; /* worst case scenario */
VA_START(fmt);
VA_INIT(fmt, const char *);
(void) vsnprintf(buf, sizeof buf, fmt, VA_ARGS);
if (redirect_stdout)
fprintf(stdout, "%s", buf);
else {
#ifdef TTY_GRAPHICS
if(!init_ttycolor_completed)
init_ttycolor();
/* if we have generated too many messages ... ask the user to
* confirm and then clear.
*/
if (console.cursor.Y > console.height - 4) {
xputs("Hit <Enter> to continue.");
while (pgetchar() != '\n')
;
raw_clear_screen();
set_console_cursor(1, 0);
}
xputs(buf);
if (ttyDisplay)
curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y);
#else
fprintf(stdout, "%s", buf);
#endif
}
VA_END();
return;
}
#ifndef VIRTUAL_TERMINAL_SEQUENCES
#endif /* ! VIRTUAL_TERMINAL_SEQUENCES */
#endif /* WIN32 */