Another part of github issue 227. Casting a function pointer when passing it to another function is iffy when lying about the return type. tputs() expects a routine which returns int, so give it one. Other xputc() usage is equivalent to putchar(), so define xputc() with the same function signature as that has. The tputs() declarations in system.h should probably be changed (third argument is a function which takes an int rather than unspecified parameters) but I've left them alone. I made that change to tputs() in sys/share/tclib.c though. NT and MSDOS changes are untested. tclib.c compiles ok with clang- as-gcc on OSX but hasn't been tested with the port that uses it (VMS).
1952 lines
53 KiB
C
1952 lines
53 KiB
C
/* NetHack 3.6 nttty.c $NHDT-Date: 1554215932 2019/04/02 14:38:52 $ $NHDT-Branch: NetHack-3.6.2-beta01 $:$NHDT-Revision: 1.99 $ */
|
|
/* Copyright (c) NetHack PC Development Team 1993 */
|
|
/* NetHack may be freely redistributed. See license for details. */
|
|
|
|
/* tty.c - (Windows NT) 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
|
|
*
|
|
*/
|
|
|
|
|
|
#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>
|
|
|
|
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.
|
|
*
|
|
*/
|
|
|
|
#define CONSOLE_CLEAR_ATTRIBUTE (FOREGROUND_RED | FOREGROUND_GREEN \
|
|
| FOREGROUND_BLUE)
|
|
#define CONSOLE_CLEAR_CHARACTER (' ')
|
|
|
|
#define CONSOLE_UNDEFINED_ATTRIBUTE (0)
|
|
#define CONSOLE_UNDEFINED_CHARACTER ('\0')
|
|
|
|
typedef struct {
|
|
WCHAR character;
|
|
WORD attribute;
|
|
} cell_t;
|
|
|
|
cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE };
|
|
cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
|
|
CONSOLE_UNDEFINED_ATTRIBUTE };
|
|
|
|
/*
|
|
* The following WIN32 Console API routines are used in this file.
|
|
*
|
|
* CreateFile
|
|
* GetConsoleScreenBufferInfo
|
|
* GetStdHandle
|
|
* SetConsoleCursorPosition
|
|
* SetConsoleTextAttribute
|
|
* SetConsoleCtrlHandler
|
|
* PeekConsoleInput
|
|
* ReadConsoleInput
|
|
* WriteConsoleOutputCharacter
|
|
* FillConsoleOutputAttribute
|
|
* GetConsoleOutputCP
|
|
*/
|
|
|
|
static BOOL FDECL(CtrlHandler, (DWORD));
|
|
static void FDECL(xputc_core, (char));
|
|
void FDECL(cmov, (int, int));
|
|
void FDECL(nocmov, (int, int));
|
|
int FDECL(process_keystroke,
|
|
(INPUT_RECORD *, boolean *, BOOLEAN_P numberpad, int portdebug));
|
|
static void NDECL(init_ttycolor);
|
|
static void NDECL(really_move_cursor);
|
|
static void NDECL(check_and_set_font);
|
|
static boolean NDECL(check_font_widths);
|
|
static void NDECL(set_known_good_console_font);
|
|
static void NDECL(restore_original_console_font);
|
|
extern void NDECL(safe_routines);
|
|
|
|
/* 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 NDECL(adjust_palette);
|
|
static int FDECL(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 origcsbi;
|
|
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 original_font_info;
|
|
UINT original_code_page;
|
|
} console = {
|
|
0,
|
|
(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
|
|
(FOREGROUND_GREEN | FOREGROUND_BLUE | FOREGROUND_RED),
|
|
NO_COLOR,
|
|
{FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE, FALSE},
|
|
{0, 0},
|
|
NULL,
|
|
NULL,
|
|
{ 0 },
|
|
0,
|
|
0,
|
|
FALSE,
|
|
0,
|
|
NULL,
|
|
NULL,
|
|
{ 0 },
|
|
FALSE,
|
|
{ 0 },
|
|
0
|
|
};
|
|
|
|
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_P, int);
|
|
|
|
typedef int(__stdcall *NHKBHIT)(HANDLE, INPUT_RECORD *);
|
|
|
|
typedef int(__stdcall *CHECKINPUT)(HANDLE, INPUT_RECORD *, DWORD *, BOOLEAN_P,
|
|
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;
|
|
|
|
|
|
/* Console buffer flipping support */
|
|
|
|
static void back_buffer_flip()
|
|
{
|
|
cell_t * back = console.back_buffer;
|
|
cell_t * front = console.front_buffer;
|
|
COORD pos;
|
|
DWORD unused;
|
|
|
|
for (pos.Y = 0; pos.Y < console.height; pos.Y++) {
|
|
for (pos.X = 0; pos.X < console.width; pos.X++) {
|
|
if (back->attribute != front->attribute) {
|
|
WriteConsoleOutputAttribute(console.hConOut, &back->attribute,
|
|
1, pos, &unused);
|
|
front->attribute = back->attribute;
|
|
}
|
|
if (back->character != front->character) {
|
|
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);
|
|
}
|
|
*front = *back;
|
|
}
|
|
back++;
|
|
front++;
|
|
}
|
|
}
|
|
}
|
|
|
|
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(s)
|
|
const char *s;
|
|
{
|
|
cmov(ttyDisplay->curx, ttyDisplay->cury);
|
|
end_screen();
|
|
if (s)
|
|
raw_print(s);
|
|
restore_original_console_font();
|
|
if (orig_QuickEdit) {
|
|
DWORD cmode;
|
|
|
|
GetConsoleMode(console.hConIn, &cmode);
|
|
cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
|
|
SetConsoleMode(console.hConIn, cmode);
|
|
}
|
|
}
|
|
|
|
/* called by init_nhwindows() and resume_nhwindows() */
|
|
void
|
|
setftty()
|
|
{
|
|
#ifdef CHANGE_COLOR
|
|
if (altered_palette)
|
|
adjust_palette();
|
|
#endif
|
|
start_screen();
|
|
}
|
|
|
|
void
|
|
tty_startup(wid, hgt)
|
|
int *wid, *hgt;
|
|
{
|
|
*wid = console.width;
|
|
*hgt = console.height;
|
|
set_option_mod_status("mouse_support", SET_IN_GAME);
|
|
}
|
|
|
|
void
|
|
tty_number_pad(state)
|
|
int state;
|
|
{
|
|
// do nothing
|
|
}
|
|
|
|
void
|
|
tty_start_screen()
|
|
{
|
|
if (iflags.num_pad)
|
|
tty_number_pad(1); /* make keypad send digits */
|
|
}
|
|
|
|
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(ctrltype)
|
|
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
|
|
nttty_open(mode)
|
|
int mode; // unused
|
|
{
|
|
DWORD cmode;
|
|
|
|
/* Initialize the function pointer that points to
|
|
* the kbhit() equivalent, in this TTY case nttty_kbhit()
|
|
*/
|
|
nt_kbhit = nttty_kbhit;
|
|
|
|
if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) {
|
|
/* Unable to set control handler */
|
|
cmode = 0; /* just to have a statement to break on for debugger */
|
|
}
|
|
|
|
LI = console.height;
|
|
CO = console.width;
|
|
|
|
really_move_cursor();
|
|
}
|
|
|
|
void
|
|
nttty_exit()
|
|
{
|
|
/* go back to using the safe routines */
|
|
safe_routines();
|
|
}
|
|
|
|
int
|
|
process_keystroke(ir, valid, numberpad, portdebug)
|
|
INPUT_RECORD *ir;
|
|
boolean *valid;
|
|
boolean numberpad;
|
|
int portdebug;
|
|
{
|
|
int ch = keyboard_handler.pProcessKeystroke(
|
|
console.hConIn, ir, valid, numberpad, portdebug);
|
|
/* check for override */
|
|
if (ch && ch < MAX_OVERRIDES && key_overrides[ch])
|
|
ch = key_overrides[ch];
|
|
return ch;
|
|
}
|
|
|
|
int
|
|
nttty_kbhit()
|
|
{
|
|
return keyboard_handler.pNHkbhit(console.hConIn, &ir);
|
|
}
|
|
|
|
int
|
|
tgetch()
|
|
{
|
|
int mod;
|
|
coord cc;
|
|
DWORD count;
|
|
really_move_cursor();
|
|
if (iflags.debug_fuzzer)
|
|
return randomkey();
|
|
return (program_state.done_hup)
|
|
? '\033'
|
|
: keyboard_handler.pCheckInput(
|
|
console.hConIn, &ir, &count, iflags.num_pad, 0, &mod, &cc);
|
|
}
|
|
|
|
int
|
|
ntposkey(x, y, mod)
|
|
int *x, *y, *mod;
|
|
{
|
|
int ch;
|
|
coord cc;
|
|
DWORD count;
|
|
really_move_cursor();
|
|
if (iflags.debug_fuzzer)
|
|
return randomkey();
|
|
ch = (program_state.done_hup)
|
|
? '\033'
|
|
: keyboard_handler.pCheckInput(
|
|
console.hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc);
|
|
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) nttty=(%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(x, y)
|
|
register int x, y;
|
|
{
|
|
ttyDisplay->cury = y;
|
|
ttyDisplay->curx = x;
|
|
|
|
set_console_cursor(x, y);
|
|
}
|
|
|
|
void
|
|
nocmov(x, y)
|
|
int x, y;
|
|
{
|
|
ttyDisplay->curx = x;
|
|
ttyDisplay->cury = y;
|
|
|
|
set_console_cursor(x, y);
|
|
}
|
|
|
|
/* same signature as 'putchar()' with potential failure result ignored */
|
|
int
|
|
xputc(ch)
|
|
int ch;
|
|
{
|
|
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
|
|
xputc_core((char) ch);
|
|
return 0;
|
|
}
|
|
|
|
void
|
|
xputs(s)
|
|
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)
|
|
xputc_core(s[k]);
|
|
}
|
|
}
|
|
|
|
/* xputc_core() and g_putch() are the only
|
|
* two routines that actually place output
|
|
* on the display.
|
|
*/
|
|
void
|
|
xputc_core(ch)
|
|
char ch;
|
|
{
|
|
nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
|
|
nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
|
|
|
|
boolean inverse = FALSE;
|
|
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:
|
|
|
|
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 {
|
|
console.cursor.X++;
|
|
}
|
|
}
|
|
|
|
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(in_ch)
|
|
int in_ch;
|
|
{
|
|
boolean inverse = FALSE;
|
|
unsigned char ch = (unsigned char) in_ch;
|
|
|
|
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
|
|
|
|
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;
|
|
|
|
cell_t cell;
|
|
|
|
cell.attribute = console.attr;
|
|
cell.character = (console.has_unicode ? cp437[ch] : ch);
|
|
|
|
buffer_write(console.back_buffer, &cell, console.cursor);
|
|
}
|
|
|
|
void
|
|
cl_end()
|
|
{
|
|
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()
|
|
{
|
|
buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
|
|
}
|
|
|
|
void
|
|
clear_screen()
|
|
{
|
|
raw_clear_screen();
|
|
home();
|
|
}
|
|
|
|
void
|
|
home()
|
|
{
|
|
ttyDisplay->curx = ttyDisplay->cury = 0;
|
|
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
|
|
}
|
|
|
|
void
|
|
backsp()
|
|
{
|
|
set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
|
|
xputc_core('\b');
|
|
}
|
|
|
|
void
|
|
cl_eos()
|
|
{
|
|
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()
|
|
{
|
|
if (flags.silent || iflags.debug_fuzzer)
|
|
return;
|
|
Beep(8000, 500);
|
|
}
|
|
|
|
volatile int junk; /* prevent optimizer from eliminating loop below */
|
|
|
|
void
|
|
tty_delay_output()
|
|
{
|
|
/* 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 */
|
|
}
|
|
}
|
|
|
|
#ifdef TEXTCOLOR
|
|
/*
|
|
* 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()
|
|
{
|
|
#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;
|
|
}
|
|
#endif /* TEXTCOLOR */
|
|
|
|
int
|
|
has_color(int color)
|
|
{
|
|
#ifdef TEXTCOLOR
|
|
if ((color >= 0) && (color < CLR_MAX))
|
|
return 1;
|
|
#else
|
|
if ((color == CLR_BLACK) || (color == CLR_WHITE) || (color == NO_COLOR))
|
|
return 1;
|
|
#endif
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
int
|
|
term_attr_fixup(int attrmask)
|
|
{
|
|
return attrmask;
|
|
}
|
|
|
|
void
|
|
term_start_attr(int attrib)
|
|
{
|
|
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:
|
|
case ATR_ULINE:
|
|
case ATR_BLINK:
|
|
case ATR_BOLD:
|
|
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
|
|
console.attr = (console.foreground | console.background);
|
|
console.current_nhcolor = NO_COLOR;
|
|
}
|
|
|
|
void
|
|
standoutbeg()
|
|
{
|
|
term_start_attr(ATR_BOLD);
|
|
}
|
|
|
|
void
|
|
standoutend()
|
|
{
|
|
term_end_attr(ATR_BOLD);
|
|
}
|
|
|
|
#ifndef NO_MOUSE_ALLOWED
|
|
void
|
|
toggle_mouse_support()
|
|
{
|
|
static int qeinit = 0;
|
|
DWORD cmode;
|
|
|
|
GetConsoleMode(console.hConIn, &cmode);
|
|
if (!qeinit) {
|
|
qeinit = 1;
|
|
orig_QuickEdit = ((cmode & ENABLE_QUICK_EDIT_MODE) != 0);
|
|
}
|
|
switch(iflags.wc_mouse_support) {
|
|
case 2:
|
|
cmode |= ENABLE_MOUSE_INPUT;
|
|
break;
|
|
case 1:
|
|
cmode |= ENABLE_MOUSE_INPUT;
|
|
cmode &= ~ENABLE_QUICK_EDIT_MODE;
|
|
cmode |= ENABLE_EXTENDED_FLAGS;
|
|
break;
|
|
case 0:
|
|
/*FALLTHRU*/
|
|
default:
|
|
cmode &= ~ENABLE_MOUSE_INPUT;
|
|
if (orig_QuickEdit)
|
|
cmode |= (ENABLE_QUICK_EDIT_MODE | ENABLE_EXTENDED_FLAGS);
|
|
}
|
|
SetConsoleMode(console.hConIn, cmode);
|
|
}
|
|
#endif
|
|
|
|
/* handle tty options updates here */
|
|
void
|
|
nttty_preference_update(pref)
|
|
const char *pref;
|
|
{
|
|
if (stricmp(pref, "mouse_support") == 0) {
|
|
#ifndef NO_MOUSE_ALLOWED
|
|
toggle_mouse_support();
|
|
#endif
|
|
}
|
|
if (stricmp(pref, "symset") == 0)
|
|
check_and_set_font();
|
|
return;
|
|
}
|
|
|
|
#ifdef PORT_DEBUG
|
|
void
|
|
win32con_debug_keystrokes()
|
|
{
|
|
DWORD count;
|
|
boolean valid = 0;
|
|
int ch;
|
|
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()
|
|
{
|
|
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()
|
|
{
|
|
display_cursor_info = !display_cursor_info;
|
|
}
|
|
#endif
|
|
|
|
void
|
|
map_subkeyvalue(op)
|
|
register 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()
|
|
{
|
|
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 nttty_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) vsprintf(&buf[1], s, VA_ARGS);
|
|
msmsg(buf);
|
|
really_move_cursor();
|
|
VA_END();
|
|
exit(EXIT_FAILURE);
|
|
}
|
|
|
|
void
|
|
synch_cursor()
|
|
{
|
|
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_ARGS)
|
|
{
|
|
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
|
|
check_font_widths()
|
|
{
|
|
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);
|
|
|
|
/* 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[l_syms[i]] = TRUE;
|
|
used[r_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];
|
|
|
|
/* measure the set of used glyphs to ensure they fit */
|
|
boolean 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()
|
|
{
|
|
CONSOLE_FONT_INFOEX console_font_info;
|
|
console_font_info.cbSize = sizeof(console_font_info);
|
|
BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
|
|
&console_font_info);
|
|
|
|
console.font_changed = TRUE;
|
|
console.original_font_info = console_font_info;
|
|
console.original_code_page = GetConsoleOutputCP();
|
|
|
|
wcscpy_s(console_font_info.FaceName,
|
|
sizeof(console_font_info.FaceName)
|
|
/ sizeof(console_font_info.FaceName[0]),
|
|
L"Consolas");
|
|
|
|
success = SetConsoleOutputCP(437);
|
|
nhassert(success);
|
|
|
|
success = SetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info);
|
|
nhassert(success);
|
|
}
|
|
|
|
/* 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()
|
|
{
|
|
if (console.font_changed) {
|
|
BOOL success;
|
|
raw_print("Restoring original font and code page\n");
|
|
success = SetConsoleOutputCP(console.original_code_page);
|
|
if (!success)
|
|
raw_print("Unable to restore original code page\n");
|
|
|
|
success = SetCurrentConsoleFontEx(console.hConOut, FALSE,
|
|
&console.original_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()
|
|
{
|
|
if (console.has_unicode) {
|
|
UINT codePage = GetConsoleOutputCP();
|
|
|
|
if (codePage == 437) {
|
|
memcpy(console.cpMap, cp437, sizeof(console.cpMap));
|
|
} else {
|
|
for (int i = 0; i < 256; i++) {
|
|
char c = (char)i;
|
|
int count = MultiByteToWideChar(codePage, 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_nttty() 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_nttty()
|
|
{
|
|
#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.origcsbi);
|
|
|
|
/* 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.origcsbi.srWindow.Right -
|
|
console.origcsbi.srWindow.Left + 1;
|
|
console.Width = max(console.Width, COLNO);
|
|
#else
|
|
console.width = COLNO;
|
|
#endif
|
|
|
|
console.height = console.origcsbi.srWindow.Bottom -
|
|
console.origcsbi.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.origcsbi.dwSize.X * console.origcsbi.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.origcsbi.dwSize.X < console.width) {
|
|
COORD size = {
|
|
size.Y = console.origcsbi.dwSize.Y,
|
|
size.X = console.width
|
|
};
|
|
|
|
SetConsoleScreenBufferSize(console.hConOut, 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);
|
|
|
|
/* check the font before we capture the code page map */
|
|
check_and_set_font();
|
|
set_cp_map();
|
|
|
|
/* Set console mode */
|
|
DWORD cmode, mask;
|
|
GetConsoleMode(console.hConIn, &cmode);
|
|
#ifdef NO_MOUSE_ALLOWED
|
|
mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_MOUSE_INPUT
|
|
| ENABLE_ECHO_INPUT | ENABLE_WINDOW_INPUT;
|
|
#else
|
|
mask = ENABLE_PROCESSED_INPUT | ENABLE_LINE_INPUT | ENABLE_ECHO_INPUT
|
|
| ENABLE_WINDOW_INPUT;
|
|
#endif
|
|
/* Turn OFF the settings specified in the mask */
|
|
cmode &= ~mask;
|
|
#ifndef NO_MOUSE_ALLOWED
|
|
cmode |= ENABLE_MOUSE_INPUT;
|
|
#endif
|
|
SetConsoleMode(console.hConIn, cmode);
|
|
|
|
/* load default keyboard handler */
|
|
HKL keyboard_layout = GetKeyboardLayout(0);
|
|
DWORD primary_language = (UINT_PTR) keyboard_layout & 0x3f;
|
|
|
|
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");
|
|
}
|
|
}
|
|
#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 *);
|
|
Vsprintf(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;
|
|
}
|
|
|
|
#endif /* WIN32 */
|