]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/win32con/win_driver.c
ncurses 5.9 - patch 20141220
[ncurses.git] / ncurses / win32con / win_driver.c
index 02cd378c9e2e4079d7ac2b29200bbfa0a3b7ea5c..f142a9456346b4c4bc7ade15d6d9884dd3fd4fa2 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright (c) 1998-2010,2012 Free Software Foundation, Inc.              *
+ * Copyright (c) 1998-2013,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            *
 
 /****************************************************************************
  *  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.14 2012/09/22 19:15:14 tom Exp $")
+MODULE_ID("$Id: win_driver.c,v 1.52 2014/10/25 00:24:24 tom Exp $")
+
+#ifndef __GNUC__
+#  error We need GCC to compile for MinGW
+#endif
 
 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
 
-#define AssertTCB() assert(TCB!=0 && TCB->magic==WINMAGIC)
-#define SetSP() assert(TCB->csp!=0); sp = TCB->csp; (void) sp
+#define EXP_OPTIMIZE 0
+
+#define array_length(a) (sizeof(a)/sizeof(a[0]))
+
+#define okConsoleHandle(TCB) (TCB != 0 && CON.hdl != INVALID_HANDLE_VALUE)
+
+#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),
@@ -60,31 +96,40 @@ static const LONG keylist[] =
     GenMap(VK_DELETE, KEY_DC),
     GenMap(VK_INSERT, KEY_IC)
 };
-#define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0])))
+#define N_INI ((int)array_length(keylist))
 #define FKEYS 24
 #define MAPSIZE (FKEYS + N_INI)
 #define NUMPAIRS 64
 
-typedef struct props {
-    CONSOLE_SCREEN_BUFFER_INFO SBI;
-    bool progMode;
+/*   A process can only have a single console, so it's save
+     to maintain all the information about it in a single
+     static scructure.
+ */
+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 map[MAPSIZE];
     DWORD rmap[MAPSIZE];
     WORD pairs[NUMPAIRS];
-} Properties;
-
-#define PropOf(TCB) ((Properties*)TCB->prop)
+    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;
 
-int
-_nc_mingw_ioctl(int fd GCC_UNUSED,
-               long int request GCC_UNUSED,
-               struct termios *arg GCC_UNUSED)
-{
-    return 0;
-    endwin();
-    fprintf(stderr, "TERMINFO currently not supported on Windows.\n");
-    exit(1);
-}
+static BOOL console_initialized = FALSE;
 
 static WORD
 MapColor(bool fore, int color)
@@ -101,29 +146,32 @@ MapColor(bool fore, int color)
     return (WORD) a;
 }
 
+#define RevAttr(attr) \
+              (WORD) (((attr) & 0xff00) | \
+                     ((((attr) & 0x07) << 4) | \
+                      (((attr) & 0x70) >> 4)))
+
 static WORD
-MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch)
+MapAttr(WORD res, attr_t ch)
 {
     if (ch & A_COLOR) {
        int p;
-       SCREEN *sp;
 
-       AssertTCB();
-       SetSP();
        p = PairNumber(ch);
-       if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
+       if (p > 0 && p < NUMPAIRS) {
            WORD a;
-           a = PropOf(TCB)->pairs[p];
-           res = (res & 0xff00) | a;
+           a = CON.pairs[p];
+           res = (WORD) ((res & 0xff00) | a);
        }
     }
 
-    if (ch & A_REVERSE)
-       res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4)));
+    if (ch & A_REVERSE) {
+       res = RevAttr(res);
+    }
 
-    if (ch & A_STANDOUT)
-       res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4))
-              | BACKGROUND_INTENSITY);
+    if (ch & A_STANDOUT) {
+       res = RevAttr(res) | BACKGROUND_INTENSITY;
+    }
 
     if (ch & A_BOLD)
        res |= FOREGROUND_INTENSITY;
@@ -134,18 +182,71 @@ MapAttr(TERMINAL_CONTROL_BLOCK * TCB, 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 n)
+con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
 {
-    CHAR_INFO ci[n];
+    int actual = 0;
+    CHAR_INFO ci[limit];
     COORD loc, siz;
     SMALL_RECT rec;
     int i;
@@ -153,43 +254,41 @@ con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int n)
     SCREEN *sp;
 
     AssertTCB();
-
-    if (TCB == 0 || InvalidConsoleHandle(TCB->hdl))
-       return FALSE;
-
     SetSP();
 
-    for (i = 0; i < n; i++) {
+    for (i = actual = 0; i < limit; i++) {
        ch = str[i];
-       ci[i].Char.UnicodeChar = CharOf(ch);
-       ci[i].Attributes = MapAttr(TCB,
-                                  PropOf(TCB)->SBI.wAttributes,
-                                  AttrOf(ch));
+       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[i].Char.UnicodeChar = CharOf(_nc_wacs[which]);
+                   ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
                } else {
-                   ci[i].Char.UnicodeChar = ' ';
+                   ci[actual].Char.UnicodeChar = ' ';
                }
            }
        }
+       ++actual;
     }
 
-    loc.X = (short) 0;
-    loc.Y = (short) 0;
-    siz.X = (short) n;
+    loc.X = (SHORT) 0;
+    loc.Y = (SHORT) 0;
+    siz.X = (SHORT) actual;
     siz.Y = 1;
 
-    rec.Left = (short) x;
-    rec.Top = (short) y;
-    rec.Right = (short) (x + n - 1);
+    rec.Left = (SHORT) x;
+    rec.Top = (SHORT) (y + AdjustY());
+    rec.Right = (SHORT) (x + limit - 1);
     rec.Bottom = rec.Top;
 
-    return WriteConsoleOutputW(TCB->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
@@ -204,22 +303,17 @@ con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
     SCREEN *sp;
 
     AssertTCB();
-
-    if (TCB == 0 || InvalidConsoleHandle(TCB->hdl))
-       return FALSE;
-
     SetSP();
 
     for (i = 0; i < n; i++) {
        ch = str[i];
        ci[i].Char.AsciiChar = ChCharOf(ch);
-       ci[i].Attributes = MapAttr(TCB,
-                                  PropOf(TCB)->SBI.wAttributes,
+       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)));
+               ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
        }
     }
 
@@ -233,70 +327,223 @@ 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(TCB->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
 
+#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
-drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
 {
+    int result = ERR;
     int y, nonempty, n, x0, x1, Width, Height;
     SCREEN *sp;
 
     AssertTCB();
     SetSP();
 
-    Width = screen_columns(sp);
-    Height = screen_lines(sp);
-    nonempty = min(Height, NewScreen(sp)->_maxy + 1);
+    T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
+    if (okConsoleHandle(TCB)) {
+
+       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);
 
-    if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
-       int x;
+           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);
+           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];
+           chtype empty[Width];
 
-       for (x = 0; x < Width; x++)
-           empty[x] = ' ';
+           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,
-                  Width * sizeof(empty[0]));
+           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()));
        }
-       CurScreen(sp)->_clear = FALSE;
-       NewScreen(sp)->_clear = FALSE;
-       touchwin(NewScreen(sp));
-    }
 
-    for (y = 0; y < nonempty; y++) {
-       x0 = NewScreen(sp)->_line[y].firstchar;
-       if (x0 != _NOCHANGE) {
-           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],
-                      n * sizeof(CurScreen(sp)->_line[y].text[x0]));
-               con_write(TCB,
-                         y,
-                         x0,
-                         &CurScreen(sp)->_line[y].text[x0], n);
+       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) {
@@ -305,95 +552,160 @@ drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
                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);
-    }
+       /* 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;
+       if (!NewScreen(sp)->_leaveok) {
+           CurScreen(sp)->_curx = NewScreen(sp)->_curx;
+           CurScreen(sp)->_cury = NewScreen(sp)->_cury;
 
-       TCB->drv->hwcur(TCB, 0, 0, CurScreen(sp)->_cury, CurScreen(sp)->_curx);
+           TCB->drv->td_hwcur(TCB,
+                              0, 0,
+                              CurScreen(sp)->_cury, CurScreen(sp)->_curx);
+       }
+       selectActiveHandle();
+       result = OK;
     }
-    SetConsoleActiveScreenBuffer(TCB->hdl);
-    return OK;
+    returnCode(result);
 }
 
 static bool
-drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
-             const char *tname,
-             int *errret GCC_UNUSED)
+wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
+              const char *tname,
+              int *errret GCC_UNUSED)
 {
     bool code = FALSE;
 
-    T((T_CALLED("win32con::drv_CanHandle(%p)"), TCB));
+    T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
 
-    assert(TCB != 0);
-    assert(tname != 0);
+    assert((TCB != 0) && (tname != 0));
 
     TCB->magic = WINMAGIC;
-    if (*tname == 0 || *tname == 0 || *tname == '#') {
-       code = TRUE;
-    } else {
-       TERMINAL my_term;
-       int status;
 
-       code = FALSE;
-#if (USE_DATABASE || USE_TERMCAP)
-       status = _nc_setup_tinfo(tname, &my_term.type);
-#else
-       status = TGETENT_NO;
-#endif
-       if (status != TGETENT_YES) {
-           const TERMTYPE *fallback = _nc_fallback(tname);
-
-           if (fallback) {
-               my_term.type = *fallback;
-               status = TGETENT_YES;
-           } else if (!strcmp(tname, "unknown")) {
-               code = TRUE;
-           }
-       }
-       if (status == TGETENT_YES) {
-           if (generic_type || hard_copy)
-               code = TRUE;
+    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;
     }
 
-    if (code) {
-       if ((TCB->term.type.Booleans) == 0) {
-           _nc_init_entry(&(TCB->term.type));
-       }
+    /*
+     * 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
-drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
-               int beepFlag GCC_UNUSED)
+wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
+                int beepFlag)
 {
     SCREEN *sp;
-    int res = ERR;
+    int res = OK;
+
+    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;
 
     AssertTCB();
+
     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 */
+    }
     return res;
 }
 
 static int
-drv_print(TERMINAL_CONTROL_BLOCK * TCB,
-         char *data GCC_UNUSED,
-         int len GCC_UNUSED)
+wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
+          char *data GCC_UNUSED,
+          int len GCC_UNUSED)
 {
     SCREEN *sp;
 
@@ -404,9 +716,9 @@ drv_print(TERMINAL_CONTROL_BLOCK * TCB,
 }
 
 static int
-drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
-                 int fg GCC_UNUSED,
-                 int bg GCC_UNUSED)
+wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
+                  int fg GCC_UNUSED,
+                  int bg GCC_UNUSED)
 {
     SCREEN *sp;
     int code = ERR;
@@ -417,39 +729,73 @@ drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
     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
-drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
-            int fore,
-            int color,
-            int (*outc) (SCREEN *, int) GCC_UNUSED)
+wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
+             int fore,
+             int color,
+             int (*outc) (SCREEN *, int) GCC_UNUSED)
 {
     AssertTCB();
 
-    if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+    if (okConsoleHandle(TCB)) {
        WORD a = MapColor(fore, color);
-       a = ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)) | a;
-       SetConsoleTextAttribute(TCB->hdl, a);
-       GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+       a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
+       SetConsoleTextAttribute(CON.hdl, a);
+       get_SBI();
     }
 }
 
 static bool
-drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
 {
     bool res = FALSE;
 
     AssertTCB();
-    if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+    if (okConsoleHandle(TCB)) {
        WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
-       SetConsoleTextAttribute(TCB->hdl, a);
-       GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+       SetConsoleTextAttribute(CON.hdl, a);
+       get_SBI();
        res = TRUE;
     }
     return res;
 }
 
 static bool
-drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
 {
     int result = FALSE;
     SCREEN *sp;
@@ -461,29 +807,42 @@ drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
 }
 
 static int
-drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
+wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
 {
+    int result = ERR;
+
     AssertTCB();
 
-    if (TCB == NULL || Lines == NULL || Cols == NULL || InvalidConsoleHandle(TCB->hdl))
-       return ERR;
+    T((T_CALLED("win32con::wcon_size(%p)"), TCB));
 
-    *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
-    *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
-    return OK;
+    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
-drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
-           int l GCC_UNUSED,
-           int c GCC_UNUSED)
+wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
+            int l GCC_UNUSED,
+            int c GCC_UNUSED)
 {
     AssertTCB();
     return ERR;
 }
 
 static int
-drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
+wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
 {
     DWORD dwFlag = 0;
     tcflag_t iflag;
@@ -498,48 +857,48 @@ drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
        iflag = buf->c_iflag;
        lflag = buf->c_lflag;
 
-       GetConsoleMode(TCB->inp, &dwFlag);
+       GetConsoleMode(CON.inp, &dwFlag);
 
        if (lflag & ICANON)
            dwFlag |= ENABLE_LINE_INPUT;
        else
-           dwFlag &= ~ENABLE_LINE_INPUT;
+           dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
 
        if (lflag & ECHO)
            dwFlag |= ENABLE_ECHO_INPUT;
        else
-           dwFlag &= ~ENABLE_ECHO_INPUT;
+           dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
 
        if (iflag & BRKINT)
            dwFlag |= ENABLE_PROCESSED_INPUT;
        else
-           dwFlag &= ~ENABLE_PROCESSED_INPUT;
+           dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
 
        dwFlag |= ENABLE_MOUSE_INPUT;
 
        buf->c_iflag = iflag;
        buf->c_lflag = lflag;
-       SetConsoleMode(TCB->inp, dwFlag);
+       SetConsoleMode(CON.inp, dwFlag);
        TCB->term.Nttyb = *buf;
     } else {
        iflag = TCB->term.Nttyb.c_iflag;
        lflag = TCB->term.Nttyb.c_lflag;
-       GetConsoleMode(TCB->inp, &dwFlag);
+       GetConsoleMode(CON.inp, &dwFlag);
 
        if (dwFlag & ENABLE_LINE_INPUT)
            lflag |= ICANON;
        else
-           lflag &= ~ICANON;
+           lflag &= (tcflag_t) (~ICANON);
 
        if (dwFlag & ENABLE_ECHO_INPUT)
            lflag |= ECHO;
        else
-           lflag &= ~ECHO;
+           lflag &= (tcflag_t) (~ECHO);
 
        if (dwFlag & ENABLE_PROCESSED_INPUT)
            iflag |= BRKINT;
        else
-           iflag &= ~BRKINT;
+           iflag &= (tcflag_t) (~BRKINT);
 
        TCB->term.Nttyb.c_iflag = iflag;
        TCB->term.Nttyb.c_lflag = lflag;
@@ -549,8 +908,86 @@ drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
     return OK;
 }
 
+#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
-drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
+wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
 {
     SCREEN *sp;
     TERMINAL *_term = (TERMINAL *) TCB;
@@ -559,30 +996,35 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
     AssertTCB();
     sp = TCB->csp;
 
-    PropOf(TCB)->progMode = progFlag;
-    SetConsoleActiveScreenBuffer(progFlag ? TCB->hdl : TCB->out);
+    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 ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
-               _term->Nttyb.c_oflag &= ~OFLAGS_TABS;
+           if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
+               _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
                code = OK;
            }
        } else {
            /* reset_prog_mode */
-           if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
+           if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
                if (sp) {
                    if (sp->_keypad_on)
                        _nc_keypad(sp, TRUE);
-                   NC_BUFFERED(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 (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
+           if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
                code = OK;
            }
        } else {
@@ -590,22 +1032,27 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
            if (sp) {
                _nc_keypad(sp, FALSE);
                NCURSES_SP_NAME(_nc_flush) (sp);
-               NC_BUFFERED(sp, FALSE);
            }
-           code = drv_sgmode(TCB, TRUE, &(_term->Ottyb));
+           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
-drv_screen_init(SCREEN *sp GCC_UNUSED)
+wcon_screen_init(SCREEN *sp GCC_UNUSED)
 {
 }
 
 static void
-drv_wrap(SCREEN *sp GCC_UNUSED)
+wcon_wrap(SCREEN *sp GCC_UNUSED)
 {
 }
 
@@ -628,17 +1075,15 @@ keycompare(const void *el1, const void *el2)
 }
 
 static int
-MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
+MapKey(WORD vKey)
 {
     WORD nKey = 0;
     void *res;
     LONG key = GenMap(vKey, 0);
     int code = -1;
 
-    AssertTCB();
-
     res = bsearch(&key,
-                 PropOf(TCB)->map,
+                 CON.map,
                  (size_t) (N_INI + FKEYS),
                  sizeof(keylist[0]),
                  keycompare);
@@ -653,9 +1098,9 @@ MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
 }
 
 static void
-drv_release(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
 {
-    T((T_CALLED("win32con::drv_release(%p)"), TCB));
+    T((T_CALLED("win32con::wcon_release(%p)"), TCB));
 
     AssertTCB();
     if (TCB->prop)
@@ -664,38 +1109,96 @@ drv_release(TERMINAL_CONTROL_BLOCK * TCB)
     returnVoid;
 }
 
-static void
-drv_init(TERMINAL_CONTROL_BLOCK * TCB)
+static bool
+read_screen_data(void)
 {
-    DWORD num_buttons;
+    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);
+       }
+    }
 
-    T((T_CALLED("win32con::drv_init(%p)"), TCB));
+    return result;
+}
 
-    AssertTCB();
+/*
+ * 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;
 
-    if (TCB) {
-       BOOL b = AllocConsole();
-       WORD a;
-       int i;
+    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 (!b)
-           b = AttachConsole(ATTACH_PARENT_PROCESS);
+    if (read_screen_data()) {
+       result = TRUE;
+    } else {
 
-       TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
-       TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
+       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;
 
-       if (getenv("NCGDB"))
-           TCB->hdl = TCB->out;
-       else
-           TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
-                                                0,
-                                                NULL,
-                                                CONSOLE_TEXTMODE_BUFFER,
-                                                NULL);
-
-       if (!InvalidConsoleHandle(TCB->hdl)) {
-           TCB->prop = typeCalloc(Properties, 1);
-           GetConsoleScreenBufferInfo(TCB->hdl, &(PropOf(TCB)->SBI));
+       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 (CON.hdl == INVALID_HANDLE_VALUE) {
+           returnVoid;
        }
 
        TCB->info.initcolor = TRUE;
@@ -711,43 +1214,18 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
        TCB->info.nocolorvideo = 1;
        TCB->info.tabsize = 8;
 
-       if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
-           T(("mouse has %ld buttons", num_buttons));
-           TCB->info.numbuttons = num_buttons;
-       } else {
-           TCB->info.numbuttons = 1;
-       }
-
+       TCB->info.numbuttons = CON.numButtons;
        TCB->info.defaultPalette = _nc_cga_palette;
 
-       for (i = 0; i < (N_INI + FKEYS); i++) {
-           if (i < N_INI)
-               PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = keylist[i];
-           else
-               PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
-                   GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
-       }
-       qsort(PropOf(TCB)->map,
-             (size_t) (MAPSIZE),
-             sizeof(keylist[0]),
-             keycompare);
-       qsort(PropOf(TCB)->rmap,
-             (size_t) (MAPSIZE),
-             sizeof(keylist[0]),
-             rkeycompare);
-
-       a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
-       for (i = 0; i < NUMPAIRS; i++)
-           PropOf(TCB)->pairs[i] = a;
     }
     returnVoid;
 }
 
 static void
-drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
-            int pair,
-            int f,
-            int b)
+wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
+             int pair,
+             int f,
+             int b)
 {
     SCREEN *sp;
 
@@ -756,16 +1234,16 @@ drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
 
     if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
        && (b >= 0) && (b < 8)) {
-       PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b);
+       CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
     }
 }
 
 static void
-drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
-             int color GCC_UNUSED,
-             int r GCC_UNUSED,
-             int g GCC_UNUSED,
-             int b GCC_UNUSED)
+wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
+              int color GCC_UNUSED,
+              int r GCC_UNUSED,
+              int g GCC_UNUSED,
+              int b GCC_UNUSED)
 {
     SCREEN *sp;
 
@@ -774,11 +1252,11 @@ drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
 }
 
 static void
-drv_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
+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;
@@ -788,7 +1266,7 @@ drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
 }
 
 static void
-drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
 {
     SCREEN *sp;
 
@@ -799,7 +1277,7 @@ drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
 }
 
 static int
-drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
+wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
 {
     int rc = 0;
     SCREEN *sp;
@@ -810,36 +1288,36 @@ drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
     if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
        rc = TW_MOUSE;
     } else {
-       rc = TCBOf(sp)->drv->twait(TCBOf(sp),
-                                  TWAIT_MASK,
-                                  delay,
-                                  (int *) 0
-                                  EVENTLIST_2nd(evl));
+       rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
+                                     TWAIT_MASK,
+                                     delay,
+                                     (int *) 0
+                                     EVENTLIST_2nd(evl));
     }
 
     return rc;
 }
 
 static int
-drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
-         int yold GCC_UNUSED, int xold GCC_UNUSED,
-         int y, int x)
+wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
+          int yold GCC_UNUSED, int xold GCC_UNUSED,
+          int y, int x)
 {
     int ret = ERR;
-    if (TCB && !InvalidConsoleHandle(TCB->hdl)) {
+    if (okConsoleHandle(TCB)) {
        COORD loc;
        loc.X = (short) x;
-       loc.Y = (short) y;
-       SetConsoleCursorPosition(TCB->hdl, loc);
+       loc.Y = (short) (y + AdjustY());
+       SetConsoleCursorPosition(CON.hdl, loc);
        ret = OK;
     }
     return ret;
 }
 
 static void
-drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
-           int labnum GCC_UNUSED,
-           char *text GCC_UNUSED)
+wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
+            int labnum GCC_UNUSED,
+            char *text GCC_UNUSED)
 {
     SCREEN *sp;
 
@@ -848,8 +1326,8 @@ drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
 }
 
 static void
-drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
-                int OnFlag GCC_UNUSED)
+wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
+                 int OnFlag GCC_UNUSED)
 {
     SCREEN *sp;
 
@@ -858,7 +1336,7 @@ drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
 }
 
 static chtype
-drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
+wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
 {
     chtype res = A_NORMAL;
     res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
@@ -866,7 +1344,7 @@ drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
 }
 
 static void
-drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
+wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
 {
     SCREEN *sp;
 
@@ -875,9 +1353,9 @@ drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
 }
 
 static void
-drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
-           chtype *real_map GCC_UNUSED,
-           chtype *fake_map GCC_UNUSED)
+wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
+            chtype *real_map GCC_UNUSED,
+            chtype *fake_map GCC_UNUSED)
 {
 #define DATA(a,b) { a, b }
     static struct {
@@ -915,7 +1393,7 @@ drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
     SetSP();
 
     for (n = 0; n < SIZEOF(table); ++n) {
-       real_map[table[n].acs_code] = table[n].use_code | A_ALTCHARSET;
+       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;
     }
@@ -940,11 +1418,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;
 }
 
@@ -955,13 +1433,12 @@ Adjust(int milliseconds, int diff)
                     RIGHTMOST_BUTTON_PRESSED)
 
 static int
-decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
+decode_mouse(SCREEN *sp, int mask)
 {
-    SCREEN *sp;
     int result = 0;
 
-    AssertTCB();
-    SetSP();
+    (void) sp;
+    assert(sp && console_initialized);
 
     if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
        result |= BUTTON1_PRESSED;
@@ -973,7 +1450,7 @@ decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
        result |= BUTTON4_PRESSED;
 
     if (mask & RIGHTMOST_BUTTON_PRESSED) {
-       switch (TCB->info.numbuttons) {
+       switch (CON.numButtons) {
        case 1:
            result |= BUTTON1_PRESSED;
            break;
@@ -993,26 +1470,26 @@ decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
 }
 
 static int
-drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
-         int mode,
-         int milliseconds,
-         int *timeleft
-         EVENTLIST_2nd(_nc_eventlist * evl))
+console_twait(
+                SCREEN *sp,
+                HANDLE fd,
+                int mode,
+                int milliseconds,
+                int *timeleft
+                EVENTLIST_2nd(_nc_eventlist * evl))
 {
-    SCREEN *sp;
     INPUT_RECORD inp_rec;
     BOOL b;
-    DWORD nRead = 0, rc = -1;
+    DWORD nRead = 0, rc = (DWORD) (-1);
     int code = 0;
     FILETIME fstart;
     FILETIME fend;
     int diff;
     bool isImmed = (milliseconds == 0);
 
-#define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead)
+#define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
 
-    AssertTCB();
-    SetSP();
+    assert(sp);
 
     TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
                      milliseconds, mode));
@@ -1024,19 +1501,19 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
 
     while (true) {
        GetSystemTimeAsFileTime(&fstart);
-       rc = WaitForSingleObject(TCB->inp, milliseconds);
+       rc = WaitForSingleObject(fd, (DWORD) milliseconds);
        GetSystemTimeAsFileTime(&fend);
        diff = (int) tdiff(fstart, fend);
        milliseconds = Adjust(milliseconds, diff);
 
-       if (!isImmed && milliseconds == 0)
+       if (!isImmed && milliseconds <= 0)
            break;
 
        if (rc == WAIT_OBJECT_0) {
            if (mode) {
-               b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
+               b = GetNumberOfConsoleInputEvents(fd, &nRead);
                if (b && nRead > 0) {
-                   b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead);
+                   b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
                    if (b && nRead > 0) {
                        switch (inp_rec.EventType) {
                        case KEY_EVENT:
@@ -1046,7 +1523,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
 
                                if (inp_rec.Event.KeyEvent.bKeyDown) {
                                    if (0 == ch) {
-                                       int nKey = MapKey(TCB, vk);
+                                       int nKey = MapKey(vk);
                                        if ((nKey < 0) || FALSE == sp->_keypad_on) {
                                            CONSUME();
                                            continue;
@@ -1060,7 +1537,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
                            }
                            continue;
                        case MOUSE_EVENT:
-                           if (decode_mouse(TCB,
+                           if (decode_mouse(sp,
                                             (inp_rec.Event.MouseEvent.dwButtonState
                                              & BUTTON_MASK)) == 0) {
                                CONSUME();
@@ -1069,9 +1546,10 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
                                goto end;
                            }
                            continue;
+                           /* e.g., FOCUS_EVENT */
                        default:
-                           SetConsoleActiveScreenBuffer(!PropOf(TCB)->progMode ?
-                                                        TCB->hdl : TCB->out);
+                           CONSUME();
+                           selectActiveHandle();
                            continue;
                        }
                    }
@@ -1099,16 +1577,35 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
     return code;
 }
 
-static bool
-handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
+static int
+wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
+          int mode,
+          int milliseconds,
+          int *timeleft
+          EVENTLIST_2nd(_nc_eventlist * evl))
 {
     SCREEN *sp;
-    MEVENT work;
-    bool result = FALSE;
+    int code;
 
     AssertTCB();
     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;
 
@@ -1122,18 +1619,20 @@ handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
 
        if (sp->_drv_mouse_new_buttons) {
 
-           work.bstate |= decode_mouse(TCB, 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 |= (decode_mouse(TCB, sp->_drv_mouse_old_buttons) >> 1);
+           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;
+       work.y = mer.dwMousePosition.Y - AdjustY();
 
        sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
        sp->_drv_mouse_tail += 1;
@@ -1143,76 +1642,59 @@ handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
 }
 
 static int
-drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
+wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
 {
     SCREEN *sp;
-    int n = 1;
-    INPUT_RECORD inp_rec;
-    BOOL b;
-    DWORD nRead;
-    WORD vk;
+    int n;
 
     AssertTCB();
     assert(buf);
     SetSP();
 
-    memset(&inp_rec, 0, sizeof(inp_rec));
-
-    T((T_CALLED("win32con::drv_read(%p)"), TCB));
-    while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) {
-       if (b && nRead > 0) {
-           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;
-               if (*buf == 0) {
-                   if (sp->_keypad_on) {
-                       *buf = MapKey(TCB, vk);
-                       if (0 > (*buf))
-                           continue;
-                       else
-                           break;
-                   } else
-                       continue;
-               } else {        /* *buf != 0 */
-                   break;
-               }
-           } else if (inp_rec.EventType == MOUSE_EVENT) {
-               if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) {
-                   *buf = KEY_MOUSE;
-                   break;
-               }
-           }
-           continue;
-       }
-    }
+    T((T_CALLED("win32con::wcon_read(%p)"), TCB));
+    n = _nc_mingw_console_read(sp, CON.inp, buf);
     returnCode(n);
 }
 
 static int
-drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
+wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
 {
-    Sleep(ms);
-    return OK;
+    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;
+    CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
+    T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
+    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
-drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
+wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
 {
-    SCREEN *sp;
     WORD nKey;
     void *res;
     bool found = FALSE;
     LONG key = GenMap(0, (WORD) keycode);
 
-    AssertTCB();
-    SetSP();
-
-    AssertTCB();
-
+    T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
     res = bsearch(&key,
-                 PropOf(TCB)->rmap,
+                 CON.rmap,
                  (size_t) (N_INI + FKEYS),
                  sizeof(keylist[0]),
                  rkeycompare);
@@ -1222,26 +1704,29 @@ drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
        if (!(nKey & 0x8000))
            found = TRUE;
     }
-    return found;
+    returnCode(found);
 }
 
 static int
-drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
+wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
 {
     SCREEN *sp;
     int code = ERR;
 
     AssertTCB();
-    sp = TCB->csp;
+    SetSP();
 
+    T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
     if (sp) {
        code = OK;
     }
-    return code;
+    returnCode(code);
 }
 
 static int
-drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
+wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
+          int keycode,
+          int flag)
 {
     int code = ERR;
     SCREEN *sp;
@@ -1250,12 +1735,14 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
     void *res;
     LONG key = GenMap(0, (WORD) keycode);
 
+    T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
+
     AssertTCB();
     SetSP();
 
     if (sp) {
        res = bsearch(&key,
-                     PropOf(TCB)->rmap,
+                     CON.rmap,
                      (size_t) (N_INI + FKEYS),
                      sizeof(keylist[0]),
                      rkeycompare);
@@ -1268,43 +1755,419 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
            *(LONG *) res = GenMap(vKey, nKey);
        }
     }
-    return code;
+    returnCode(code);
 }
 
 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
     FALSE,
-       drv_CanHandle,          /* CanHandle */
-       drv_init,               /* init */
-       drv_release,            /* release */
-       drv_size,               /* size */
-       drv_sgmode,             /* sgmode */
-       drv_conattr,            /* conattr */
-       drv_mvcur,              /* hwcur */
-       drv_mode,               /* mode */
-       drv_rescol,             /* rescol */
-       drv_rescolors,          /* rescolors */
-       drv_setcolor,           /* color */
-       drv_dobeepflash,        /* DoBeepFlash */
-       drv_initpair,           /* initpair */
-       drv_initcolor,          /* initcolor */
-       drv_do_color,           /* docolor */
-       drv_initmouse,          /* initmouse */
-       drv_testmouse,          /* testmouse */
-       drv_setfilter,          /* setfilter */
-       drv_hwlabel,            /* hwlabel */
-       drv_hwlabelOnOff,       /* hwlabelOnOff */
-       drv_doupdate,           /* update */
-       drv_defaultcolors,      /* defaultcolors */
-       drv_print,              /* print */
-       drv_size,               /* getsize */
-       drv_setsize,            /* setsize */
-       drv_initacs,            /* initacs */
-       drv_screen_init,        /* scinit */
-       drv_wrap,               /* scexit */
-       drv_twait,              /* twait */
-       drv_read,               /* read */
-       drv_nap,                /* nap */
-       drv_kpad,               /* kpad */
-       drv_keyok,              /* kyOk */
-       drv_kyExist             /* kyExist */
+       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 n = 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 (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;
+               if (*buf == 0) {
+                   if (sp->_keypad_on) {
+                       *buf = MapKey(vk);
+                       if (0 > (*buf))
+                           continue;
+                       else
+                           break;
+                   } else
+                       continue;
+               } else {        /* *buf != 0 */
+                   break;
+               }
+           } else if (inp_rec.EventType == MOUSE_EVENT) {
+               if (handle_mouse(sp,
+                                inp_rec.Event.MouseEvent)) {
+                   *buf = KEY_MOUSE;
+                   break;
+               }
+           }
+           continue;
+       }
+    }
+    returnCode(n);
+}
+
+static
+__attribute__((constructor))
+     void _enter_console(void)
+{
+    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];
+           else
+               CON.rmap[i] = CON.map[i] =
+                   (DWORD) GenMap((VK_F1 + (i - N_INI)),
+                                  (KEY_F(1) + (i - N_INI)));
+       }
+       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;
+    }
+}