OSDN Git Service

change xputc2 to take strings instead of two chars
[jnethack/source.git] / sys / winnt / nttty.c
index c07d994..3da2b6a 100644 (file)
@@ -1,4 +1,4 @@
-/* NetHack 3.6 nttty.c $NHDT-Date: 1520825872 2018/03/12 03:37:52 $  $NHDT-Branch: NetHack-3.6.0 $:$NHDT-Revision: 1.70 $ */
+/* 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. */
 
@@ -8,17 +8,60 @@
  * 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
+ * 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>
-#include "win32api.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;
+#if 1 /*JP*/
+    int     iskanji;
+#endif
+} cell_t;
+
+#if 0 /*JP*/
+cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE };
+cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
+                          CONSOLE_UNDEFINED_ATTRIBUTE };
+#else
+cell_t clear_cell = { CONSOLE_CLEAR_CHARACTER, CONSOLE_CLEAR_ATTRIBUTE, 0 };
+cell_t undefined_cell = { CONSOLE_UNDEFINED_CHARACTER,
+                          CONSOLE_UNDEFINED_ATTRIBUTE, 0 };
+#endif
 
 /*
  * The following WIN32 Console API routines are used in this file.
@@ -38,6 +81,9 @@
 
 static BOOL FDECL(CtrlHandler, (DWORD));
 static void FDECL(xputc_core, (char));
+#if 1 /*JP*/
+static void FDECL(xputc2_core, (unsigned char *));
+#endif
 void FDECL(cmov, (int, int));
 void FDECL(nocmov, (int, int));
 int FDECL(process_keystroke,
@@ -45,26 +91,19 @@ int FDECL(process_keystroke,
 static void NDECL(init_ttycolor);
 static void NDECL(really_move_cursor);
 static void NDECL(check_and_set_font);
+#if 0 /*JP*/
 static boolean NDECL(check_font_widths);
+#endif
 static void NDECL(set_known_good_console_font);
 static void NDECL(restore_original_console_font);
-
-/* Win32 Console handles for input and output */
-HANDLE hConIn;
-HANDLE hConOut;
+extern void NDECL(safe_routines);
 
 /* Win32 Screen buffer,coordinate,console I/O information */
-CONSOLE_SCREEN_BUFFER_INFO csbi, origcsbi;
 COORD ntcoord;
 INPUT_RECORD ir;
+static boolean orig_QuickEdit;
 
 /* Support for changing console font if existing glyph widths are too wide */
-boolean console_font_changed;
-CONSOLE_FONT_INFOEX original_console_font_info;
-UINT original_console_code_page;
-
-extern boolean getreturn_enabled; /* from sys/share/pcsys.c */
-extern int redirect_stdout;
 
 /* 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
@@ -73,9 +112,8 @@ extern int redirect_stdout;
  * immediately after it is displayed, yet not bother when started
  * from the command line.
  */
-int GUILaunched;
+int GUILaunched = FALSE;
 /* Flag for whether unicode is supported */
-static boolean has_unicode;
 static boolean init_ttycolor_completed;
 #ifdef PORT_DEBUG
 static boolean display_cursor_info = FALSE;
@@ -106,14 +144,41 @@ struct console_t {
     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}
+    {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
@@ -143,13 +208,131 @@ typedef int(__stdcall *SOURCEAUTHOR)(char **);
 
 typedef int(__stdcall *KEYHANDLERNAME)(char **, int);
 
-HANDLE hLibrary;
-PROCESS_KEYSTROKE pProcessKeystroke;
-NHKBHIT pNHkbhit;
-CHECKINPUT pCheckInput;
-SOURCEWHERE pSourceWhere;
-SOURCEAUTHOR pSourceAuthor;
-KEYHANDLERNAME pKeyHandlerName;
+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 1 /*JP*/
+            if (back->iskanji == 1) {
+                cell_t * back2 = back + 1;
+                cell_t * front2 = front + 1;
+                /* pos.x == 0 \82Ì\8fð\8c\8f\82Í\95s\97v\82Ì\82Í\82¸\82¾\82ª #42072 \91Î\8dô\82Å\92Ç\89Á\81B */
+                if (back->attribute != front->attribute ||
+                    back2->attribute != front2->attribute || pos.X == 0) {
+                    WORD attrs[2];
+                    attrs[0] = attrs[1] = back->attribute;
+                    WriteConsoleOutputAttribute(console.hConOut, attrs,
+                                                2, pos, &unused);
+                    front->attribute = back->attribute;
+                    front2->attribute = back2->attribute;
+                }
+                /* pos.x == 0 \82Ì\8fð\8c\8f\82Í\95s\97v\82Ì\82Í\82¸\82¾\82ª #42072 \91Î\8dô\82Å\92Ç\89Á\81B */
+                if (back->character != front->character ||
+                    back2->character != front2->character || pos.X == 0) {
+                    wchar_t wbuf[1];
+                    wbuf[0] = back->character;
+                    WriteConsoleOutputCharacterW(console.hConOut, wbuf, 1, pos,
+                                                    &unused);
+                    *front = *back;
+                    *front2 = *back2;
+                }
+                pos.X++;
+                back += 2;
+                front += 2;
+                continue;
+            }
+#endif
+            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);
+                }
+#if 1 /*JP*/
+                /* \8a¿\8e\9a\82Ì1\83o\83C\83g\96Ú\82¾\82Á\82½\8fê\8d\87\81A
+                   2\83o\83C\83g\96Ú\82ð\83N\83\8a\83A\82µ\82Ä\8am\8eÀ\82É\8dX\90V\82·\82é */
+                if (front->iskanji == 1) {
+                    (front + 1)->character = '\0';
+                }
+#endif
+                *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
@@ -157,10 +340,6 @@ KEYHANDLERNAME pKeyHandlerName;
 void
 gettty()
 {
-    console_font_changed = FALSE;
-
-    check_and_set_font();
-
 #ifndef TEXTCOLOR
     int k;
 #endif
@@ -184,8 +363,14 @@ const char *s;
     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() */
@@ -197,19 +382,14 @@ setftty()
         adjust_palette();
 #endif
     start_screen();
-    has_unicode = ((GetVersion() & 0x80000000) == 0);
 }
 
 void
 tty_startup(wid, hgt)
 int *wid, *hgt;
 {
-    int twid = origcsbi.srWindow.Right - origcsbi.srWindow.Left + 1;
-
-    if (twid > 80)
-        twid = 80;
-    *wid = twid;
-    *hgt = origcsbi.srWindow.Bottom - origcsbi.srWindow.Top + 1;
+    *wid = console.width;
+    *hgt = console.height;
     set_option_mod_status("mouse_support", SET_IN_GAME);
 }
 
@@ -217,6 +397,7 @@ void
 tty_number_pad(state)
 int state;
 {
+    // do nothing
 }
 
 void
@@ -231,19 +412,9 @@ tty_end_screen()
 {
     clear_screen();
     really_move_cursor();
-    if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
-        DWORD ccnt;
-        COORD newcoord;
-
-        newcoord.X = 0;
-        newcoord.Y = 0;
-        FillConsoleOutputAttribute(
-            hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
-            csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt);
-        FillConsoleOutputCharacter(
-            hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt);
-    }
-    FlushConsoleInputBuffer(hConIn);
+    buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);
+    back_buffer_flip();
+    FlushConsoleInputBuffer(console.hConIn);
 }
 
 static BOOL
@@ -262,7 +433,7 @@ DWORD ctrltype;
         hangup(0);
 #endif
 #if defined(SAFERHANGUP)
-        CloseHandle(hConIn); /* trigger WAIT_FAILED */
+        CloseHandle(console.hConIn); /* trigger WAIT_FAILED */
         return TRUE;
 #endif
     default:
@@ -270,79 +441,36 @@ DWORD ctrltype;
     }
 }
 
-/* called by init_tty in wintty.c for WIN32 port only */
+/* called by pcmain() and process_options() */
 void
 nttty_open(mode)
-int mode;
+int mode; // unused
 {
-    HANDLE hStdOut;
     DWORD cmode;
-    long mask;
-
-    GUILaunched = 0;
-
-    try :
-        /* The following lines of code were suggested by
-         * Bob Landau of Microsoft WIN32 Developer support,
-         * as the only current means of determining whether
-         * we were launched from the command prompt, or from
-         * the NT program manager. M. Allison
-         */
-    hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
-
-    if (hStdOut) {
-        GetConsoleScreenBufferInfo(hStdOut, &origcsbi);
-    } else if (mode) {
-        HANDLE hStdOut = GetStdHandle(STD_OUTPUT_HANDLE);
-        HANDLE hStdIn = GetStdHandle(STD_INPUT_HANDLE);
-
-        if (!hStdOut && !hStdIn) {
-            /* Bool rval; */
-            AllocConsole();
-            AttachConsole(GetCurrentProcessId());
-            /*         rval = SetStdHandle(STD_OUTPUT_HANDLE, hWrite); */
-            freopen("CON", "w", stdout);
-            freopen("CON", "r", stdin);
-        }
-        mode = 0;
-        goto try;
-    } else {
-        return;
-    }
-
-    /* Obtain handles for the standard Console I/O devices */
-    hConIn = GetStdHandle(STD_INPUT_HANDLE);
-    hConOut = GetStdHandle(STD_OUTPUT_HANDLE);
 
-    load_keyboard_handler();
     /* Initialize the function pointer that points to
-    * the kbhit() equivalent, in this TTY case nttty_kbhit()
-    */
+     * the kbhit() equivalent, in this TTY case nttty_kbhit()
+     */
     nt_kbhit = nttty_kbhit;
 
-    GetConsoleMode(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(hConIn, cmode);
     if (!SetConsoleCtrlHandler((PHANDLER_ROUTINE) CtrlHandler, TRUE)) {
         /* Unable to set control handler */
         cmode = 0; /* just to have a statement to break on for debugger */
     }
-    get_scr_size();
-    console.cursor.X = console.cursor.Y = 0;
+
+    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;
@@ -350,7 +478,17 @@ boolean *valid;
 boolean numberpad;
 int portdebug;
 {
-    int ch = pProcessKeystroke(hConIn, ir, valid, numberpad, portdebug);
+    int ch;
+
+#ifdef QWERTZ_SUPPORT
+    if (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];
@@ -360,33 +498,7 @@ int portdebug;
 int
 nttty_kbhit()
 {
-    return pNHkbhit(hConIn, &ir);
-}
-
-void
-get_scr_size()
-{
-    int lines, cols;
-    
-    GetConsoleScreenBufferInfo(hConOut, &csbi);
-    
-    lines = csbi.srWindow.Bottom - (csbi.srWindow.Top + 1);
-    cols = csbi.srWindow.Right - (csbi.srWindow.Left + 1);
-
-    LI = lines;
-    CO = min(cols, 80);
-    
-    if ((LI < 25) || (CO < 80)) {
-        COORD newcoord;
-
-        LI = 25;
-        CO = 80;
-
-        newcoord.Y = LI;
-        newcoord.X = CO;
-
-        SetConsoleScreenBufferSize(hConOut, newcoord);
-    }
+    return keyboard_handler.pNHkbhit(console.hConIn, &ir);
 }
 
 int
@@ -395,11 +507,20 @@ 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 (Cmd.swap_yz)
+        numpad |= 0x10;
+#endif
+
     return (program_state.done_hup)
                ? '\033'
-               : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 0, &mod,
-                             &cc);
+               : keyboard_handler.pCheckInput(
+                   console.hConIn, &ir, &count, numpad, 0, &mod, &cc);
 }
 
 int
@@ -409,10 +530,22 @@ int *x, *y, *mod;
     int ch;
     coord cc;
     DWORD count;
+    boolean numpad = iflags.num_pad;
+
     really_move_cursor();
+    if (iflags.debug_fuzzer)
+        return randomkey();
+#ifdef QWERTZ_SUPPORT
+    if (Cmd.swap_yz)
+        numpad |= 0x10;
+#endif
     ch = (program_state.done_hup)
              ? '\033'
-             : pCheckInput(hConIn, &ir, &count, iflags.num_pad, 1, mod, &cc);
+             : 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;
@@ -420,6 +553,15 @@ int *x, *y, *mod;
     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()
 {
@@ -431,15 +573,16 @@ really_move_cursor()
             oldtitle[39] = '\0';
         }
         Sprintf(newtitle, "%-55s tty=(%02d,%02d) nttty=(%02d,%02d)", oldtitle,
-                ttyDisplay->curx, ttyDisplay->cury, console.cursor.X, console.cursor.Y);
+                ttyDisplay->curx, ttyDisplay->cury,
+                console.cursor.X, console.cursor.Y);
         (void) SetConsoleTitle(newtitle);
     }
 #endif
-    if (ttyDisplay) {
-        console.cursor.X = ttyDisplay->curx;
-        console.cursor.Y = ttyDisplay->cury;
-    }
-    SetConsoleCursorPosition(hConOut, console.cursor);
+    if (ttyDisplay)
+        set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
+
+    back_buffer_flip();
+    SetConsoleCursorPosition(console.hConOut, console.cursor);
 }
 
 void
@@ -448,62 +591,113 @@ register int x, y;
 {
     ttyDisplay->cury = y;
     ttyDisplay->curx = x;
-    console.cursor.X = x;
-    console.cursor.Y = y;
+
+    set_console_cursor(x, y);
 }
 
 void
 nocmov(x, y)
 int x, y;
 {
-    console.cursor.X = x;
-    console.cursor.Y = y;
     ttyDisplay->curx = x;
     ttyDisplay->cury = y;
+
+    set_console_cursor(x, y);
 }
 
-void
+/* same signature as 'putchar()' with potential failure result ignored */
+int
 xputc(ch)
-char ch;
+int ch;
 {
-    console.cursor.X = ttyDisplay->curx;
-    console.cursor.Y = ttyDisplay->cury;
-    xputc_core(ch);
+    set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
+    xputc_core((char) ch);
+    return 0;
 }
 
 #if 1 /*JP*/
 void
-xputc2_core(ch1, ch2)
-int ch1;
-int ch2;
+xputc2_core(str)
+unsigned char *str;
 {
-    unsigned char buf[2];
-    WORD attrs[2];
+    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;
+    wchar_t wbuf[1];
+
+    /* xputc_core()\82©\82ç\82Ì\83R\83s\81[ */
+    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;
 
-    buf[0] = ch1;
-    buf[1] = ch2;
+    /* \89E\92[\82É1\83o\83C\83g\95ª\82µ\82©\8bó\82«\82ª\82È\82¢\8fê\8d\87 */
+    if (console.cursor.X == console.width - 2) {
+        /* \8bó\94\92\95\\8e¦ */
+        cell.character = ' ';
+        cell.iskanji = 0;
+        buffer_write(console.back_buffer, &cell, console.cursor);
+        console.cursor.X++;
+        if (console.cursor.Y < console.height - 1) {
+            /* \8e\9f\82Ì\8ds\82É */
+            console.cursor.X = 1;
+            console.cursor.Y++;
+        } else {
+            /* \8aù\82É\89º\92[\82Ì\8fê\8d\87\82Í\82È\82É\82à\82µ\82È\82¢ */
+            return;
+        }
+    }
 
-    attrs[0] = attrs[1] = console.attr;
+    int ret = MultiByteToWideChar(
+        CP_ACP,
+        MB_PRECOMPOSED,
+        str,
+        strlen(str),
+        wbuf,
+        1);
+
+    /* \8d\91¤\82É\83\8f\83C\83h\95\8e\9a\8fî\95ñ\82ð\8bl\82ß\82é */
+    cell.character = wbuf[0];
+    cell.iskanji = 1;
+    buffer_write(console.back_buffer, &cell, console.cursor);
+    console.cursor.X++;
+
+    /* \89E\91¤\82Í\83_\83~\81[ */
+    cell.character = 255;
+    cell.iskanji = 2;
+    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++;
+    }
 
-    WriteConsoleOutputAttribute(hConOut, (WORD *)(&attrs), 2,
-                                console.cursor, &acount);
-    WriteConsoleOutputCharacter(hConOut, buf, 2,
-                                console.cursor, &ccount);
-    console.cursor.X += 2;
+    nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
+    nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
 }
 
 void
-xputc2(ch1, ch2)
-int ch1;
-int ch2;
+xputc2(str)
+unsigned char *str;
 {
     /* wintty.c \82Å\82Í 1 \83o\83C\83g\96\88\82É curx \82ð\89Á\8eZ\82·\82é\82ª\81A\82±\82±\82Í
-       \83o\83C\83g\82½\82Ü\82Á\82Ä\82©\82ç\8cÄ\82Ñ\8fo\82³\82ê\82é\82Ì\82Å\81A\95\8e\9a\95ª\90æ\82É\90i\82ñ\82Å
-      \82µ\82Ü\82Á\82Ä\82¢\82é\81B\8f]\82Á\82Ä 1 \82ð\88ø\82­\81B */
-    console.cursor.X = ttyDisplay->curx - 1;
+       \83o\83C\83g\82½\82Ü\82Á\82Ä\82©\82ç\8cÄ\82Ñ\8fo\82³\82ê\82é\82Ì\82Å\81An-\95\8e\9a\95ª\90æ\82É\90i\82ñ\82Å
+      \82µ\82Ü\82Á\82Ä\82¢\82é\81B\8f]\82Á\82Ä n-\82ð\88ø\82­\81B */
+    console.cursor.X = ttyDisplay->curx - (strlen(str) - 1);
     console.cursor.Y = ttyDisplay->cury;
 
-    xputc2_core(ch1, ch2);
+    xputc2_core(str);
 }
 #endif
 
@@ -512,12 +706,10 @@ xputs(s)
 const char *s;
 {
     int k;
-    int slen = strlen(s);
+    int slen = (int) strlen(s);
 
-    if (ttyDisplay) {
-        console.cursor.X = ttyDisplay->curx;
-        console.cursor.Y = ttyDisplay->cury;
-    }
+    if (ttyDisplay)
+        set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
 
     if (s) {
         for (k = 0; k < slen && s[k]; ++k)
@@ -533,18 +725,30 @@ 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':
-        console.cursor.Y++;
+        if (console.cursor.Y < console.height - 1)
+            console.cursor.Y++;
     /* fall through */
     case '\r':
         console.cursor.X = 1;
         break;
     case '\b':
-        console.cursor.X--;
+        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] :
@@ -552,18 +756,31 @@ char ch;
         if (console.current_nhattr[ATR_BOLD])
                 console.attr |= (inverse) ?
                                 BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
-        WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount);
-        if (has_unicode) {
-            /* Avoid bug in ANSI API on WinNT */
-            WCHAR c2[2];
-            int rc;
-            rc = MultiByteToWideChar(GetConsoleOutputCP(), 0, &ch, 1, c2, 2);
-            WriteConsoleOutputCharacterW(hConOut, c2, rc, console.cursor, &ccount);
+
+        cell.attribute = console.attr;
+#if 0 /*JP*/
+        cell.character = (console.has_unicode ? console.cpMap[ch] : ch);
+#else
+        cell.character = ch;
+#endif
+#if 1 /*JP*//*\8fí\82É1\83o\83C\83g\95\8e\9a*/
+        cell.iskanji = 0;
+#endif
+
+        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 {
-            WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount);
+            console.cursor.X++;
         }
-        console.cursor.X++;
     }
+
+    nhassert(console.cursor.X >= 0 && console.cursor.X < console.width);
+    nhassert(console.cursor.Y >= 0 && console.cursor.Y < console.height);
 }
 
 /*
@@ -571,42 +788,6 @@ char ch;
  * for win32. It is used for glyphs only, not text.
  */
 
-/* CP437 to Unicode mapping according to the Unicode Consortium */
-static const WCHAR cp437[] = {
-    0x0020, 0x263A, 0x263B, 0x2665, 0x2666, 0x2663, 0x2660, 0x2022,
-    0x25D8, 0x25CB, 0x25D9, 0x2642, 0x2640, 0x266A, 0x266B, 0x263C,
-    0x25BA, 0x25C4, 0x2195, 0x203C, 0x00B6, 0x00A7, 0x25AC, 0x21A8,
-    0x2191, 0x2193, 0x2192, 0x2190, 0x221F, 0x2194, 0x25B2, 0x25BC,
-    0x0020, 0x0021, 0x0022, 0x0023, 0x0024, 0x0025, 0x0026, 0x0027,
-    0x0028, 0x0029, 0x002a, 0x002b, 0x002c, 0x002d, 0x002e, 0x002f,
-    0x0030, 0x0031, 0x0032, 0x0033, 0x0034, 0x0035, 0x0036, 0x0037,
-    0x0038, 0x0039, 0x003a, 0x003b, 0x003c, 0x003d, 0x003e, 0x003f,
-    0x0040, 0x0041, 0x0042, 0x0043, 0x0044, 0x0045, 0x0046, 0x0047,
-    0x0048, 0x0049, 0x004a, 0x004b, 0x004c, 0x004d, 0x004e, 0x004f,
-    0x0050, 0x0051, 0x0052, 0x0053, 0x0054, 0x0055, 0x0056, 0x0057,
-    0x0058, 0x0059, 0x005a, 0x005b, 0x005c, 0x005d, 0x005e, 0x005f,
-    0x0060, 0x0061, 0x0062, 0x0063, 0x0064, 0x0065, 0x0066, 0x0067,
-    0x0068, 0x0069, 0x006a, 0x006b, 0x006c, 0x006d, 0x006e, 0x006f,
-    0x0070, 0x0071, 0x0072, 0x0073, 0x0074, 0x0075, 0x0076, 0x0077,
-    0x0078, 0x0079, 0x007a, 0x007b, 0x007c, 0x007d, 0x007e, 0x2302,
-    0x00c7, 0x00fc, 0x00e9, 0x00e2, 0x00e4, 0x00e0, 0x00e5, 0x00e7,
-    0x00ea, 0x00eb, 0x00e8, 0x00ef, 0x00ee, 0x00ec, 0x00c4, 0x00c5,
-    0x00c9, 0x00e6, 0x00c6, 0x00f4, 0x00f6, 0x00f2, 0x00fb, 0x00f9,
-    0x00ff, 0x00d6, 0x00dc, 0x00a2, 0x00a3, 0x00a5, 0x20a7, 0x0192,
-    0x00e1, 0x00ed, 0x00f3, 0x00fa, 0x00f1, 0x00d1, 0x00aa, 0x00ba,
-    0x00bf, 0x2310, 0x00ac, 0x00bd, 0x00bc, 0x00a1, 0x00ab, 0x00bb,
-    0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
-    0x2555, 0x2563, 0x2551, 0x2557, 0x255d, 0x255c, 0x255b, 0x2510,
-    0x2514, 0x2534, 0x252c, 0x251c, 0x2500, 0x253c, 0x255e, 0x255f,
-    0x255a, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256c, 0x2567,
-    0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256b,
-    0x256a, 0x2518, 0x250c, 0x2588, 0x2584, 0x258c, 0x2590, 0x2580,
-    0x03b1, 0x00df, 0x0393, 0x03c0, 0x03a3, 0x03c3, 0x00b5, 0x03c4,
-    0x03a6, 0x0398, 0x03a9, 0x03b4, 0x221e, 0x03c6, 0x03b5, 0x2229,
-    0x2261, 0x00b1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00f7, 0x2248,
-    0x00b0, 0x2219, 0x00b7, 0x221a, 0x207f, 0x00b2, 0x25a0, 0x00a0
-};
-
 void
 g_putch(in_ch)
 int in_ch;
@@ -614,8 +795,7 @@ int in_ch;
     boolean inverse = FALSE;
     unsigned char ch = (unsigned char) in_ch;
 
-    console.cursor.X = ttyDisplay->curx;
-    console.cursor.Y = ttyDisplay->cury;
+    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) ?
@@ -623,89 +803,94 @@ int in_ch;
                     ttycolors[console.current_nhcolor];
     if (console.current_nhattr[ATR_BOLD])
         console.attr |= (inverse) ? BACKGROUND_INTENSITY : FOREGROUND_INTENSITY;
-    WriteConsoleOutputAttribute(hConOut, &console.attr, 1, console.cursor, &acount);
 
-    if (has_unicode)
-        WriteConsoleOutputCharacterW(hConOut, &cp437[ch], 1, console.cursor, &ccount);
-    else
-        WriteConsoleOutputCharacterA(hConOut, &ch, 1, console.cursor, &ccount);
+    cell_t cell;
+
+    cell.attribute = console.attr;
+#if 0 /*JP*/
+    cell.character = (console.has_unicode ? cp437[ch] : ch);
+#else
+    cell.character = ch;
+#endif
+#if 1 /*JP*//*\8fí\82É1\83o\83C\83g\95\8e\9a*/
+    cell.iskanji = 0;
+#endif
+
+    buffer_write(console.back_buffer, &cell, console.cursor);
 }
 
 void
 cl_end()
 {
-    int cx;
-    console.cursor.X = ttyDisplay->curx;
-    console.cursor.Y = ttyDisplay->cury;
-    cx = CO - console.cursor.X;
-    FillConsoleOutputAttribute(hConOut, DEFTEXTCOLOR, cx, console.cursor, &acount);
-    FillConsoleOutputCharacter(hConOut, ' ', cx, console.cursor, &ccount);
+    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()
 {
-    if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
-        DWORD ccnt;
-        COORD newcoord;
-
-        newcoord.X = 0;
-        newcoord.Y = 0;
-        FillConsoleOutputAttribute(
-            hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
-            csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt);
-        FillConsoleOutputCharacter(
-            hConOut, ' ', csbi.dwSize.X * csbi.dwSize.Y, newcoord, &ccnt);
+    if (WINDOWPORT("tty")) {
+        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++) {
+                 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);
+                 }
+                 *front = *back;
+                 back++;
+                 front++;
+            }
+        }
     }
 }
 
 void
 clear_screen()
 {
-    raw_clear_screen();
+    buffer_fill_to_end(console.back_buffer, &clear_cell, 0, 0);    
     home();
 }
 
 void
 home()
 {
-    console.cursor.X = console.cursor.Y = 0;
     ttyDisplay->curx = ttyDisplay->cury = 0;
+    set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
 }
 
 void
 backsp()
 {
-    console.cursor.X = ttyDisplay->curx;
-    console.cursor.Y = ttyDisplay->cury;
+    set_console_cursor(ttyDisplay->curx, ttyDisplay->cury);
     xputc_core('\b');
 }
 
 void
 cl_eos()
 {
-    int cy = ttyDisplay->cury + 1;
-    if (GetConsoleScreenBufferInfo(hConOut, &csbi)) {
-        DWORD ccnt;
-        COORD newcoord;
-
-        newcoord.X = ttyDisplay->curx;
-        newcoord.Y = ttyDisplay->cury;
-        FillConsoleOutputAttribute(
-            hConOut, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE,
-            csbi.dwSize.X * csbi.dwSize.Y - cy, newcoord, &ccnt);
-        FillConsoleOutputCharacter(hConOut, ' ',
-                                   csbi.dwSize.X * csbi.dwSize.Y - cy,
-                                   newcoord, &ccnt);
-    }
+    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)
+    if (flags.silent || iflags.debug_fuzzer)
         return;
     Beep(8000, 500);
 }
@@ -720,12 +905,15 @@ tty_delay_output()
     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
@@ -798,10 +986,10 @@ init_ttycolor()
 #endif
     init_ttycolor_completed = TRUE;
 }
-#endif /* TEXTCOLOR */
 
+#if 0
 int
-has_color(int color)
+has_color(int color)        /* this function is commented out */
 {
 #ifdef TEXTCOLOR
     if ((color >= 0) && (color < CLR_MAX))
@@ -813,6 +1001,13 @@ has_color(int color)
     else
         return 0;
 }
+#endif
+
+int
+term_attr_fixup(int attrmask)
+{
+    return attrmask;
+}
 
 void
 term_start_attr(int attrib)
@@ -891,13 +1086,31 @@ standoutend()
 void
 toggle_mouse_support()
 {
+    static int qeinit = 0;
     DWORD cmode;
-    GetConsoleMode(hConIn, &cmode);
-    if (iflags.wc_mouse_support)
-        cmode |= ENABLE_MOUSE_INPUT;
-    else
-        cmode &= ~ENABLE_MOUSE_INPUT;
-    SetConsoleMode(hConIn, 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
 
@@ -926,7 +1139,7 @@ win32con_debug_keystrokes()
     xputs("\n");
     while (!valid || ch != 27) {
         nocmov(ttyDisplay->curx, ttyDisplay->cury);
-        ReadConsoleInput(hConIn, &ir, 1, &count);
+        ReadConsoleInput(console.hConIn, &ir, 1, &count);
         if ((ir.EventType == KEY_EVENT) && ir.Event.KeyEvent.bKeyDown)
             ch = process_keystroke(&ir, &valid, iflags.num_pad, 1);
     }
@@ -937,20 +1150,23 @@ win32con_handler_info()
 {
     char *buf;
     int ci;
-    if (!pSourceAuthor && !pSourceWhere)
+    if (!keyboard_handler.pSourceAuthor && !keyboard_handler.pSourceWhere)
         pline("Keyboard handler source info and author unavailable.");
     else {
-        if (pKeyHandlerName && pKeyHandlerName(&buf, 1)) {
+        if (keyboard_handler.pKeyHandlerName &&
+            keyboard_handler.pKeyHandlerName(&buf, 1)) {
             xputs("\n");
             xputs("Keystroke handler loaded: \n    ");
             xputs(buf);
         }
-        if (pSourceAuthor && pSourceAuthor(&buf)) {
+        if (keyboard_handler.pSourceAuthor &&
+            keyboard_handler.pSourceAuthor(&buf)) {
             xputs("\n");
             xputs("Keystroke handler Author: \n    ");
             xputs(buf);
         }
-        if (pSourceWhere && pSourceWhere(&buf)) {
+        if (keyboard_handler.pSourceWhere &&
+            keyboard_handler.pSourceWhere(&buf)) {
             xputs("\n");
             xputs("Keystroke handler source code available at:\n    ");
             xputs(buf);
@@ -1002,125 +1218,82 @@ register char *op;
     key_overrides[idx] = val;
 }
 
-void
-load_keyboard_handler()
-{
-    char suffx[] = ".dll";
-    char *truncspot;
-#define MAX_DLLNAME 25
-    char kh[MAX_ALTKEYHANDLER];
-    if (iflags.altkeyhandler[0]) {
-        if (hLibrary) { /* already one loaded apparently */
-            FreeLibrary(hLibrary);
-            hLibrary = (HANDLE) 0;
-            pNHkbhit = (NHKBHIT) 0;
-            pCheckInput = (CHECKINPUT) 0;
-            pSourceWhere = (SOURCEWHERE) 0;
-            pSourceAuthor = (SOURCEAUTHOR) 0;
-            pKeyHandlerName = (KEYHANDLERNAME) 0;
-            pProcessKeystroke = (PROCESS_KEYSTROKE) 0;
-        }
-        if ((truncspot = strstri(iflags.altkeyhandler, suffx)) != 0)
-            *truncspot = '\0';
-        (void) strncpy(kh, iflags.altkeyhandler,
-                       (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
-        kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
-        Strcat(kh, suffx);
-        Strcpy(iflags.altkeyhandler, kh);
-        hLibrary = LoadLibrary(kh);
-        if (hLibrary) {
-            pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
-                hLibrary, TEXT("ProcessKeystroke"));
-            pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit"));
-            pCheckInput =
-                (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
-            pSourceWhere =
-                (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
-            pSourceAuthor =
-                (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
-            pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
-                hLibrary, TEXT("KeyHandlerName"));
-        }
-    }
-    if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
-        if (hLibrary) {
-            FreeLibrary(hLibrary);
-            hLibrary = (HANDLE) 0;
-            pNHkbhit = (NHKBHIT) 0;
-            pCheckInput = (CHECKINPUT) 0;
-            pSourceWhere = (SOURCEWHERE) 0;
-            pSourceAuthor = (SOURCEAUTHOR) 0;
-            pKeyHandlerName = (KEYHANDLERNAME) 0;
-            pProcessKeystroke = (PROCESS_KEYSTROKE) 0;
-        }
-        (void) strncpy(kh, "nhdefkey.dll",
-                       (MAX_ALTKEYHANDLER - sizeof suffx) - 1);
-        kh[(MAX_ALTKEYHANDLER - sizeof suffx) - 1] = '\0';
-        Strcpy(iflags.altkeyhandler, kh);
-        hLibrary = LoadLibrary(kh);
-        if (hLibrary) {
-            pProcessKeystroke = (PROCESS_KEYSTROKE) GetProcAddress(
-                hLibrary, TEXT("ProcessKeystroke"));
-            pCheckInput =
-                (CHECKINPUT) GetProcAddress(hLibrary, TEXT("CheckInput"));
-            pNHkbhit = (NHKBHIT) GetProcAddress(hLibrary, TEXT("NHkbhit"));
-            pSourceWhere =
-                (SOURCEWHERE) GetProcAddress(hLibrary, TEXT("SourceWhere"));
-            pSourceAuthor =
-                (SOURCEAUTHOR) GetProcAddress(hLibrary, TEXT("SourceAuthor"));
-            pKeyHandlerName = (KEYHANDLERNAME) GetProcAddress(
-                hLibrary, TEXT("KeyHandlerName"));
-        }
-    }
-    if (!pProcessKeystroke || !pNHkbhit || !pCheckInput) {
-        if (!hLibrary)
-            raw_printf("\nNetHack was unable to load keystroke handler.\n");
-        else {
-            FreeLibrary(hLibrary);
-            hLibrary = (HANDLE) 0;
-            raw_printf("\nNetHack keystroke handler is invalid.\n");
-        }
-        exit(EXIT_FAILURE);
+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;
 }
 
-/* this is used as a printf() replacement when the window
- * system isn't initialized yet
- */
-void msmsg
-VA_DECL(const char *, fmt)
+void set_altkeyhandler(const char * inName)
 {
-    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 {
-        if(!init_ttycolor_completed)
-            init_ttycolor();
+    if (strlen(inName) >= MAX_ALTKEYHANDLER) {
+        config_error_add("altkeyhandler name '%s' is too long", inName);
+        return;
+    }
 
-#if 0 /*JP*/
-        xputs(buf);
-#else
-        if(ttyDisplay){
-            console.cursor.X = ttyDisplay->curx;
-            console.cursor.Y = ttyDisplay->cury;
-        }
-        {
-            char *str = buf;
-            while(*str){
-                jbuffer(*(str++), NULL, xputc_core, xputc2_core);
-            }
-        }
-#endif
-        if (ttyDisplay)
-            curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y);
+    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;
     }
-    VA_END();
+
     return;
 }
 
+
 /* fatal error */
 /*VARARGS1*/
 void nttty_error
@@ -1133,7 +1306,7 @@ VA_DECL(const char *, s)
     if (iflags.window_inited)
         end_screen();
     buf[0] = '\n';
-    (void) vsprintf(&buf[1], s, VA_ARGS);
+    (void) vsnprintf(&buf[1], sizeof buf - 1, s, VA_ARGS);
     msmsg(buf);
     really_move_cursor();
     VA_END();
@@ -1555,13 +1728,16 @@ static int CALLBACK EnumFontCallback(
 void
 check_and_set_font()
 {
+#if 0 /*JP*//* \83R\81[\83h\83y\81[\83W\82Í\95Ï\8dX\82µ\82È\82¢\81B932\82ð\89¼\92è\82·\82é\81B*/
     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();
     }
+#endif
 }
 
+#if 0 /*JP*/
 /* check_font_widths returns TRUE if all glyphs in current console font
  * fit within the width of a single console cell.
  */
@@ -1570,7 +1746,7 @@ check_font_widths()
 {
     CONSOLE_FONT_INFOEX console_font_info;
     console_font_info.cbSize = sizeof(console_font_info);
-    BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE,
+    BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
                                             &console_font_info);
 
     /* get console window and DC
@@ -1599,7 +1775,7 @@ check_font_widths()
     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 = 0;
+    console_font_log_font.lfWidth = console_font_info.dwFontSize.X;
     HFONT console_font = CreateFontIndirectW(&console_font_log_font);
 
     if (console_font == NULL) {
@@ -1625,8 +1801,8 @@ check_font_widths()
     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;
+        used[primary_syms[i]] = TRUE;
+        used[rogue_syms[i]] = TRUE;
     }
 
     int wcUsedCount = 0;
@@ -1661,6 +1837,7 @@ clean_up:
 
     return all_glyphs_fit;
 }
+#endif
 
 /* 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
@@ -1671,12 +1848,12 @@ set_known_good_console_font()
 {
     CONSOLE_FONT_INFOEX console_font_info;
     console_font_info.cbSize = sizeof(console_font_info);
-    BOOL success = GetCurrentConsoleFontEx(hConOut, FALSE,
+    BOOL success = GetCurrentConsoleFontEx(console.hConOut, FALSE,
                                             &console_font_info);
 
-    console_font_changed = TRUE;
-    original_console_font_info = console_font_info;
-    original_console_code_page = GetConsoleOutputCP();
+    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)
@@ -1684,12 +1861,10 @@ set_known_good_console_font()
         L"Consolas");
 
     success = SetConsoleOutputCP(437);
-    if (!success)
-        raw_print("Unable to set console code page to 437\n");
+    nhassert(success);
 
-    success = SetCurrentConsoleFontEx(hConOut, FALSE, &console_font_info);
-    if (!success)
-        raw_print("Unable to set console font to Consolas\n");
+    success = SetCurrentConsoleFontEx(console.hConOut, FALSE, &console_font_info);
+    nhassert(success);
 }
 
 /* restore_original_console_font will restore the console font and code page
@@ -1698,20 +1873,309 @@ set_known_good_console_font()
 void
 restore_original_console_font()
 {
-    if (console_font_changed) {
+    if (console.font_changed) {
         BOOL success;
         raw_print("Restoring original font and code page\n");
-        success = SetConsoleOutputCP(original_console_code_page);
+        success = SetConsoleOutputCP(console.original_code_page);
         if (!success)
             raw_print("Unable to restore original code page\n");
 
-        success = SetCurrentConsoleFontEx(hConOut, FALSE,
-                                            &original_console_font_info);
+        success = SetCurrentConsoleFontEx(console.hConOut, FALSE,
+                                            &console.original_font_info);
         if (!success)
             raw_print("Unable to restore original font\n");
 
-        console_font_changed = FALSE;
+        console.font_changed = FALSE;
+    }
+}
+
+#if 0 /*JP*/
+/* 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]];
+            }        
+        }
+
+    }
+}
+#endif
+
+#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();
+#if 0 /*JP*/
+    set_cp_map();
+#endif
+
+    /* 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;
+
+    /* This was overriding the handler that had already
+       been loaded during options parsing. Needs to
+       check first */
+#if 0 /*JP*//* \93ú\96{\8cê\82Å\82Ínhdefkey\82µ\82©\8eg\82í\82È\82¢ */
+    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");
+        }
+    }
+#else
+    if (!load_keyboard_handler("nhdefkey"))
+        error("nhdefkey.dll\82ð\93Ç\82Ý\8d\9e\82ß\82Ü\82¹\82ñ");
+#endif
+}
+#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);
+        }
+#if 0 /*JP*/
+        xputs(buf);
+#else
+        if(ttyDisplay){
+            console.cursor.X = ttyDisplay->curx;
+            console.cursor.Y = ttyDisplay->cury;
+        }
+        {
+            char *str = buf;
+            while(*str){
+                jbuffer(*(str++), NULL, (void (__cdecl *)(unsigned int))xputc_core, xputc2_core);
+            }
+        }
+#endif
+        if (ttyDisplay)
+            curs(BASE_WINDOW, console.cursor.X + 1, console.cursor.Y);
+#else
+        fprintf(stdout, "%s", buf);
+#endif
+    }
+    VA_END();
+    return;
 }
 
 #endif /* WIN32 */