]> ncurses.scripts.mit.edu Git - ncurses.git/blobdiff - ncurses/win32con/win_driver.c
ncurses 5.9 - patch 20130928
[ncurses.git] / ncurses / win32con / win_driver.c
index fe1f745e4afd8d3e1331beed92df9616ef5741b0..d3660d24abd602f02ef98b26ac9658f95e009d1e 100644 (file)
@@ -1,5 +1,5 @@
 /****************************************************************************
- * Copyright (c) 1998-2008,2009 Free Software Foundation, Inc.              *
+ * Copyright (c) 1998-2012,2013 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                                                 *
- *                                                                          *
  ****************************************************************************/
 
+/*
+ * TODO - GetMousePos(POINT * result) from ntconio.c
+ * TODO - implement nodelay
+ */
+
 #include <curses.priv.h>
+#define CUR my_term.type.
 
-MODULE_ID("$Id: win_driver.c,v 1.1 2009/02/21 15:11:29 juergen Exp $")
-
-static bool drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, const char *tname, int *);
-static void drv_init(TERMINAL_CONTROL_BLOCK *);
-static void drv_release(TERMINAL_CONTROL_BLOCK *);
-static int drv_size(TERMINAL_CONTROL_BLOCK *, int *, int *);
-static int drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB,
-                     bool setFlag,
-                     TTY * buf);
-static chtype drv_conattr(TERMINAL_CONTROL_BLOCK * TCB);
-
-static int drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
-                    int yold, int xold, int ynew, int xnew);
-static int drv_mode(TERMINAL_CONTROL_BLOCK * TCB,
-                   bool progFlag, bool defFlag);
-static bool drv_rescol(TERMINAL_CONTROL_BLOCK * TCB);
-static bool drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB);
-static void drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
-                        bool fore,
-                        int color,
-                        int (*outc) (SCREEN *, int));
-static int drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB, bool);
-static void drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
-                        short pair,
-                        short f,
-                        short b);
-static void drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
-                         short color,
-                         short r,
-                         short g,
-                         short b);
-static void drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
-                        short old_pair,
-                        short pair,
-                        bool reverse,
-                        int (*outc) (SCREEN *, int));
-static void drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB);
-static void drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB);
-static void drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
-                       int labnum,
-                       char *text);
-static void drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
-                            bool OnFlag);
-static int drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB);
-
-static int drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
-                            int fg,
-                            int bg);
-static int drv_print(TERMINAL_CONTROL_BLOCK * TCB,
-                    char *data,
-                    int len);
-/*static int _getsize(TERMINAL_CONTROL_BLOCK*,int *, int *);*/
-static int drv_setsize(TERMINAL_CONTROL_BLOCK * TCB, int l, int c);
-static void drv_initacs(TERMINAL_CONTROL_BLOCK * TCB, chtype *, chtype *);
-static void drv_wrap(SCREEN *);
-static void drv_screen_init(SCREEN *);
-static int drv_twait(TERMINAL_CONTROL_BLOCK *,
-                    int,
-                    int,
-                    int *EVENTLIST_2nd(_nc_eventlist *));
-static int drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf);
-static int drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms);
-static int drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool);
-static int drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int, bool);
-static bool drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int);
-
-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_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 */
-};
+MODULE_ID("$Id: win_driver.c,v 1.20 2013/08/17 19:25:30 tom Exp $")
 
 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
 
-#define AssertTCB() assert(TCB!=0 && TCB->magic==WINMAGIC)
-#define SetSP() assert(TCB->csp!=0); sp = TCB->csp
+#define EXP_OPTIMIZE 0
+
+#define okConsoleHandle(TCB) (TCB != 0 && !InvalidConsoleHandle(TCB->hdl))
+
+#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)
 
@@ -164,6 +72,7 @@ static const LONG keylist[] =
 typedef struct props {
     CONSOLE_SCREEN_BUFFER_INFO SBI;
     bool progMode;
+    TERM_HANDLE lastOut;
     DWORD map[MAPSIZE];
     DWORD rmap[MAPSIZE];
     WORD pairs[NUMPAIRS];
@@ -198,7 +107,7 @@ MapColor(bool fore, int color)
 }
 
 static WORD
-MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
+MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch)
 {
     if (ch & A_COLOR) {
        int p;
@@ -206,7 +115,7 @@ MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
 
        AssertTCB();
        SetSP();
-       p = PAIR_NUMBER(ch);
+       p = PairNumber(ch);
        if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
            WORD a;
            a = PropOf(TCB)->pairs[p];
@@ -230,8 +139,68 @@ MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, chtype ch)
     return res;
 }
 
+#if USE_WIDEC_SUPPORT
+/*
+ * TODO: support surrogate pairs
+ * TODO: support combining characters
+ * TODO: support acsc
+ * TODO: check wcwidth of base character, fill if needed for double-width
+ * TODO: _nc_wacs should be part of sp.
+ */
+static BOOL
+con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
+{
+    int actual = 0;
+    CHAR_INFO ci[limit];
+    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(TCB,
+                                       PropOf(TCB)->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;
+    rec.Right = (short) (x + limit - 1);
+    rec.Bottom = rec.Top;
+
+    return WriteConsoleOutputW(TCB->hdl, ci, siz, loc, &rec);
+}
+#define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
+#else
 static BOOL
-con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
+con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
 {
     CHAR_INFO ci[n];
     COORD loc, siz;
@@ -242,9 +211,6 @@ con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
 
     AssertTCB();
 
-    if (TCB == 0 || InvalidConsoleHandle(TCB->hdl))
-       return FALSE;
-
     SetSP();
 
     for (i = 0; i < n; i++) {
@@ -272,83 +238,215 @@ con_write(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
 
     return WriteConsoleOutput(TCB->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(TERMINAL_CONTROL_BLOCK * TCB)
+{
+    if (PropOf(TCB)->lastOut != TCB->hdl) {
+       PropOf(TCB)->lastOut = TCB->hdl;
+       SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
+    }
+}
+
 static int
 drv_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, sp->_newscr->_maxy + 1);
-
-    if ((sp->_curscr->_clear || sp->_newscr->_clear)) {
-       int x;
-       chtype empty[Width];
-
-       for (x = 0; x < Width; x++)
-           empty[x] = ' ';
-
-       for (y = 0; y < nonempty; y++) {
-           con_write(TCB, y, 0, empty, Width);
-           memcpy(empty,
-                  sp->_curscr->_line[y].text,
-                  Width * sizeof(chtype));
+    T((T_CALLED("win32con::drv_doupdate(%p)"), TCB));
+    if (okConsoleHandle(TCB)) {
+
+       Width = screen_columns(sp);
+       Height = screen_lines(sp);
+       nonempty = min(Height, NewScreen(sp)->_maxy + 1);
+
+       if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
+           int x;
+#if USE_WIDEC_SUPPORT
+           cchar_t empty[Width];
+           wchar_t blank[2] =
+           {
+               L' ', L'\0'
+           };
+
+           for (x = 0; x < Width; x++)
+               setcchar(&empty[x], blank, 0, 0, 0);
+#else
+           chtype empty[Width];
+
+           for (x = 0; x < Width; x++)
+               empty[x] = ' ';
+#endif
+
+           for (y = 0; y < nonempty; y++) {
+               con_write(TCB, y, 0, empty, Width);
+               memcpy(empty,
+                      CurScreen(sp)->_line[y].text,
+                      Width * sizeof(empty[0]));
+           }
+           CurScreen(sp)->_clear = FALSE;
+           NewScreen(sp)->_clear = FALSE;
+           touchwin(NewScreen(sp));
        }
-       sp->_curscr->_clear = FALSE;
-       sp->_newscr->_clear = FALSE;
-       touchwin(sp->_newscr);
-    }
 
-    for (y = 0; y < nonempty; y++) {
-       x0 = sp->_newscr->_line[y].firstchar;
-       if (x0 != _NOCHANGE) {
-           x1 = sp->_newscr->_line[y].lastchar;
-           n = x1 - x0 + 1;
-           if (n > 0) {
-               memcpy(sp->_curscr->_line[y].text + x0,
-                      sp->_newscr->_line[y].text + x0,
-                      n * sizeof(chtype));
-               con_write(TCB,
-                         y,
-                         x0,
-                         ((chtype *) sp->_curscr->_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 <= sp->_newscr->_maxy) {
-                   MARK_NOCHANGE(sp->_newscr, y);
+               if (y <= NewScreen(sp)->_maxy) {
+                   MARK_NOCHANGE(NewScreen(sp), y);
+               }
+               if (y <= CurScreen(sp)->_maxy) {
+                   MARK_NOCHANGE(CurScreen(sp), y);
                }
-               if (y <= sp->_curscr->_maxy) {
-                   MARK_NOCHANGE(sp->_curscr, 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],
+                          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 <= sp->_newscr->_maxy; y++) {
-       MARK_NOCHANGE(sp->_newscr, y);
-    }
-    for (y = nonempty; y <= sp->_curscr->_maxy; y++) {
-       MARK_NOCHANGE(sp->_curscr, 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 (!sp->_newscr->_leaveok) {
-       sp->_curscr->_curx = sp->_newscr->_curx;
-       sp->_curscr->_cury = sp->_newscr->_cury;
+       if (!NewScreen(sp)->_leaveok) {
+           CurScreen(sp)->_curx = NewScreen(sp)->_curx;
+           CurScreen(sp)->_cury = NewScreen(sp)->_cury;
 
-       TCB->drv->hwcur(TCB, 0, 0, sp->_curscr->_cury, sp->_curscr->_curx);
+           TCB->drv->hwcur(TCB,
+                           0, 0,
+                           CurScreen(sp)->_cury, CurScreen(sp)->_curx);
+       }
+       selectActiveHandle(TCB);
+       result = OK;
     }
-    SetConsoleActiveScreenBuffer(TCB->hdl);
-    return OK;
+    returnCode(result);
 }
 
 static bool
@@ -356,18 +454,54 @@ drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
              const char *tname,
              int *errret GCC_UNUSED)
 {
+    bool code = FALSE;
+
+    T((T_CALLED("win32con::drv_CanHandle(%p)"), TCB));
+
     assert(TCB != 0);
     assert(tname != 0);
+
     TCB->magic = WINMAGIC;
-    if (*tname == 0 || *tname == 0 || strcmp(tname, "unknown") == 0) {
-       return TRUE;
-    } else
-       return FALSE;
+    if (*tname == 0 || *tname == 0 || *tname == '#') {
+       code = TRUE;
+    } else {
+       TERMINAL my_term;
+       int status;
+
+       code = FALSE;
+#if (NCURSES_USE_DATABASE || NCURSES_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 (code) {
+       if ((TCB->term.type.Booleans) == 0) {
+           _nc_init_termtype(&(TCB->term.type));
+       }
+    }
+
+    returnBool(code);
 }
 
 static int
 drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
-               bool beepFlag GCC_UNUSED)
+               int beepFlag GCC_UNUSED)
 {
     SCREEN *sp;
     int res = ERR;
@@ -407,13 +541,13 @@ drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
 
 static void
 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
-            bool fore,
+            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);
@@ -427,7 +561,7 @@ drv_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));
@@ -451,14 +585,20 @@ drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
 static int
 drv_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::drv_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) {
+       *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
+       *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
+       result = OK;
+    }
+    returnCode(result);
 }
 
 static int
@@ -471,7 +611,74 @@ drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
 }
 
 static int
-drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
+drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
+{
+    DWORD dwFlag = 0;
+    tcflag_t iflag;
+    tcflag_t lflag;
+
+    AssertTCB();
+
+    if (TCB == 0 || buf == NULL)
+       return ERR;
+
+    if (setFlag) {
+       iflag = buf->c_iflag;
+       lflag = buf->c_lflag;
+
+       GetConsoleMode(TCB->inp, &dwFlag);
+
+       if (lflag & ICANON)
+           dwFlag |= ENABLE_LINE_INPUT;
+       else
+           dwFlag &= ~ENABLE_LINE_INPUT;
+
+       if (lflag & ECHO)
+           dwFlag |= ENABLE_ECHO_INPUT;
+       else
+           dwFlag &= ~ENABLE_ECHO_INPUT;
+
+       if (iflag & BRKINT)
+           dwFlag |= ENABLE_PROCESSED_INPUT;
+       else
+           dwFlag &= ~ENABLE_PROCESSED_INPUT;
+
+       dwFlag |= ENABLE_MOUSE_INPUT;
+
+       buf->c_iflag = iflag;
+       buf->c_lflag = lflag;
+       SetConsoleMode(TCB->inp, dwFlag);
+       TCB->term.Nttyb = *buf;
+    } else {
+       iflag = TCB->term.Nttyb.c_iflag;
+       lflag = TCB->term.Nttyb.c_lflag;
+       GetConsoleMode(TCB->inp, &dwFlag);
+
+       if (dwFlag & ENABLE_LINE_INPUT)
+           lflag |= ICANON;
+       else
+           lflag &= ~ICANON;
+
+       if (dwFlag & ENABLE_ECHO_INPUT)
+           lflag |= ECHO;
+       else
+           lflag &= ~ECHO;
+
+       if (dwFlag & ENABLE_PROCESSED_INPUT)
+           iflag |= BRKINT;
+       else
+           iflag &= ~BRKINT;
+
+       TCB->term.Nttyb.c_iflag = iflag;
+       TCB->term.Nttyb.c_lflag = lflag;
+
+       *buf = TCB->term.Nttyb;
+    }
+    return OK;
+}
+
+static int
+drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
 {
     SCREEN *sp;
     TERMINAL *_term = (TERMINAL *) TCB;
@@ -481,7 +688,8 @@ drv_mode(TERMINAL_CONTROL_BLOCK * TCB, bool progFlag, bool defFlag)
     sp = TCB->csp;
 
     PropOf(TCB)->progMode = progFlag;
-    SetConsoleActiveScreenBuffer(progFlag ? TCB->hdl : TCB->out);
+    PropOf(TCB)->lastOut = progFlag ? TCB->hdl : TCB->out;
+    SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
 
     if (progFlag) /* prog mode */  {
        if (defFlag) {
@@ -576,14 +784,22 @@ MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
 static void
 drv_release(TERMINAL_CONTROL_BLOCK * TCB)
 {
+    T((T_CALLED("win32con::drv_release(%p)"), TCB));
+
     AssertTCB();
     if (TCB->prop)
        free(TCB->prop);
+
+    returnVoid;
 }
 
 static void
 drv_init(TERMINAL_CONTROL_BLOCK * TCB)
 {
+    DWORD num_buttons;
+
+    T((T_CALLED("win32con::drv_init(%p)"), TCB));
+
     AssertTCB();
 
     if (TCB) {
@@ -624,6 +840,13 @@ 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.defaultPalette = _nc_cga_palette;
 
        for (i = 0; i < (N_INI + FKEYS); i++) {
@@ -646,13 +869,14 @@ drv_init(TERMINAL_CONTROL_BLOCK * TCB)
        for (i = 0; i < NUMPAIRS; i++)
            PropOf(TCB)->pairs[i] = a;
     }
+    returnVoid;
 }
 
 static void
 drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
-            short pair,
-            short f,
-            short b)
+            int pair,
+            int f,
+            int b)
 {
     SCREEN *sp;
 
@@ -667,10 +891,10 @@ drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
 
 static void
 drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
-             short color GCC_UNUSED,
-             short r GCC_UNUSED,
-             short g GCC_UNUSED,
-             short b GCC_UNUSED)
+             int color GCC_UNUSED,
+             int r GCC_UNUSED,
+             int g GCC_UNUSED,
+             int b GCC_UNUSED)
 {
     SCREEN *sp;
 
@@ -680,9 +904,9 @@ drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
 
 static void
 drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
-            short old_pair GCC_UNUSED,
-            short pair GCC_UNUSED,
-            bool reverse GCC_UNUSED,
+            int old_pair GCC_UNUSED,
+            int pair GCC_UNUSED,
+            int reverse GCC_UNUSED,
             int (*outc) (SCREEN *, int) GCC_UNUSED
 )
 {
@@ -699,6 +923,30 @@ drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
 
     AssertTCB();
     SetSP();
+
+    sp->_mouse_type = M_TERM_DRIVER;
+}
+
+static int
+drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
+{
+    int rc = 0;
+    SCREEN *sp;
+
+    AssertTCB();
+    SetSP();
+
+    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));
+    }
+
+    return rc;
 }
 
 static int
@@ -707,7 +955,7 @@ drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
          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;
@@ -730,7 +978,7 @@ drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
 
 static void
 drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
-                bool OnFlag GCC_UNUSED)
+                int OnFlag GCC_UNUSED)
 {
     SCREEN *sp;
 
@@ -755,82 +1003,51 @@ drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
     SetSP();
 }
 
-static int
-drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, bool setFlag, TTY * buf)
-{
-    DWORD dwFlag = 0;
-    tcflag_t iflag;
-    tcflag_t lflag;
-
-    AssertTCB();
-
-    if (TCB == 0 || buf == NULL)
-       return ERR;
-
-    if (setFlag) {
-       iflag = buf->c_iflag;
-       lflag = buf->c_lflag;
-
-       GetConsoleMode(TCB->inp, &dwFlag);
-
-       if (lflag & ICANON)
-           dwFlag |= ENABLE_LINE_INPUT;
-       else
-           dwFlag &= ~ENABLE_LINE_INPUT;
-
-       if (lflag & ECHO)
-           dwFlag |= ENABLE_ECHO_INPUT;
-       else
-           dwFlag &= ~ENABLE_ECHO_INPUT;
-
-       if (iflag & BRKINT)
-           dwFlag |= ENABLE_PROCESSED_INPUT;
-       else
-           dwFlag &= ~ENABLE_PROCESSED_INPUT;
-
-       /* we disable that for now to focus on keyboard. */
-       dwFlag &= ~ENABLE_MOUSE_INPUT;
-
-       buf->c_iflag = iflag;
-       buf->c_lflag = lflag;
-       SetConsoleMode(TCB->inp, dwFlag);
-       TCB->term.Nttyb = *buf;
-    } else {
-       iflag = TCB->term.Nttyb.c_iflag;
-       lflag = TCB->term.Nttyb.c_lflag;
-       GetConsoleMode(TCB->inp, &dwFlag);
-
-       if (dwFlag & ENABLE_LINE_INPUT)
-           lflag |= ICANON;
-       else
-           lflag &= ~ICANON;
-
-       if (dwFlag & ENABLE_ECHO_INPUT)
-           lflag |= ECHO;
-       else
-           lflag &= ~ECHO;
-
-       if (dwFlag & ENABLE_PROCESSED_INPUT)
-           iflag |= BRKINT;
-       else
-           iflag &= ~BRKINT;
-
-       TCB->term.Nttyb.c_iflag = iflag;
-       TCB->term.Nttyb.c_lflag = lflag;
-
-       *buf = TCB->term.Nttyb;
-    }
-    return OK;
-}
-
 static void
 drv_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;
     AssertTCB();
     SetSP();
+
+    for (n = 0; n < SIZEOF(table); ++n) {
+       real_map[table[n].acs_code] = table[n].use_code | A_ALTCHARSET;
+       if (sp != 0)
+           sp->_screen_acs_map[table[n].acs_code] = TRUE;
+    }
 }
 
 static ULONGLONG
@@ -860,6 +1077,50 @@ Adjust(int milliseconds, int diff)
     return milliseconds;
 }
 
+#define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
+                    FROM_LEFT_2ND_BUTTON_PRESSED | \
+                    FROM_LEFT_3RD_BUTTON_PRESSED | \
+                    FROM_LEFT_4TH_BUTTON_PRESSED | \
+                    RIGHTMOST_BUTTON_PRESSED)
+
+static int
+decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
+{
+    SCREEN *sp;
+    int result = 0;
+
+    AssertTCB();
+    SetSP();
+
+    if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
+       result |= BUTTON1_PRESSED;
+    if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
+       result |= BUTTON2_PRESSED;
+    if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
+       result |= BUTTON3_PRESSED;
+    if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
+       result |= BUTTON4_PRESSED;
+
+    if (mask & RIGHTMOST_BUTTON_PRESSED) {
+       switch (TCB->info.numbuttons) {
+       case 1:
+           result |= BUTTON1_PRESSED;
+           break;
+       case 2:
+           result |= BUTTON2_PRESSED;
+           break;
+       case 3:
+           result |= BUTTON3_PRESSED;
+           break;
+       case 4:
+           result |= BUTTON4_PRESSED;
+           break;
+       }
+    }
+
+    return result;
+}
+
 static int
 drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
          int mode,
@@ -868,7 +1129,7 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
          EVENTLIST_2nd(_nc_eventlist * evl))
 {
     SCREEN *sp;
-    INPUT_RECORD inp;
+    INPUT_RECORD inp_rec;
     BOOL b;
     DWORD nRead = 0, rc = -1;
     int code = 0;
@@ -877,15 +1138,18 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
     int diff;
     bool isImmed = (milliseconds == 0);
 
-#define CONSUME() ReadConsoleInput(TCB->inp,&inp,1,&nRead)
+#define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead)
 
     AssertTCB();
     SetSP();
 
+    TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
+                     milliseconds, mode));
+
     if (milliseconds < 0)
        milliseconds = INFINITY;
 
-    memset(&inp, 0, sizeof(inp));
+    memset(&inp_rec, 0, sizeof(inp_rec));
 
     while (true) {
        GetSystemTimeAsFileTime(&fstart);
@@ -901,15 +1165,15 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
            if (mode) {
                b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
                if (b && nRead > 0) {
-                   b = PeekConsoleInput(TCB->inp, &inp, 1, &nRead);
+                   b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead);
                    if (b && nRead > 0) {
-                       switch (inp.EventType) {
+                       switch (inp_rec.EventType) {
                        case KEY_EVENT:
                            if (mode & TW_INPUT) {
-                               WORD vk = inp.Event.KeyEvent.wVirtualKeyCode;
-                               char ch = inp.Event.KeyEvent.uChar.AsciiChar;
+                               WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
+                               char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
 
-                               if (inp.Event.KeyEvent.bKeyDown) {
+                               if (inp_rec.Event.KeyEvent.bKeyDown) {
                                    if (0 == ch) {
                                        int nKey = MapKey(TCB, vk);
                                        if ((nKey < 0) || FALSE == sp->_keypad_on) {
@@ -925,14 +1189,17 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
                            }
                            continue;
                        case MOUSE_EVENT:
-                           if (0 && mode & TW_MOUSE) {
+                           if (decode_mouse(TCB,
+                                            (inp_rec.Event.MouseEvent.dwButtonState
+                                             & BUTTON_MASK)) == 0) {
+                               CONSUME();
+                           } else if (mode & TW_MOUSE) {
                                code = TW_MOUSE;
                                goto end;
-                           } else
-                               continue;
+                           }
+                           continue;
                        default:
-                           SetConsoleActiveScreenBuffer(!PropOf(TCB)->progMode ?
-                                                        TCB->hdl : TCB->out);
+                           selectActiveHandle(TCB);
                            continue;
                        }
                    }
@@ -950,37 +1217,83 @@ drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
        }
     }
   end:
+
+    TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
+                     code, errno, milliseconds));
+
     if (timeleft)
        *timeleft = milliseconds;
 
     return code;
 }
 
+static bool
+handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
+{
+    SCREEN *sp;
+    MEVENT work;
+    bool result = FALSE;
+
+    AssertTCB();
+    SetSP();
+
+    sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
+    sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
+
+    /*
+     * We're only interested if the button is pressed or released.
+     * FIXME: implement continuous event-tracking.
+     */
+    if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
+
+       memset(&work, 0, sizeof(work));
+
+       if (sp->_drv_mouse_new_buttons) {
+
+           work.bstate |= decode_mouse(TCB, sp->_drv_mouse_new_buttons);
+
+       } else {
+
+           /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
+           work.bstate |= (decode_mouse(TCB, sp->_drv_mouse_old_buttons) >> 1);
+
+           result = TRUE;
+       }
+
+       work.x = mer.dwMousePosition.X;
+       work.y = mer.dwMousePosition.Y;
+
+       sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
+       sp->_drv_mouse_tail += 1;
+    }
+
+    return result;
+}
+
 static int
 drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
 {
     SCREEN *sp;
     int n = 1;
-    INPUT_RECORD inp;
+    INPUT_RECORD inp_rec;
     BOOL b;
     DWORD nRead;
     WORD vk;
-    WORD sc;
 
     AssertTCB();
     assert(buf);
     SetSP();
 
-    memset(&inp, 0, sizeof(inp));
+    memset(&inp_rec, 0, sizeof(inp_rec));
 
-    while ((b = ReadConsoleInput(TCB->inp, &inp, 1, &nRead))) {
+    T((T_CALLED("win32con::drv_read(%p)"), TCB));
+    while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) {
        if (b && nRead > 0) {
-           if (inp.EventType == KEY_EVENT) {
-               if (!inp.Event.KeyEvent.bKeyDown)
+           if (inp_rec.EventType == KEY_EVENT) {
+               if (!inp_rec.Event.KeyEvent.bKeyDown)
                    continue;
-               *buf = (int) inp.Event.KeyEvent.uChar.AsciiChar;
-               vk = inp.Event.KeyEvent.wVirtualKeyCode;
-               sc = inp.Event.KeyEvent.wVirtualScanCode;
+               *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);
@@ -993,21 +1306,24 @@ drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
                } else {        /* *buf != 0 */
                    break;
                }
-           } else if (0 && inp.EventType == MOUSE_EVENT) {
-               *buf = KEY_MOUSE;
-               break;
+           } else if (inp_rec.EventType == MOUSE_EVENT) {
+               if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) {
+                   *buf = KEY_MOUSE;
+                   break;
+               }
            }
            continue;
        }
     }
-    return n;
+    returnCode(n);
 }
 
 static int
 drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
 {
+    T((T_CALLED("win32con::drv_nap(%p, %d)"), TCB, ms));
     Sleep(ms);
-    return OK;
+    returnCode(OK);
 }
 
 static bool
@@ -1024,6 +1340,7 @@ drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
 
     AssertTCB();
 
+    T((T_CALLED("win32con::drv_kyExist(%p, %d)"), TCB, keycode));
     res = bsearch(&key,
                  PropOf(TCB)->rmap,
                  (size_t) (N_INI + FKEYS),
@@ -1035,11 +1352,11 @@ 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, bool flag GCC_UNUSED)
+drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
 {
     SCREEN *sp;
     int code = ERR;
@@ -1047,14 +1364,15 @@ drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, bool flag GCC_UNUSED)
     AssertTCB();
     sp = TCB->csp;
 
+    T((T_CALLED("win32con::drv_kpad(%p, %d)"), TCB, flag));
     if (sp) {
        code = OK;
     }
-    return code;
+    returnCode(code);
 }
 
 static int
-drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
+drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
 {
     int code = ERR;
     SCREEN *sp;
@@ -1066,6 +1384,7 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool flag)
     AssertTCB();
     SetSP();
 
+    T((T_CALLED("win32con::drv_keyok(%p, %d, %d)"), TCB, keycode, flag));
     if (sp) {
        res = bsearch(&key,
                      PropOf(TCB)->rmap,
@@ -1081,5 +1400,43 @@ drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, bool 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 */
+};