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.
2882 lines
87 KiB
C
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 */
|