]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/win32con/win32_driver.c
ncurses 6.2 - patch 20200829
[ncurses.git] / ncurses / win32con / win32_driver.c
diff --git a/ncurses/win32con/win32_driver.c b/ncurses/win32con/win32_driver.c
new file mode 100644 (file)
index 0000000..9797cdb
--- /dev/null
@@ -0,0 +1,1218 @@
+/****************************************************************************
+ * Copyright 2018,2020 Thomas E. Dickey                                     *
+ * Copyright 2008-2016,2017 Free Software Foundation, Inc.                  *
+ *                                                                          *
+ * Permission is hereby granted, free of charge, to any person obtaining a  *
+ * copy of this software and associated documentation files (the            *
+ * "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 - 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 _NC_WINDOWS
+#if (defined(__MINGW32__) || defined(__MINGW64__))
+#include <wchar.h>
+#else
+#include <tchar.h>
+#endif
+#include <io.h>
+
+#define CUR TerminalType(my_term).
+
+MODULE_ID("$Id: win32_driver.c,v 1.1 2020/08/29 19:26:24 tom Exp $")
+
+#define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
+#define EXP_OPTIMIZE 0
+
+static bool console_initialized = FALSE;
+
+#define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
+#define validateConsoleHandle() (AssertTCB() , console_initialized ||\
+                                 (console_initialized=\
+                                  _nc_console_checkinit(TRUE,FALSE)))
+#define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
+#define AdjustY() (WINCONSOLE.buffered ?\
+                   0 : (int) WINCONSOLE.SBI.srWindow.Top)
+#define RevAttr(attr) (WORD) (((attr) & 0xff00) |   \
+                              ((((attr) & 0x07) << 4) | \
+                               (((attr) & 0x70) >> 4)))
+
+#if USE_WIDEC_SUPPORT
+#define write_screen WriteConsoleOutputW
+#define read_screen  ReadConsoleOutputW
+#else
+#define write_screen WriteConsoleOutput
+#define read_screen  ReadConsoleOutput
+#endif
+
+static WORD
+MapAttr(WORD res, attr_t ch)
+{
+    if (ch & A_COLOR) {
+       int p;
+
+       p = PairNumber(ch);
+       if (p > 0 && p < CON_NUMPAIRS) {
+           WORD a;
+           a = WINCONSOLE.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 = (WINCONSOLE.SBI.dwSize.Y *
+                    (1 + WINCONSOLE.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 = WINCONSOLE.SBI.srWindow.Top;
+    save_region.Left = WINCONSOLE.SBI.srWindow.Left;
+    save_region.Bottom = WINCONSOLE.SBI.srWindow.Bottom;
+    save_region.Right = WINCONSOLE.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(WINCONSOLE.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 = TypeAlloca(CHAR_INFO, 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(WINCONSOLE.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(WINCONSOLE.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 = TypeAlloca(CHAR_INFO, 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(WINCONSOLE.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(WINCONSOLE.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 bool
+restore_original_screen(void)
+{
+    COORD bufferCoord;
+    bool result = FALSE;
+    SMALL_RECT save_region = WINCONSOLE.save_region;
+
+    T(("... restoring %s", WINCONSOLE.window_only ?
+       "window" : "entire buffer"));
+
+    bufferCoord.X = (SHORT) (WINCONSOLE.window_only ?
+                            WINCONSOLE.SBI.srWindow.Left : 0);
+    bufferCoord.Y = (SHORT) (WINCONSOLE.window_only ?
+                            WINCONSOLE.SBI.srWindow.Top : 0);
+
+    if (write_screen(WINCONSOLE.hdl,
+                    WINCONSOLE.save_screen,
+                    WINCONSOLE.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)",
+          WINCONSOLE.save_size.Y,
+          WINCONSOLE.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 (validateConsoleHandle()) {
+       SetSP();
+
+       Width = screen_columns(sp);
+       Height = screen_lines(sp);
+       nonempty = min(Height, NewScreen(sp)->_maxy + 1);
+
+       T(("... %dx%d clear cur:%d new:%d",
+          Height, Width,
+          CurScreen(sp)->_clear,
+          NewScreen(sp)->_clear));
+
+       if (SP_PARM->_endwin == ewSuspend) {
+
+           T(("coming back from shell mode"));
+           NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
+
+           NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
+           NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
+           SP_PARM->_mouse_resume(SP_PARM);
+
+           SP_PARM->_endwin = ewRunning;
+       }
+
+       if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
+           int x;
+#if USE_WIDEC_SUPPORT
+           cchar_t *empty = TypeAlloca(cchar_t, Width);
+           wchar_t blank[2] =
+           {
+               L' ', L'\0'
+           };
+
+           for (x = 0; x < Width; x++)
+               setcchar(&empty[x], blank, 0, 0, 0);
+#else
+           chtype *empty = TypeAlloca(chtype, 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);
+       }
+       _nc_console_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) {
+       if (!_nc_console_vt_supported())
+           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 && (TerminalType(&TCB->term).Booleans == 0)) {
+       _nc_init_termtype(&TerminalType(&TCB->term));
+#if NCURSES_EXT_NUMBERS
+       _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
+#endif
+    }
+
+    if (!code) {
+       if (_nc_console_test(0)) {
+           T(("isTermInfoConsole=TRUE"));
+           WINCONSOLE.isTermInfoConsole = TRUE;
+       }
+    }
+    returnBool(code);
+}
+
+static int
+wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
+                int beepFlag)
+{
+    SCREEN *sp;
+    int res = ERR;
+
+    int high = (WINCONSOLE.SBI.srWindow.Bottom -
+               WINCONSOLE.SBI.srWindow.Top + 1);
+    int wide = (WINCONSOLE.SBI.srWindow.Right -
+               WINCONSOLE.SBI.srWindow.Left + 1);
+    int max_cells = (high * wide);
+    int i;
+
+    CHAR_INFO *this_screen = TypeAlloca(CHAR_INFO, max_cells);
+    CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells);
+    COORD this_size;
+    SMALL_RECT this_region;
+    COORD bufferCoord;
+
+    if (validateConsoleHandle()) {
+       SetSP();
+       this_region.Top = WINCONSOLE.SBI.srWindow.Top;
+       this_region.Left = WINCONSOLE.SBI.srWindow.Left;
+       this_region.Bottom = WINCONSOLE.SBI.srWindow.Bottom;
+       this_region.Right = WINCONSOLE.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(WINCONSOLE.hdl,
+                       this_screen,
+                       this_size,
+                       bufferCoord,
+                       &this_region)) {
+
+           memcpy(that_screen,
+                  this_screen,
+                  sizeof(CHAR_INFO) * (size_t) max_cells);
+
+           for (i = 0; i < max_cells; i++) {
+               that_screen[i].Attributes =
+                   RevAttr(that_screen[i].Attributes);
+           }
+
+           write_screen(WINCONSOLE.hdl, that_screen, this_size,
+                        bufferCoord, &this_region);
+           Sleep(200);
+           write_screen(WINCONSOLE.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 void
+wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
+             int fore,
+             int color,
+             int (*outc) (SCREEN *, int) GCC_UNUSED)
+{
+    if (validateConsoleHandle()) {
+       WORD a = _nc_console_MapColor(fore, color);
+       a |= (WORD) ((WINCONSOLE.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
+       SetConsoleTextAttribute(WINCONSOLE.hdl, a);
+       _nc_console_get_SBI();
+    }
+}
+
+static bool
+wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    bool res = FALSE;
+
+    if (validateConsoleHandle()) {
+       WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
+       SetConsoleTextAttribute(WINCONSOLE.hdl, a);
+       _nc_console_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 (validateConsoleHandle() &&
+       (Lines != NULL) && (Cols != NULL)) {
+       _nc_console_size(Lines, Cols);
+       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)
+{
+    TERMINAL *_term = (TERMINAL *) TCB;
+    int result = ERR;
+
+    T((T_CALLED("win32con::wcon_sgmode(TCB=(%p),setFlag=%d,TTY=(%p)"),
+       TCB, setFlag, buf));
+    if (buf != NULL && validateConsoleHandle()) {
+
+       if (setFlag) {
+           _nc_console_setmode(WINCONSOLE.hdl, buf);
+           TCB->term.Nttyb = *buf;
+       } else {
+           _nc_console_getmode(WINCONSOLE.hdl, &(TCB->term.Nttyb));
+           *buf = TCB->term.Nttyb;
+       }
+       result = OK;
+    }
+    returnCode(result);
+}
+
+#define MIN_WIDE 80
+#define MIN_HIGH 24
+
+static int
+wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
+{
+    SCREEN *sp;
+    TERMINAL *_term = (TERMINAL *) TCB;
+    int code = ERR;
+
+    if (validateConsoleHandle()) {
+       sp = TCB->csp;
+
+       T((T_CALLED("win32con::wcon_mode(%p, progFlag=%d, defFlag=%d)"),
+          TCB, progFlag, defFlag));
+
+       WINCONSOLE.progMode = progFlag;
+       WINCONSOLE.lastOut = progFlag ? WINCONSOLE.hdl : WINCONSOLE.out;
+       SetConsoleActiveScreenBuffer(WINCONSOLE.lastOut);
+
+       if (progFlag) /* prog mode */  {
+           if (defFlag) {
+               if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
+                   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 (!WINCONSOLE.buffered) {
+                       _nc_console_set_scrollback(FALSE, &WINCONSOLE.SBI);
+                   }
+                   code = OK;
+               }
+           }
+           T(("... buffered:%d, clear:%d",
+              WINCONSOLE.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 (!WINCONSOLE.buffered) {
+                   _nc_console_set_scrollback(TRUE, &WINCONSOLE.save_SBI);
+                   if (!restore_original_screen())
+                       code = ERR;
+               }
+               SetConsoleCursorInfo(WINCONSOLE.hdl, &WINCONSOLE.save_CI);
+           }
+       }
+
+    }
+    returnCode(code);
+}
+
+static void
+wcon_screen_init(SCREEN *sp GCC_UNUSED)
+{
+}
+
+static void
+wcon_wrap(SCREEN *sp GCC_UNUSED)
+{
+}
+
+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 void
+wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    T((T_CALLED("win32con::wcon_init(%p)"), TCB));
+
+    AssertTCB();
+
+    if (!(console_initialized = _nc_console_checkinit(TRUE, FALSE))) {
+       returnVoid;
+    }
+
+    if (TCB) {
+       TCB->info.initcolor = TRUE;
+       TCB->info.canchange = FALSE;
+       TCB->info.hascolor = TRUE;
+       TCB->info.caninit = TRUE;
+
+       TCB->info.maxpairs = CON_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 = WINCONSOLE.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 (validateConsoleHandle()) {
+       SetSP();
+
+       if ((pair > 0) && (pair < CON_NUMPAIRS) && (f >= 0) && (f < 8)
+           && (b >= 0) && (b < 8)) {
+           WINCONSOLE.pairs[pair] =
+               _nc_console_MapColor(true, f) |
+               _nc_console_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 (validateConsoleHandle()) {
+       SetSP();
+
+       sp->_mouse_type = M_TERM_DRIVER;
+    }
+}
+
+static int
+wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
+              int delay
+              EVENTLIST_2nd(_nc_eventlist * evl))
+{
+    int rc = 0;
+    SCREEN *sp;
+
+    if (validateConsoleHandle()) {
+       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 (validateConsoleHandle()) {
+       COORD loc;
+       loc.X = (short) x;
+       loc.Y = (short) (y + AdjustY());
+       SetConsoleCursorPosition(WINCONSOLE.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 (validateConsoleHandle()) {
+       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 int
+wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
+          int mode,
+          int milliseconds,
+          int *timeleft
+          EVENTLIST_2nd(_nc_eventlist * evl))
+{
+    SCREEN *sp;
+    int code = 0;
+
+    if (validateConsoleHandle()) {
+       SetSP();
+
+       code = _nc_console_twait(sp,
+                                WINCONSOLE.inp,
+                                mode,
+                                milliseconds,
+                                timeleft EVENTLIST_2nd(evl));
+    }
+    return code;
+}
+
+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 (validateConsoleHandle()) {
+       SetSP();
+
+       n = _nc_console_read(sp, WINCONSOLE.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 (validateConsoleHandle()) {
+       CONSOLE_CURSOR_INFO this_CI = WINCONSOLE.save_CI;
+       switch (mode) {
+       case 0:
+           this_CI.bVisible = FALSE;
+           break;
+       case 1:
+           break;
+       case 2:
+           this_CI.dwSize = 100;
+           break;
+       }
+       SetConsoleCursorInfo(WINCONSOLE.hdl, &this_CI);
+    }
+    returnCode(res);
+}
+
+static bool
+wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
+{
+    bool found = FALSE;
+
+    T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
+    found = _nc_console_keyExist(keycode);
+    returnBool(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 (validateConsoleHandle()) {
+       SetSP();
+
+       if (sp) {
+           code = OK;
+       }
+    }
+    returnCode(code);
+}
+
+static int
+wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
+          int keycode,
+          int flag)
+{
+    int code = ERR;
+    SCREEN *sp;
+
+    T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
+
+    if (validateConsoleHandle()) {
+       SetSP();
+       if (sp) {
+           code = _nc_console_keyok(keycode, flag);
+       }
+    }
+    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     */
+};
+
+#endif /* _NC_WINDOWS */