ncurses 5.9 - patch 20140222
[ncurses.git] / ncurses / win32con / win_driver.c
1 /****************************************************************************
2  * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc.              *
3  *                                                                          *
4  * Permission is hereby granted, free of charge, to any person obtaining a  *
5  * copy of this software and associated documentation files (the            *
6  * "Software"), to deal in the Software without restriction, including      *
7  * without limitation the rights to use, copy, modify, merge, publish,      *
8  * distribute, distribute with modifications, sublicense, and/or sell       *
9  * copies of the Software, and to permit persons to whom the Software is    *
10  * furnished to do so, subject to the following conditions:                 *
11  *                                                                          *
12  * The above copyright notice and this permission notice shall be included  *
13  * in all copies or substantial portions of the Software.                   *
14  *                                                                          *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22  *                                                                          *
23  * Except as contained in this notice, the name(s) of the above copyright   *
24  * holders shall not be used in advertising or otherwise to promote the     *
25  * sale, use or other dealings in this Software without prior written       *
26  * authorization.                                                           *
27  ****************************************************************************/
28
29 /****************************************************************************
30  *  Author: Juergen Pfeifer                                                 *
31  ****************************************************************************/
32
33 /*
34  * TODO - GetMousePos(POINT * result) from ntconio.c
35  * TODO - implement nodelay
36  * TODO - when $NCGDB is set, implement non-buffered output, like PDCurses
37  */
38
39 #include <curses.priv.h>
40 #define CUR my_term.type.
41
42 MODULE_ID("$Id: win_driver.c,v 1.24 2014/02/23 01:23:29 tom Exp $")
43
44 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
45
46 #define EXP_OPTIMIZE 0
47
48 #define okConsoleHandle(TCB) (TCB != 0 && !InvalidConsoleHandle(TCB->hdl))
49
50 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
51 #define SetSP()     assert(TCB->csp != 0); sp = TCB->csp; (void) sp
52
53 #define GenMap(vKey,key) MAKELONG(key, vKey)
54
55 #define AdjustY(p) ((p)->buffered ? 0 : (int) (p)->SBI.srWindow.Top)
56
57 static const LONG keylist[] =
58 {
59     GenMap(VK_PRIOR, KEY_PPAGE),
60     GenMap(VK_NEXT, KEY_NPAGE),
61     GenMap(VK_END, KEY_END),
62     GenMap(VK_HOME, KEY_HOME),
63     GenMap(VK_LEFT, KEY_LEFT),
64     GenMap(VK_UP, KEY_UP),
65     GenMap(VK_RIGHT, KEY_RIGHT),
66     GenMap(VK_DOWN, KEY_DOWN),
67     GenMap(VK_DELETE, KEY_DC),
68     GenMap(VK_INSERT, KEY_IC)
69 };
70 #define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0])))
71 #define FKEYS 24
72 #define MAPSIZE (FKEYS + N_INI)
73 #define NUMPAIRS 64
74
75 typedef struct props {
76     CONSOLE_SCREEN_BUFFER_INFO SBI;
77     bool progMode;
78     TERM_HANDLE lastOut;
79     DWORD map[MAPSIZE];
80     DWORD rmap[MAPSIZE];
81     WORD pairs[NUMPAIRS];
82     bool buffered;
83     COORD origin;
84     CHAR_INFO *save_screen;
85 } Properties;
86
87 #define PropOf(TCB) ((Properties*)TCB->prop)
88
89 int
90 _nc_mingw_ioctl(int fd GCC_UNUSED,
91                 long int request GCC_UNUSED,
92                 struct termios *arg GCC_UNUSED)
93 {
94     return 0;
95     endwin();
96     fprintf(stderr, "TERMINFO currently not supported on Windows.\n");
97     exit(1);
98 }
99
100 static WORD
101 MapColor(bool fore, int color)
102 {
103     static const int _cmap[] =
104     {0, 4, 2, 6, 1, 5, 3, 7};
105     int a;
106     if (color < 0 || color > 7)
107         a = fore ? 7 : 0;
108     else
109         a = _cmap[color];
110     if (!fore)
111         a = a << 4;
112     return (WORD) a;
113 }
114
115 static WORD
116 MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch)
117 {
118     if (ch & A_COLOR) {
119         int p;
120         SCREEN *sp;
121
122         AssertTCB();
123         SetSP();
124         p = PairNumber(ch);
125         if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
126             WORD a;
127             a = PropOf(TCB)->pairs[p];
128             res = (res & 0xff00) | a;
129         }
130     }
131
132     if (ch & A_REVERSE)
133         res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4)));
134
135     if (ch & A_STANDOUT)
136         res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4))
137                | BACKGROUND_INTENSITY);
138
139     if (ch & A_BOLD)
140         res |= FOREGROUND_INTENSITY;
141
142     if (ch & A_DIM)
143         res |= BACKGROUND_INTENSITY;
144
145     return res;
146 }
147
148 #if USE_WIDEC_SUPPORT
149 /*
150  * TODO: support surrogate pairs
151  * TODO: support combining characters
152  * TODO: support acsc
153  * TODO: check wcwidth of base character, fill if needed for double-width
154  * TODO: _nc_wacs should be part of sp.
155  */
156 static BOOL
157 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
158 {
159     int actual = 0;
160     CHAR_INFO ci[limit];
161     COORD loc, siz;
162     SMALL_RECT rec;
163     int i;
164     cchar_t ch;
165     SCREEN *sp;
166     Properties *p = PropOf(TCB);
167
168     AssertTCB();
169
170     SetSP();
171
172     for (i = actual = 0; i < limit; i++) {
173         ch = str[i];
174         if (isWidecExt(ch))
175             continue;
176         ci[actual].Char.UnicodeChar = CharOf(ch);
177         ci[actual].Attributes = MapAttr(TCB,
178                                         PropOf(TCB)->SBI.wAttributes,
179                                         AttrOf(ch));
180         if (AttrOf(ch) & A_ALTCHARSET) {
181             if (_nc_wacs) {
182                 int which = CharOf(ch);
183                 if (which > 0
184                     && which < ACS_LEN
185                     && CharOf(_nc_wacs[which]) != 0) {
186                     ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
187                 } else {
188                     ci[actual].Char.UnicodeChar = ' ';
189                 }
190             }
191         }
192         ++actual;
193     }
194
195     loc.X = (short) 0;
196     loc.Y = (short) 0;
197     siz.X = (short) actual;
198     siz.Y = 1;
199
200     rec.Left = (short) x;
201     rec.Top = (SHORT) (y + AdjustY(p));
202     rec.Right = (short) (x + limit - 1);
203     rec.Bottom = rec.Top;
204
205     return WriteConsoleOutputW(TCB->hdl, ci, siz, loc, &rec);
206 }
207 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
208 #else
209 static BOOL
210 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
211 {
212     CHAR_INFO ci[n];
213     COORD loc, siz;
214     SMALL_RECT rec;
215     int i;
216     chtype ch;
217     SCREEN *sp;
218
219     AssertTCB();
220
221     SetSP();
222
223     for (i = 0; i < n; i++) {
224         ch = str[i];
225         ci[i].Char.AsciiChar = ChCharOf(ch);
226         ci[i].Attributes = MapAttr(TCB,
227                                    PropOf(TCB)->SBI.wAttributes,
228                                    ChAttrOf(ch));
229         if (ChAttrOf(ch) & A_ALTCHARSET) {
230             if (sp->_acs_map)
231                 ci[i].Char.AsciiChar =
232                 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
233         }
234     }
235
236     loc.X = (short) 0;
237     loc.Y = (short) 0;
238     siz.X = (short) n;
239     siz.Y = 1;
240
241     rec.Left = (short) x;
242     rec.Top = (short) y;
243     rec.Right = (short) (x + n - 1);
244     rec.Bottom = rec.Top;
245
246     return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec);
247 }
248 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
249 #endif
250
251 #if EXP_OPTIMIZE
252 /*
253  * Comparing new/current screens, determine the last column-index for a change
254  * beginning on the given row,col position.  Unlike a serial terminal, there is
255  * no cost for "moving" the "cursor" on the line as we update it.
256  */
257 static int
258 find_end_of_change(SCREEN *sp, int row, int col)
259 {
260     int result = col;
261     struct ldat *curdat = CurScreen(sp)->_line + row;
262     struct ldat *newdat = NewScreen(sp)->_line + row;
263
264     while (col <= newdat->lastchar) {
265 #if USE_WIDEC_SUPPORT
266         if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
267             result = col;
268         } else if (memcmp(&curdat->text[col],
269                           &newdat->text[col],
270                           sizeof(curdat->text[0]))) {
271             result = col;
272         } else {
273             break;
274         }
275 #else
276         if (curdat->text[col] != newdat->text[col]) {
277             result = col;
278         } else {
279             break;
280         }
281 #endif
282         ++col;
283     }
284     return result;
285 }
286
287 /*
288  * Given a row,col position at the end of a change-chunk, look for the
289  * beginning of the next change-chunk.
290  */
291 static int
292 find_next_change(SCREEN *sp, int row, int col)
293 {
294     struct ldat *curdat = CurScreen(sp)->_line + row;
295     struct ldat *newdat = NewScreen(sp)->_line + row;
296     int result = newdat->lastchar + 1;
297
298     while (++col <= newdat->lastchar) {
299 #if USE_WIDEC_SUPPORT
300         if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
301             result = col;
302             break;
303         } else if (memcmp(&curdat->text[col],
304                           &newdat->text[col],
305                           sizeof(curdat->text[0]))) {
306             result = col;
307             break;
308         }
309 #else
310         if (curdat->text[col] != newdat->text[col]) {
311             result = col;
312             break;
313         }
314 #endif
315     }
316     return result;
317 }
318
319 #define EndChange(first) \
320         find_end_of_change(sp, y, first)
321 #define NextChange(last) \
322         find_next_change(sp, y, last)
323
324 #endif /* EXP_OPTIMIZE */
325
326 #define MARK_NOCHANGE(win,row) \
327                 win->_line[row].firstchar = _NOCHANGE; \
328                 win->_line[row].lastchar  = _NOCHANGE
329
330 static void
331 selectActiveHandle(TERMINAL_CONTROL_BLOCK * TCB)
332 {
333     if (PropOf(TCB)->lastOut != TCB->hdl) {
334         PropOf(TCB)->lastOut = TCB->hdl;
335         SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
336     }
337 }
338
339 static int
340 drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
341 {
342     int result = ERR;
343     int y, nonempty, n, x0, x1, Width, Height;
344     SCREEN *sp;
345
346     AssertTCB();
347     SetSP();
348
349     T((T_CALLED("win32con::drv_doupdate(%p)"), TCB));
350     if (okConsoleHandle(TCB)) {
351
352         Width = screen_columns(sp);
353         Height = screen_lines(sp);
354         nonempty = min(Height, NewScreen(sp)->_maxy + 1);
355
356         if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
357             int x;
358 #if USE_WIDEC_SUPPORT
359             cchar_t empty[Width];
360             wchar_t blank[2] =
361             {
362                 L' ', L'\0'
363             };
364
365             for (x = 0; x < Width; x++)
366                 setcchar(&empty[x], blank, 0, 0, 0);
367 #else
368             chtype empty[Width];
369
370             for (x = 0; x < Width; x++)
371                 empty[x] = ' ';
372 #endif
373
374             for (y = 0; y < nonempty; y++) {
375                 con_write(TCB, y, 0, empty, Width);
376                 memcpy(empty,
377                        CurScreen(sp)->_line[y].text,
378                        (size_t) Width * sizeof(empty[0]));
379             }
380             CurScreen(sp)->_clear = FALSE;
381             NewScreen(sp)->_clear = FALSE;
382             touchwin(NewScreen(sp));
383         }
384
385         for (y = 0; y < nonempty; y++) {
386             x0 = NewScreen(sp)->_line[y].firstchar;
387             if (x0 != _NOCHANGE) {
388 #if EXP_OPTIMIZE
389                 int x2;
390                 int limit = NewScreen(sp)->_line[y].lastchar;
391                 while ((x1 = EndChange(x0)) <= limit) {
392                     while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
393                         x1 = x2;
394                     }
395                     n = x1 - x0 + 1;
396                     memcpy(&CurScreen(sp)->_line[y].text[x0],
397                            &NewScreen(sp)->_line[y].text[x0],
398                            n * sizeof(CurScreen(sp)->_line[y].text[x0]));
399                     con_write(TCB,
400                               y,
401                               x0,
402                               &CurScreen(sp)->_line[y].text[x0], n);
403                     x0 = NextChange(x1);
404                 }
405
406                 /* mark line changed successfully */
407                 if (y <= NewScreen(sp)->_maxy) {
408                     MARK_NOCHANGE(NewScreen(sp), y);
409                 }
410                 if (y <= CurScreen(sp)->_maxy) {
411                     MARK_NOCHANGE(CurScreen(sp), y);
412                 }
413 #else
414                 x1 = NewScreen(sp)->_line[y].lastchar;
415                 n = x1 - x0 + 1;
416                 if (n > 0) {
417                     memcpy(&CurScreen(sp)->_line[y].text[x0],
418                            &NewScreen(sp)->_line[y].text[x0],
419                            (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
420                     con_write(TCB,
421                               y,
422                               x0,
423                               &CurScreen(sp)->_line[y].text[x0], n);
424
425                     /* mark line changed successfully */
426                     if (y <= NewScreen(sp)->_maxy) {
427                         MARK_NOCHANGE(NewScreen(sp), y);
428                     }
429                     if (y <= CurScreen(sp)->_maxy) {
430                         MARK_NOCHANGE(CurScreen(sp), y);
431                     }
432                 }
433 #endif
434             }
435         }
436
437         /* put everything back in sync */
438         for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
439             MARK_NOCHANGE(NewScreen(sp), y);
440         }
441         for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
442             MARK_NOCHANGE(CurScreen(sp), y);
443         }
444
445         if (!NewScreen(sp)->_leaveok) {
446             CurScreen(sp)->_curx = NewScreen(sp)->_curx;
447             CurScreen(sp)->_cury = NewScreen(sp)->_cury;
448
449             TCB->drv->hwcur(TCB,
450                             0, 0,
451                             CurScreen(sp)->_cury, CurScreen(sp)->_curx);
452         }
453         selectActiveHandle(TCB);
454         result = OK;
455     }
456     returnCode(result);
457 }
458
459 static bool
460 drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
461               const char *tname,
462               int *errret GCC_UNUSED)
463 {
464     bool code = FALSE;
465
466     T((T_CALLED("win32con::drv_CanHandle(%p)"), TCB));
467
468     assert(TCB != 0);
469     assert(tname != 0);
470
471     TCB->magic = WINMAGIC;
472     if (*tname == 0 || *tname == 0 || *tname == '#') {
473         code = TRUE;
474     } else {
475         TERMINAL my_term;
476         int status;
477
478         code = FALSE;
479 #if (NCURSES_USE_DATABASE || NCURSES_USE_TERMCAP)
480         status = _nc_setup_tinfo(tname, &my_term.type);
481 #else
482         status = TGETENT_NO;
483 #endif
484         if (status != TGETENT_YES) {
485             const TERMTYPE *fallback = _nc_fallback(tname);
486
487             if (fallback) {
488                 my_term.type = *fallback;
489                 status = TGETENT_YES;
490             } else if (!strcmp(tname, "unknown")) {
491                 code = TRUE;
492             }
493         }
494         if (status == TGETENT_YES) {
495             if (generic_type || hard_copy)
496                 code = TRUE;
497         }
498     }
499
500     if (code) {
501         if ((TCB->term.type.Booleans) == 0) {
502             _nc_init_termtype(&(TCB->term.type));
503         }
504     }
505
506     returnBool(code);
507 }
508
509 static int
510 drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
511                 int beepFlag GCC_UNUSED)
512 {
513     SCREEN *sp;
514     int res = ERR;
515
516     AssertTCB();
517     SetSP();
518
519     return res;
520 }
521
522 static int
523 drv_print(TERMINAL_CONTROL_BLOCK * TCB,
524           char *data GCC_UNUSED,
525           int len GCC_UNUSED)
526 {
527     SCREEN *sp;
528
529     AssertTCB();
530     SetSP();
531
532     return ERR;
533 }
534
535 static int
536 drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
537                   int fg GCC_UNUSED,
538                   int bg GCC_UNUSED)
539 {
540     SCREEN *sp;
541     int code = ERR;
542
543     AssertTCB();
544     SetSP();
545
546     return (code);
547 }
548
549 static bool
550 get_SBI(TERMINAL_CONTROL_BLOCK * TCB)
551 {
552     bool rc = FALSE;
553     Properties *p = PropOf(TCB);
554     if (GetConsoleScreenBufferInfo(TCB->hdl, &(p->SBI))) {
555         T(("GetConsoleScreenBufferInfo"));
556         T(("... buffer(X:%d Y:%d)",
557            p->SBI.dwSize.X,
558            p->SBI.dwSize.Y));
559         T(("... window(X:%d Y:%d)",
560            p->SBI.dwMaximumWindowSize.X,
561            p->SBI.dwMaximumWindowSize.Y));
562         T(("... cursor(X:%d Y:%d)",
563            p->SBI.dwCursorPosition.X,
564            p->SBI.dwCursorPosition.Y));
565         T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
566            p->SBI.srWindow.Top,
567            p->SBI.srWindow.Bottom,
568            p->SBI.srWindow.Left,
569            p->SBI.srWindow.Right));
570         if (p->buffered) {
571             p->origin.X = 0;
572             p->origin.Y = 0;
573         } else {
574             p->origin.X = p->SBI.srWindow.Left;
575             p->origin.Y = p->SBI.srWindow.Top;
576         }
577         rc = TRUE;
578     } else {
579         T(("GetConsoleScreenBufferInfo ERR"));
580     }
581     return rc;
582 }
583
584 static void
585 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
586              int fore,
587              int color,
588              int (*outc) (SCREEN *, int) GCC_UNUSED)
589 {
590     AssertTCB();
591
592     if (okConsoleHandle(TCB) &&
593         PropOf(TCB) != 0) {
594         WORD a = MapColor(fore, color);
595         a |= (WORD) ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
596         SetConsoleTextAttribute(TCB->hdl, a);
597         get_SBI(TCB);
598     }
599 }
600
601 static bool
602 drv_rescol(TERMINAL_CONTROL_BLOCK * TCB)
603 {
604     bool res = FALSE;
605
606     AssertTCB();
607     if (okConsoleHandle(TCB)) {
608         WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
609         SetConsoleTextAttribute(TCB->hdl, a);
610         get_SBI(TCB);
611         res = TRUE;
612     }
613     return res;
614 }
615
616 static bool
617 drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
618 {
619     int result = FALSE;
620     SCREEN *sp;
621
622     AssertTCB();
623     SetSP();
624
625     return result;
626 }
627
628 static int
629 drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
630 {
631     int result = ERR;
632
633     AssertTCB();
634
635     T((T_CALLED("win32con::drv_size(%p)"), TCB));
636
637     if (okConsoleHandle(TCB) &&
638         PropOf(TCB) != 0 &&
639         Lines != NULL &&
640         Cols != NULL) {
641         if (PropOf(TCB)->buffered) {
642             *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
643             *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
644         } else {
645             *Lines = (int) (PropOf(TCB)->SBI.srWindow.Bottom + 1 -
646                             PropOf(TCB)->SBI.srWindow.Top);
647             *Cols = (int) (PropOf(TCB)->SBI.srWindow.Right + 1 -
648                            PropOf(TCB)->SBI.srWindow.Left);
649         }
650         result = OK;
651     }
652     returnCode(result);
653 }
654
655 static int
656 drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
657             int l GCC_UNUSED,
658             int c GCC_UNUSED)
659 {
660     AssertTCB();
661     return ERR;
662 }
663
664 static int
665 drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
666 {
667     DWORD dwFlag = 0;
668     tcflag_t iflag;
669     tcflag_t lflag;
670
671     AssertTCB();
672
673     if (TCB == 0 || buf == NULL)
674         return ERR;
675
676     if (setFlag) {
677         iflag = buf->c_iflag;
678         lflag = buf->c_lflag;
679
680         GetConsoleMode(TCB->inp, &dwFlag);
681
682         if (lflag & ICANON)
683             dwFlag |= ENABLE_LINE_INPUT;
684         else
685             dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
686
687         if (lflag & ECHO)
688             dwFlag |= ENABLE_ECHO_INPUT;
689         else
690             dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
691
692         if (iflag & BRKINT)
693             dwFlag |= ENABLE_PROCESSED_INPUT;
694         else
695             dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
696
697         dwFlag |= ENABLE_MOUSE_INPUT;
698
699         buf->c_iflag = iflag;
700         buf->c_lflag = lflag;
701         SetConsoleMode(TCB->inp, dwFlag);
702         TCB->term.Nttyb = *buf;
703     } else {
704         iflag = TCB->term.Nttyb.c_iflag;
705         lflag = TCB->term.Nttyb.c_lflag;
706         GetConsoleMode(TCB->inp, &dwFlag);
707
708         if (dwFlag & ENABLE_LINE_INPUT)
709             lflag |= ICANON;
710         else
711             lflag &= (tcflag_t) (~ICANON);
712
713         if (dwFlag & ENABLE_ECHO_INPUT)
714             lflag |= ECHO;
715         else
716             lflag &= (tcflag_t) (~ECHO);
717
718         if (dwFlag & ENABLE_PROCESSED_INPUT)
719             iflag |= BRKINT;
720         else
721             iflag &= (tcflag_t) (~BRKINT);
722
723         TCB->term.Nttyb.c_iflag = iflag;
724         TCB->term.Nttyb.c_lflag = lflag;
725
726         *buf = TCB->term.Nttyb;
727     }
728     return OK;
729 }
730
731 static int
732 drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
733 {
734     SCREEN *sp;
735     TERMINAL *_term = (TERMINAL *) TCB;
736     int code = ERR;
737
738     AssertTCB();
739     sp = TCB->csp;
740
741     PropOf(TCB)->progMode = progFlag;
742     PropOf(TCB)->lastOut = progFlag ? TCB->hdl : TCB->out;
743     SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
744
745     if (progFlag) /* prog mode */  {
746         if (defFlag) {
747             if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
748                 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
749                 code = OK;
750             }
751         } else {
752             /* reset_prog_mode */
753             if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
754                 if (sp) {
755                     if (sp->_keypad_on)
756                         _nc_keypad(sp, TRUE);
757                     NC_BUFFERED(sp, TRUE);
758                 }
759                 code = OK;
760             }
761         }
762     } else {                    /* shell mode */
763         if (defFlag) {
764             /* def_shell_mode */
765             if (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
766                 code = OK;
767             }
768         } else {
769             /* reset_shell_mode */
770             if (sp) {
771                 _nc_keypad(sp, FALSE);
772                 NCURSES_SP_NAME(_nc_flush) (sp);
773                 NC_BUFFERED(sp, FALSE);
774             }
775             code = drv_sgmode(TCB, TRUE, &(_term->Ottyb));
776         }
777     }
778
779     return (code);
780 }
781
782 static void
783 drv_screen_init(SCREEN *sp GCC_UNUSED)
784 {
785 }
786
787 static void
788 drv_wrap(SCREEN *sp GCC_UNUSED)
789 {
790 }
791
792 static int
793 rkeycompare(const void *el1, const void *el2)
794 {
795     WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
796     WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
797
798     return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
799 }
800
801 static int
802 keycompare(const void *el1, const void *el2)
803 {
804     WORD key1 = HIWORD((*((const LONG *) el1)));
805     WORD key2 = HIWORD((*((const LONG *) el2)));
806
807     return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
808 }
809
810 static int
811 MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
812 {
813     WORD nKey = 0;
814     void *res;
815     LONG key = GenMap(vKey, 0);
816     int code = -1;
817
818     AssertTCB();
819
820     res = bsearch(&key,
821                   PropOf(TCB)->map,
822                   (size_t) (N_INI + FKEYS),
823                   sizeof(keylist[0]),
824                   keycompare);
825     if (res) {
826         key = *((LONG *) res);
827         nKey = LOWORD(key);
828         code = (int) (nKey & 0x7fff);
829         if (nKey & 0x8000)
830             code = -code;
831     }
832     return code;
833 }
834
835 static void
836 drv_release(TERMINAL_CONTROL_BLOCK * TCB)
837 {
838     T((T_CALLED("win32con::drv_release(%p)"), TCB));
839
840     AssertTCB();
841     if (TCB->prop)
842         free(TCB->prop);
843
844     returnVoid;
845 }
846
847 /*
848  * Attempt to save the screen contents.  PDCurses does this if
849  * PDC_RESTORE_SCREEN is set, giving the same visual appearance on restoration
850  * as if the library had allocated a console buffer.
851  */
852 static bool
853 save_original_screen(TERMINAL_CONTROL_BLOCK * TCB)
854 {
855     bool result = FALSE;
856     Properties *p = PropOf(TCB);
857     COORD bufferSize;
858     COORD bufferCoord;
859     SMALL_RECT readRegion;
860     size_t want;
861
862     bufferSize.X = p->SBI.dwSize.X;
863     bufferSize.Y = p->SBI.dwSize.Y;
864     want = (size_t) (bufferSize.X * bufferSize.Y);
865
866     if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
867         bufferCoord.X = bufferCoord.Y = 0;
868
869         readRegion.Top = 0;
870         readRegion.Left = 0;
871         readRegion.Bottom = (SHORT) (bufferSize.Y - 1);
872         readRegion.Right = (SHORT) (bufferSize.X - 1);
873
874         T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d",
875            bufferSize.Y, bufferSize.X,
876            readRegion.Top,
877            readRegion.Left,
878            readRegion.Bottom,
879            readRegion.Right,
880            bufferCoord.Y,
881            bufferCoord.X));
882
883         if (ReadConsoleOutput(TCB->hdl,
884                               p->save_screen,
885                               bufferSize,
886                               bufferCoord,
887                               &readRegion)) {
888             result = TRUE;
889         } else {
890             T((" error %#lx", (unsigned long) GetLastError()));
891             FreeAndNull(p->save_screen);
892
893             bufferSize.X = (SHORT) (p->SBI.srWindow.Right
894                                     - p->SBI.srWindow.Left + 1);
895             bufferSize.Y = (SHORT) (p->SBI.srWindow.Bottom
896                                     - p->SBI.srWindow.Top + 1);
897             want = (size_t) (bufferSize.X * bufferSize.Y);
898
899             if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
900                 bufferCoord.X = bufferCoord.Y = 0;
901
902                 readRegion.Top = p->SBI.srWindow.Top;
903                 readRegion.Left = p->SBI.srWindow.Left;
904                 readRegion.Bottom = p->SBI.srWindow.Bottom;
905                 readRegion.Right = p->SBI.srWindow.Right;
906
907                 T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d",
908                    bufferSize.Y, bufferSize.X,
909                    readRegion.Top,
910                    readRegion.Left,
911                    readRegion.Bottom,
912                    readRegion.Right,
913                    bufferCoord.Y,
914                    bufferCoord.X));
915
916                 if (ReadConsoleOutput(TCB->hdl,
917                                       p->save_screen,
918                                       bufferSize,
919                                       bufferCoord,
920                                       &readRegion)) {
921                     result = TRUE;
922                 } else {
923                     T((" error %#lx", (unsigned long) GetLastError()));
924                 }
925             }
926         }
927     }
928
929     T(("... save original screen contents %s", result ? "ok" : "err"));
930     return result;
931 }
932
933 static void
934 drv_init(TERMINAL_CONTROL_BLOCK * TCB)
935 {
936     DWORD num_buttons;
937
938     T((T_CALLED("win32con::drv_init(%p)"), TCB));
939
940     AssertTCB();
941
942     if (TCB) {
943         BOOL b = AllocConsole();
944         WORD a;
945         int i;
946         bool buffered = TRUE;
947
948         if (!b)
949             b = AttachConsole(ATTACH_PARENT_PROCESS);
950
951         TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
952         TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
953
954         if (getenv("NCGDB")) {
955             TCB->hdl = TCB->out;
956             buffered = FALSE;
957         } else {
958             TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
959                                                  0,
960                                                  NULL,
961                                                  CONSOLE_TEXTMODE_BUFFER,
962                                                  NULL);
963         }
964
965         if (InvalidConsoleHandle(TCB->hdl)) {
966             returnVoid;
967         } else if ((TCB->prop = typeCalloc(Properties, 1)) != 0) {
968             PropOf(TCB)->buffered = buffered;
969             if (!get_SBI(TCB)) {
970                 FreeAndNull(TCB->prop);         /* force error in drv_size */
971                 returnVoid;
972             }
973             if (!buffered) {
974                 if (!save_original_screen(TCB)) {
975                     FreeAndNull(TCB->prop);     /* force error in drv_size */
976                     returnVoid;
977                 }
978             }
979         }
980
981         TCB->info.initcolor = TRUE;
982         TCB->info.canchange = FALSE;
983         TCB->info.hascolor = TRUE;
984         TCB->info.caninit = TRUE;
985
986         TCB->info.maxpairs = NUMPAIRS;
987         TCB->info.maxcolors = 8;
988         TCB->info.numlabels = 0;
989         TCB->info.labelwidth = 0;
990         TCB->info.labelheight = 0;
991         TCB->info.nocolorvideo = 1;
992         TCB->info.tabsize = 8;
993
994         if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
995             T(("mouse has %ld buttons", num_buttons));
996             TCB->info.numbuttons = (int) num_buttons;
997         } else {
998             TCB->info.numbuttons = 1;
999         }
1000
1001         TCB->info.defaultPalette = _nc_cga_palette;
1002
1003         for (i = 0; i < (N_INI + FKEYS); i++) {
1004             if (i < N_INI)
1005                 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = (DWORD) keylist[i];
1006             else
1007                 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
1008                     GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
1009         }
1010         qsort(PropOf(TCB)->map,
1011               (size_t) (MAPSIZE),
1012               sizeof(keylist[0]),
1013               keycompare);
1014         qsort(PropOf(TCB)->rmap,
1015               (size_t) (MAPSIZE),
1016               sizeof(keylist[0]),
1017               rkeycompare);
1018
1019         a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
1020         for (i = 0; i < NUMPAIRS; i++)
1021             PropOf(TCB)->pairs[i] = a;
1022     }
1023     returnVoid;
1024 }
1025
1026 static void
1027 drv_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1028              int pair,
1029              int f,
1030              int b)
1031 {
1032     SCREEN *sp;
1033
1034     AssertTCB();
1035     SetSP();
1036
1037     if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1038         && (b >= 0) && (b < 8)) {
1039         PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b);
1040     }
1041 }
1042
1043 static void
1044 drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1045               int color GCC_UNUSED,
1046               int r GCC_UNUSED,
1047               int g GCC_UNUSED,
1048               int b GCC_UNUSED)
1049 {
1050     SCREEN *sp;
1051
1052     AssertTCB();
1053     SetSP();
1054 }
1055
1056 static void
1057 drv_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1058              int old_pair GCC_UNUSED,
1059              int pair GCC_UNUSED,
1060              int reverse GCC_UNUSED,
1061              int (*outc) (SCREEN *, int) GCC_UNUSED
1062 )
1063 {
1064     SCREEN *sp;
1065
1066     AssertTCB();
1067     SetSP();
1068 }
1069
1070 static void
1071 drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1072 {
1073     SCREEN *sp;
1074
1075     AssertTCB();
1076     SetSP();
1077
1078     sp->_mouse_type = M_TERM_DRIVER;
1079 }
1080
1081 static int
1082 drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
1083 {
1084     int rc = 0;
1085     SCREEN *sp;
1086
1087     AssertTCB();
1088     SetSP();
1089
1090     if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1091         rc = TW_MOUSE;
1092     } else {
1093         rc = TCBOf(sp)->drv->twait(TCBOf(sp),
1094                                    TWAIT_MASK,
1095                                    delay,
1096                                    (int *) 0
1097                                    EVENTLIST_2nd(evl));
1098     }
1099
1100     return rc;
1101 }
1102
1103 static int
1104 drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1105           int yold GCC_UNUSED, int xold GCC_UNUSED,
1106           int y, int x)
1107 {
1108     int ret = ERR;
1109     if (okConsoleHandle(TCB)) {
1110         Properties *p = PropOf(TCB);
1111         COORD loc;
1112         loc.X = (short) x;
1113         loc.Y = (short) (y + AdjustY(p));
1114         SetConsoleCursorPosition(TCB->hdl, loc);
1115         ret = OK;
1116     }
1117     return ret;
1118 }
1119
1120 static void
1121 drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1122             int labnum GCC_UNUSED,
1123             char *text GCC_UNUSED)
1124 {
1125     SCREEN *sp;
1126
1127     AssertTCB();
1128     SetSP();
1129 }
1130
1131 static void
1132 drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1133                  int OnFlag GCC_UNUSED)
1134 {
1135     SCREEN *sp;
1136
1137     AssertTCB();
1138     SetSP();
1139 }
1140
1141 static chtype
1142 drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1143 {
1144     chtype res = A_NORMAL;
1145     res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1146     return res;
1147 }
1148
1149 static void
1150 drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1151 {
1152     SCREEN *sp;
1153
1154     AssertTCB();
1155     SetSP();
1156 }
1157
1158 static void
1159 drv_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1160             chtype *real_map GCC_UNUSED,
1161             chtype *fake_map GCC_UNUSED)
1162 {
1163 #define DATA(a,b) { a, b }
1164     static struct {
1165         int acs_code;
1166         int use_code;
1167     } table[] = {
1168         DATA('a', 0xb1),        /* ACS_CKBOARD  */
1169             DATA('f', 0xf8),    /* ACS_DEGREE   */
1170             DATA('g', 0xf1),    /* ACS_PLMINUS  */
1171             DATA('j', 0xd9),    /* ACS_LRCORNER */
1172             DATA('l', 0xda),    /* ACS_ULCORNER */
1173             DATA('k', 0xbf),    /* ACS_URCORNER */
1174             DATA('m', 0xc0),    /* ACS_LLCORNER */
1175             DATA('n', 0xc5),    /* ACS_PLUS     */
1176             DATA('q', 0xc4),    /* ACS_HLINE    */
1177             DATA('t', 0xc3),    /* ACS_LTEE     */
1178             DATA('u', 0xb4),    /* ACS_RTEE     */
1179             DATA('v', 0xc1),    /* ACS_BTEE     */
1180             DATA('w', 0xc2),    /* ACS_TTEE     */
1181             DATA('x', 0xb3),    /* ACS_VLINE    */
1182             DATA('y', 0xf3),    /* ACS_LEQUAL   */
1183             DATA('z', 0xf2),    /* ACS_GEQUAL   */
1184             DATA('0', 0xdb),    /* ACS_BLOCK    */
1185             DATA('{', 0xe3),    /* ACS_PI       */
1186             DATA('}', 0x9c),    /* ACS_STERLING */
1187             DATA(',', 0xae),    /* ACS_LARROW   */
1188             DATA('+', 0xaf),    /* ACS_RARROW   */
1189             DATA('~', 0xf9),    /* ACS_BULLET   */
1190     };
1191 #undef DATA
1192     unsigned n;
1193
1194     SCREEN *sp;
1195     AssertTCB();
1196     SetSP();
1197
1198     for (n = 0; n < SIZEOF(table); ++n) {
1199         real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1200         if (sp != 0)
1201             sp->_screen_acs_map[table[n].acs_code] = TRUE;
1202     }
1203 }
1204
1205 static ULONGLONG
1206 tdiff(FILETIME fstart, FILETIME fend)
1207 {
1208     ULARGE_INTEGER ustart;
1209     ULARGE_INTEGER uend;
1210     ULONGLONG diff;
1211
1212     ustart.LowPart = fstart.dwLowDateTime;
1213     ustart.HighPart = fstart.dwHighDateTime;
1214     uend.LowPart = fend.dwLowDateTime;
1215     uend.HighPart = fend.dwHighDateTime;
1216
1217     diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1218     return diff;
1219 }
1220
1221 static int
1222 Adjust(int milliseconds, int diff)
1223 {
1224     if (milliseconds == INFINITY)
1225         return milliseconds;
1226     milliseconds -= diff;
1227     if (milliseconds < 0)
1228         milliseconds = 0;
1229     return milliseconds;
1230 }
1231
1232 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1233                      FROM_LEFT_2ND_BUTTON_PRESSED | \
1234                      FROM_LEFT_3RD_BUTTON_PRESSED | \
1235                      FROM_LEFT_4TH_BUTTON_PRESSED | \
1236                      RIGHTMOST_BUTTON_PRESSED)
1237
1238 static int
1239 decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
1240 {
1241     SCREEN *sp;
1242     int result = 0;
1243
1244     AssertTCB();
1245     SetSP();
1246
1247     if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1248         result |= BUTTON1_PRESSED;
1249     if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1250         result |= BUTTON2_PRESSED;
1251     if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1252         result |= BUTTON3_PRESSED;
1253     if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1254         result |= BUTTON4_PRESSED;
1255
1256     if (mask & RIGHTMOST_BUTTON_PRESSED) {
1257         switch (TCB->info.numbuttons) {
1258         case 1:
1259             result |= BUTTON1_PRESSED;
1260             break;
1261         case 2:
1262             result |= BUTTON2_PRESSED;
1263             break;
1264         case 3:
1265             result |= BUTTON3_PRESSED;
1266             break;
1267         case 4:
1268             result |= BUTTON4_PRESSED;
1269             break;
1270         }
1271     }
1272
1273     return result;
1274 }
1275
1276 static int
1277 drv_twait(TERMINAL_CONTROL_BLOCK * TCB,
1278           int mode,
1279           int milliseconds,
1280           int *timeleft
1281           EVENTLIST_2nd(_nc_eventlist * evl))
1282 {
1283     SCREEN *sp;
1284     INPUT_RECORD inp_rec;
1285     BOOL b;
1286     DWORD nRead = 0, rc = (DWORD) (-1);
1287     int code = 0;
1288     FILETIME fstart;
1289     FILETIME fend;
1290     int diff;
1291     bool isImmed = (milliseconds == 0);
1292
1293 #define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead)
1294
1295     AssertTCB();
1296     SetSP();
1297
1298     TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1299                       milliseconds, mode));
1300
1301     if (milliseconds < 0)
1302         milliseconds = INFINITY;
1303
1304     memset(&inp_rec, 0, sizeof(inp_rec));
1305
1306     while (true) {
1307         GetSystemTimeAsFileTime(&fstart);
1308         rc = WaitForSingleObject(TCB->inp, (DWORD) milliseconds);
1309         GetSystemTimeAsFileTime(&fend);
1310         diff = (int) tdiff(fstart, fend);
1311         milliseconds = Adjust(milliseconds, diff);
1312
1313         if (!isImmed && milliseconds == 0)
1314             break;
1315
1316         if (rc == WAIT_OBJECT_0) {
1317             if (mode) {
1318                 b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
1319                 if (b && nRead > 0) {
1320                     b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead);
1321                     if (b && nRead > 0) {
1322                         switch (inp_rec.EventType) {
1323                         case KEY_EVENT:
1324                             if (mode & TW_INPUT) {
1325                                 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1326                                 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1327
1328                                 if (inp_rec.Event.KeyEvent.bKeyDown) {
1329                                     if (0 == ch) {
1330                                         int nKey = MapKey(TCB, vk);
1331                                         if ((nKey < 0) || FALSE == sp->_keypad_on) {
1332                                             CONSUME();
1333                                             continue;
1334                                         }
1335                                     }
1336                                     code = TW_INPUT;
1337                                     goto end;
1338                                 } else {
1339                                     CONSUME();
1340                                 }
1341                             }
1342                             continue;
1343                         case MOUSE_EVENT:
1344                             if (decode_mouse(TCB,
1345                                              (inp_rec.Event.MouseEvent.dwButtonState
1346                                               & BUTTON_MASK)) == 0) {
1347                                 CONSUME();
1348                             } else if (mode & TW_MOUSE) {
1349                                 code = TW_MOUSE;
1350                                 goto end;
1351                             }
1352                             continue;
1353                         default:
1354                             selectActiveHandle(TCB);
1355                             continue;
1356                         }
1357                     }
1358                 }
1359             }
1360             continue;
1361         } else {
1362             if (rc != WAIT_TIMEOUT) {
1363                 code = -1;
1364                 break;
1365             } else {
1366                 code = 0;
1367                 break;
1368             }
1369         }
1370     }
1371   end:
1372
1373     TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1374                       code, errno, milliseconds));
1375
1376     if (timeleft)
1377         *timeleft = milliseconds;
1378
1379     return code;
1380 }
1381
1382 static bool
1383 handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
1384 {
1385     SCREEN *sp;
1386     MEVENT work;
1387     bool result = FALSE;
1388
1389     AssertTCB();
1390     SetSP();
1391
1392     sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1393     sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1394
1395     /*
1396      * We're only interested if the button is pressed or released.
1397      * FIXME: implement continuous event-tracking.
1398      */
1399     if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1400         Properties *p = PropOf(TCB);
1401
1402         memset(&work, 0, sizeof(work));
1403
1404         if (sp->_drv_mouse_new_buttons) {
1405
1406             work.bstate |= (mmask_t) decode_mouse(TCB, sp->_drv_mouse_new_buttons);
1407
1408         } else {
1409
1410             /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1411             work.bstate |= (mmask_t) (decode_mouse(TCB,
1412                                                    sp->_drv_mouse_old_buttons)
1413                                       >> 1);
1414
1415             result = TRUE;
1416         }
1417
1418         work.x = mer.dwMousePosition.X;
1419         work.y = mer.dwMousePosition.Y - AdjustY(p);
1420
1421         sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1422         sp->_drv_mouse_tail += 1;
1423     }
1424
1425     return result;
1426 }
1427
1428 static int
1429 drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1430 {
1431     SCREEN *sp;
1432     int n = 1;
1433     INPUT_RECORD inp_rec;
1434     BOOL b;
1435     DWORD nRead;
1436     WORD vk;
1437
1438     AssertTCB();
1439     assert(buf);
1440     SetSP();
1441
1442     memset(&inp_rec, 0, sizeof(inp_rec));
1443
1444     T((T_CALLED("win32con::drv_read(%p)"), TCB));
1445     while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) {
1446         if (b && nRead > 0) {
1447             if (inp_rec.EventType == KEY_EVENT) {
1448                 if (!inp_rec.Event.KeyEvent.bKeyDown)
1449                     continue;
1450                 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
1451                 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1452                 if (*buf == 0) {
1453                     if (sp->_keypad_on) {
1454                         *buf = MapKey(TCB, vk);
1455                         if (0 > (*buf))
1456                             continue;
1457                         else
1458                             break;
1459                     } else
1460                         continue;
1461                 } else {        /* *buf != 0 */
1462                     break;
1463                 }
1464             } else if (inp_rec.EventType == MOUSE_EVENT) {
1465                 if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) {
1466                     *buf = KEY_MOUSE;
1467                     break;
1468                 }
1469             }
1470             continue;
1471         }
1472     }
1473     returnCode(n);
1474 }
1475
1476 static int
1477 drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1478 {
1479     T((T_CALLED("win32con::drv_nap(%p, %d)"), TCB, ms));
1480     Sleep((DWORD) ms);
1481     returnCode(OK);
1482 }
1483
1484 static bool
1485 drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
1486 {
1487     SCREEN *sp;
1488     WORD nKey;
1489     void *res;
1490     bool found = FALSE;
1491     LONG key = GenMap(0, (WORD) keycode);
1492
1493     AssertTCB();
1494     SetSP();
1495
1496     AssertTCB();
1497
1498     T((T_CALLED("win32con::drv_kyExist(%p, %d)"), TCB, keycode));
1499     res = bsearch(&key,
1500                   PropOf(TCB)->rmap,
1501                   (size_t) (N_INI + FKEYS),
1502                   sizeof(keylist[0]),
1503                   rkeycompare);
1504     if (res) {
1505         key = *((LONG *) res);
1506         nKey = LOWORD(key);
1507         if (!(nKey & 0x8000))
1508             found = TRUE;
1509     }
1510     returnCode(found);
1511 }
1512
1513 static int
1514 drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1515 {
1516     SCREEN *sp;
1517     int code = ERR;
1518
1519     AssertTCB();
1520     sp = TCB->csp;
1521
1522     T((T_CALLED("win32con::drv_kpad(%p, %d)"), TCB, flag));
1523     if (sp) {
1524         code = OK;
1525     }
1526     returnCode(code);
1527 }
1528
1529 static int
1530 drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
1531 {
1532     int code = ERR;
1533     SCREEN *sp;
1534     WORD nKey;
1535     WORD vKey;
1536     void *res;
1537     LONG key = GenMap(0, (WORD) keycode);
1538
1539     AssertTCB();
1540     SetSP();
1541
1542     T((T_CALLED("win32con::drv_keyok(%p, %d, %d)"), TCB, keycode, flag));
1543     if (sp) {
1544         res = bsearch(&key,
1545                       PropOf(TCB)->rmap,
1546                       (size_t) (N_INI + FKEYS),
1547                       sizeof(keylist[0]),
1548                       rkeycompare);
1549         if (res) {
1550             key = *((LONG *) res);
1551             vKey = HIWORD(key);
1552             nKey = (LOWORD(key)) & 0x7fff;
1553             if (!flag)
1554                 nKey |= 0x8000;
1555             *(LONG *) res = GenMap(vKey, nKey);
1556         }
1557     }
1558     returnCode(code);
1559 }
1560
1561 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1562     FALSE,
1563         drv_CanHandle,          /* CanHandle */
1564         drv_init,               /* init */
1565         drv_release,            /* release */
1566         drv_size,               /* size */
1567         drv_sgmode,             /* sgmode */
1568         drv_conattr,            /* conattr */
1569         drv_mvcur,              /* hwcur */
1570         drv_mode,               /* mode */
1571         drv_rescol,             /* rescol */
1572         drv_rescolors,          /* rescolors */
1573         drv_setcolor,           /* color */
1574         drv_dobeepflash,        /* DoBeepFlash */
1575         drv_initpair,           /* initpair */
1576         drv_initcolor,          /* initcolor */
1577         drv_do_color,           /* docolor */
1578         drv_initmouse,          /* initmouse */
1579         drv_testmouse,          /* testmouse */
1580         drv_setfilter,          /* setfilter */
1581         drv_hwlabel,            /* hwlabel */
1582         drv_hwlabelOnOff,       /* hwlabelOnOff */
1583         drv_doupdate,           /* update */
1584         drv_defaultcolors,      /* defaultcolors */
1585         drv_print,              /* print */
1586         drv_size,               /* getsize */
1587         drv_setsize,            /* setsize */
1588         drv_initacs,            /* initacs */
1589         drv_screen_init,        /* scinit */
1590         drv_wrap,               /* scexit */
1591         drv_twait,              /* twait */
1592         drv_read,               /* read */
1593         drv_nap,                /* nap */
1594         drv_kpad,               /* kpad */
1595         drv_keyok,              /* kyOk */
1596         drv_kyExist             /* kyExist */
1597 };