]> ncurses.scripts.mit.edu Git - ncurses.git/blob - ncurses/win32con/win_driver.c
ncurses 5.9 - patch 20150124
[ncurses.git] / ncurses / win32con / win_driver.c
1 /****************************************************************************
2  * Copyright (c) 1998-2014,2015 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  *     and: Thomas E. Dickey                                                *
32  ****************************************************************************/
33
34 /*
35  * TODO - GetMousePos(POINT * result) from ntconio.c
36  * TODO - implement nodelay
37  * TODO - improve screen-repainting performance, using implied wraparound to reduce write's
38  * TODO - make it optional whether screen is restored or not when non-buffered
39  */
40
41 #include <curses.priv.h>
42
43 #ifdef __MINGW32__
44 #include <tchar.h>
45 #else
46 #include <windows.h>
47 #include <wchar.h>
48 #endif
49
50 #include <io.h>
51
52 #define PSAPI_VERSION 2
53 #include <psapi.h>
54
55 #define CUR my_term.type.
56
57 MODULE_ID("$Id: win_driver.c,v 1.54 2015/01/10 23:13:24 tom Exp $")
58
59 #ifndef __GNUC__
60 #  error We need GCC to compile for MinGW
61 #endif
62
63 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
64
65 #define EXP_OPTIMIZE 0
66
67 #define array_length(a) (sizeof(a)/sizeof(a[0]))
68
69 #define okConsoleHandle(TCB) (TCB != 0 && CON.hdl != INVALID_HANDLE_VALUE)
70
71 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
72 #define SetSP()     assert(TCB->csp != 0); sp = TCB->csp; (void) sp
73
74 #define GenMap(vKey,key) MAKELONG(key, vKey)
75
76 #define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
77
78 #if USE_WIDEC_SUPPORT
79 #define write_screen WriteConsoleOutputW
80 #define read_screen  ReadConsoleOutputW
81 #else
82 #define write_screen WriteConsoleOutput
83 #define read_screen  ReadConsoleOutput
84 #endif
85
86 static const LONG keylist[] =
87 {
88     GenMap(VK_PRIOR, KEY_PPAGE),
89     GenMap(VK_NEXT, KEY_NPAGE),
90     GenMap(VK_END, KEY_END),
91     GenMap(VK_HOME, KEY_HOME),
92     GenMap(VK_LEFT, KEY_LEFT),
93     GenMap(VK_UP, KEY_UP),
94     GenMap(VK_RIGHT, KEY_RIGHT),
95     GenMap(VK_DOWN, KEY_DOWN),
96     GenMap(VK_DELETE, KEY_DC),
97     GenMap(VK_INSERT, KEY_IC)
98 };
99 static const LONG ansi_keys[] =
100 {
101     GenMap(VK_PRIOR, 'I'),
102     GenMap(VK_NEXT, 'Q'),
103     GenMap(VK_END, 'O'),
104     GenMap(VK_HOME, 'H'),
105     GenMap(VK_LEFT, 'K'),
106     GenMap(VK_UP, 'H'),
107     GenMap(VK_RIGHT, 'M'),
108     GenMap(VK_DOWN, 'P'),
109     GenMap(VK_DELETE, 'S'),
110     GenMap(VK_INSERT, 'R')
111 };
112 #define N_INI ((int)array_length(keylist))
113 #define FKEYS 24
114 #define MAPSIZE (FKEYS + N_INI)
115 #define NUMPAIRS 64
116
117 /*   A process can only have a single console, so it's safe
118      to maintain all the information about it in a single
119      static structure.
120  */
121 static struct {
122     BOOL initialized;
123     BOOL buffered;
124     BOOL window_only;
125     BOOL progMode;
126     BOOL isMinTTY;
127     BOOL isTermInfoConsole;
128     HANDLE out;
129     HANDLE inp;
130     HANDLE hdl;
131     HANDLE lastOut;
132     int numButtons;
133     DWORD ansi_map[MAPSIZE];
134     DWORD map[MAPSIZE];
135     DWORD rmap[MAPSIZE];
136     WORD pairs[NUMPAIRS];
137     COORD origin;
138     CHAR_INFO *save_screen;
139     COORD save_size;
140     SMALL_RECT save_region;
141     CONSOLE_SCREEN_BUFFER_INFO SBI;
142     CONSOLE_SCREEN_BUFFER_INFO save_SBI;
143     CONSOLE_CURSOR_INFO save_CI;
144 } CON;
145
146 static BOOL console_initialized = FALSE;
147
148 static WORD
149 MapColor(bool fore, int color)
150 {
151     static const int _cmap[] =
152     {0, 4, 2, 6, 1, 5, 3, 7};
153     int a;
154     if (color < 0 || color > 7)
155         a = fore ? 7 : 0;
156     else
157         a = _cmap[color];
158     if (!fore)
159         a = a << 4;
160     return (WORD) a;
161 }
162
163 #define RevAttr(attr) \
164                (WORD) (((attr) & 0xff00) | \
165                       ((((attr) & 0x07) << 4) | \
166                        (((attr) & 0x70) >> 4)))
167
168 static WORD
169 MapAttr(WORD res, attr_t ch)
170 {
171     if (ch & A_COLOR) {
172         int p;
173
174         p = PairNumber(ch);
175         if (p > 0 && p < NUMPAIRS) {
176             WORD a;
177             a = CON.pairs[p];
178             res = (WORD) ((res & 0xff00) | a);
179         }
180     }
181
182     if (ch & A_REVERSE) {
183         res = RevAttr(res);
184     }
185
186     if (ch & A_STANDOUT) {
187         res = RevAttr(res) | BACKGROUND_INTENSITY;
188     }
189
190     if (ch & A_BOLD)
191         res |= FOREGROUND_INTENSITY;
192
193     if (ch & A_DIM)
194         res |= BACKGROUND_INTENSITY;
195
196     return res;
197 }
198
199 #if 0                           /* def TRACE */
200 static void
201 dump_screen(const char *fn, int ln)
202 {
203     int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1;
204     char output[max_cells];
205     CHAR_INFO save_screen[max_cells];
206     COORD save_size;
207     SMALL_RECT save_region;
208     COORD bufferCoord;
209
210     T(("dump_screen %s@%d", fn, ln));
211
212     save_region.Top = CON.SBI.srWindow.Top;
213     save_region.Left = CON.SBI.srWindow.Left;
214     save_region.Bottom = CON.SBI.srWindow.Bottom;
215     save_region.Right = CON.SBI.srWindow.Right;
216
217     save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
218     save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
219
220     bufferCoord.X = bufferCoord.Y = 0;
221
222     if (read_screen(CON.hdl,
223                     save_screen,
224                     save_size,
225                     bufferCoord,
226                     &save_region)) {
227         int i, j;
228         int ij = 0;
229         int k = 0;
230
231         for (i = save_region.Top; i <= save_region.Bottom; ++i) {
232             for (j = save_region.Left; j <= save_region.Right; ++j) {
233                 output[k++] = save_screen[ij++].Char.AsciiChar;
234             }
235             output[k++] = '\n';
236         }
237         output[k] = 0;
238
239         T(("DUMP: %d,%d - %d,%d",
240            save_region.Top,
241            save_region.Left,
242            save_region.Bottom,
243            save_region.Right));
244         T(("%s", output));
245     }
246 }
247
248 #else
249 #define dump_screen(fn,ln)      /* nothing */
250 #endif
251
252 #if USE_WIDEC_SUPPORT
253 /*
254  * TODO: support surrogate pairs
255  * TODO: support combining characters
256  * TODO: support acsc
257  * TODO: _nc_wacs should be part of sp.
258  */
259 static BOOL
260 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
261 {
262     int actual = 0;
263     CHAR_INFO ci[limit];
264     COORD loc, siz;
265     SMALL_RECT rec;
266     int i;
267     cchar_t ch;
268     SCREEN *sp;
269
270     AssertTCB();
271     SetSP();
272
273     for (i = actual = 0; i < limit; i++) {
274         ch = str[i];
275         if (isWidecExt(ch))
276             continue;
277         ci[actual].Char.UnicodeChar = CharOf(ch);
278         ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
279                                         AttrOf(ch));
280         if (AttrOf(ch) & A_ALTCHARSET) {
281             if (_nc_wacs) {
282                 int which = CharOf(ch);
283                 if (which > 0
284                     && which < ACS_LEN
285                     && CharOf(_nc_wacs[which]) != 0) {
286                     ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
287                 } else {
288                     ci[actual].Char.UnicodeChar = ' ';
289                 }
290             }
291         }
292         ++actual;
293     }
294
295     loc.X = (SHORT) 0;
296     loc.Y = (SHORT) 0;
297     siz.X = (SHORT) actual;
298     siz.Y = 1;
299
300     rec.Left = (SHORT) x;
301     rec.Top = (SHORT) (y + AdjustY());
302     rec.Right = (SHORT) (x + limit - 1);
303     rec.Bottom = rec.Top;
304
305     return write_screen(CON.hdl, ci, siz, loc, &rec);
306 }
307 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
308 #else
309 static BOOL
310 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
311 {
312     CHAR_INFO ci[n];
313     COORD loc, siz;
314     SMALL_RECT rec;
315     int i;
316     chtype ch;
317     SCREEN *sp;
318
319     AssertTCB();
320     SetSP();
321
322     for (i = 0; i < n; i++) {
323         ch = str[i];
324         ci[i].Char.AsciiChar = ChCharOf(ch);
325         ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
326                                    ChAttrOf(ch));
327         if (ChAttrOf(ch) & A_ALTCHARSET) {
328             if (sp->_acs_map)
329                 ci[i].Char.AsciiChar =
330                 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
331         }
332     }
333
334     loc.X = (short) 0;
335     loc.Y = (short) 0;
336     siz.X = (short) n;
337     siz.Y = 1;
338
339     rec.Left = (short) x;
340     rec.Top = (short) y;
341     rec.Right = (short) (x + n - 1);
342     rec.Bottom = rec.Top;
343
344     return write_screen(CON.hdl, ci, siz, loc, &rec);
345 }
346 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
347 #endif
348
349 #if EXP_OPTIMIZE
350 /*
351  * Comparing new/current screens, determine the last column-index for a change
352  * beginning on the given row,col position.  Unlike a serial terminal, there is
353  * no cost for "moving" the "cursor" on the line as we update it.
354  */
355 static int
356 find_end_of_change(SCREEN *sp, int row, int col)
357 {
358     int result = col;
359     struct ldat *curdat = CurScreen(sp)->_line + row;
360     struct ldat *newdat = NewScreen(sp)->_line + row;
361
362     while (col <= newdat->lastchar) {
363 #if USE_WIDEC_SUPPORT
364         if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
365             result = col;
366         } else if (memcmp(&curdat->text[col],
367                           &newdat->text[col],
368                           sizeof(curdat->text[0]))) {
369             result = col;
370         } else {
371             break;
372         }
373 #else
374         if (curdat->text[col] != newdat->text[col]) {
375             result = col;
376         } else {
377             break;
378         }
379 #endif
380         ++col;
381     }
382     return result;
383 }
384
385 /*
386  * Given a row,col position at the end of a change-chunk, look for the
387  * beginning of the next change-chunk.
388  */
389 static int
390 find_next_change(SCREEN *sp, int row, int col)
391 {
392     struct ldat *curdat = CurScreen(sp)->_line + row;
393     struct ldat *newdat = NewScreen(sp)->_line + row;
394     int result = newdat->lastchar + 1;
395
396     while (++col <= newdat->lastchar) {
397 #if USE_WIDEC_SUPPORT
398         if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
399             result = col;
400             break;
401         } else if (memcmp(&curdat->text[col],
402                           &newdat->text[col],
403                           sizeof(curdat->text[0]))) {
404             result = col;
405             break;
406         }
407 #else
408         if (curdat->text[col] != newdat->text[col]) {
409             result = col;
410             break;
411         }
412 #endif
413     }
414     return result;
415 }
416
417 #define EndChange(first) \
418         find_end_of_change(sp, y, first)
419 #define NextChange(last) \
420         find_next_change(sp, y, last)
421
422 #endif /* EXP_OPTIMIZE */
423
424 #define MARK_NOCHANGE(win,row) \
425                 win->_line[row].firstchar = _NOCHANGE; \
426                 win->_line[row].lastchar  = _NOCHANGE
427
428 static void
429 selectActiveHandle(void)
430 {
431     if (CON.lastOut != CON.hdl) {
432         CON.lastOut = CON.hdl;
433         SetConsoleActiveScreenBuffer(CON.lastOut);
434     }
435 }
436
437 static bool
438 restore_original_screen(void)
439 {
440     COORD bufferCoord;
441     bool result = FALSE;
442     SMALL_RECT save_region = CON.save_region;
443
444     T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
445
446     bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
447     bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
448
449     if (write_screen(CON.hdl,
450                      CON.save_screen,
451                      CON.save_size,
452                      bufferCoord,
453                      &save_region)) {
454         result = TRUE;
455         mvcur(-1, -1, LINES - 2, 0);
456         T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
457            CON.save_size.Y,
458            CON.save_size.X,
459            save_region.Top,
460            save_region.Left,
461            save_region.Bottom,
462            save_region.Right));
463     } else {
464         T(("... restore original screen contents err"));
465     }
466     return result;
467 }
468
469 static const char *
470 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
471 {
472     (void) TCB;
473     return "win32console";
474 }
475
476 static int
477 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
478 {
479     int result = ERR;
480     int y, nonempty, n, x0, x1, Width, Height;
481     SCREEN *sp;
482
483     AssertTCB();
484     SetSP();
485
486     T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
487     if (okConsoleHandle(TCB)) {
488
489         Width = screen_columns(sp);
490         Height = screen_lines(sp);
491         nonempty = min(Height, NewScreen(sp)->_maxy + 1);
492
493         T(("... %dx%d clear cur:%d new:%d",
494            Height, Width,
495            CurScreen(sp)->_clear,
496            NewScreen(sp)->_clear));
497
498         if (SP_PARM->_endwin) {
499
500             T(("coming back from shell mode"));
501             NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
502
503             NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
504             NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
505             SP_PARM->_mouse_resume(SP_PARM);
506
507             SP_PARM->_endwin = FALSE;
508         }
509
510         if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
511             int x;
512 #if USE_WIDEC_SUPPORT
513             cchar_t empty[Width];
514             wchar_t blank[2] =
515             {
516                 L' ', L'\0'
517             };
518
519             for (x = 0; x < Width; x++)
520                 setcchar(&empty[x], blank, 0, 0, 0);
521 #else
522             chtype empty[Width];
523
524             for (x = 0; x < Width; x++)
525                 empty[x] = ' ';
526 #endif
527
528             for (y = 0; y < nonempty; y++) {
529                 con_write(TCB, y, 0, empty, Width);
530                 memcpy(empty,
531                        CurScreen(sp)->_line[y].text,
532                        (size_t) Width * sizeof(empty[0]));
533             }
534             CurScreen(sp)->_clear = FALSE;
535             NewScreen(sp)->_clear = FALSE;
536             touchwin(NewScreen(sp));
537             T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
538                AdjustY()));
539         }
540
541         for (y = 0; y < nonempty; y++) {
542             x0 = NewScreen(sp)->_line[y].firstchar;
543             if (x0 != _NOCHANGE) {
544 #if EXP_OPTIMIZE
545                 int x2;
546                 int limit = NewScreen(sp)->_line[y].lastchar;
547                 while ((x1 = EndChange(x0)) <= limit) {
548                     while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
549                         x1 = x2;
550                     }
551                     n = x1 - x0 + 1;
552                     memcpy(&CurScreen(sp)->_line[y].text[x0],
553                            &NewScreen(sp)->_line[y].text[x0],
554                            n * sizeof(CurScreen(sp)->_line[y].text[x0]));
555                     con_write(TCB,
556                               y,
557                               x0,
558                               &CurScreen(sp)->_line[y].text[x0], n);
559                     x0 = NextChange(x1);
560                 }
561
562                 /* mark line changed successfully */
563                 if (y <= NewScreen(sp)->_maxy) {
564                     MARK_NOCHANGE(NewScreen(sp), y);
565                 }
566                 if (y <= CurScreen(sp)->_maxy) {
567                     MARK_NOCHANGE(CurScreen(sp), y);
568                 }
569 #else
570                 x1 = NewScreen(sp)->_line[y].lastchar;
571                 n = x1 - x0 + 1;
572                 if (n > 0) {
573                     memcpy(&CurScreen(sp)->_line[y].text[x0],
574                            &NewScreen(sp)->_line[y].text[x0],
575                            (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
576                     con_write(TCB,
577                               y,
578                               x0,
579                               &CurScreen(sp)->_line[y].text[x0], n);
580
581                     /* mark line changed successfully */
582                     if (y <= NewScreen(sp)->_maxy) {
583                         MARK_NOCHANGE(NewScreen(sp), y);
584                     }
585                     if (y <= CurScreen(sp)->_maxy) {
586                         MARK_NOCHANGE(CurScreen(sp), y);
587                     }
588                 }
589 #endif
590             }
591         }
592
593         /* put everything back in sync */
594         for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
595             MARK_NOCHANGE(NewScreen(sp), y);
596         }
597         for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
598             MARK_NOCHANGE(CurScreen(sp), y);
599         }
600
601         if (!NewScreen(sp)->_leaveok) {
602             CurScreen(sp)->_curx = NewScreen(sp)->_curx;
603             CurScreen(sp)->_cury = NewScreen(sp)->_cury;
604
605             TCB->drv->td_hwcur(TCB,
606                                0, 0,
607                                CurScreen(sp)->_cury, CurScreen(sp)->_curx);
608         }
609         selectActiveHandle();
610         result = OK;
611     }
612     returnCode(result);
613 }
614
615 static bool
616 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
617                const char *tname,
618                int *errret GCC_UNUSED)
619 {
620     bool code = FALSE;
621
622     T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
623
624     assert((TCB != 0) && (tname != 0));
625
626     TCB->magic = WINMAGIC;
627
628     if (tname == 0 || *tname == 0)
629         code = TRUE;
630     else if (tname != 0 && *tname == '#') {
631         /*
632          * Use "#" (a character which cannot begin a terminal's name) to
633          * select specific driver from the table.
634          *
635          * In principle, we could have more than one non-terminfo driver,
636          * e.g., "win32gui".
637          */
638         size_t n = strlen(tname + 1);
639         if (n != 0
640             && ((strncmp(tname + 1, "win32console", n) == 0)
641                 || (strncmp(tname + 1, "win32con", n) == 0))) {
642             code = TRUE;
643         }
644     } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
645         code = TRUE;
646     }
647
648     /*
649      * This is intentional, to avoid unnecessary breakage of applications
650      * using <term.h> symbols.
651      */
652     if (code && (TCB->term.type.Booleans == 0)) {
653         _nc_init_termtype(&(TCB->term.type));
654     }
655
656     if (!code) {
657         if (_nc_mingw_isconsole(0))
658             CON.isTermInfoConsole = TRUE;
659     }
660     returnBool(code);
661 }
662
663 static int
664 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
665                  int beepFlag)
666 {
667     SCREEN *sp;
668     int res = OK;
669
670     int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
671     int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
672     int max_cells = (high * wide);
673     int i;
674
675     CHAR_INFO this_screen[max_cells];
676     CHAR_INFO that_screen[max_cells];
677     COORD this_size;
678     SMALL_RECT this_region;
679     COORD bufferCoord;
680
681     AssertTCB();
682
683     SetSP();
684
685     this_region.Top = CON.SBI.srWindow.Top;
686     this_region.Left = CON.SBI.srWindow.Left;
687     this_region.Bottom = CON.SBI.srWindow.Bottom;
688     this_region.Right = CON.SBI.srWindow.Right;
689
690     this_size.X = (SHORT) wide;
691     this_size.Y = (SHORT) high;
692
693     bufferCoord.X = this_region.Left;
694     bufferCoord.Y = this_region.Top;
695
696     if (!beepFlag &&
697         read_screen(CON.hdl,
698                     this_screen,
699                     this_size,
700                     bufferCoord,
701                     &this_region)) {
702
703         memcpy(that_screen, this_screen, sizeof(that_screen));
704
705         for (i = 0; i < max_cells; i++) {
706             that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
707         }
708
709         write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
710         Sleep(200);
711         write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
712
713     } else {
714         MessageBeep(MB_ICONWARNING);    /* MB_OK might be better */
715     }
716     return res;
717 }
718
719 static int
720 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
721            char *data GCC_UNUSED,
722            int len GCC_UNUSED)
723 {
724     SCREEN *sp;
725
726     AssertTCB();
727     SetSP();
728
729     return ERR;
730 }
731
732 static int
733 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
734                    int fg GCC_UNUSED,
735                    int bg GCC_UNUSED)
736 {
737     SCREEN *sp;
738     int code = ERR;
739
740     AssertTCB();
741     SetSP();
742
743     return (code);
744 }
745
746 static bool
747 get_SBI(void)
748 {
749     bool rc = FALSE;
750     if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
751         T(("GetConsoleScreenBufferInfo"));
752         T(("... buffer(X:%d Y:%d)",
753            CON.SBI.dwSize.X,
754            CON.SBI.dwSize.Y));
755         T(("... window(X:%d Y:%d)",
756            CON.SBI.dwMaximumWindowSize.X,
757            CON.SBI.dwMaximumWindowSize.Y));
758         T(("... cursor(X:%d Y:%d)",
759            CON.SBI.dwCursorPosition.X,
760            CON.SBI.dwCursorPosition.Y));
761         T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
762            CON.SBI.srWindow.Top,
763            CON.SBI.srWindow.Bottom,
764            CON.SBI.srWindow.Left,
765            CON.SBI.srWindow.Right));
766         if (CON.buffered) {
767             CON.origin.X = 0;
768             CON.origin.Y = 0;
769         } else {
770             CON.origin.X = CON.SBI.srWindow.Left;
771             CON.origin.Y = CON.SBI.srWindow.Top;
772         }
773         rc = TRUE;
774     } else {
775         T(("GetConsoleScreenBufferInfo ERR"));
776     }
777     return rc;
778 }
779
780 static void
781 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
782               int fore,
783               int color,
784               int (*outc) (SCREEN *, int) GCC_UNUSED)
785 {
786     AssertTCB();
787
788     if (okConsoleHandle(TCB)) {
789         WORD a = MapColor(fore, color);
790         a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
791         SetConsoleTextAttribute(CON.hdl, a);
792         get_SBI();
793     }
794 }
795
796 static bool
797 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
798 {
799     bool res = FALSE;
800
801     AssertTCB();
802     if (okConsoleHandle(TCB)) {
803         WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
804         SetConsoleTextAttribute(CON.hdl, a);
805         get_SBI();
806         res = TRUE;
807     }
808     return res;
809 }
810
811 static bool
812 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
813 {
814     int result = FALSE;
815     SCREEN *sp;
816
817     AssertTCB();
818     SetSP();
819
820     return result;
821 }
822
823 static int
824 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
825 {
826     int result = ERR;
827
828     AssertTCB();
829
830     T((T_CALLED("win32con::wcon_size(%p)"), TCB));
831
832     if (okConsoleHandle(TCB) &&
833         Lines != NULL &&
834         Cols != NULL) {
835         if (CON.buffered) {
836             *Lines = (int) (CON.SBI.dwSize.Y);
837             *Cols = (int) (CON.SBI.dwSize.X);
838         } else {
839             *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
840                             CON.SBI.srWindow.Top);
841             *Cols = (int) (CON.SBI.srWindow.Right + 1 -
842                            CON.SBI.srWindow.Left);
843         }
844         result = OK;
845     }
846     returnCode(result);
847 }
848
849 static int
850 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
851              int l GCC_UNUSED,
852              int c GCC_UNUSED)
853 {
854     AssertTCB();
855     return ERR;
856 }
857
858 static int
859 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
860 {
861     DWORD dwFlag = 0;
862     tcflag_t iflag;
863     tcflag_t lflag;
864
865     AssertTCB();
866
867     if (TCB == 0 || buf == NULL)
868         return ERR;
869
870     if (setFlag) {
871         iflag = buf->c_iflag;
872         lflag = buf->c_lflag;
873
874         GetConsoleMode(CON.inp, &dwFlag);
875
876         if (lflag & ICANON)
877             dwFlag |= ENABLE_LINE_INPUT;
878         else
879             dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
880
881         if (lflag & ECHO)
882             dwFlag |= ENABLE_ECHO_INPUT;
883         else
884             dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
885
886         if (iflag & BRKINT)
887             dwFlag |= ENABLE_PROCESSED_INPUT;
888         else
889             dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
890
891         dwFlag |= ENABLE_MOUSE_INPUT;
892
893         buf->c_iflag = iflag;
894         buf->c_lflag = lflag;
895         SetConsoleMode(CON.inp, dwFlag);
896         TCB->term.Nttyb = *buf;
897     } else {
898         iflag = TCB->term.Nttyb.c_iflag;
899         lflag = TCB->term.Nttyb.c_lflag;
900         GetConsoleMode(CON.inp, &dwFlag);
901
902         if (dwFlag & ENABLE_LINE_INPUT)
903             lflag |= ICANON;
904         else
905             lflag &= (tcflag_t) (~ICANON);
906
907         if (dwFlag & ENABLE_ECHO_INPUT)
908             lflag |= ECHO;
909         else
910             lflag &= (tcflag_t) (~ECHO);
911
912         if (dwFlag & ENABLE_PROCESSED_INPUT)
913             iflag |= BRKINT;
914         else
915             iflag &= (tcflag_t) (~BRKINT);
916
917         TCB->term.Nttyb.c_iflag = iflag;
918         TCB->term.Nttyb.c_lflag = lflag;
919
920         *buf = TCB->term.Nttyb;
921     }
922     return OK;
923 }
924
925 #define MIN_WIDE 80
926 #define MIN_HIGH 24
927
928 /*
929  * In "normal" mode, reset the buffer- and window-sizes back to their original values.
930  */
931 static void
932 set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
933 {
934     SMALL_RECT rect;
935     COORD coord;
936     bool changed = FALSE;
937
938     T((T_CALLED("win32con::set_scrollback(%s)"),
939        (normal
940         ? "normal"
941         : "application")));
942
943     T(("... SBI.srWindow %d,%d .. %d,%d",
944        info->srWindow.Top,
945        info->srWindow.Left,
946        info->srWindow.Bottom,
947        info->srWindow.Right));
948     T(("... SBI.dwSize %dx%d",
949        info->dwSize.Y,
950        info->dwSize.X));
951
952     if (normal) {
953         rect = info->srWindow;
954         coord = info->dwSize;
955         if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
956             changed = TRUE;
957             CON.SBI = *info;
958         }
959     } else {
960         int high = info->srWindow.Bottom - info->srWindow.Top + 1;
961         int wide = info->srWindow.Right - info->srWindow.Left + 1;
962
963         if (high < MIN_HIGH) {
964             T(("... height %d < %d", high, MIN_HIGH));
965             high = MIN_HIGH;
966             changed = TRUE;
967         }
968         if (wide < MIN_WIDE) {
969             T(("... width %d < %d", wide, MIN_WIDE));
970             wide = MIN_WIDE;
971             changed = TRUE;
972         }
973
974         rect.Left =
975             rect.Top = 0;
976         rect.Right = (SHORT) (wide - 1);
977         rect.Bottom = (SHORT) (high - 1);
978
979         coord.X = (SHORT) wide;
980         coord.Y = (SHORT) high;
981
982         if (info->dwSize.Y != high ||
983             info->dwSize.X != wide ||
984             info->srWindow.Top != 0 ||
985             info->srWindow.Left != 0) {
986             changed = TRUE;
987         }
988
989     }
990
991     if (changed) {
992         T(("... coord %d,%d", coord.Y, coord.X));
993         T(("... rect %d,%d - %d,%d",
994            rect.Top, rect.Left,
995            rect.Bottom, rect.Right));
996         SetConsoleScreenBufferSize(CON.hdl, coord);     /* dwSize */
997         SetConsoleWindowInfo(CON.hdl, TRUE, &rect);     /* srWindow */
998         get_SBI();
999     }
1000     returnVoid;
1001 }
1002
1003 static int
1004 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
1005 {
1006     SCREEN *sp;
1007     TERMINAL *_term = (TERMINAL *) TCB;
1008     int code = ERR;
1009
1010     AssertTCB();
1011     sp = TCB->csp;
1012
1013     T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"), TCB, progFlag, defFlag));
1014     CON.progMode = progFlag;
1015     CON.lastOut = progFlag ? CON.hdl : CON.out;
1016     SetConsoleActiveScreenBuffer(CON.lastOut);
1017
1018     if (progFlag) /* prog mode */  {
1019         if (defFlag) {
1020             if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
1021                 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
1022                 code = OK;
1023             }
1024         } else {
1025             /* reset_prog_mode */
1026             if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
1027                 if (sp) {
1028                     if (sp->_keypad_on)
1029                         _nc_keypad(sp, TRUE);
1030                 }
1031                 if (!CON.buffered) {
1032                     set_scrollback(FALSE, &CON.SBI);
1033                 }
1034                 code = OK;
1035             }
1036         }
1037         T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
1038     } else {                    /* shell mode */
1039         if (defFlag) {
1040             /* def_shell_mode */
1041             if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
1042                 code = OK;
1043             }
1044         } else {
1045             /* reset_shell_mode */
1046             if (sp) {
1047                 _nc_keypad(sp, FALSE);
1048                 NCURSES_SP_NAME(_nc_flush) (sp);
1049             }
1050             code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
1051             if (!CON.buffered) {
1052                 set_scrollback(TRUE, &CON.save_SBI);
1053                 if (!restore_original_screen())
1054                     code = ERR;
1055             }
1056             SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
1057         }
1058     }
1059
1060     returnCode(code);
1061 }
1062
1063 static void
1064 wcon_screen_init(SCREEN *sp GCC_UNUSED)
1065 {
1066 }
1067
1068 static void
1069 wcon_wrap(SCREEN *sp GCC_UNUSED)
1070 {
1071 }
1072
1073 static int
1074 rkeycompare(const void *el1, const void *el2)
1075 {
1076     WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
1077     WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
1078
1079     return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1080 }
1081
1082 static int
1083 keycompare(const void *el1, const void *el2)
1084 {
1085     WORD key1 = HIWORD((*((const LONG *) el1)));
1086     WORD key2 = HIWORD((*((const LONG *) el2)));
1087
1088     return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1089 }
1090
1091 static int
1092 MapKey(WORD vKey)
1093 {
1094     WORD nKey = 0;
1095     void *res;
1096     LONG key = GenMap(vKey, 0);
1097     int code = -1;
1098
1099     res = bsearch(&key,
1100                   CON.map,
1101                   (size_t) (N_INI + FKEYS),
1102                   sizeof(keylist[0]),
1103                   keycompare);
1104     if (res) {
1105         key = *((LONG *) res);
1106         nKey = LOWORD(key);
1107         code = (int) (nKey & 0x7fff);
1108         if (nKey & 0x8000)
1109             code = -code;
1110     }
1111     return code;
1112 }
1113
1114 static int
1115 AnsiKey(WORD vKey)
1116 {
1117     WORD nKey = 0;
1118     void *res;
1119     LONG key = GenMap(vKey, 0);
1120     int code = -1;
1121
1122     res = bsearch(&key,
1123                   CON.ansi_map,
1124                   (size_t) (N_INI + FKEYS),
1125                   sizeof(keylist[0]),
1126                   keycompare);
1127     if (res) {
1128         key = *((LONG *) res);
1129         nKey = LOWORD(key);
1130         code = (int) (nKey & 0x7fff);
1131         if (nKey & 0x8000)
1132             code = -code;
1133     }
1134     return code;
1135 }
1136
1137 static void
1138 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
1139 {
1140     T((T_CALLED("win32con::wcon_release(%p)"), TCB));
1141
1142     AssertTCB();
1143     if (TCB->prop)
1144         free(TCB->prop);
1145
1146     returnVoid;
1147 }
1148
1149 static bool
1150 read_screen_data(void)
1151 {
1152     bool result = FALSE;
1153     COORD bufferCoord;
1154     size_t want;
1155
1156     CON.save_size.X = (SHORT) (CON.save_region.Right
1157                                - CON.save_region.Left + 1);
1158     CON.save_size.Y = (SHORT) (CON.save_region.Bottom
1159                                - CON.save_region.Top + 1);
1160
1161     want = (size_t) (CON.save_size.X * CON.save_size.Y);
1162
1163     if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1164         bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
1165         bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
1166
1167         T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
1168            CON.window_only ? "window" : "buffer",
1169            CON.save_size.Y, CON.save_size.X,
1170            CON.save_region.Top,
1171            CON.save_region.Left,
1172            CON.save_region.Bottom,
1173            CON.save_region.Right,
1174            bufferCoord.Y,
1175            bufferCoord.X));
1176
1177         if (read_screen(CON.hdl,
1178                         CON.save_screen,
1179                         CON.save_size,
1180                         bufferCoord,
1181                         &CON.save_region)) {
1182             result = TRUE;
1183         } else {
1184             T((" error %#lx", (unsigned long) GetLastError()));
1185             FreeAndNull(CON.save_screen);
1186         }
1187     }
1188
1189     return result;
1190 }
1191
1192 /*
1193  * Attempt to save the screen contents.  PDCurses does this if
1194  * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
1195  * restoration as if the library had allocated a console buffer.  MSDN
1196  * says that the data which can be read is limited to 64Kb (and may be
1197  * less).
1198  */
1199 static bool
1200 save_original_screen(void)
1201 {
1202     bool result = FALSE;
1203
1204     CON.save_region.Top = 0;
1205     CON.save_region.Left = 0;
1206     CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
1207     CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
1208
1209     if (read_screen_data()) {
1210         result = TRUE;
1211     } else {
1212
1213         CON.save_region.Top = CON.SBI.srWindow.Top;
1214         CON.save_region.Left = CON.SBI.srWindow.Left;
1215         CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
1216         CON.save_region.Right = CON.SBI.srWindow.Right;
1217
1218         CON.window_only = TRUE;
1219
1220         if (read_screen_data()) {
1221             result = TRUE;
1222         }
1223     }
1224
1225     T(("... save original screen contents %s", result ? "ok" : "err"));
1226     return result;
1227 }
1228
1229 static void
1230 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1231 {
1232     T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1233
1234     AssertTCB();
1235
1236     if (TCB) {
1237         if (CON.hdl == INVALID_HANDLE_VALUE) {
1238             returnVoid;
1239         }
1240
1241         TCB->info.initcolor = TRUE;
1242         TCB->info.canchange = FALSE;
1243         TCB->info.hascolor = TRUE;
1244         TCB->info.caninit = TRUE;
1245
1246         TCB->info.maxpairs = NUMPAIRS;
1247         TCB->info.maxcolors = 8;
1248         TCB->info.numlabels = 0;
1249         TCB->info.labelwidth = 0;
1250         TCB->info.labelheight = 0;
1251         TCB->info.nocolorvideo = 1;
1252         TCB->info.tabsize = 8;
1253
1254         TCB->info.numbuttons = CON.numButtons;
1255         TCB->info.defaultPalette = _nc_cga_palette;
1256
1257     }
1258     returnVoid;
1259 }
1260
1261 static void
1262 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1263               int pair,
1264               int f,
1265               int b)
1266 {
1267     SCREEN *sp;
1268
1269     AssertTCB();
1270     SetSP();
1271
1272     if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1273         && (b >= 0) && (b < 8)) {
1274         CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
1275     }
1276 }
1277
1278 static void
1279 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1280                int color GCC_UNUSED,
1281                int r GCC_UNUSED,
1282                int g GCC_UNUSED,
1283                int b GCC_UNUSED)
1284 {
1285     SCREEN *sp;
1286
1287     AssertTCB();
1288     SetSP();
1289 }
1290
1291 static void
1292 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1293               int old_pair GCC_UNUSED,
1294               int pair GCC_UNUSED,
1295               int reverse GCC_UNUSED,
1296               int (*outc) (SCREEN *, int) GCC_UNUSED
1297 )
1298 {
1299     SCREEN *sp;
1300
1301     AssertTCB();
1302     SetSP();
1303 }
1304
1305 static void
1306 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1307 {
1308     SCREEN *sp;
1309
1310     AssertTCB();
1311     SetSP();
1312
1313     sp->_mouse_type = M_TERM_DRIVER;
1314 }
1315
1316 static int
1317 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
1318 {
1319     int rc = 0;
1320     SCREEN *sp;
1321
1322     AssertTCB();
1323     SetSP();
1324
1325     if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1326         rc = TW_MOUSE;
1327     } else {
1328         rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1329                                       TWAIT_MASK,
1330                                       delay,
1331                                       (int *) 0
1332                                       EVENTLIST_2nd(evl));
1333     }
1334
1335     return rc;
1336 }
1337
1338 static int
1339 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1340            int yold GCC_UNUSED, int xold GCC_UNUSED,
1341            int y, int x)
1342 {
1343     int ret = ERR;
1344     if (okConsoleHandle(TCB)) {
1345         COORD loc;
1346         loc.X = (short) x;
1347         loc.Y = (short) (y + AdjustY());
1348         SetConsoleCursorPosition(CON.hdl, loc);
1349         ret = OK;
1350     }
1351     return ret;
1352 }
1353
1354 static void
1355 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1356              int labnum GCC_UNUSED,
1357              char *text GCC_UNUSED)
1358 {
1359     SCREEN *sp;
1360
1361     AssertTCB();
1362     SetSP();
1363 }
1364
1365 static void
1366 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1367                   int OnFlag GCC_UNUSED)
1368 {
1369     SCREEN *sp;
1370
1371     AssertTCB();
1372     SetSP();
1373 }
1374
1375 static chtype
1376 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1377 {
1378     chtype res = A_NORMAL;
1379     res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1380     return res;
1381 }
1382
1383 static void
1384 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1385 {
1386     SCREEN *sp;
1387
1388     AssertTCB();
1389     SetSP();
1390 }
1391
1392 static void
1393 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1394              chtype *real_map GCC_UNUSED,
1395              chtype *fake_map GCC_UNUSED)
1396 {
1397 #define DATA(a,b) { a, b }
1398     static struct {
1399         int acs_code;
1400         int use_code;
1401     } table[] = {
1402         DATA('a', 0xb1),        /* ACS_CKBOARD  */
1403             DATA('f', 0xf8),    /* ACS_DEGREE   */
1404             DATA('g', 0xf1),    /* ACS_PLMINUS  */
1405             DATA('j', 0xd9),    /* ACS_LRCORNER */
1406             DATA('l', 0xda),    /* ACS_ULCORNER */
1407             DATA('k', 0xbf),    /* ACS_URCORNER */
1408             DATA('m', 0xc0),    /* ACS_LLCORNER */
1409             DATA('n', 0xc5),    /* ACS_PLUS     */
1410             DATA('q', 0xc4),    /* ACS_HLINE    */
1411             DATA('t', 0xc3),    /* ACS_LTEE     */
1412             DATA('u', 0xb4),    /* ACS_RTEE     */
1413             DATA('v', 0xc1),    /* ACS_BTEE     */
1414             DATA('w', 0xc2),    /* ACS_TTEE     */
1415             DATA('x', 0xb3),    /* ACS_VLINE    */
1416             DATA('y', 0xf3),    /* ACS_LEQUAL   */
1417             DATA('z', 0xf2),    /* ACS_GEQUAL   */
1418             DATA('0', 0xdb),    /* ACS_BLOCK    */
1419             DATA('{', 0xe3),    /* ACS_PI       */
1420             DATA('}', 0x9c),    /* ACS_STERLING */
1421             DATA(',', 0xae),    /* ACS_LARROW   */
1422             DATA('+', 0xaf),    /* ACS_RARROW   */
1423             DATA('~', 0xf9),    /* ACS_BULLET   */
1424     };
1425 #undef DATA
1426     unsigned n;
1427
1428     SCREEN *sp;
1429     AssertTCB();
1430     SetSP();
1431
1432     for (n = 0; n < SIZEOF(table); ++n) {
1433         real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1434         if (sp != 0)
1435             sp->_screen_acs_map[table[n].acs_code] = TRUE;
1436     }
1437 }
1438
1439 static ULONGLONG
1440 tdiff(FILETIME fstart, FILETIME fend)
1441 {
1442     ULARGE_INTEGER ustart;
1443     ULARGE_INTEGER uend;
1444     ULONGLONG diff;
1445
1446     ustart.LowPart = fstart.dwLowDateTime;
1447     ustart.HighPart = fstart.dwHighDateTime;
1448     uend.LowPart = fend.dwLowDateTime;
1449     uend.HighPart = fend.dwHighDateTime;
1450
1451     diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1452     return diff;
1453 }
1454
1455 static int
1456 Adjust(int milliseconds, int diff)
1457 {
1458     if (milliseconds != INFINITY) {
1459         milliseconds -= diff;
1460         if (milliseconds < 0)
1461             milliseconds = 0;
1462     }
1463     return milliseconds;
1464 }
1465
1466 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1467                      FROM_LEFT_2ND_BUTTON_PRESSED | \
1468                      FROM_LEFT_3RD_BUTTON_PRESSED | \
1469                      FROM_LEFT_4TH_BUTTON_PRESSED | \
1470                      RIGHTMOST_BUTTON_PRESSED)
1471
1472 static int
1473 decode_mouse(SCREEN *sp, int mask)
1474 {
1475     int result = 0;
1476
1477     (void) sp;
1478     assert(sp && console_initialized);
1479
1480     if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1481         result |= BUTTON1_PRESSED;
1482     if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1483         result |= BUTTON2_PRESSED;
1484     if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1485         result |= BUTTON3_PRESSED;
1486     if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1487         result |= BUTTON4_PRESSED;
1488
1489     if (mask & RIGHTMOST_BUTTON_PRESSED) {
1490         switch (CON.numButtons) {
1491         case 1:
1492             result |= BUTTON1_PRESSED;
1493             break;
1494         case 2:
1495             result |= BUTTON2_PRESSED;
1496             break;
1497         case 3:
1498             result |= BUTTON3_PRESSED;
1499             break;
1500         case 4:
1501             result |= BUTTON4_PRESSED;
1502             break;
1503         }
1504     }
1505
1506     return result;
1507 }
1508
1509 static int
1510 console_twait(
1511                  SCREEN *sp,
1512                  HANDLE fd,
1513                  int mode,
1514                  int milliseconds,
1515                  int *timeleft
1516                  EVENTLIST_2nd(_nc_eventlist * evl))
1517 {
1518     INPUT_RECORD inp_rec;
1519     BOOL b;
1520     DWORD nRead = 0, rc = (DWORD) (-1);
1521     int code = 0;
1522     FILETIME fstart;
1523     FILETIME fend;
1524     int diff;
1525     bool isImmed = (milliseconds == 0);
1526
1527 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1528
1529     assert(sp);
1530
1531     TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1532                       milliseconds, mode));
1533
1534     if (milliseconds < 0)
1535         milliseconds = INFINITY;
1536
1537     memset(&inp_rec, 0, sizeof(inp_rec));
1538
1539     while (true) {
1540         GetSystemTimeAsFileTime(&fstart);
1541         rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1542         GetSystemTimeAsFileTime(&fend);
1543         diff = (int) tdiff(fstart, fend);
1544         milliseconds = Adjust(milliseconds, diff);
1545
1546         if (!isImmed && milliseconds <= 0)
1547             break;
1548
1549         if (rc == WAIT_OBJECT_0) {
1550             if (mode) {
1551                 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1552                 if (b && nRead > 0) {
1553                     b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1554                     if (b && nRead > 0) {
1555                         switch (inp_rec.EventType) {
1556                         case KEY_EVENT:
1557                             if (mode & TW_INPUT) {
1558                                 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1559                                 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1560
1561                                 if (inp_rec.Event.KeyEvent.bKeyDown) {
1562                                     if (0 == ch) {
1563                                         int nKey = MapKey(vk);
1564                                         if (nKey < 0) {
1565                                             CONSUME();
1566                                             continue;
1567                                         }
1568                                     }
1569                                     code = TW_INPUT;
1570                                     goto end;
1571                                 } else {
1572                                     CONSUME();
1573                                 }
1574                             }
1575                             continue;
1576                         case MOUSE_EVENT:
1577                             if (decode_mouse(sp,
1578                                              (inp_rec.Event.MouseEvent.dwButtonState
1579                                               & BUTTON_MASK)) == 0) {
1580                                 CONSUME();
1581                             } else if (mode & TW_MOUSE) {
1582                                 code = TW_MOUSE;
1583                                 goto end;
1584                             }
1585                             continue;
1586                             /* e.g., FOCUS_EVENT */
1587                         default:
1588                             CONSUME();
1589                             selectActiveHandle();
1590                             continue;
1591                         }
1592                     }
1593                 }
1594             }
1595             continue;
1596         } else {
1597             if (rc != WAIT_TIMEOUT) {
1598                 code = -1;
1599                 break;
1600             } else {
1601                 code = 0;
1602                 break;
1603             }
1604         }
1605     }
1606   end:
1607
1608     TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1609                       code, errno, milliseconds));
1610
1611     if (timeleft)
1612         *timeleft = milliseconds;
1613
1614     return code;
1615 }
1616
1617 static int
1618 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1619            int mode,
1620            int milliseconds,
1621            int *timeleft
1622            EVENTLIST_2nd(_nc_eventlist * evl))
1623 {
1624     SCREEN *sp;
1625     int code;
1626
1627     AssertTCB();
1628     SetSP();
1629
1630     code = console_twait(sp,
1631                          CON.inp,
1632                          mode,
1633                          milliseconds,
1634                          timeleft EVENTLIST_2nd(_nc_eventlist * evl));
1635     return code;
1636 }
1637
1638 static bool
1639 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1640 {
1641     MEVENT work;
1642     bool result = FALSE;
1643
1644     assert(sp);
1645
1646     sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1647     sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1648
1649     /*
1650      * We're only interested if the button is pressed or released.
1651      * FIXME: implement continuous event-tracking.
1652      */
1653     if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1654
1655         memset(&work, 0, sizeof(work));
1656
1657         if (sp->_drv_mouse_new_buttons) {
1658
1659             work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1660
1661         } else {
1662
1663             /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1664             work.bstate |= (mmask_t) (decode_mouse(sp,
1665                                                    sp->_drv_mouse_old_buttons)
1666                                       >> 1);
1667
1668             result = TRUE;
1669         }
1670
1671         work.x = mer.dwMousePosition.X;
1672         work.y = mer.dwMousePosition.Y - AdjustY();
1673
1674         sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1675         sp->_drv_mouse_tail += 1;
1676     }
1677
1678     return result;
1679 }
1680
1681 static int
1682 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1683 {
1684     SCREEN *sp;
1685     int n;
1686
1687     AssertTCB();
1688     assert(buf);
1689     SetSP();
1690
1691     T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1692     n = _nc_mingw_console_read(sp, CON.inp, buf);
1693     returnCode(n);
1694 }
1695
1696 static int
1697 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1698 {
1699     T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1700     Sleep((DWORD) ms);
1701     returnCode(OK);
1702 }
1703
1704 static int
1705 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1706 {
1707     int res = -1;
1708     CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1709     T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1710     switch (mode) {
1711     case 0:
1712         this_CI.bVisible = FALSE;
1713         break;
1714     case 1:
1715         break;
1716     case 2:
1717         this_CI.dwSize = 100;
1718         break;
1719     }
1720     SetConsoleCursorInfo(CON.hdl, &this_CI);
1721     returnCode(res);
1722 }
1723
1724 static bool
1725 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1726 {
1727     WORD nKey;
1728     void *res;
1729     bool found = FALSE;
1730     LONG key = GenMap(0, (WORD) keycode);
1731
1732     T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1733     res = bsearch(&key,
1734                   CON.rmap,
1735                   (size_t) (N_INI + FKEYS),
1736                   sizeof(keylist[0]),
1737                   rkeycompare);
1738     if (res) {
1739         key = *((LONG *) res);
1740         nKey = LOWORD(key);
1741         if (!(nKey & 0x8000))
1742             found = TRUE;
1743     }
1744     returnCode(found);
1745 }
1746
1747 static int
1748 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1749 {
1750     SCREEN *sp;
1751     int code = ERR;
1752
1753     AssertTCB();
1754     SetSP();
1755
1756     T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1757     if (sp) {
1758         code = OK;
1759     }
1760     returnCode(code);
1761 }
1762
1763 static int
1764 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1765            int keycode,
1766            int flag)
1767 {
1768     int code = ERR;
1769     SCREEN *sp;
1770     WORD nKey;
1771     WORD vKey;
1772     void *res;
1773     LONG key = GenMap(0, (WORD) keycode);
1774
1775     T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1776
1777     AssertTCB();
1778     SetSP();
1779
1780     if (sp) {
1781         res = bsearch(&key,
1782                       CON.rmap,
1783                       (size_t) (N_INI + FKEYS),
1784                       sizeof(keylist[0]),
1785                       rkeycompare);
1786         if (res) {
1787             key = *((LONG *) res);
1788             vKey = HIWORD(key);
1789             nKey = (LOWORD(key)) & 0x7fff;
1790             if (!flag)
1791                 nKey |= 0x8000;
1792             *(LONG *) res = GenMap(vKey, nKey);
1793         }
1794     }
1795     returnCode(code);
1796 }
1797
1798 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1799     FALSE,
1800         wcon_name,              /* Name */
1801         wcon_CanHandle,         /* CanHandle */
1802         wcon_init,              /* init */
1803         wcon_release,           /* release */
1804         wcon_size,              /* size */
1805         wcon_sgmode,            /* sgmode */
1806         wcon_conattr,           /* conattr */
1807         wcon_mvcur,             /* hwcur */
1808         wcon_mode,              /* mode */
1809         wcon_rescol,            /* rescol */
1810         wcon_rescolors,         /* rescolors */
1811         wcon_setcolor,          /* color */
1812         wcon_dobeepflash,       /* DoBeepFlash */
1813         wcon_initpair,          /* initpair */
1814         wcon_initcolor,         /* initcolor */
1815         wcon_do_color,          /* docolor */
1816         wcon_initmouse,         /* initmouse */
1817         wcon_testmouse,         /* testmouse */
1818         wcon_setfilter,         /* setfilter */
1819         wcon_hwlabel,           /* hwlabel */
1820         wcon_hwlabelOnOff,      /* hwlabelOnOff */
1821         wcon_doupdate,          /* update */
1822         wcon_defaultcolors,     /* defaultcolors */
1823         wcon_print,             /* print */
1824         wcon_size,              /* getsize */
1825         wcon_setsize,           /* setsize */
1826         wcon_initacs,           /* initacs */
1827         wcon_screen_init,       /* scinit */
1828         wcon_wrap,              /* scexit */
1829         wcon_twait,             /* twait */
1830         wcon_read,              /* read */
1831         wcon_nap,               /* nap */
1832         wcon_kpad,              /* kpad */
1833         wcon_keyok,             /* kyOk */
1834         wcon_kyExist,           /* kyExist */
1835         wcon_cursorSet          /* cursorSet */
1836 };
1837
1838 /* --------------------------------------------------------- */
1839
1840 static HANDLE
1841 get_handle(int fd)
1842 {
1843     intptr_t value = _get_osfhandle(fd);
1844     return (HANDLE) value;
1845 }
1846
1847 #if WINVER >= 0x0600
1848 /*   This function tests, whether or not the ncurses application
1849      is running as a descendant of MSYS2/cygwin mintty terminal
1850      application. mintty doesn't use Windows Console for it's screen
1851      I/O, so the native Windows _isatty doesn't recognize it as
1852      character device. But we can discover we are at the end of an
1853      Pipe and can query to server side of the pipe, looking whether
1854      or not this is mintty.
1855  */
1856 static int
1857 _ismintty(int fd, LPHANDLE pMinTTY)
1858 {
1859     HANDLE handle = get_handle(fd);
1860     DWORD dw;
1861     int code = 0;
1862
1863     T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1864
1865     if (handle != INVALID_HANDLE_VALUE) {
1866         dw = GetFileType(handle);
1867         if (dw == FILE_TYPE_PIPE) {
1868             if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1869                 ULONG pPid;
1870                 /* Requires NT6 */
1871                 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1872                     TCHAR buf[MAX_PATH];
1873                     DWORD len = 0;
1874                     /* These security attributes may allow us to
1875                        create a remote thread in mintty to manipulate
1876                        the terminal state remotely */
1877                     HANDLE pHandle = OpenProcess(
1878                                                     PROCESS_CREATE_THREAD
1879                                                     | PROCESS_QUERY_INFORMATION
1880                                                     | PROCESS_VM_OPERATION
1881                                                     | PROCESS_VM_WRITE
1882                                                     | PROCESS_VM_READ,
1883                                                     FALSE,
1884                                                     pPid);
1885                     if (pMinTTY)
1886                         *pMinTTY = INVALID_HANDLE_VALUE;
1887                     if (pHandle != INVALID_HANDLE_VALUE) {
1888                         if ((len = GetProcessImageFileName(
1889                                                               pHandle,
1890                                                               buf,
1891                                                               (DWORD)
1892                                                               array_length(buf)))) {
1893                             TCHAR *pos = _tcsrchr(buf, _T('\\'));
1894                             if (pos) {
1895                                 pos++;
1896                                 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1897                                     == 0) {
1898                                     if (pMinTTY)
1899                                         *pMinTTY = pHandle;
1900                                     code = 1;
1901                                 }
1902                             }
1903                         }
1904                     }
1905                 }
1906             }
1907         }
1908     }
1909     returnCode(code);
1910 }
1911 #endif
1912
1913 /*   Borrowed from ansicon project.
1914      Check whether or not an I/O handle is associated with
1915      a Windows console.
1916 */
1917 static BOOL
1918 IsConsoleHandle(HANDLE hdl)
1919 {
1920     DWORD dwFlag = 0;
1921     BOOL result;
1922
1923     if (!GetConsoleMode(hdl, &dwFlag)) {
1924         result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1925     } else {
1926         result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1927     }
1928     return result;
1929 }
1930
1931 /*   Our replacement for the systems _isatty to include also
1932      a test for mintty. This is called from the NC_ISATTY macro
1933      defined in curses.priv.h
1934  */
1935 int
1936 _nc_mingw_isatty(int fd)
1937 {
1938     int result = 0;
1939
1940 #ifdef __MING32__
1941 #define SysISATTY(fd) _isatty(fd)
1942 #else
1943 #define SysISATTY(fd) isatty(fd)
1944 #endif
1945     if (SysISATTY(fd)) {
1946         result = 1;
1947     } else {
1948 #if WINVER >= 0x0600
1949         result = _ismintty(fd, NULL);
1950 #endif
1951     }
1952     return result;
1953 }
1954
1955 /*   This is used when running in terminfo mode to discover,
1956      whether or not the "terminal" is actually a Windows
1957      Console. It's the responsibilty of the console to deal
1958      with the terminal escape sequences that are sent by
1959      terminfo.
1960  */
1961 int
1962 _nc_mingw_isconsole(int fd)
1963 {
1964     HANDLE hdl = get_handle(fd);
1965     int code = 0;
1966
1967     T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1968
1969     code = (int) IsConsoleHandle(hdl);
1970
1971     returnCode(code);
1972 }
1973
1974 #define TC_PROLOGUE(fd) \
1975     SCREEN *sp;                                               \
1976     TERMINAL *term = 0;                                       \
1977     int code = ERR;                                           \
1978     if (_nc_screen_chain == 0)                                \
1979         return 0;                                             \
1980     for (each_screen(sp)) {                                   \
1981         if (sp->_term && (sp->_term->Filedes == fd)) {        \
1982             term = sp->_term;                                 \
1983             break;                                            \
1984         }                                                     \
1985     }                                                         \
1986     assert(term != 0)
1987
1988 int
1989 _nc_mingw_tcsetattr(
1990                        int fd,
1991                        int optional_action GCC_UNUSED,
1992                        const struct termios *arg)
1993 {
1994     TC_PROLOGUE(fd);
1995
1996     if (_nc_mingw_isconsole(fd)) {
1997         DWORD dwFlag = 0;
1998         HANDLE ofd = get_handle(fd);
1999         if (ofd != INVALID_HANDLE_VALUE) {
2000             if (arg) {
2001                 if (arg->c_lflag & ICANON)
2002                     dwFlag |= ENABLE_LINE_INPUT;
2003                 else
2004                     dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
2005
2006                 if (arg->c_lflag & ECHO)
2007                     dwFlag = dwFlag | ENABLE_ECHO_INPUT;
2008                 else
2009                     dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
2010
2011                 if (arg->c_iflag & BRKINT)
2012                     dwFlag |= ENABLE_PROCESSED_INPUT;
2013                 else
2014                     dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
2015             }
2016             dwFlag |= ENABLE_MOUSE_INPUT;
2017             SetConsoleMode(ofd, dwFlag);
2018             code = OK;
2019         }
2020     }
2021     if (arg)
2022         term->Nttyb = *arg;
2023
2024     return code;
2025 }
2026
2027 int
2028 _nc_mingw_tcgetattr(int fd, struct termios *arg)
2029 {
2030     TC_PROLOGUE(fd);
2031
2032     if (_nc_mingw_isconsole(fd)) {
2033         if (arg)
2034             *arg = term->Nttyb;
2035     }
2036     return code;
2037 }
2038
2039 int
2040 _nc_mingw_tcflush(int fd, int queue)
2041 {
2042     TC_PROLOGUE(fd);
2043     (void) term;
2044
2045     if (_nc_mingw_isconsole(fd)) {
2046         if (queue == TCIFLUSH) {
2047             BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2048             if (!b)
2049                 return (int) GetLastError();
2050         }
2051     }
2052     return code;
2053 }
2054
2055 int
2056 _nc_mingw_testmouse(
2057                        SCREEN *sp,
2058                        HANDLE fd,
2059                        int delay)
2060 {
2061     int rc = 0;
2062
2063     assert(sp);
2064
2065     if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2066         rc = TW_MOUSE;
2067     } else {
2068         rc = console_twait(sp,
2069                            fd,
2070                            TWAIT_MASK,
2071                            delay,
2072                            (int *) 0
2073                            EVENTLIST_2nd(evl));
2074     }
2075     return rc;
2076 }
2077
2078 int
2079 _nc_mingw_console_read(
2080                           SCREEN *sp,
2081                           HANDLE fd,
2082                           int *buf)
2083 {
2084     int n = 1;
2085     INPUT_RECORD inp_rec;
2086     BOOL b;
2087     DWORD nRead;
2088     WORD vk;
2089
2090     assert(sp);
2091     assert(buf);
2092
2093     memset(&inp_rec, 0, sizeof(inp_rec));
2094
2095     T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2096
2097     while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2098         if (b && nRead > 0) {
2099             if (inp_rec.EventType == KEY_EVENT) {
2100                 if (!inp_rec.Event.KeyEvent.bKeyDown)
2101                     continue;
2102                 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2103                 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2104                 /*
2105                  * There are 24 virtual function-keys, and typically
2106                  * 12 function-keys on a keyboard.  Use the shift-modifier
2107                  * to provide the remaining 12 keys.
2108                  */
2109                 if (vk >= VK_F1 && vk <= VK_F12) {
2110                     if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
2111                         vk = (WORD) (vk + 12);
2112                     }
2113                 }
2114                 if (*buf == 0) {
2115                     int key = MapKey(vk);
2116                     if (key < 0)
2117                         continue;
2118                     if (sp->_keypad_on) {
2119                         *buf = key;
2120                     } else {
2121                         ungetch('\0');
2122                         *buf = AnsiKey(vk);
2123                     }
2124                 }
2125                 break;
2126             } else if (inp_rec.EventType == MOUSE_EVENT) {
2127                 if (handle_mouse(sp,
2128                                  inp_rec.Event.MouseEvent)) {
2129                     *buf = KEY_MOUSE;
2130                     break;
2131                 }
2132             }
2133             continue;
2134         }
2135     }
2136     returnCode(n);
2137 }
2138
2139 static
2140 __attribute__((constructor))
2141      void _enter_console(void)
2142 {
2143     if (!console_initialized) {
2144         int i;
2145         DWORD num_buttons;
2146         WORD a;
2147         BOOL buffered = TRUE;
2148         BOOL b;
2149
2150         START_TRACE();
2151         if (_nc_mingw_isatty(0)) {
2152             CON.isMinTTY = TRUE;
2153         }
2154
2155         for (i = 0; i < (N_INI + FKEYS); i++) {
2156             if (i < N_INI) {
2157                 CON.rmap[i] = CON.map[i] =
2158                     (DWORD) keylist[i];
2159                 CON.ansi_map[i] = (DWORD) ansi_keys[i];
2160             } else {
2161                 CON.rmap[i] = CON.map[i] =
2162                     (DWORD) GenMap((VK_F1 + (i - N_INI)),
2163                                    (KEY_F(1) + (i - N_INI)));
2164                 CON.ansi_map[i] =
2165                     (DWORD) GenMap((VK_F1 + (i - N_INI)),
2166                                    (';' + (i - N_INI)));
2167             }
2168         }
2169         qsort(CON.ansi_map,
2170               (size_t) (MAPSIZE),
2171               sizeof(keylist[0]),
2172               keycompare);
2173         qsort(CON.map,
2174               (size_t) (MAPSIZE),
2175               sizeof(keylist[0]),
2176               keycompare);
2177         qsort(CON.rmap,
2178               (size_t) (MAPSIZE),
2179               sizeof(keylist[0]),
2180               rkeycompare);
2181
2182         if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2183             CON.numButtons = (int) num_buttons;
2184         } else {
2185             CON.numButtons = 1;
2186         }
2187
2188         a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2189         for (i = 0; i < NUMPAIRS; i++)
2190             CON.pairs[i] = a;
2191
2192         CON.inp = GetStdHandle(STD_INPUT_HANDLE);
2193         CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
2194
2195         b = AllocConsole();
2196
2197         if (!b)
2198             b = AttachConsole(ATTACH_PARENT_PROCESS);
2199
2200         if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2201             T(("... will not buffer console"));
2202             buffered = FALSE;
2203             CON.hdl = CON.out;
2204         } else {
2205             T(("... creating console buffer"));
2206             CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2207                                                 0,
2208                                                 NULL,
2209                                                 CONSOLE_TEXTMODE_BUFFER,
2210                                                 NULL);
2211         }
2212
2213         if (CON.hdl != INVALID_HANDLE_VALUE) {
2214             CON.buffered = buffered;
2215             get_SBI();
2216             CON.save_SBI = CON.SBI;
2217             if (!buffered) {
2218                 save_original_screen();
2219                 set_scrollback(FALSE, &CON.SBI);
2220             }
2221             GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
2222             T(("... initial cursor is %svisible, %d%%",
2223                (CON.save_CI.bVisible ? "" : "not-"),
2224                (int) CON.save_CI.dwSize));
2225         }
2226
2227         console_initialized = TRUE;
2228     }
2229 }