Update to ncurses-6.0

Change-Id: I98ab2ea8a5e13cca9f8b7cf6277b9b14a4da4299
diff --git a/ncurses/win32con/gettimeofday.c b/ncurses/win32con/gettimeofday.c
new file mode 100644
index 0000000..867041f
--- /dev/null
+++ b/ncurses/win32con/gettimeofday.c
@@ -0,0 +1,54 @@
+/****************************************************************************
+ * Copyright (c) 2008-2010,2014 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            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
+
+#ifdef WINVER
+#  undef WINVER
+#endif
+#define WINVER 0x0501
+
+#include <curses.priv.h>
+
+#include <windows.h>
+
+MODULE_ID("$Id: gettimeofday.c,v 1.3 2014/04/26 19:41:34 juergen Exp $")
+
+#define JAN1970 116444736000000000LL	/* the value for 01/01/1970 00:00 */
+
+int
+gettimeofday(struct timeval *tv, void *tz GCC_UNUSED)
+{
+    union {
+	FILETIME ft;
+	long long since1601;	/* time since 1 Jan 1601 in 100ns units */
+    } data;
+
+    GetSystemTimeAsFileTime(&data.ft);
+    tv->tv_usec = (long) ((data.since1601 / 10LL) % 1000000LL);
+    tv->tv_sec = (long) ((data.since1601 - JAN1970) / 10000000LL);
+    return (0);
+}
diff --git a/ncurses/win32con/wcwidth.c b/ncurses/win32con/wcwidth.c
new file mode 100644
index 0000000..cdef64a
--- /dev/null
+++ b/ncurses/win32con/wcwidth.c
@@ -0,0 +1,50 @@
+/****************************************************************************
+ * Copyright (c) 2010 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            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
+#include <curses.priv.h>
+
+MODULE_ID("$Id: wcwidth.c,v 1.2 2010/08/07 20:52:43 tom Exp $")
+
+#if USE_WIDEC_SUPPORT
+#define mk_wcwidth(ucs)          _nc_wcwidth(ucs)
+#define mk_wcswidth(pwcs, n)     _nc_wcswidth(pwcs, n)
+#define mk_wcwidth_cjk(ucs)      _nc_wcwidth_cjk(ucs)
+#define mk_wcswidth_cjk(pwcs, n) _nc_wcswidth_cjk(pwcs, n)
+
+extern int mk_wcwidth(wchar_t);
+extern int mk_wcswidth(const wchar_t *, size_t);
+extern int mk_wcwidth_cjk(wchar_t);
+extern int mk_wcswidth_cjk(const wchar_t *, size_t);
+
+#include <wcwidth.h>
+#else
+void _nc_empty_wcwidth(void);
+void
+_nc_empty_wcwidth(void)
+{
+}
+#endif
diff --git a/ncurses/win32con/win_driver.c b/ncurses/win32con/win_driver.c
new file mode 100644
index 0000000..78ccfed
--- /dev/null
+++ b/ncurses/win32con/win_driver.c
@@ -0,0 +1,2264 @@
+/****************************************************************************
+ * Copyright (c) 1998-2014,2015 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            *
+ * "Software"), to deal in the Software without restriction, including      *
+ * without limitation the rights to use, copy, modify, merge, publish,      *
+ * distribute, distribute with modifications, sublicense, and/or sell       *
+ * copies of the Software, and to permit persons to whom the Software is    *
+ * furnished to do so, subject to the following conditions:                 *
+ *                                                                          *
+ * The above copyright notice and this permission notice shall be included  *
+ * in all copies or substantial portions of the Software.                   *
+ *                                                                          *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
+ * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
+ * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
+ * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
+ * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
+ * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
+ *                                                                          *
+ * Except as contained in this notice, the name(s) of the above copyright   *
+ * holders shall not be used in advertising or otherwise to promote the     *
+ * sale, use or other dealings in this Software without prior written       *
+ * authorization.                                                           *
+ ****************************************************************************/
+
+/****************************************************************************
+ *  Author: Juergen Pfeifer                                                 *
+ *     and: Thomas E. Dickey                                                *
+ ****************************************************************************/
+
+/*
+ * 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 __MINGW32__
+#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.
+
+MODULE_ID("$Id: win_driver.c,v 1.55 2015/02/28 21:30:23 tom Exp $")
+
+#ifndef __GNUC__
+#  error We need GCC to compile for MinGW
+#endif
+
+#define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
+
+#define EXP_OPTIMIZE 0
+
+#define array_length(a) (sizeof(a)/sizeof(a[0]))
+
+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
+
+#define GenMap(vKey,key) MAKELONG(key, vKey)
+
+#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),
+    GenMap(VK_NEXT, KEY_NPAGE),
+    GenMap(VK_END, KEY_END),
+    GenMap(VK_HOME, KEY_HOME),
+    GenMap(VK_LEFT, KEY_LEFT),
+    GenMap(VK_UP, KEY_UP),
+    GenMap(VK_RIGHT, KEY_RIGHT),
+    GenMap(VK_DOWN, KEY_DOWN),
+    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 safe
+     to maintain all the information about it in a single
+     static structure.
+ */
+static struct {
+    BOOL initialized;
+    BOOL buffered;
+    BOOL window_only;
+    BOOL progMode;
+    BOOL isMinTTY;
+    BOOL isTermInfoConsole;
+    HANDLE out;
+    HANDLE inp;
+    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;
+
+static WORD
+MapColor(bool fore, int color)
+{
+    static const int _cmap[] =
+    {0, 4, 2, 6, 1, 5, 3, 7};
+    int a;
+    if (color < 0 || color > 7)
+	a = fore ? 7 : 0;
+    else
+	a = _cmap[color];
+    if (!fore)
+	a = a << 4;
+    return (WORD) a;
+}
+
+#define RevAttr(attr) \
+	       (WORD) (((attr) & 0xff00) | \
+		      ((((attr) & 0x07) << 4) | \
+		       (((attr) & 0x70) >> 4)))
+
+static WORD
+MapAttr(WORD res, attr_t ch)
+{
+    if (ch & A_COLOR) {
+	int p;
+
+	p = PairNumber(ch);
+	if (p > 0 && p < NUMPAIRS) {
+	    WORD a;
+	    a = CON.pairs[p];
+	    res = (WORD) ((res & 0xff00) | a);
+	}
+    }
+
+    if (ch & A_REVERSE) {
+	res = RevAttr(res);
+    }
+
+    if (ch & A_STANDOUT) {
+	res = RevAttr(res) | BACKGROUND_INTENSITY;
+    }
+
+    if (ch & A_BOLD)
+	res |= FOREGROUND_INTENSITY;
+
+    if (ch & A_DIM)
+	res |= BACKGROUND_INTENSITY;
+
+    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: _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];
+    COORD loc, siz;
+    SMALL_RECT rec;
+    int i;
+    cchar_t ch;
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+
+    for (i = actual = 0; i < limit; i++) {
+	ch = str[i];
+	if (isWidecExt(ch))
+	    continue;
+	ci[actual].Char.UnicodeChar = CharOf(ch);
+	ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
+					AttrOf(ch));
+	if (AttrOf(ch) & A_ALTCHARSET) {
+	    if (_nc_wacs) {
+		int which = CharOf(ch);
+		if (which > 0
+		    && which < ACS_LEN
+		    && CharOf(_nc_wacs[which]) != 0) {
+		    ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
+		} else {
+		    ci[actual].Char.UnicodeChar = ' ';
+		}
+	    }
+	}
+	++actual;
+    }
+
+    loc.X = (SHORT) 0;
+    loc.Y = (SHORT) 0;
+    siz.X = (SHORT) actual;
+    siz.Y = 1;
+
+    rec.Left = (SHORT) x;
+    rec.Top = (SHORT) (y + AdjustY());
+    rec.Right = (SHORT) (x + limit - 1);
+    rec.Bottom = rec.Top;
+
+    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];
+    COORD loc, siz;
+    SMALL_RECT rec;
+    int i;
+    chtype ch;
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+
+    for (i = 0; i < n; i++) {
+	ch = str[i];
+	ci[i].Char.AsciiChar = ChCharOf(ch);
+	ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
+				   ChAttrOf(ch));
+	if (ChAttrOf(ch) & A_ALTCHARSET) {
+	    if (sp->_acs_map)
+		ci[i].Char.AsciiChar =
+		ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
+	}
+    }
+
+    loc.X = (short) 0;
+    loc.Y = (short) 0;
+    siz.X = (short) n;
+    siz.Y = 1;
+
+    rec.Left = (short) x;
+    rec.Top = (short) y;
+    rec.Right = (short) (x + n - 1);
+    rec.Bottom = rec.Top;
+
+    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
+
+#if EXP_OPTIMIZE
+/*
+ * Comparing new/current screens, determine the last column-index for a change
+ * beginning on the given row,col position.  Unlike a serial terminal, there is
+ * no cost for "moving" the "cursor" on the line as we update it.
+ */
+static int
+find_end_of_change(SCREEN *sp, int row, int col)
+{
+    int result = col;
+    struct ldat *curdat = CurScreen(sp)->_line + row;
+    struct ldat *newdat = NewScreen(sp)->_line + row;
+
+    while (col <= newdat->lastchar) {
+#if USE_WIDEC_SUPPORT
+	if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
+	    result = col;
+	} else if (memcmp(&curdat->text[col],
+			  &newdat->text[col],
+			  sizeof(curdat->text[0]))) {
+	    result = col;
+	} else {
+	    break;
+	}
+#else
+	if (curdat->text[col] != newdat->text[col]) {
+	    result = col;
+	} else {
+	    break;
+	}
+#endif
+	++col;
+    }
+    return result;
+}
+
+/*
+ * Given a row,col position at the end of a change-chunk, look for the
+ * beginning of the next change-chunk.
+ */
+static int
+find_next_change(SCREEN *sp, int row, int col)
+{
+    struct ldat *curdat = CurScreen(sp)->_line + row;
+    struct ldat *newdat = NewScreen(sp)->_line + row;
+    int result = newdat->lastchar + 1;
+
+    while (++col <= newdat->lastchar) {
+#if USE_WIDEC_SUPPORT
+	if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
+	    result = col;
+	    break;
+	} else if (memcmp(&curdat->text[col],
+			  &newdat->text[col],
+			  sizeof(curdat->text[0]))) {
+	    result = col;
+	    break;
+	}
+#else
+	if (curdat->text[col] != newdat->text[col]) {
+	    result = col;
+	    break;
+	}
+#endif
+    }
+    return result;
+}
+
+#define EndChange(first) \
+	find_end_of_change(sp, y, first)
+#define NextChange(last) \
+	find_next_change(sp, y, last)
+
+#endif /* EXP_OPTIMIZE */
+
+#define MARK_NOCHANGE(win,row) \
+		win->_line[row].firstchar = _NOCHANGE; \
+		win->_line[row].lastchar  = _NOCHANGE
+
+static void
+selectActiveHandle(void)
+{
+    if (CON.lastOut != CON.hdl) {
+	CON.lastOut = CON.hdl;
+	SetConsoleActiveScreenBuffer(CON.lastOut);
+    }
+}
+
+static bool
+restore_original_screen(void)
+{
+    COORD bufferCoord;
+    bool result = FALSE;
+    SMALL_RECT save_region = CON.save_region;
+
+    T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
+
+    bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
+    bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
+
+    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"));
+    }
+    return result;
+}
+
+static const char *
+wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    (void) TCB;
+    return "win32console";
+}
+
+static int
+wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    int result = ERR;
+    int y, nonempty, n, x0, x1, Width, Height;
+    SCREEN *sp;
+
+    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) {
+
+	    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 = FALSE;
+	}
+
+	if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
+	    int x;
+#if USE_WIDEC_SUPPORT
+	    cchar_t empty[Width];
+	    wchar_t blank[2] =
+	    {
+		L' ', L'\0'
+	    };
+
+	    for (x = 0; x < Width; x++)
+		setcchar(&empty[x], blank, 0, 0, 0);
+#else
+	    chtype empty[Width];
+
+	    for (x = 0; x < Width; x++)
+		empty[x] = ' ';
+#endif
+
+	    for (y = 0; y < nonempty; y++) {
+		con_write(TCB, y, 0, empty, Width);
+		memcpy(empty,
+		       CurScreen(sp)->_line[y].text,
+		       (size_t) Width * sizeof(empty[0]));
+	    }
+	    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++) {
+	    x0 = NewScreen(sp)->_line[y].firstchar;
+	    if (x0 != _NOCHANGE) {
+#if EXP_OPTIMIZE
+		int x2;
+		int limit = NewScreen(sp)->_line[y].lastchar;
+		while ((x1 = EndChange(x0)) <= limit) {
+		    while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
+			x1 = x2;
+		    }
+		    n = x1 - x0 + 1;
+		    memcpy(&CurScreen(sp)->_line[y].text[x0],
+			   &NewScreen(sp)->_line[y].text[x0],
+			   n * sizeof(CurScreen(sp)->_line[y].text[x0]));
+		    con_write(TCB,
+			      y,
+			      x0,
+			      &CurScreen(sp)->_line[y].text[x0], n);
+		    x0 = NextChange(x1);
+		}
+
+		/* mark line changed successfully */
+		if (y <= NewScreen(sp)->_maxy) {
+		    MARK_NOCHANGE(NewScreen(sp), y);
+		}
+		if (y <= CurScreen(sp)->_maxy) {
+		    MARK_NOCHANGE(CurScreen(sp), y);
+		}
+#else
+		x1 = NewScreen(sp)->_line[y].lastchar;
+		n = x1 - x0 + 1;
+		if (n > 0) {
+		    memcpy(&CurScreen(sp)->_line[y].text[x0],
+			   &NewScreen(sp)->_line[y].text[x0],
+			   (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
+		    con_write(TCB,
+			      y,
+			      x0,
+			      &CurScreen(sp)->_line[y].text[x0], n);
+
+		    /* mark line changed successfully */
+		    if (y <= NewScreen(sp)->_maxy) {
+			MARK_NOCHANGE(NewScreen(sp), y);
+		    }
+		    if (y <= CurScreen(sp)->_maxy) {
+			MARK_NOCHANGE(CurScreen(sp), y);
+		    }
+		}
+#endif
+	    }
+	}
+
+	/* put everything back in sync */
+	for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
+	    MARK_NOCHANGE(NewScreen(sp), y);
+	}
+	for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
+	    MARK_NOCHANGE(CurScreen(sp), y);
+	}
+
+	if (!NewScreen(sp)->_leaveok) {
+	    CurScreen(sp)->_curx = NewScreen(sp)->_curx;
+	    CurScreen(sp)->_cury = NewScreen(sp)->_cury;
+
+	    TCB->drv->td_hwcur(TCB,
+			       0, 0,
+			       CurScreen(sp)->_cury, CurScreen(sp)->_curx);
+	}
+	selectActiveHandle();
+	result = OK;
+    }
+    returnCode(result);
+}
+
+static bool
+wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
+	       const char *tname,
+	       int *errret GCC_UNUSED)
+{
+    bool code = FALSE;
+
+    T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
+
+    assert((TCB != 0) && (tname != 0));
+
+    TCB->magic = WINMAGIC;
+
+    if (tname == 0 || *tname == 0)
+	code = TRUE;
+    else if (tname != 0 && *tname == '#') {
+	/*
+	 * Use "#" (a character which cannot begin a terminal's name) to
+	 * select specific driver from the table.
+	 *
+	 * In principle, we could have more than one non-terminfo driver,
+	 * e.g., "win32gui".
+	 */
+	size_t n = strlen(tname + 1);
+	if (n != 0
+	    && ((strncmp(tname + 1, "win32console", n) == 0)
+		|| (strncmp(tname + 1, "win32con", n) == 0))) {
+	    code = TRUE;
+	}
+    } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
+	code = TRUE;
+    }
+
+    /*
+     * 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) {
+	if (_nc_mingw_isconsole(0))
+	    CON.isTermInfoConsole = TRUE;
+    }
+    returnBool(code);
+}
+
+static int
+wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
+		 int beepFlag)
+{
+    SCREEN *sp;
+    int res = ERR;
+
+    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[max_cells];
+    CHAR_INFO that_screen[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(that_screen));
+
+	    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;
+}
+
+static int
+wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
+	   char *data GCC_UNUSED,
+	   int len GCC_UNUSED)
+{
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+
+    return ERR;
+}
+
+static int
+wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
+		   int fg GCC_UNUSED,
+		   int bg GCC_UNUSED)
+{
+    SCREEN *sp;
+    int code = ERR;
+
+    AssertTCB();
+    SetSP();
+
+    return (code);
+}
+
+static bool
+get_SBI(void)
+{
+    bool rc = FALSE;
+    if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
+	T(("GetConsoleScreenBufferInfo"));
+	T(("... buffer(X:%d Y:%d)",
+	   CON.SBI.dwSize.X,
+	   CON.SBI.dwSize.Y));
+	T(("... window(X:%d Y:%d)",
+	   CON.SBI.dwMaximumWindowSize.X,
+	   CON.SBI.dwMaximumWindowSize.Y));
+	T(("... cursor(X:%d Y:%d)",
+	   CON.SBI.dwCursorPosition.X,
+	   CON.SBI.dwCursorPosition.Y));
+	T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
+	   CON.SBI.srWindow.Top,
+	   CON.SBI.srWindow.Bottom,
+	   CON.SBI.srWindow.Left,
+	   CON.SBI.srWindow.Right));
+	if (CON.buffered) {
+	    CON.origin.X = 0;
+	    CON.origin.Y = 0;
+	} else {
+	    CON.origin.X = CON.SBI.srWindow.Left;
+	    CON.origin.Y = CON.SBI.srWindow.Top;
+	}
+	rc = TRUE;
+    } else {
+	T(("GetConsoleScreenBufferInfo ERR"));
+    }
+    return rc;
+}
+
+static void
+wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
+	      int fore,
+	      int color,
+	      int (*outc) (SCREEN *, int) GCC_UNUSED)
+{
+    if (okConsoleHandle(TCB)) {
+	WORD a = MapColor(fore, color);
+	a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
+	SetConsoleTextAttribute(CON.hdl, a);
+	get_SBI();
+    }
+}
+
+static bool
+wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    bool res = FALSE;
+
+    if (okConsoleHandle(TCB)) {
+	WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
+	SetConsoleTextAttribute(CON.hdl, a);
+	get_SBI();
+	res = TRUE;
+    }
+    return res;
+}
+
+static bool
+wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    int result = FALSE;
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+
+    return result;
+}
+
+static int
+wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
+{
+    int result = ERR;
+
+    T((T_CALLED("win32con::wcon_size(%p)"), TCB));
+
+    if (okConsoleHandle(TCB) &&
+	Lines != NULL &&
+	Cols != NULL) {
+	if (CON.buffered) {
+	    *Lines = (int) (CON.SBI.dwSize.Y);
+	    *Cols = (int) (CON.SBI.dwSize.X);
+	} else {
+	    *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
+			    CON.SBI.srWindow.Top);
+	    *Cols = (int) (CON.SBI.srWindow.Right + 1 -
+			   CON.SBI.srWindow.Left);
+	}
+	result = OK;
+    }
+    returnCode(result);
+}
+
+static int
+wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
+	     int l GCC_UNUSED,
+	     int c GCC_UNUSED)
+{
+    AssertTCB();
+    return ERR;
+}
+
+static int
+wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
+{
+    DWORD dwFlag = 0;
+    tcflag_t iflag;
+    tcflag_t lflag;
+    int result = ERR;
+
+    if (buf != NULL && okConsoleHandle(TCB)) {
+
+	if (setFlag) {
+	    iflag = buf->c_iflag;
+	    lflag = buf->c_lflag;
+
+	    GetConsoleMode(CON.inp, &dwFlag);
+
+	    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 (iflag & BRKINT)
+		dwFlag |= ENABLE_PROCESSED_INPUT;
+	    else
+		dwFlag &= (DWORD) (~ENABLE_PROCESSED_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);
+
+	    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 {
+	int high = info->srWindow.Bottom - info->srWindow.Top + 1;
+	int wide = info->srWindow.Right - info->srWindow.Left + 1;
+
+	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;
+	}
+
+	rect.Left =
+	    rect.Top = 0;
+	rect.Right = (SHORT) (wide - 1);
+	rect.Bottom = (SHORT) (high - 1);
+
+	coord.X = (SHORT) wide;
+	coord.Y = (SHORT) high;
+
+	if (info->dwSize.Y != high ||
+	    info->dwSize.X != wide ||
+	    info->srWindow.Top != 0 ||
+	    info->srWindow.Left != 0) {
+	    changed = TRUE;
+	}
+
+    }
+
+    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
+wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
+{
+    SCREEN *sp;
+    TERMINAL *_term = (TERMINAL *) TCB;
+    int code = ERR;
+
+    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;
+		}
+	    }
+	    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) {
+		    _nc_keypad(sp, FALSE);
+		    NCURSES_SP_NAME(_nc_flush) (sp);
+		}
+		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);
+	    }
+	}
+
+    }
+    returnCode(code);
+}
+
+static void
+wcon_screen_init(SCREEN *sp GCC_UNUSED)
+{
+}
+
+static void
+wcon_wrap(SCREEN *sp GCC_UNUSED)
+{
+}
+
+static int
+rkeycompare(const void *el1, const void *el2)
+{
+    WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
+    WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
+
+    return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
+}
+
+static int
+keycompare(const void *el1, const void *el2)
+{
+    WORD key1 = HIWORD((*((const LONG *) el1)));
+    WORD key2 = HIWORD((*((const LONG *) el2)));
+
+    return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
+}
+
+static int
+MapKey(WORD vKey)
+{
+    WORD nKey = 0;
+    void *res;
+    LONG key = GenMap(vKey, 0);
+    int code = -1;
+
+    res = bsearch(&key,
+		  CON.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 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)
+{
+    T((T_CALLED("win32con::wcon_release(%p)"), TCB));
+
+    AssertTCB();
+    if (TCB->prop)
+	free(TCB->prop);
+
+    returnVoid;
+}
+
+static bool
+read_screen_data(void)
+{
+    bool result = FALSE;
+    COORD bufferCoord;
+    size_t want;
+
+    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 = (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 (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);
+	}
+    }
+
+    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;
+	}
+    }
+
+    T(("... save original screen contents %s", result ? "ok" : "err"));
+    return result;
+}
+
+static void
+wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    T((T_CALLED("win32con::wcon_init(%p)"), TCB));
+
+    AssertTCB();
+
+    if (TCB) {
+	if (!InitConsole()) {
+	    returnVoid;
+	}
+
+	TCB->info.initcolor = TRUE;
+	TCB->info.canchange = FALSE;
+	TCB->info.hascolor = TRUE;
+	TCB->info.caninit = TRUE;
+
+	TCB->info.maxpairs = NUMPAIRS;
+	TCB->info.maxcolors = 8;
+	TCB->info.numlabels = 0;
+	TCB->info.labelwidth = 0;
+	TCB->info.labelheight = 0;
+	TCB->info.nocolorvideo = 1;
+	TCB->info.tabsize = 8;
+
+	TCB->info.numbuttons = CON.numButtons;
+	TCB->info.defaultPalette = _nc_cga_palette;
+
+    }
+    returnVoid;
+}
+
+static void
+wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
+	      int pair,
+	      int f,
+	      int b)
+{
+    SCREEN *sp;
+
+    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);
+	}
+    }
+}
+
+static void
+wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
+	       int color GCC_UNUSED,
+	       int r GCC_UNUSED,
+	       int g GCC_UNUSED,
+	       int b GCC_UNUSED)
+{
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+}
+
+static void
+wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
+	      int old_pair GCC_UNUSED,
+	      int pair GCC_UNUSED,
+	      int reverse GCC_UNUSED,
+	      int (*outc) (SCREEN *, int) GCC_UNUSED
+)
+{
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+}
+
+static void
+wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    SCREEN *sp;
+
+    if (okConsoleHandle(TCB)) {
+	SetSP();
+
+	sp->_mouse_type = M_TERM_DRIVER;
+    }
+}
+
+static int
+wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
+{
+    int rc = 0;
+    SCREEN *sp;
+
+    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));
+	}
+    }
+
+    return rc;
+}
+
+static int
+wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
+	   int yold GCC_UNUSED, int xold GCC_UNUSED,
+	   int y, int x)
+{
+    int ret = ERR;
+    if (okConsoleHandle(TCB)) {
+	COORD loc;
+	loc.X = (short) x;
+	loc.Y = (short) (y + AdjustY());
+	SetConsoleCursorPosition(CON.hdl, loc);
+	ret = OK;
+    }
+    return ret;
+}
+
+static void
+wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
+	     int labnum GCC_UNUSED,
+	     char *text GCC_UNUSED)
+{
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+}
+
+static void
+wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
+		  int OnFlag GCC_UNUSED)
+{
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+}
+
+static chtype
+wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
+{
+    chtype res = A_NORMAL;
+    res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
+    return res;
+}
+
+static void
+wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+}
+
+static void
+wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
+	     chtype *real_map GCC_UNUSED,
+	     chtype *fake_map GCC_UNUSED)
+{
+#define DATA(a,b) { a, b }
+    static struct {
+	int acs_code;
+	int use_code;
+    } table[] = {
+	DATA('a', 0xb1),	/* ACS_CKBOARD  */
+	    DATA('f', 0xf8),	/* ACS_DEGREE   */
+	    DATA('g', 0xf1),	/* ACS_PLMINUS  */
+	    DATA('j', 0xd9),	/* ACS_LRCORNER */
+	    DATA('l', 0xda),	/* ACS_ULCORNER */
+	    DATA('k', 0xbf),	/* ACS_URCORNER */
+	    DATA('m', 0xc0),	/* ACS_LLCORNER */
+	    DATA('n', 0xc5),	/* ACS_PLUS     */
+	    DATA('q', 0xc4),	/* ACS_HLINE    */
+	    DATA('t', 0xc3),	/* ACS_LTEE     */
+	    DATA('u', 0xb4),	/* ACS_RTEE     */
+	    DATA('v', 0xc1),	/* ACS_BTEE     */
+	    DATA('w', 0xc2),	/* ACS_TTEE     */
+	    DATA('x', 0xb3),	/* ACS_VLINE    */
+	    DATA('y', 0xf3),	/* ACS_LEQUAL   */
+	    DATA('z', 0xf2),	/* ACS_GEQUAL   */
+	    DATA('0', 0xdb),	/* ACS_BLOCK    */
+	    DATA('{', 0xe3),	/* ACS_PI       */
+	    DATA('}', 0x9c),	/* ACS_STERLING */
+	    DATA(',', 0xae),	/* ACS_LARROW   */
+	    DATA('+', 0xaf),	/* ACS_RARROW   */
+	    DATA('~', 0xf9),	/* ACS_BULLET   */
+    };
+#undef DATA
+    unsigned n;
+
+    SCREEN *sp;
+    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;
+	}
+    }
+}
+
+static ULONGLONG
+tdiff(FILETIME fstart, FILETIME fend)
+{
+    ULARGE_INTEGER ustart;
+    ULARGE_INTEGER uend;
+    ULONGLONG diff;
+
+    ustart.LowPart = fstart.dwLowDateTime;
+    ustart.HighPart = fstart.dwHighDateTime;
+    uend.LowPart = fend.dwLowDateTime;
+    uend.HighPart = fend.dwHighDateTime;
+
+    diff = (uend.QuadPart - ustart.QuadPart) / 10000;
+    return diff;
+}
+
+static int
+Adjust(int milliseconds, int diff)
+{
+    if (milliseconds != INFINITY) {
+	milliseconds -= diff;
+	if (milliseconds < 0)
+	    milliseconds = 0;
+    }
+    return milliseconds;
+}
+
+#define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
+		     FROM_LEFT_2ND_BUTTON_PRESSED | \
+		     FROM_LEFT_3RD_BUTTON_PRESSED | \
+		     FROM_LEFT_4TH_BUTTON_PRESSED | \
+		     RIGHTMOST_BUTTON_PRESSED)
+
+static int
+decode_mouse(SCREEN *sp, int mask)
+{
+    int result = 0;
+
+    (void) sp;
+    assert(sp && console_initialized);
+
+    if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
+	result |= BUTTON1_PRESSED;
+    if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
+	result |= BUTTON2_PRESSED;
+    if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
+	result |= BUTTON3_PRESSED;
+    if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
+	result |= BUTTON4_PRESSED;
+
+    if (mask & RIGHTMOST_BUTTON_PRESSED) {
+	switch (CON.numButtons) {
+	case 1:
+	    result |= BUTTON1_PRESSED;
+	    break;
+	case 2:
+	    result |= BUTTON2_PRESSED;
+	    break;
+	case 3:
+	    result |= BUTTON3_PRESSED;
+	    break;
+	case 4:
+	    result |= BUTTON4_PRESSED;
+	    break;
+	}
+    }
+
+    return result;
+}
+
+static int
+console_twait(
+		 SCREEN *sp,
+		 HANDLE fd,
+		 int mode,
+		 int milliseconds,
+		 int *timeleft
+		 EVENTLIST_2nd(_nc_eventlist * evl))
+{
+    INPUT_RECORD inp_rec;
+    BOOL b;
+    DWORD nRead = 0, rc = (DWORD) (-1);
+    int code = 0;
+    FILETIME fstart;
+    FILETIME fend;
+    int diff;
+    bool isImmed = (milliseconds == 0);
+
+#define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
+
+    assert(sp);
+
+    TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
+		      milliseconds, mode));
+
+    if (milliseconds < 0)
+	milliseconds = INFINITY;
+
+    memset(&inp_rec, 0, sizeof(inp_rec));
+
+    while (true) {
+	GetSystemTimeAsFileTime(&fstart);
+	rc = WaitForSingleObject(fd, (DWORD) milliseconds);
+	GetSystemTimeAsFileTime(&fend);
+	diff = (int) tdiff(fstart, fend);
+	milliseconds = Adjust(milliseconds, diff);
+
+	if (!isImmed && milliseconds <= 0)
+	    break;
+
+	if (rc == WAIT_OBJECT_0) {
+	    if (mode) {
+		b = GetNumberOfConsoleInputEvents(fd, &nRead);
+		if (b && nRead > 0) {
+		    b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
+		    if (b && nRead > 0) {
+			switch (inp_rec.EventType) {
+			case KEY_EVENT:
+			    if (mode & TW_INPUT) {
+				WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
+				char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
+
+				if (inp_rec.Event.KeyEvent.bKeyDown) {
+				    if (0 == ch) {
+					int nKey = MapKey(vk);
+					if (nKey < 0) {
+					    CONSUME();
+					    continue;
+					}
+				    }
+				    code = TW_INPUT;
+				    goto end;
+				} else {
+				    CONSUME();
+				}
+			    }
+			    continue;
+			case MOUSE_EVENT:
+			    if (decode_mouse(sp,
+					     (inp_rec.Event.MouseEvent.dwButtonState
+					      & BUTTON_MASK)) == 0) {
+				CONSUME();
+			    } else if (mode & TW_MOUSE) {
+				code = TW_MOUSE;
+				goto end;
+			    }
+			    continue;
+			    /* e.g., FOCUS_EVENT */
+			default:
+			    CONSUME();
+			    selectActiveHandle();
+			    continue;
+			}
+		    }
+		}
+	    }
+	    continue;
+	} else {
+	    if (rc != WAIT_TIMEOUT) {
+		code = -1;
+		break;
+	    } else {
+		code = 0;
+		break;
+	    }
+	}
+    }
+  end:
+
+    TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
+		      code, errno, milliseconds));
+
+    if (timeleft)
+	*timeleft = milliseconds;
+
+    return code;
+}
+
+static int
+wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
+	   int mode,
+	   int milliseconds,
+	   int *timeleft
+	   EVENTLIST_2nd(_nc_eventlist * evl))
+{
+    SCREEN *sp;
+    int code = 0;
+
+    if (okConsoleHandle(TCB)) {
+	SetSP();
+
+	code = console_twait(sp,
+			     CON.inp,
+			     mode,
+			     milliseconds,
+			     timeleft EVENTLIST_2nd(_nc_eventlist * evl));
+    }
+    return code;
+}
+
+static bool
+handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
+{
+    MEVENT work;
+    bool result = FALSE;
+
+    assert(sp);
+
+    sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
+    sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
+
+    /*
+     * We're only interested if the button is pressed or released.
+     * FIXME: implement continuous event-tracking.
+     */
+    if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
+
+	memset(&work, 0, sizeof(work));
+
+	if (sp->_drv_mouse_new_buttons) {
+
+	    work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
+
+	} else {
+
+	    /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
+	    work.bstate |= (mmask_t) (decode_mouse(sp,
+						   sp->_drv_mouse_old_buttons)
+				      >> 1);
+
+	    result = TRUE;
+	}
+
+	work.x = mer.dwMousePosition.X;
+	work.y = mer.dwMousePosition.Y - AdjustY();
+
+	sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
+	sp->_drv_mouse_tail += 1;
+    }
+
+    return result;
+}
+
+static int
+wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
+{
+    SCREEN *sp;
+    int n = -1;
+
+    T((T_CALLED("win32con::wcon_read(%p)"), TCB));
+
+    assert(buf);
+    if (okConsoleHandle(TCB)) {
+	SetSP();
+
+	n = _nc_mingw_console_read(sp, CON.inp, buf);
+    }
+    returnCode(n);
+}
+
+static int
+wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
+{
+    T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
+    Sleep((DWORD) 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)
+{
+    WORD nKey;
+    void *res;
+    bool found = FALSE;
+    LONG key = GenMap(0, (WORD) keycode);
+
+    T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
+    res = bsearch(&key,
+		  CON.rmap,
+		  (size_t) (N_INI + FKEYS),
+		  sizeof(keylist[0]),
+		  rkeycompare);
+    if (res) {
+	key = *((LONG *) res);
+	nKey = LOWORD(key);
+	if (!(nKey & 0x8000))
+	    found = TRUE;
+    }
+    returnCode(found);
+}
+
+static int
+wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
+{
+    SCREEN *sp;
+    int code = ERR;
+
+    T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
+
+    if (okConsoleHandle(TCB)) {
+	SetSP();
+
+	if (sp) {
+	    code = OK;
+	}
+    }
+    returnCode(code);
+}
+
+static int
+wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
+	   int keycode,
+	   int flag)
+{
+    int code = ERR;
+    SCREEN *sp;
+    WORD nKey;
+    WORD vKey;
+    void *res;
+    LONG key = GenMap(0, (WORD) keycode);
+
+    T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
+
+    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);
+}
+
+NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
+    FALSE,
+	wcon_name,		/* Name */
+	wcon_CanHandle,		/* CanHandle */
+	wcon_init,		/* init */
+	wcon_release,		/* release */
+	wcon_size,		/* size */
+	wcon_sgmode,		/* sgmode */
+	wcon_conattr,		/* conattr */
+	wcon_mvcur,		/* hwcur */
+	wcon_mode,		/* mode */
+	wcon_rescol,		/* rescol */
+	wcon_rescolors,		/* rescolors */
+	wcon_setcolor,		/* color */
+	wcon_dobeepflash,	/* DoBeepFlash */
+	wcon_initpair,		/* initpair */
+	wcon_initcolor,		/* initcolor */
+	wcon_do_color,		/* docolor */
+	wcon_initmouse,		/* initmouse */
+	wcon_testmouse,		/* testmouse */
+	wcon_setfilter,		/* setfilter */
+	wcon_hwlabel,		/* hwlabel */
+	wcon_hwlabelOnOff,	/* hwlabelOnOff */
+	wcon_doupdate,		/* update */
+	wcon_defaultcolors,	/* defaultcolors */
+	wcon_print,		/* print */
+	wcon_size,		/* getsize */
+	wcon_setsize,		/* setsize */
+	wcon_initacs,		/* initacs */
+	wcon_screen_init,	/* scinit */
+	wcon_wrap,		/* scexit */
+	wcon_twait,		/* twait */
+	wcon_read,		/* read */
+	wcon_nap,		/* nap */
+	wcon_kpad,		/* kpad */
+	wcon_keyok,		/* kyOk */
+	wcon_kyExist,		/* kyExist */
+	wcon_cursorSet		/* cursorSet */
+};
+
+/* --------------------------------------------------------- */
+
+static HANDLE
+get_handle(int fd)
+{
+    intptr_t value = _get_osfhandle(fd);
+    return (HANDLE) value;
+}
+
+#if WINVER >= 0x0600
+/*   This function tests, whether or not the ncurses application
+     is running as a descendant of MSYS2/cygwin mintty terminal
+     application. mintty doesn't use Windows Console for it's screen
+     I/O, so the native Windows _isatty doesn't recognize it as
+     character device. But we can discover we are at the end of an
+     Pipe and can query to server side of the pipe, looking whether
+     or not this is mintty.
+ */
+static int
+_ismintty(int fd, LPHANDLE pMinTTY)
+{
+    HANDLE handle = get_handle(fd);
+    DWORD dw;
+    int code = 0;
+
+    T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
+
+    if (handle != INVALID_HANDLE_VALUE) {
+	dw = GetFileType(handle);
+	if (dw == FILE_TYPE_PIPE) {
+	    if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
+		ULONG pPid;
+		/* Requires NT6 */
+		if (GetNamedPipeServerProcessId(handle, &pPid)) {
+		    TCHAR buf[MAX_PATH];
+		    DWORD len = 0;
+		    /* These security attributes may allow us to
+		       create a remote thread in mintty to manipulate
+		       the terminal state remotely */
+		    HANDLE pHandle = OpenProcess(
+						    PROCESS_CREATE_THREAD
+						    | PROCESS_QUERY_INFORMATION
+						    | PROCESS_VM_OPERATION
+						    | PROCESS_VM_WRITE
+						    | PROCESS_VM_READ,
+						    FALSE,
+						    pPid);
+		    if (pMinTTY)
+			*pMinTTY = INVALID_HANDLE_VALUE;
+		    if (pHandle != INVALID_HANDLE_VALUE) {
+			if ((len = GetProcessImageFileName(
+							      pHandle,
+							      buf,
+							      (DWORD)
+							      array_length(buf)))) {
+			    TCHAR *pos = _tcsrchr(buf, _T('\\'));
+			    if (pos) {
+				pos++;
+				if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
+				    == 0) {
+				    if (pMinTTY)
+					*pMinTTY = pHandle;
+				    code = 1;
+				}
+			    }
+			}
+		    }
+		}
+	    }
+	}
+    }
+    returnCode(code);
+}
+#endif
+
+/*   Borrowed from ansicon project.
+     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)) {
+	result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
+    } else {
+	result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
+    }
+    return result;
+}
+
+/*   Our replacement for the systems _isatty to include also
+     a test for mintty. This is called from the NC_ISATTY macro
+     defined in curses.priv.h
+ */
+int
+_nc_mingw_isatty(int fd)
+{
+    int result = 0;
+
+#ifdef __MING32__
+#define SysISATTY(fd) _isatty(fd)
+#else
+#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
+     with the terminal escape sequences that are sent by
+     terminfo.
+ */
+int
+_nc_mingw_isconsole(int fd)
+{
+    HANDLE hdl = get_handle(fd);
+    int code = 0;
+
+    T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
+
+    code = (int) IsConsoleHandle(hdl);
+
+    returnCode(code);
+}
+
+#define TC_PROLOGUE(fd) \
+    SCREEN *sp;                                               \
+    TERMINAL *term = 0;                                       \
+    int code = ERR;                                           \
+    if (_nc_screen_chain == 0)                                \
+        return 0;                                             \
+    for (each_screen(sp)) {                                   \
+        if (sp->_term && (sp->_term->Filedes == fd)) {        \
+            term = sp->_term;                                 \
+            break;                                            \
+        }                                                     \
+    }                                                         \
+    assert(term != 0)
+
+int
+_nc_mingw_tcsetattr(
+		       int fd,
+		       int optional_action GCC_UNUSED,
+		       const struct termios *arg)
+{
+    TC_PROLOGUE(fd);
+
+    if (_nc_mingw_isconsole(fd)) {
+	DWORD dwFlag = 0;
+	HANDLE ofd = get_handle(fd);
+	if (ofd != INVALID_HANDLE_VALUE) {
+	    if (arg) {
+		if (arg->c_lflag & ICANON)
+		    dwFlag |= ENABLE_LINE_INPUT;
+		else
+		    dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
+
+		if (arg->c_lflag & ECHO)
+		    dwFlag = dwFlag | ENABLE_ECHO_INPUT;
+		else
+		    dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
+
+		if (arg->c_iflag & BRKINT)
+		    dwFlag |= ENABLE_PROCESSED_INPUT;
+		else
+		    dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
+	    }
+	    dwFlag |= ENABLE_MOUSE_INPUT;
+	    SetConsoleMode(ofd, dwFlag);
+	    code = OK;
+	}
+    }
+    if (arg)
+	term->Nttyb = *arg;
+
+    return code;
+}
+
+int
+_nc_mingw_tcgetattr(int fd, struct termios *arg)
+{
+    TC_PROLOGUE(fd);
+
+    if (_nc_mingw_isconsole(fd)) {
+	if (arg)
+	    *arg = term->Nttyb;
+    }
+    return code;
+}
+
+int
+_nc_mingw_tcflush(int fd, int queue)
+{
+    TC_PROLOGUE(fd);
+    (void) term;
+
+    if (_nc_mingw_isconsole(fd)) {
+	if (queue == TCIFLUSH) {
+	    BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
+	    if (!b)
+		return (int) GetLastError();
+	}
+    }
+    return code;
+}
+
+int
+_nc_mingw_testmouse(
+		       SCREEN *sp,
+		       HANDLE fd,
+		       int delay)
+{
+    int rc = 0;
+
+    assert(sp);
+
+    if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
+	rc = TW_MOUSE;
+    } else {
+	rc = console_twait(sp,
+			   fd,
+			   TWAIT_MASK,
+			   delay,
+			   (int *) 0
+			   EVENTLIST_2nd(evl));
+    }
+    return rc;
+}
+
+int
+_nc_mingw_console_read(
+			  SCREEN *sp,
+			  HANDLE fd,
+			  int *buf)
+{
+    int rc = -1;
+    INPUT_RECORD inp_rec;
+    BOOL b;
+    DWORD nRead;
+    WORD vk;
+
+    assert(sp);
+    assert(buf);
+
+    memset(&inp_rec, 0, sizeof(inp_rec));
+
+    T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
+
+    while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
+	if (b && nRead > 0) {
+	    if (rc < 0)
+		rc = 0;
+	    rc += 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) {
+		    int key = MapKey(vk);
+		    if (key < 0)
+			continue;
+		    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)) {
+		    *buf = KEY_MOUSE;
+		    break;
+		}
+	    }
+	    continue;
+	}
+    }
+    returnCode(rc);
+}
+
+static bool
+InitConsole(void)
+{
+    /* initalize once, or not at all */
+    if (!console_initialized) {
+	int i;
+	DWORD num_buttons;
+	WORD a;
+	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) {
+		CON.rmap[i] = CON.map[i] =
+		    (DWORD) keylist[i];
+		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]),
+	      keycompare);
+	qsort(CON.rmap,
+	      (size_t) (MAPSIZE),
+	      sizeof(keylist[0]),
+	      rkeycompare);
+
+	if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
+	    CON.numButtons = (int) num_buttons;
+	} else {
+	    CON.numButtons = 1;
+	}
+
+	a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
+	for (i = 0; i < NUMPAIRS; i++)
+	    CON.pairs[i] = a;
+
+	CON.inp = GetStdHandle(STD_INPUT_HANDLE);
+	CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
+
+	b = AllocConsole();
+
+	if (!b)
+	    b = AttachConsole(ATTACH_PARENT_PROCESS);
+
+	if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
+	    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,
+						CONSOLE_TEXTMODE_BUFFER,
+						NULL);
+	}
+
+	if (CON.hdl != INVALID_HANDLE_VALUE) {
+	    CON.buffered = buffered;
+	    get_SBI();
+	    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