ncurses 6.2 - patch 20200229
[ncurses.git] / ncurses / win32con / win_driver.c
index 443476460eb1fd23c20193000a248c76b8f4562b..72a9cf53525f8a94d692384347f3b56a552df929 100644 (file)
@@ -1,5 +1,6 @@
 /****************************************************************************
- * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc.              *
+ * Copyright 2018,2020 Thomas E. Dickey                                     *
+ * Copyright 2008-2016,2017 Free Software Foundation, Inc.                  *
  *                                                                          *
  * Permission is hereby granted, free of charge, to any person obtaining a  *
  * copy of this software and associated documentation files (the            *
 /*
  * TODO - GetMousePos(POINT * result) from ntconio.c
  * TODO - implement nodelay
+ * TODO - improve screen-repainting performance, using implied wraparound to reduce write's
+ * TODO - make it optional whether screen is restored or not when non-buffered
  */
 
 #include <curses.priv.h>
+
+#ifdef _WIN32
 #include <tchar.h>
+#else
+#include <windows.h>
+#include <wchar.h>
+#endif
+
 #include <io.h>
 
 #define PSAPI_VERSION 2
 #include <psapi.h>
 
-#define CUR my_term.type.
+#define CUR TerminalType(my_term).
 
-MODULE_ID("$Id: win_driver.c,v 1.38 2014/05/10 21:50:00 tom Exp $")
+MODULE_ID("$Id: win_driver.c,v 1.66 2020/03/01 00:18:49 tom Exp $")
 
-#ifndef __GNUC__
-#  error We need GCC to compile for MinGW
-#endif
+#define TypeAlloca(type,count) (type*) _alloca(sizeof(type) * (size_t) (count))
 
 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
 
@@ -57,7 +65,8 @@ MODULE_ID("$Id: win_driver.c,v 1.38 2014/05/10 21:50:00 tom Exp $")
 
 #define array_length(a) (sizeof(a)/sizeof(a[0]))
 
-#define okConsoleHandle(TCB) (TCB != 0 && CON.hdl != INVALID_HANDLE_VALUE)
+static bool InitConsole(void);
+static bool okConsoleHandle(TERMINAL_CONTROL_BLOCK *);
 
 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
 #define SetSP()     assert(TCB->csp != 0); sp = TCB->csp; (void) sp
@@ -66,6 +75,14 @@ MODULE_ID("$Id: win_driver.c,v 1.38 2014/05/10 21:50:00 tom Exp $")
 
 #define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
 
+#if USE_WIDEC_SUPPORT
+#define write_screen WriteConsoleOutputW
+#define read_screen  ReadConsoleOutputW
+#else
+#define write_screen WriteConsoleOutput
+#define read_screen  ReadConsoleOutput
+#endif
+
 static const LONG keylist[] =
 {
     GenMap(VK_PRIOR, KEY_PPAGE),
@@ -79,14 +96,27 @@ static const LONG keylist[] =
     GenMap(VK_DELETE, KEY_DC),
     GenMap(VK_INSERT, KEY_IC)
 };
+static const LONG ansi_keys[] =
+{
+    GenMap(VK_PRIOR, 'I'),
+    GenMap(VK_NEXT, 'Q'),
+    GenMap(VK_END, 'O'),
+    GenMap(VK_HOME, 'H'),
+    GenMap(VK_LEFT, 'K'),
+    GenMap(VK_UP, 'H'),
+    GenMap(VK_RIGHT, 'M'),
+    GenMap(VK_DOWN, 'P'),
+    GenMap(VK_DELETE, 'S'),
+    GenMap(VK_INSERT, 'R')
+};
 #define N_INI ((int)array_length(keylist))
 #define FKEYS 24
 #define MAPSIZE (FKEYS + N_INI)
 #define NUMPAIRS 64
 
-/*   A process can only have a single console, so it's save
+/*   A process can only have a single console, so it's safe
      to maintain all the information about it in a single
-     static scructure.
+     static structure.
  */
 static struct {
     BOOL initialized;
@@ -100,12 +130,17 @@ static struct {
     HANDLE hdl;
     HANDLE lastOut;
     int numButtons;
+    DWORD ansi_map[MAPSIZE];
     DWORD map[MAPSIZE];
     DWORD rmap[MAPSIZE];
     WORD pairs[NUMPAIRS];
     COORD origin;
     CHAR_INFO *save_screen;
+    COORD save_size;
+    SMALL_RECT save_region;
     CONSOLE_SCREEN_BUFFER_INFO SBI;
+    CONSOLE_SCREEN_BUFFER_INFO save_SBI;
+    CONSOLE_CURSOR_INFO save_CI;
 } CON;
 
 static BOOL console_initialized = FALSE;
@@ -125,6 +160,11 @@ MapColor(bool fore, int color)
     return (WORD) a;
 }
 
+#define RevAttr(attr) \
+              (WORD) (((attr) & 0xff00) | \
+                     ((((attr) & 0x07) << 4) | \
+                      (((attr) & 0x70) >> 4)))
+
 static WORD
 MapAttr(WORD res, attr_t ch)
 {
@@ -140,16 +180,11 @@ MapAttr(WORD res, attr_t ch)
     }
 
     if (ch & A_REVERSE) {
-       res = (WORD) ((res & 0xff00) |
-                     (((res & 0x07) << 4) |
-                      ((res & 0x70) >> 4)));
+       res = RevAttr(res);
     }
 
     if (ch & A_STANDOUT) {
-       res = (WORD) ((res & 0xff00) |
-                     (((res & 0x07) << 4) |
-                      ((res & 0x70) >> 4)) |
-                     BACKGROUND_INTENSITY);
+       res = RevAttr(res) | BACKGROUND_INTENSITY;
     }
 
     if (ch & A_BOLD)
@@ -161,19 +196,71 @@ MapAttr(WORD res, attr_t ch)
     return res;
 }
 
+#if 0                          /* def TRACE */
+static void
+dump_screen(const char *fn, int ln)
+{
+    int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1;
+    char output[max_cells];
+    CHAR_INFO save_screen[max_cells];
+    COORD save_size;
+    SMALL_RECT save_region;
+    COORD bufferCoord;
+
+    T(("dump_screen %s@%d", fn, ln));
+
+    save_region.Top = CON.SBI.srWindow.Top;
+    save_region.Left = CON.SBI.srWindow.Left;
+    save_region.Bottom = CON.SBI.srWindow.Bottom;
+    save_region.Right = CON.SBI.srWindow.Right;
+
+    save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
+    save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
+
+    bufferCoord.X = bufferCoord.Y = 0;
+
+    if (read_screen(CON.hdl,
+                   save_screen,
+                   save_size,
+                   bufferCoord,
+                   &save_region)) {
+       int i, j;
+       int ij = 0;
+       int k = 0;
+
+       for (i = save_region.Top; i <= save_region.Bottom; ++i) {
+           for (j = save_region.Left; j <= save_region.Right; ++j) {
+               output[k++] = save_screen[ij++].Char.AsciiChar;
+           }
+           output[k++] = '\n';
+       }
+       output[k] = 0;
+
+       T(("DUMP: %d,%d - %d,%d",
+          save_region.Top,
+          save_region.Left,
+          save_region.Bottom,
+          save_region.Right));
+       T(("%s", output));
+    }
+}
+
+#else
+#define dump_screen(fn,ln)     /* nothing */
+#endif
+
 #if USE_WIDEC_SUPPORT
 /*
  * TODO: support surrogate pairs
  * TODO: support combining characters
  * TODO: support acsc
- * TODO: check wcwidth of base character, fill if needed for double-width
  * TODO: _nc_wacs should be part of sp.
  */
 static BOOL
 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
 {
     int actual = 0;
-    CHAR_INFO ci[limit];
+    CHAR_INFO *ci = TypeAlloca(CHAR_INFO, limit);
     COORD loc, siz;
     SMALL_RECT rec;
     int i;
@@ -205,24 +292,24 @@ con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
        ++actual;
     }
 
-    loc.X = (short) 0;
-    loc.Y = (short) 0;
-    siz.X = (short) actual;
+    loc.X = (SHORT) 0;
+    loc.Y = (SHORT) 0;
+    siz.X = (SHORT) actual;
     siz.Y = 1;
 
-    rec.Left = (short) x;
+    rec.Left = (SHORT) x;
     rec.Top = (SHORT) (y + AdjustY());
-    rec.Right = (short) (x + limit - 1);
+    rec.Right = (SHORT) (x + limit - 1);
     rec.Bottom = rec.Top;
 
-    return WriteConsoleOutputW(CON.hdl, ci, siz, loc, &rec);
+    return write_screen(CON.hdl, ci, siz, loc, &rec);
 }
 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
 #else
 static BOOL
 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
 {
-    CHAR_INFO ci[n];
+    CHAR_INFO *ci = TypeAlloca(CHAR_INFO, n);
     COORD loc, siz;
     SMALL_RECT rec;
     int i;
@@ -254,7 +341,7 @@ con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
     rec.Right = (short) (x + n - 1);
     rec.Bottom = rec.Top;
 
-    return WriteConsoleOutput(CON.hdl, ci, siz, loc, &rec);
+    return write_screen(CON.hdl, ci, siz, loc, &rec);
 }
 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
 #endif
@@ -351,34 +438,31 @@ static bool
 restore_original_screen(void)
 {
     COORD bufferCoord;
-    SMALL_RECT writeRegion;
     bool result = FALSE;
+    SMALL_RECT save_region = CON.save_region;
 
-    if (CON.window_only) {
-       writeRegion.Top = CON.SBI.srWindow.Top;
-       writeRegion.Left = CON.SBI.srWindow.Left;
-       writeRegion.Bottom = CON.SBI.srWindow.Bottom;
-       writeRegion.Right = CON.SBI.srWindow.Right;
-       T(("... restoring window"));
-    } else {
-       writeRegion.Top = 0;
-       writeRegion.Left = 0;
-       writeRegion.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
-       writeRegion.Right = (SHORT) (CON.SBI.dwSize.X - 1);
-       T(("... restoring entire buffer"));
-    }
+    T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
 
-    bufferCoord.X = bufferCoord.Y = 0;
+    bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
+    bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
 
-    if (WriteConsoleOutput(CON.hdl,
-                          CON.save_screen,
-                          CON.SBI.dwSize,
-                          bufferCoord,
-                          &writeRegion)) {
+    if (write_screen(CON.hdl,
+                    CON.save_screen,
+                    CON.save_size,
+                    bufferCoord,
+                    &save_region)) {
        result = TRUE;
        mvcur(-1, -1, LINES - 2, 0);
+       T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
+          CON.save_size.Y,
+          CON.save_size.X,
+          save_region.Top,
+          save_region.Left,
+          save_region.Bottom,
+          save_region.Right));
+    } else {
+       T(("... restore original screen contents err"));
     }
-    T(("... restore original screen contents %s", result ? "ok" : "err"));
     return result;
 }
 
@@ -396,20 +480,35 @@ wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
     int y, nonempty, n, x0, x1, Width, Height;
     SCREEN *sp;
 
-    AssertTCB();
-    SetSP();
-
     T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
     if (okConsoleHandle(TCB)) {
+       SetSP();
 
        Width = screen_columns(sp);
        Height = screen_lines(sp);
        nonempty = min(Height, NewScreen(sp)->_maxy + 1);
 
+       T(("... %dx%d clear cur:%d new:%d",
+          Height, Width,
+          CurScreen(sp)->_clear,
+          NewScreen(sp)->_clear));
+
+       if (SP_PARM->_endwin == ewSuspend) {
+
+           T(("coming back from shell mode"));
+           NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
+
+           NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
+           NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
+           SP_PARM->_mouse_resume(SP_PARM);
+
+           SP_PARM->_endwin = ewRunning;
+       }
+
        if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
            int x;
 #if USE_WIDEC_SUPPORT
-           cchar_t empty[Width];
+           cchar_t *empty = TypeAlloca(cchar_t, Width);
            wchar_t blank[2] =
            {
                L' ', L'\0'
@@ -418,7 +517,7 @@ wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
            for (x = 0; x < Width; x++)
                setcchar(&empty[x], blank, 0, 0, 0);
 #else
-           chtype empty[Width];
+           chtype *empty = TypeAlloca(chtype, Width);
 
            for (x = 0; x < Width; x++)
                empty[x] = ' ';
@@ -433,6 +532,8 @@ wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
            CurScreen(sp)->_clear = FALSE;
            NewScreen(sp)->_clear = FALSE;
            touchwin(NewScreen(sp));
+           T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
+              AdjustY()));
        }
 
        for (y = 0; y < nonempty; y++) {
@@ -546,8 +647,11 @@ wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
      * This is intentional, to avoid unnecessary breakage of applications
      * using <term.h> symbols.
      */
-    if (code && (TCB->term.type.Booleans == 0)) {
-       _nc_init_termtype(&(TCB->term.type));
+    if (code && (TerminalType(&TCB->term).Booleans == 0)) {
+       _nc_init_termtype(&TerminalType(&TCB->term));
+#if NCURSES_EXT_NUMBERS
+       _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
+#endif
     }
 
     if (!code) {
@@ -559,14 +663,59 @@ wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
 
 static int
 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
-                int beepFlag GCC_UNUSED)
+                int beepFlag)
 {
     SCREEN *sp;
     int res = ERR;
 
-    AssertTCB();
-    SetSP();
+    int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
+    int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
+    int max_cells = (high * wide);
+    int i;
+
+    CHAR_INFO *this_screen = TypeAlloca(CHAR_INFO, max_cells);
+    CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells);
+    COORD this_size;
+    SMALL_RECT this_region;
+    COORD bufferCoord;
+
+    if (okConsoleHandle(TCB)) {
+       SetSP();
+       this_region.Top = CON.SBI.srWindow.Top;
+       this_region.Left = CON.SBI.srWindow.Left;
+       this_region.Bottom = CON.SBI.srWindow.Bottom;
+       this_region.Right = CON.SBI.srWindow.Right;
+
+       this_size.X = (SHORT) wide;
+       this_size.Y = (SHORT) high;
+
+       bufferCoord.X = this_region.Left;
+       bufferCoord.Y = this_region.Top;
+
+       if (!beepFlag &&
+           read_screen(CON.hdl,
+                       this_screen,
+                       this_size,
+                       bufferCoord,
+                       &this_region)) {
+
+           memcpy(that_screen,
+                  this_screen,
+                  sizeof(CHAR_INFO) * (size_t) max_cells);
+
+           for (i = 0; i < max_cells; i++) {
+               that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
+           }
+
+           write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
+           Sleep(200);
+           write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
 
+       } else {
+           MessageBeep(MB_ICONWARNING);        /* MB_OK might be better */
+       }
+       res = OK;
+    }
     return res;
 }
 
@@ -637,8 +786,6 @@ wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
              int color,
              int (*outc) (SCREEN *, int) GCC_UNUSED)
 {
-    AssertTCB();
-
     if (okConsoleHandle(TCB)) {
        WORD a = MapColor(fore, color);
        a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
@@ -652,7 +799,6 @@ wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
 {
     bool res = FALSE;
 
-    AssertTCB();
     if (okConsoleHandle(TCB)) {
        WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
        SetConsoleTextAttribute(CON.hdl, a);
@@ -679,8 +825,6 @@ wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
 {
     int result = ERR;
 
-    AssertTCB();
-
     T((T_CALLED("win32con::wcon_size(%p)"), TCB));
 
     if (okConsoleHandle(TCB) &&
@@ -715,65 +859,143 @@ wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
     DWORD dwFlag = 0;
     tcflag_t iflag;
     tcflag_t lflag;
+    int result = ERR;
 
-    AssertTCB();
+    if (buf != NULL && okConsoleHandle(TCB)) {
 
-    if (TCB == 0 || buf == NULL)
-       return ERR;
+       if (setFlag) {
+           iflag = buf->c_iflag;
+           lflag = buf->c_lflag;
 
-    if (setFlag) {
-       iflag = buf->c_iflag;
-       lflag = buf->c_lflag;
+           GetConsoleMode(CON.inp, &dwFlag);
 
-       GetConsoleMode(CON.inp, &dwFlag);
+           if (lflag & ICANON)
+               dwFlag |= ENABLE_LINE_INPUT;
+           else
+               dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
 
-       if (lflag & ICANON)
-           dwFlag |= ENABLE_LINE_INPUT;
-       else
-           dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
+           if (lflag & ECHO)
+               dwFlag |= ENABLE_ECHO_INPUT;
+           else
+               dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
 
-       if (lflag & ECHO)
-           dwFlag |= ENABLE_ECHO_INPUT;
-       else
-           dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
+           if (iflag & BRKINT)
+               dwFlag |= ENABLE_PROCESSED_INPUT;
+           else
+               dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
 
-       if (iflag & BRKINT)
-           dwFlag |= ENABLE_PROCESSED_INPUT;
-       else
-           dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
+           dwFlag |= ENABLE_MOUSE_INPUT;
 
-       dwFlag |= ENABLE_MOUSE_INPUT;
+           buf->c_iflag = iflag;
+           buf->c_lflag = lflag;
+           SetConsoleMode(CON.inp, dwFlag);
+           TCB->term.Nttyb = *buf;
+       } else {
+           iflag = TCB->term.Nttyb.c_iflag;
+           lflag = TCB->term.Nttyb.c_lflag;
+           GetConsoleMode(CON.inp, &dwFlag);
 
-       buf->c_iflag = iflag;
-       buf->c_lflag = lflag;
-       SetConsoleMode(CON.inp, dwFlag);
-       TCB->term.Nttyb = *buf;
+           if (dwFlag & ENABLE_LINE_INPUT)
+               lflag |= ICANON;
+           else
+               lflag &= (tcflag_t) (~ICANON);
+
+           if (dwFlag & ENABLE_ECHO_INPUT)
+               lflag |= ECHO;
+           else
+               lflag &= (tcflag_t) (~ECHO);
+
+           if (dwFlag & ENABLE_PROCESSED_INPUT)
+               iflag |= BRKINT;
+           else
+               iflag &= (tcflag_t) (~BRKINT);
+
+           TCB->term.Nttyb.c_iflag = iflag;
+           TCB->term.Nttyb.c_lflag = lflag;
+
+           *buf = TCB->term.Nttyb;
+       }
+       result = OK;
+    }
+    return result;
+}
+
+#define MIN_WIDE 80
+#define MIN_HIGH 24
+
+/*
+ * In "normal" mode, reset the buffer- and window-sizes back to their original values.
+ */
+static void
+set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
+{
+    SMALL_RECT rect;
+    COORD coord;
+    bool changed = FALSE;
+
+    T((T_CALLED("win32con::set_scrollback(%s)"),
+       (normal
+       ? "normal"
+       : "application")));
+
+    T(("... SBI.srWindow %d,%d .. %d,%d",
+       info->srWindow.Top,
+       info->srWindow.Left,
+       info->srWindow.Bottom,
+       info->srWindow.Right));
+    T(("... SBI.dwSize %dx%d",
+       info->dwSize.Y,
+       info->dwSize.X));
+
+    if (normal) {
+       rect = info->srWindow;
+       coord = info->dwSize;
+       if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
+           changed = TRUE;
+           CON.SBI = *info;
+       }
     } else {
-       iflag = TCB->term.Nttyb.c_iflag;
-       lflag = TCB->term.Nttyb.c_lflag;
-       GetConsoleMode(CON.inp, &dwFlag);
+       int high = info->srWindow.Bottom - info->srWindow.Top + 1;
+       int wide = info->srWindow.Right - info->srWindow.Left + 1;
 
-       if (dwFlag & ENABLE_LINE_INPUT)
-           lflag |= ICANON;
-       else
-           lflag &= (tcflag_t) (~ICANON);
+       if (high < MIN_HIGH) {
+           T(("... height %d < %d", high, MIN_HIGH));
+           high = MIN_HIGH;
+           changed = TRUE;
+       }
+       if (wide < MIN_WIDE) {
+           T(("... width %d < %d", wide, MIN_WIDE));
+           wide = MIN_WIDE;
+           changed = TRUE;
+       }
 
-       if (dwFlag & ENABLE_ECHO_INPUT)
-           lflag |= ECHO;
-       else
-           lflag &= (tcflag_t) (~ECHO);
+       rect.Left =
+           rect.Top = 0;
+       rect.Right = (SHORT) (wide - 1);
+       rect.Bottom = (SHORT) (high - 1);
 
-       if (dwFlag & ENABLE_PROCESSED_INPUT)
-           iflag |= BRKINT;
-       else
-           iflag &= (tcflag_t) (~BRKINT);
+       coord.X = (SHORT) wide;
+       coord.Y = (SHORT) high;
 
-       TCB->term.Nttyb.c_iflag = iflag;
-       TCB->term.Nttyb.c_lflag = lflag;
+       if (info->dwSize.Y != high ||
+           info->dwSize.X != wide ||
+           info->srWindow.Top != 0 ||
+           info->srWindow.Left != 0) {
+           changed = TRUE;
+       }
 
-       *buf = TCB->term.Nttyb;
     }
-    return OK;
+
+    if (changed) {
+       T(("... coord %d,%d", coord.Y, coord.X));
+       T(("... rect %d,%d - %d,%d",
+          rect.Top, rect.Left,
+          rect.Bottom, rect.Right));
+       SetConsoleScreenBufferSize(CON.hdl, coord);     /* dwSize */
+       SetConsoleWindowInfo(CON.hdl, TRUE, &rect);     /* srWindow */
+       get_SBI();
+    }
+    returnVoid;
 }
 
 static int
@@ -783,51 +1005,60 @@ wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
     TERMINAL *_term = (TERMINAL *) TCB;
     int code = ERR;
 
-    AssertTCB();
-    sp = TCB->csp;
-
-    T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"), TCB, progFlag, defFlag));
-    CON.progMode = progFlag;
-    CON.lastOut = progFlag ? CON.hdl : CON.out;
-    SetConsoleActiveScreenBuffer(CON.lastOut);
-
-    if (progFlag) /* prog mode */  {
-       if (defFlag) {
-           if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
-               _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
-               code = OK;
+    if (okConsoleHandle(TCB)) {
+       sp = TCB->csp;
+
+       T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"),
+          TCB, progFlag, defFlag));
+
+       CON.progMode = progFlag;
+       CON.lastOut = progFlag ? CON.hdl : CON.out;
+       SetConsoleActiveScreenBuffer(CON.lastOut);
+
+       if (progFlag) /* prog mode */  {
+           if (defFlag) {
+               if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
+                   _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
+                   code = OK;
+               }
+           } else {
+               /* reset_prog_mode */
+               if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
+                   if (sp) {
+                       if (sp->_keypad_on)
+                           _nc_keypad(sp, TRUE);
+                   }
+                   if (!CON.buffered) {
+                       set_scrollback(FALSE, &CON.SBI);
+                   }
+                   code = OK;
+               }
            }
-       } else {
-           /* reset_prog_mode */
-           if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
+           T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
+       } else {                /* shell mode */
+           if (defFlag) {
+               /* def_shell_mode */
+               if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
+                   code = OK;
+               }
+           } else {
+               /* reset_shell_mode */
                if (sp) {
-                   if (sp->_keypad_on)
-                       _nc_keypad(sp, TRUE);
+                   _nc_keypad(sp, FALSE);
+                   NCURSES_SP_NAME(_nc_flush) (sp);
                }
-               code = OK;
-           }
-       }
-    } else {                   /* shell mode */
-       if (defFlag) {
-           /* def_shell_mode */
-           if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
-               code = OK;
-           }
-       } else {
-           /* reset_shell_mode */
-           if (sp) {
-               _nc_keypad(sp, FALSE);
-               NCURSES_SP_NAME(_nc_flush) (sp);
-           }
-           code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
-           if (!CON.buffered) {
-               if (!restore_original_screen())
-                   code = ERR;
+               code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
+               if (!CON.buffered) {
+                   set_scrollback(TRUE, &CON.save_SBI);
+                   if (!restore_original_screen())
+                       code = ERR;
+               }
+               SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
            }
        }
-    }
 
-    return (code);
+    }
+    returnCode(code);
 }
 
 static void
@@ -881,6 +1112,29 @@ MapKey(WORD vKey)
     return code;
 }
 
+static int
+AnsiKey(WORD vKey)
+{
+    WORD nKey = 0;
+    void *res;
+    LONG key = GenMap(vKey, 0);
+    int code = -1;
+
+    res = bsearch(&key,
+                 CON.ansi_map,
+                 (size_t) (N_INI + FKEYS),
+                 sizeof(keylist[0]),
+                 keycompare);
+    if (res) {
+       key = *((LONG *) res);
+       nKey = LOWORD(key);
+       code = (int) (nKey & 0x7fff);
+       if (nKey & 0x8000)
+           code = -code;
+    }
+    return code;
+}
+
 static void
 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
 {
@@ -893,85 +1147,79 @@ wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
     returnVoid;
 }
 
-/*
- * Attempt to save the screen contents.  PDCurses does this if
- * PDC_RESTORE_SCREEN is set, giving the same visual appearance on restoration
- * as if the library had allocated a console buffer.
- */
 static bool
-save_original_screen(void)
+read_screen_data(void)
 {
     bool result = FALSE;
-    COORD bufferSize;
     COORD bufferCoord;
-    SMALL_RECT readRegion;
     size_t want;
 
-    bufferSize.X = CON.SBI.dwSize.X;
-    bufferSize.Y = CON.SBI.dwSize.Y;
-    want = (size_t) (bufferSize.X * bufferSize.Y);
+    CON.save_size.X = (SHORT) (CON.save_region.Right
+                              - CON.save_region.Left + 1);
+    CON.save_size.Y = (SHORT) (CON.save_region.Bottom
+                              - CON.save_region.Top + 1);
+
+    want = (size_t) (CON.save_size.X * CON.save_size.Y);
 
     if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
-       bufferCoord.X = bufferCoord.Y = 0;
-
-       readRegion.Top = 0;
-       readRegion.Left = 0;
-       readRegion.Bottom = (SHORT) (bufferSize.Y - 1);
-       readRegion.Right = (SHORT) (bufferSize.X - 1);
-
-       T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d",
-          bufferSize.Y, bufferSize.X,
-          readRegion.Top,
-          readRegion.Left,
-          readRegion.Bottom,
-          readRegion.Right,
+       bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
+       bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
+
+       T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
+          CON.window_only ? "window" : "buffer",
+          CON.save_size.Y, CON.save_size.X,
+          CON.save_region.Top,
+          CON.save_region.Left,
+          CON.save_region.Bottom,
+          CON.save_region.Right,
           bufferCoord.Y,
           bufferCoord.X));
 
-       if (ReadConsoleOutput(CON.hdl,
-                             CON.save_screen,
-                             bufferSize,
-                             bufferCoord,
-                             &readRegion)) {
+       if (read_screen(CON.hdl,
+                       CON.save_screen,
+                       CON.save_size,
+                       bufferCoord,
+                       &CON.save_region)) {
            result = TRUE;
        } else {
            T((" error %#lx", (unsigned long) GetLastError()));
            FreeAndNull(CON.save_screen);
+       }
+    }
 
-           bufferSize.X = (SHORT) (CON.SBI.srWindow.Right
-                                   - CON.SBI.srWindow.Left + 1);
-           bufferSize.Y = (SHORT) (CON.SBI.srWindow.Bottom
-                                   - CON.SBI.srWindow.Top + 1);
-           want = (size_t) (bufferSize.X * bufferSize.Y);
-
-           if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
-               bufferCoord.X = bufferCoord.Y = 0;
-
-               readRegion.Top = CON.SBI.srWindow.Top;
-               readRegion.Left = CON.SBI.srWindow.Left;
-               readRegion.Bottom = CON.SBI.srWindow.Bottom;
-               readRegion.Right = CON.SBI.srWindow.Right;
-
-               T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d",
-                  bufferSize.Y, bufferSize.X,
-                  readRegion.Top,
-                  readRegion.Left,
-                  readRegion.Bottom,
-                  readRegion.Right,
-                  bufferCoord.Y,
-                  bufferCoord.X));
-
-               if (ReadConsoleOutput(CON.hdl,
-                                     CON.save_screen,
-                                     bufferSize,
-                                     bufferCoord,
-                                     &readRegion)) {
-                   result = TRUE;
-                   CON.window_only = TRUE;
-               } else {
-                   T((" error %#lx", (unsigned long) GetLastError()));
-               }
-           }
+    return result;
+}
+
+/*
+ * Attempt to save the screen contents.  PDCurses does this if
+ * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
+ * restoration as if the library had allocated a console buffer.  MSDN
+ * says that the data which can be read is limited to 64Kb (and may be
+ * less).
+ */
+static bool
+save_original_screen(void)
+{
+    bool result = FALSE;
+
+    CON.save_region.Top = 0;
+    CON.save_region.Left = 0;
+    CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
+    CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
+
+    if (read_screen_data()) {
+       result = TRUE;
+    } else {
+
+       CON.save_region.Top = CON.SBI.srWindow.Top;
+       CON.save_region.Left = CON.SBI.srWindow.Left;
+       CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
+       CON.save_region.Right = CON.SBI.srWindow.Right;
+
+       CON.window_only = TRUE;
+
+       if (read_screen_data()) {
+           result = TRUE;
        }
     }
 
@@ -987,7 +1235,7 @@ wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
     AssertTCB();
 
     if (TCB) {
-       if (CON.hdl == INVALID_HANDLE_VALUE) {
+       if (!InitConsole()) {
            returnVoid;
        }
 
@@ -1019,12 +1267,13 @@ wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
 {
     SCREEN *sp;
 
-    AssertTCB();
-    SetSP();
+    if (okConsoleHandle(TCB)) {
+       SetSP();
 
-    if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
-       && (b >= 0) && (b < 8)) {
-       CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
+       if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
+           && (b >= 0) && (b < 8)) {
+           CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
+       }
     }
 }
 
@@ -1060,29 +1309,33 @@ wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
 {
     SCREEN *sp;
 
-    AssertTCB();
-    SetSP();
+    if (okConsoleHandle(TCB)) {
+       SetSP();
 
-    sp->_mouse_type = M_TERM_DRIVER;
+       sp->_mouse_type = M_TERM_DRIVER;
+    }
 }
 
 static int
-wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
+wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
+              int delay
+              EVENTLIST_2nd(_nc_eventlist * evl))
 {
     int rc = 0;
     SCREEN *sp;
 
-    AssertTCB();
-    SetSP();
+    if (okConsoleHandle(TCB)) {
+       SetSP();
 
-    if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
-       rc = TW_MOUSE;
-    } else {
-       rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
-                                     TWAIT_MASK,
-                                     delay,
-                                     (int *) 0
-                                     EVENTLIST_2nd(evl));
+       if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
+           rc = TW_MOUSE;
+       } else {
+           rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
+                                         TWAIT_MASK,
+                                         delay,
+                                         (int *) 0
+                                         EVENTLIST_2nd(evl));
+       }
     }
 
     return rc;
@@ -1179,13 +1432,14 @@ wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
     unsigned n;
 
     SCREEN *sp;
-    AssertTCB();
-    SetSP();
+    if (okConsoleHandle(TCB)) {
+       SetSP();
 
-    for (n = 0; n < SIZEOF(table); ++n) {
-       real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
-       if (sp != 0)
-           sp->_screen_acs_map[table[n].acs_code] = TRUE;
+       for (n = 0; n < SIZEOF(table); ++n) {
+           real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
+           if (sp != 0)
+               sp->_screen_acs_map[table[n].acs_code] = TRUE;
+       }
     }
 }
 
@@ -1208,11 +1462,11 @@ tdiff(FILETIME fstart, FILETIME fend)
 static int
 Adjust(int milliseconds, int diff)
 {
-    if (milliseconds == INFINITY)
-       return milliseconds;
-    milliseconds -= diff;
-    if (milliseconds < 0)
-       milliseconds = 0;
+    if (milliseconds != INFINITY) {
+       milliseconds -= diff;
+       if (milliseconds < 0)
+           milliseconds = 0;
+    }
     return milliseconds;
 }
 
@@ -1277,6 +1531,10 @@ console_twait(
     int diff;
     bool isImmed = (milliseconds == 0);
 
+#ifdef NCURSES_WGETCH_EVENTS
+    (void) evl;                        /* TODO: implement wgetch-events */
+#endif
+
 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
 
     assert(sp);
@@ -1296,7 +1554,7 @@ console_twait(
        diff = (int) tdiff(fstart, fend);
        milliseconds = Adjust(milliseconds, diff);
 
-       if (!isImmed && milliseconds == 0)
+       if (!isImmed && milliseconds <= 0)
            break;
 
        if (rc == WAIT_OBJECT_0) {
@@ -1314,7 +1572,7 @@ console_twait(
                                if (inp_rec.Event.KeyEvent.bKeyDown) {
                                    if (0 == ch) {
                                        int nKey = MapKey(vk);
-                                       if ((nKey < 0) || FALSE == sp->_keypad_on) {
+                                       if (nKey < 0) {
                                            CONSUME();
                                            continue;
                                        }
@@ -1336,7 +1594,9 @@ console_twait(
                                goto end;
                            }
                            continue;
+                           /* e.g., FOCUS_EVENT */
                        default:
+                           CONSUME();
                            selectActiveHandle();
                            continue;
                        }
@@ -1373,16 +1633,17 @@ wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
           EVENTLIST_2nd(_nc_eventlist * evl))
 {
     SCREEN *sp;
-    int code;
+    int code = 0;
 
-    AssertTCB();
-    SetSP();
+    if (okConsoleHandle(TCB)) {
+       SetSP();
 
-    code = console_twait(sp,
-                        CON.inp,
-                        mode,
-                        milliseconds,
-                        timeleft EVENTLIST_2nd(_nc_eventlist * evl));
+       code = console_twait(sp,
+                            CON.inp,
+                            mode,
+                            milliseconds,
+                            timeleft EVENTLIST_2nd(evl));
+    }
     return code;
 }
 
@@ -1433,14 +1694,16 @@ static int
 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
 {
     SCREEN *sp;
-    int n;
+    int n = -1;
+
+    T((T_CALLED("win32con::wcon_read(%p)"), TCB));
 
-    AssertTCB();
     assert(buf);
-    SetSP();
+    if (okConsoleHandle(TCB)) {
+       SetSP();
 
-    T((T_CALLED("win32con::wcon_read(%p)"), TCB));
-    n = _nc_mingw_console_read(sp, CON.inp, buf);
+       n = _nc_mingw_console_read(sp, CON.inp, buf);
+    }
     returnCode(n);
 }
 
@@ -1452,6 +1715,29 @@ wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
     returnCode(OK);
 }
 
+static int
+wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
+{
+    int res = -1;
+
+    T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
+    if (okConsoleHandle(TCB)) {
+       CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
+       switch (mode) {
+       case 0:
+           this_CI.bVisible = FALSE;
+           break;
+       case 1:
+           break;
+       case 2:
+           this_CI.dwSize = 100;
+           break;
+       }
+       SetConsoleCursorInfo(CON.hdl, &this_CI);
+    }
+    returnCode(res);
+}
+
 static bool
 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
 {
@@ -1481,12 +1767,14 @@ wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
     SCREEN *sp;
     int code = ERR;
 
-    AssertTCB();
-    SetSP();
-
     T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
-    if (sp) {
-       code = OK;
+
+    if (okConsoleHandle(TCB)) {
+       SetSP();
+
+       if (sp) {
+           code = OK;
+       }
     }
     returnCode(code);
 }
@@ -1505,22 +1793,23 @@ wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
 
     T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
 
-    AssertTCB();
-    SetSP();
-
-    if (sp) {
-       res = bsearch(&key,
-                     CON.rmap,
-                     (size_t) (N_INI + FKEYS),
-                     sizeof(keylist[0]),
-                     rkeycompare);
-       if (res) {
-           key = *((LONG *) res);
-           vKey = HIWORD(key);
-           nKey = (LOWORD(key)) & 0x7fff;
-           if (!flag)
-               nKey |= 0x8000;
-           *(LONG *) res = GenMap(vKey, nKey);
+    if (okConsoleHandle(TCB)) {
+       SetSP();
+
+       if (sp) {
+           res = bsearch(&key,
+                         CON.rmap,
+                         (size_t) (N_INI + FKEYS),
+                         sizeof(keylist[0]),
+                         rkeycompare);
+           if (res) {
+               key = *((LONG *) res);
+               vKey = HIWORD(key);
+               nKey = (LOWORD(key)) & 0x7fff;
+               if (!flag)
+                   nKey |= 0x8000;
+               *(LONG *) res = GenMap(vKey, nKey);
+           }
        }
     }
     returnCode(code);
@@ -1562,7 +1851,8 @@ NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
        wcon_nap,               /* nap */
        wcon_kpad,              /* kpad */
        wcon_keyok,             /* kyOk */
-       wcon_kyExist            /* kyExist */
+       wcon_kyExist,           /* kyExist */
+       wcon_cursorSet          /* cursorSet */
 };
 
 /* --------------------------------------------------------- */
@@ -1641,17 +1931,21 @@ _ismintty(int fd, LPHANDLE pMinTTY)
 #endif
 
 /*   Borrowed from ansicon project.
-     Check wether or not a I/O handle is associated with
+     Check whether or not an I/O handle is associated with
      a Windows console.
 */
 static BOOL
 IsConsoleHandle(HANDLE hdl)
 {
     DWORD dwFlag = 0;
+    BOOL result;
+
     if (!GetConsoleMode(hdl, &dwFlag)) {
-       return (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
+       result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
+    } else {
+       result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
     }
-    return (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
+    return result;
 }
 
 /*   Our replacement for the systems _isatty to include also
@@ -1661,18 +1955,26 @@ IsConsoleHandle(HANDLE hdl)
 int
 _nc_mingw_isatty(int fd)
 {
-    if (_isatty(fd))
-       return 1;
-#if WINVER < 0x0600
-    return 0;
+    int result = 0;
+
+#ifdef __MING32__
+#define SysISATTY(fd) _isatty(fd)
 #else
-    return _ismintty(fd, NULL);
+#define SysISATTY(fd) isatty(fd)
+#endif
+    if (SysISATTY(fd)) {
+       result = 1;
+    } else {
+#if WINVER >= 0x0600
+       result = _ismintty(fd, NULL);
 #endif
+    }
+    return result;
 }
 
 /*   This is used when running in terminfo mode to discover,
      whether or not the "terminal" is actually a Windows
-     Console. It's the responsibilty of the console to deal
+     Console. It's the responsibility of the console to deal
      with the terminal escape sequences that are sent by
      terminfo.
  */
@@ -1693,15 +1995,15 @@ _nc_mingw_isconsole(int fd)
     SCREEN *sp;                                               \
     TERMINAL *term = 0;                                       \
     int code = ERR;                                           \
-    if (_nc_screen_chain==0)                                  \
-      return 0;                                               \
+    if (_nc_screen_chain == 0)                                \
+        return 0;                                             \
     for (each_screen(sp)) {                                   \
-        if (sp->_term && sp->_term->Filedes==fd) {            \
-           term = sp->_term;                                 \
-           break;                                            \
+        if (sp->_term && (sp->_term->Filedes == fd)) {        \
+            term = sp->_term;                                 \
+            break;                                            \
         }                                                     \
     }                                                         \
-    assert(term!=0)
+    assert(term != 0)
 
 int
 _nc_mingw_tcsetattr(
@@ -1774,7 +2076,8 @@ int
 _nc_mingw_testmouse(
                       SCREEN *sp,
                       HANDLE fd,
-                      int delay)
+                      int delay
+                      EVENTLIST_2nd(_nc_eventlist * evl))
 {
     int rc = 0;
 
@@ -1799,7 +2102,7 @@ _nc_mingw_console_read(
                          HANDLE fd,
                          int *buf)
 {
-    int n = 1;
+    int rc = -1;
     INPUT_RECORD inp_rec;
     BOOL b;
     DWORD nRead;
@@ -1814,23 +2117,36 @@ _nc_mingw_console_read(
 
     while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
        if (b && nRead > 0) {
+           if (rc < 0)
+               rc = 0;
+           rc = rc + (int) nRead;
            if (inp_rec.EventType == KEY_EVENT) {
                if (!inp_rec.Event.KeyEvent.bKeyDown)
                    continue;
                *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
                vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
+               /*
+                * There are 24 virtual function-keys, and typically
+                * 12 function-keys on a keyboard.  Use the shift-modifier
+                * to provide the remaining 12 keys.
+                */
+               if (vk >= VK_F1 && vk <= VK_F12) {
+                   if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
+                       vk = (WORD) (vk + 12);
+                   }
+               }
                if (*buf == 0) {
-                   if (sp->_keypad_on) {
-                       *buf = MapKey(vk);
-                       if (0 > (*buf))
-                           continue;
-                       else
-                           break;
-                   } else
+                   int key = MapKey(vk);
+                   if (key < 0)
                        continue;
-               } else {        /* *buf != 0 */
-                   break;
+                   if (sp->_keypad_on) {
+                       *buf = key;
+                   } else {
+                       ungetch('\0');
+                       *buf = AnsiKey(vk);
+                   }
                }
+               break;
            } else if (inp_rec.EventType == MOUSE_EVENT) {
                if (handle_mouse(sp,
                                 inp_rec.Event.MouseEvent)) {
@@ -1841,13 +2157,13 @@ _nc_mingw_console_read(
            continue;
        }
     }
-    returnCode(n);
+    returnCode(rc);
 }
 
-static
-__attribute__((constructor))
-     void _enter_console(void)
+static bool
+InitConsole(void)
 {
+    /* initialize once, or not at all */
     if (!console_initialized) {
        int i;
        DWORD num_buttons;
@@ -1855,19 +2171,29 @@ __attribute__((constructor))
        BOOL buffered = TRUE;
        BOOL b;
 
+       START_TRACE();
        if (_nc_mingw_isatty(0)) {
            CON.isMinTTY = TRUE;
        }
 
        for (i = 0; i < (N_INI + FKEYS); i++) {
-           if (i < N_INI)
+           if (i < N_INI) {
                CON.rmap[i] = CON.map[i] =
                    (DWORD) keylist[i];
-           else
+               CON.ansi_map[i] = (DWORD) ansi_keys[i];
+           } else {
                CON.rmap[i] = CON.map[i] =
                    (DWORD) GenMap((VK_F1 + (i - N_INI)),
                                   (KEY_F(1) + (i - N_INI)));
+               CON.ansi_map[i] =
+                   (DWORD) GenMap((VK_F1 + (i - N_INI)),
+                                  (';' + (i - N_INI)));
+           }
        }
+       qsort(CON.ansi_map,
+             (size_t) (MAPSIZE),
+             sizeof(keylist[0]),
+             keycompare);
        qsort(CON.map,
              (size_t) (MAPSIZE),
              sizeof(keylist[0]),
@@ -1896,9 +2222,11 @@ __attribute__((constructor))
            b = AttachConsole(ATTACH_PARENT_PROCESS);
 
        if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
-           CON.hdl = CON.out;
+           T(("... will not buffer console"));
            buffered = FALSE;
+           CON.hdl = CON.out;
        } else {
+           T(("... creating console buffer"));
            CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
                                                0,
                                                NULL,
@@ -1909,11 +2237,39 @@ __attribute__((constructor))
        if (CON.hdl != INVALID_HANDLE_VALUE) {
            CON.buffered = buffered;
            get_SBI();
-           if (buffered) {
+           CON.save_SBI = CON.SBI;
+           if (!buffered) {
                save_original_screen();
+               set_scrollback(FALSE, &CON.SBI);
            }
+           GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
+           T(("... initial cursor is %svisible, %d%%",
+              (CON.save_CI.bVisible ? "" : "not-"),
+              (int) CON.save_CI.dwSize));
        }
 
        console_initialized = TRUE;
     }
+    return (CON.hdl != INVALID_HANDLE_VALUE);
 }
+
+static bool
+okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    return ((TCB != 0) &&
+           (TCB->magic == WINMAGIC) &&
+           InitConsole());
+}
+
+/*
+ * While a constructor would ensure that this module is initialized, that will
+ * interfere with applications that may combine this with GUI interfaces.
+ */
+#if 0
+static
+__attribute__((constructor))
+     void _enter_console(void)
+{
+    (void) InitConsole();
+}
+#endif