1 /****************************************************************************
2 * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. *
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: *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
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. *
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 *
27 ****************************************************************************/
29 /****************************************************************************
30 * Author: Juergen Pfeifer *
31 * and: Thomas E. Dickey *
32 ****************************************************************************/
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
41 #include <curses.priv.h>
45 #define PSAPI_VERSION 2
48 #define CUR my_term.type.
50 MODULE_ID("$Id: win_driver.c,v 1.51 2014/09/27 22:17:36 tom Exp $")
53 # error We need GCC to compile for MinGW
56 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
58 #define EXP_OPTIMIZE 0
60 #define array_length(a) (sizeof(a)/sizeof(a[0]))
62 #define okConsoleHandle(TCB) (TCB != 0 && CON.hdl != INVALID_HANDLE_VALUE)
64 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
65 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
67 #define GenMap(vKey,key) MAKELONG(key, vKey)
69 #define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
72 #define write_screen WriteConsoleOutputW
73 #define read_screen ReadConsoleOutputW
75 #define write_screen WriteConsoleOutput
76 #define read_screen ReadConsoleOutput
79 static const LONG keylist[] =
81 GenMap(VK_PRIOR, KEY_PPAGE),
82 GenMap(VK_NEXT, KEY_NPAGE),
83 GenMap(VK_END, KEY_END),
84 GenMap(VK_HOME, KEY_HOME),
85 GenMap(VK_LEFT, KEY_LEFT),
86 GenMap(VK_UP, KEY_UP),
87 GenMap(VK_RIGHT, KEY_RIGHT),
88 GenMap(VK_DOWN, KEY_DOWN),
89 GenMap(VK_DELETE, KEY_DC),
90 GenMap(VK_INSERT, KEY_IC)
92 #define N_INI ((int)array_length(keylist))
94 #define MAPSIZE (FKEYS + N_INI)
97 /* A process can only have a single console, so it's save
98 to maintain all the information about it in a single
107 BOOL isTermInfoConsole;
115 WORD pairs[NUMPAIRS];
117 CHAR_INFO *save_screen;
119 SMALL_RECT save_region;
120 CONSOLE_SCREEN_BUFFER_INFO SBI;
121 CONSOLE_SCREEN_BUFFER_INFO save_SBI;
122 CONSOLE_CURSOR_INFO save_CI;
125 static BOOL console_initialized = FALSE;
128 MapColor(bool fore, int color)
130 static const int _cmap[] =
131 {0, 4, 2, 6, 1, 5, 3, 7};
133 if (color < 0 || color > 7)
142 #define RevAttr(attr) \
143 (WORD) (((attr) & 0xff00) | \
144 ((((attr) & 0x07) << 4) | \
145 (((attr) & 0x70) >> 4)))
148 MapAttr(WORD res, attr_t ch)
154 if (p > 0 && p < NUMPAIRS) {
157 res = (WORD) ((res & 0xff00) | a);
161 if (ch & A_REVERSE) {
165 if (ch & A_STANDOUT) {
166 res = RevAttr(res) | BACKGROUND_INTENSITY;
170 res |= FOREGROUND_INTENSITY;
173 res |= BACKGROUND_INTENSITY;
178 #if 0 /* def TRACE */
180 dump_screen(const char *fn, int ln)
182 int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1;
183 char output[max_cells];
184 CHAR_INFO save_screen[max_cells];
186 SMALL_RECT save_region;
189 T(("dump_screen %s@%d", fn, ln));
191 save_region.Top = CON.SBI.srWindow.Top;
192 save_region.Left = CON.SBI.srWindow.Left;
193 save_region.Bottom = CON.SBI.srWindow.Bottom;
194 save_region.Right = CON.SBI.srWindow.Right;
196 save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
197 save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
199 bufferCoord.X = bufferCoord.Y = 0;
201 if (read_screen(CON.hdl,
210 for (i = save_region.Top; i <= save_region.Bottom; ++i) {
211 for (j = save_region.Left; j <= save_region.Right; ++j) {
212 output[k++] = save_screen[ij++].Char.AsciiChar;
218 T(("DUMP: %d,%d - %d,%d",
228 #define dump_screen(fn,ln) /* nothing */
231 #if USE_WIDEC_SUPPORT
233 * TODO: support surrogate pairs
234 * TODO: support combining characters
236 * TODO: _nc_wacs should be part of sp.
239 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
252 for (i = actual = 0; i < limit; i++) {
256 ci[actual].Char.UnicodeChar = CharOf(ch);
257 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
259 if (AttrOf(ch) & A_ALTCHARSET) {
261 int which = CharOf(ch);
264 && CharOf(_nc_wacs[which]) != 0) {
265 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
267 ci[actual].Char.UnicodeChar = ' ';
276 siz.X = (SHORT) actual;
279 rec.Left = (SHORT) x;
280 rec.Top = (SHORT) (y + AdjustY());
281 rec.Right = (SHORT) (x + limit - 1);
282 rec.Bottom = rec.Top;
284 return write_screen(CON.hdl, ci, siz, loc, &rec);
286 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
289 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
301 for (i = 0; i < n; i++) {
303 ci[i].Char.AsciiChar = ChCharOf(ch);
304 ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
306 if (ChAttrOf(ch) & A_ALTCHARSET) {
308 ci[i].Char.AsciiChar =
309 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
318 rec.Left = (short) x;
320 rec.Right = (short) (x + n - 1);
321 rec.Bottom = rec.Top;
323 return write_screen(CON.hdl, ci, siz, loc, &rec);
325 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
330 * Comparing new/current screens, determine the last column-index for a change
331 * beginning on the given row,col position. Unlike a serial terminal, there is
332 * no cost for "moving" the "cursor" on the line as we update it.
335 find_end_of_change(SCREEN *sp, int row, int col)
338 struct ldat *curdat = CurScreen(sp)->_line + row;
339 struct ldat *newdat = NewScreen(sp)->_line + row;
341 while (col <= newdat->lastchar) {
342 #if USE_WIDEC_SUPPORT
343 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
345 } else if (memcmp(&curdat->text[col],
347 sizeof(curdat->text[0]))) {
353 if (curdat->text[col] != newdat->text[col]) {
365 * Given a row,col position at the end of a change-chunk, look for the
366 * beginning of the next change-chunk.
369 find_next_change(SCREEN *sp, int row, int col)
371 struct ldat *curdat = CurScreen(sp)->_line + row;
372 struct ldat *newdat = NewScreen(sp)->_line + row;
373 int result = newdat->lastchar + 1;
375 while (++col <= newdat->lastchar) {
376 #if USE_WIDEC_SUPPORT
377 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
380 } else if (memcmp(&curdat->text[col],
382 sizeof(curdat->text[0]))) {
387 if (curdat->text[col] != newdat->text[col]) {
396 #define EndChange(first) \
397 find_end_of_change(sp, y, first)
398 #define NextChange(last) \
399 find_next_change(sp, y, last)
401 #endif /* EXP_OPTIMIZE */
403 #define MARK_NOCHANGE(win,row) \
404 win->_line[row].firstchar = _NOCHANGE; \
405 win->_line[row].lastchar = _NOCHANGE
408 selectActiveHandle(void)
410 if (CON.lastOut != CON.hdl) {
411 CON.lastOut = CON.hdl;
412 SetConsoleActiveScreenBuffer(CON.lastOut);
417 restore_original_screen(void)
421 SMALL_RECT save_region = CON.save_region;
423 T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
425 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
426 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
428 if (write_screen(CON.hdl,
434 mvcur(-1, -1, LINES - 2, 0);
435 T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
443 T(("... restore original screen contents err"));
449 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
452 return "win32console";
456 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
459 int y, nonempty, n, x0, x1, Width, Height;
465 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
466 if (okConsoleHandle(TCB)) {
468 Width = screen_columns(sp);
469 Height = screen_lines(sp);
470 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
472 T(("... %dx%d clear cur:%d new:%d",
474 CurScreen(sp)->_clear,
475 NewScreen(sp)->_clear));
477 if (SP_PARM->_endwin) {
479 T(("coming back from shell mode"));
480 NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
482 NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
483 NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
484 SP_PARM->_mouse_resume(SP_PARM);
486 SP_PARM->_endwin = FALSE;
489 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
491 #if USE_WIDEC_SUPPORT
492 cchar_t empty[Width];
498 for (x = 0; x < Width; x++)
499 setcchar(&empty[x], blank, 0, 0, 0);
503 for (x = 0; x < Width; x++)
507 for (y = 0; y < nonempty; y++) {
508 con_write(TCB, y, 0, empty, Width);
510 CurScreen(sp)->_line[y].text,
511 (size_t) Width * sizeof(empty[0]));
513 CurScreen(sp)->_clear = FALSE;
514 NewScreen(sp)->_clear = FALSE;
515 touchwin(NewScreen(sp));
516 T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
520 for (y = 0; y < nonempty; y++) {
521 x0 = NewScreen(sp)->_line[y].firstchar;
522 if (x0 != _NOCHANGE) {
525 int limit = NewScreen(sp)->_line[y].lastchar;
526 while ((x1 = EndChange(x0)) <= limit) {
527 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
531 memcpy(&CurScreen(sp)->_line[y].text[x0],
532 &NewScreen(sp)->_line[y].text[x0],
533 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
537 &CurScreen(sp)->_line[y].text[x0], n);
541 /* mark line changed successfully */
542 if (y <= NewScreen(sp)->_maxy) {
543 MARK_NOCHANGE(NewScreen(sp), y);
545 if (y <= CurScreen(sp)->_maxy) {
546 MARK_NOCHANGE(CurScreen(sp), y);
549 x1 = NewScreen(sp)->_line[y].lastchar;
552 memcpy(&CurScreen(sp)->_line[y].text[x0],
553 &NewScreen(sp)->_line[y].text[x0],
554 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
558 &CurScreen(sp)->_line[y].text[x0], n);
560 /* mark line changed successfully */
561 if (y <= NewScreen(sp)->_maxy) {
562 MARK_NOCHANGE(NewScreen(sp), y);
564 if (y <= CurScreen(sp)->_maxy) {
565 MARK_NOCHANGE(CurScreen(sp), y);
572 /* put everything back in sync */
573 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
574 MARK_NOCHANGE(NewScreen(sp), y);
576 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
577 MARK_NOCHANGE(CurScreen(sp), y);
580 if (!NewScreen(sp)->_leaveok) {
581 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
582 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
584 TCB->drv->td_hwcur(TCB,
586 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
588 selectActiveHandle();
595 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
597 int *errret GCC_UNUSED)
601 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
603 assert((TCB != 0) && (tname != 0));
605 TCB->magic = WINMAGIC;
607 if (tname == 0 || *tname == 0)
609 else if (tname != 0 && *tname == '#') {
611 * Use "#" (a character which cannot begin a terminal's name) to
612 * select specific driver from the table.
614 * In principle, we could have more than one non-terminfo driver,
617 size_t n = strlen(tname + 1);
619 && ((strncmp(tname + 1, "win32console", n) == 0)
620 || (strncmp(tname + 1, "win32con", n) == 0))) {
623 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
628 * This is intentional, to avoid unnecessary breakage of applications
629 * using <term.h> symbols.
631 if (code && (TCB->term.type.Booleans == 0)) {
632 _nc_init_termtype(&(TCB->term.type));
636 if (_nc_mingw_isconsole(0))
637 CON.isTermInfoConsole = TRUE;
643 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
649 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
650 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
651 int max_cells = (high * wide);
654 CHAR_INFO this_screen[max_cells];
655 CHAR_INFO that_screen[max_cells];
657 SMALL_RECT this_region;
664 this_region.Top = CON.SBI.srWindow.Top;
665 this_region.Left = CON.SBI.srWindow.Left;
666 this_region.Bottom = CON.SBI.srWindow.Bottom;
667 this_region.Right = CON.SBI.srWindow.Right;
669 this_size.X = (SHORT) wide;
670 this_size.Y = (SHORT) high;
672 bufferCoord.X = this_region.Left;
673 bufferCoord.Y = this_region.Top;
682 memcpy(that_screen, this_screen, sizeof(that_screen));
684 for (i = 0; i < max_cells; i++) {
685 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
688 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
690 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
693 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */
699 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
700 char *data GCC_UNUSED,
712 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
729 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
730 T(("GetConsoleScreenBufferInfo"));
731 T(("... buffer(X:%d Y:%d)",
734 T(("... window(X:%d Y:%d)",
735 CON.SBI.dwMaximumWindowSize.X,
736 CON.SBI.dwMaximumWindowSize.Y));
737 T(("... cursor(X:%d Y:%d)",
738 CON.SBI.dwCursorPosition.X,
739 CON.SBI.dwCursorPosition.Y));
740 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
741 CON.SBI.srWindow.Top,
742 CON.SBI.srWindow.Bottom,
743 CON.SBI.srWindow.Left,
744 CON.SBI.srWindow.Right));
749 CON.origin.X = CON.SBI.srWindow.Left;
750 CON.origin.Y = CON.SBI.srWindow.Top;
754 T(("GetConsoleScreenBufferInfo ERR"));
760 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
763 int (*outc) (SCREEN *, int) GCC_UNUSED)
767 if (okConsoleHandle(TCB)) {
768 WORD a = MapColor(fore, color);
769 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
770 SetConsoleTextAttribute(CON.hdl, a);
776 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
781 if (okConsoleHandle(TCB)) {
782 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
783 SetConsoleTextAttribute(CON.hdl, a);
791 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
803 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
809 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
811 if (okConsoleHandle(TCB) &&
815 *Lines = (int) (CON.SBI.dwSize.Y);
816 *Cols = (int) (CON.SBI.dwSize.X);
818 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
819 CON.SBI.srWindow.Top);
820 *Cols = (int) (CON.SBI.srWindow.Right + 1 -
821 CON.SBI.srWindow.Left);
829 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
838 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
846 if (TCB == 0 || buf == NULL)
850 iflag = buf->c_iflag;
851 lflag = buf->c_lflag;
853 GetConsoleMode(CON.inp, &dwFlag);
856 dwFlag |= ENABLE_LINE_INPUT;
858 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
861 dwFlag |= ENABLE_ECHO_INPUT;
863 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
866 dwFlag |= ENABLE_PROCESSED_INPUT;
868 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
870 dwFlag |= ENABLE_MOUSE_INPUT;
872 buf->c_iflag = iflag;
873 buf->c_lflag = lflag;
874 SetConsoleMode(CON.inp, dwFlag);
875 TCB->term.Nttyb = *buf;
877 iflag = TCB->term.Nttyb.c_iflag;
878 lflag = TCB->term.Nttyb.c_lflag;
879 GetConsoleMode(CON.inp, &dwFlag);
881 if (dwFlag & ENABLE_LINE_INPUT)
884 lflag &= (tcflag_t) (~ICANON);
886 if (dwFlag & ENABLE_ECHO_INPUT)
889 lflag &= (tcflag_t) (~ECHO);
891 if (dwFlag & ENABLE_PROCESSED_INPUT)
894 iflag &= (tcflag_t) (~BRKINT);
896 TCB->term.Nttyb.c_iflag = iflag;
897 TCB->term.Nttyb.c_lflag = lflag;
899 *buf = TCB->term.Nttyb;
908 * In "normal" mode, reset the buffer- and window-sizes back to their original values.
911 set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
915 bool changed = FALSE;
917 T((T_CALLED("win32con::set_scrollback(%s)"),
922 T(("... SBI.srWindow %d,%d .. %d,%d",
925 info->srWindow.Bottom,
926 info->srWindow.Right));
927 T(("... SBI.dwSize %dx%d",
932 rect = info->srWindow;
933 coord = info->dwSize;
934 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
939 int high = info->srWindow.Bottom - info->srWindow.Top + 1;
940 int wide = info->srWindow.Right - info->srWindow.Left + 1;
942 if (high < MIN_HIGH) {
943 T(("... height %d < %d", high, MIN_HIGH));
947 if (wide < MIN_WIDE) {
948 T(("... width %d < %d", wide, MIN_WIDE));
955 rect.Right = (SHORT) (wide - 1);
956 rect.Bottom = (SHORT) (high - 1);
958 coord.X = (SHORT) wide;
959 coord.Y = (SHORT) high;
961 if (info->dwSize.Y != high ||
962 info->dwSize.X != wide ||
963 info->srWindow.Top != 0 ||
964 info->srWindow.Left != 0) {
971 T(("... coord %d,%d", coord.Y, coord.X));
972 T(("... rect %d,%d - %d,%d",
974 rect.Bottom, rect.Right));
975 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */
976 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */
983 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
986 TERMINAL *_term = (TERMINAL *) TCB;
992 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"), TCB, progFlag, defFlag));
993 CON.progMode = progFlag;
994 CON.lastOut = progFlag ? CON.hdl : CON.out;
995 SetConsoleActiveScreenBuffer(CON.lastOut);
997 if (progFlag) /* prog mode */ {
999 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
1000 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
1004 /* reset_prog_mode */
1005 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
1008 _nc_keypad(sp, TRUE);
1010 if (!CON.buffered) {
1011 set_scrollback(FALSE, &CON.SBI);
1016 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
1017 } else { /* shell mode */
1019 /* def_shell_mode */
1020 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
1024 /* reset_shell_mode */
1026 _nc_keypad(sp, FALSE);
1027 NCURSES_SP_NAME(_nc_flush) (sp);
1029 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
1030 if (!CON.buffered) {
1031 set_scrollback(TRUE, &CON.save_SBI);
1032 if (!restore_original_screen())
1035 SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
1043 wcon_screen_init(SCREEN *sp GCC_UNUSED)
1048 wcon_wrap(SCREEN *sp GCC_UNUSED)
1053 rkeycompare(const void *el1, const void *el2)
1055 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
1056 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
1058 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1062 keycompare(const void *el1, const void *el2)
1064 WORD key1 = HIWORD((*((const LONG *) el1)));
1065 WORD key2 = HIWORD((*((const LONG *) el2)));
1067 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1075 LONG key = GenMap(vKey, 0);
1080 (size_t) (N_INI + FKEYS),
1084 key = *((LONG *) res);
1086 code = (int) (nKey & 0x7fff);
1094 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
1096 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
1106 read_screen_data(void)
1108 bool result = FALSE;
1112 CON.save_size.X = (SHORT) (CON.save_region.Right
1113 - CON.save_region.Left + 1);
1114 CON.save_size.Y = (SHORT) (CON.save_region.Bottom
1115 - CON.save_region.Top + 1);
1117 want = (size_t) (CON.save_size.X * CON.save_size.Y);
1119 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1120 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
1121 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
1123 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
1124 CON.window_only ? "window" : "buffer",
1125 CON.save_size.Y, CON.save_size.X,
1126 CON.save_region.Top,
1127 CON.save_region.Left,
1128 CON.save_region.Bottom,
1129 CON.save_region.Right,
1133 if (read_screen(CON.hdl,
1137 &CON.save_region)) {
1140 T((" error %#lx", (unsigned long) GetLastError()));
1141 FreeAndNull(CON.save_screen);
1149 * Attempt to save the screen contents. PDCurses does this if
1150 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
1151 * restoration as if the library had allocated a console buffer. MSDN
1152 * says that the data which can be read is limited to 64Kb (and may be
1156 save_original_screen(void)
1158 bool result = FALSE;
1160 CON.save_region.Top = 0;
1161 CON.save_region.Left = 0;
1162 CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
1163 CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
1165 if (read_screen_data()) {
1169 CON.save_region.Top = CON.SBI.srWindow.Top;
1170 CON.save_region.Left = CON.SBI.srWindow.Left;
1171 CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
1172 CON.save_region.Right = CON.SBI.srWindow.Right;
1174 CON.window_only = TRUE;
1176 if (read_screen_data()) {
1181 T(("... save original screen contents %s", result ? "ok" : "err"));
1186 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1188 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1193 if (CON.hdl == INVALID_HANDLE_VALUE) {
1197 TCB->info.initcolor = TRUE;
1198 TCB->info.canchange = FALSE;
1199 TCB->info.hascolor = TRUE;
1200 TCB->info.caninit = TRUE;
1202 TCB->info.maxpairs = NUMPAIRS;
1203 TCB->info.maxcolors = 8;
1204 TCB->info.numlabels = 0;
1205 TCB->info.labelwidth = 0;
1206 TCB->info.labelheight = 0;
1207 TCB->info.nocolorvideo = 1;
1208 TCB->info.tabsize = 8;
1210 TCB->info.numbuttons = CON.numButtons;
1211 TCB->info.defaultPalette = _nc_cga_palette;
1218 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1228 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1229 && (b >= 0) && (b < 8)) {
1230 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
1235 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1236 int color GCC_UNUSED,
1248 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1249 int old_pair GCC_UNUSED,
1250 int pair GCC_UNUSED,
1251 int reverse GCC_UNUSED,
1252 int (*outc) (SCREEN *, int) GCC_UNUSED
1262 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1269 sp->_mouse_type = M_TERM_DRIVER;
1273 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
1281 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1284 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1288 EVENTLIST_2nd(evl));
1295 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1296 int yold GCC_UNUSED, int xold GCC_UNUSED,
1300 if (okConsoleHandle(TCB)) {
1303 loc.Y = (short) (y + AdjustY());
1304 SetConsoleCursorPosition(CON.hdl, loc);
1311 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1312 int labnum GCC_UNUSED,
1313 char *text GCC_UNUSED)
1322 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1323 int OnFlag GCC_UNUSED)
1332 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1334 chtype res = A_NORMAL;
1335 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1340 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1349 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1350 chtype *real_map GCC_UNUSED,
1351 chtype *fake_map GCC_UNUSED)
1353 #define DATA(a,b) { a, b }
1358 DATA('a', 0xb1), /* ACS_CKBOARD */
1359 DATA('f', 0xf8), /* ACS_DEGREE */
1360 DATA('g', 0xf1), /* ACS_PLMINUS */
1361 DATA('j', 0xd9), /* ACS_LRCORNER */
1362 DATA('l', 0xda), /* ACS_ULCORNER */
1363 DATA('k', 0xbf), /* ACS_URCORNER */
1364 DATA('m', 0xc0), /* ACS_LLCORNER */
1365 DATA('n', 0xc5), /* ACS_PLUS */
1366 DATA('q', 0xc4), /* ACS_HLINE */
1367 DATA('t', 0xc3), /* ACS_LTEE */
1368 DATA('u', 0xb4), /* ACS_RTEE */
1369 DATA('v', 0xc1), /* ACS_BTEE */
1370 DATA('w', 0xc2), /* ACS_TTEE */
1371 DATA('x', 0xb3), /* ACS_VLINE */
1372 DATA('y', 0xf3), /* ACS_LEQUAL */
1373 DATA('z', 0xf2), /* ACS_GEQUAL */
1374 DATA('0', 0xdb), /* ACS_BLOCK */
1375 DATA('{', 0xe3), /* ACS_PI */
1376 DATA('}', 0x9c), /* ACS_STERLING */
1377 DATA(',', 0xae), /* ACS_LARROW */
1378 DATA('+', 0xaf), /* ACS_RARROW */
1379 DATA('~', 0xf9), /* ACS_BULLET */
1388 for (n = 0; n < SIZEOF(table); ++n) {
1389 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1391 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1396 tdiff(FILETIME fstart, FILETIME fend)
1398 ULARGE_INTEGER ustart;
1399 ULARGE_INTEGER uend;
1402 ustart.LowPart = fstart.dwLowDateTime;
1403 ustart.HighPart = fstart.dwHighDateTime;
1404 uend.LowPart = fend.dwLowDateTime;
1405 uend.HighPart = fend.dwHighDateTime;
1407 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1412 Adjust(int milliseconds, int diff)
1414 if (milliseconds != INFINITY) {
1415 milliseconds -= diff;
1416 if (milliseconds < 0)
1419 return milliseconds;
1422 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1423 FROM_LEFT_2ND_BUTTON_PRESSED | \
1424 FROM_LEFT_3RD_BUTTON_PRESSED | \
1425 FROM_LEFT_4TH_BUTTON_PRESSED | \
1426 RIGHTMOST_BUTTON_PRESSED)
1429 decode_mouse(SCREEN *sp, int mask)
1434 assert(sp && console_initialized);
1436 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1437 result |= BUTTON1_PRESSED;
1438 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1439 result |= BUTTON2_PRESSED;
1440 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1441 result |= BUTTON3_PRESSED;
1442 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1443 result |= BUTTON4_PRESSED;
1445 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1446 switch (CON.numButtons) {
1448 result |= BUTTON1_PRESSED;
1451 result |= BUTTON2_PRESSED;
1454 result |= BUTTON3_PRESSED;
1457 result |= BUTTON4_PRESSED;
1472 EVENTLIST_2nd(_nc_eventlist * evl))
1474 INPUT_RECORD inp_rec;
1476 DWORD nRead = 0, rc = (DWORD) (-1);
1481 bool isImmed = (milliseconds == 0);
1483 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1487 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1488 milliseconds, mode));
1490 if (milliseconds < 0)
1491 milliseconds = INFINITY;
1493 memset(&inp_rec, 0, sizeof(inp_rec));
1496 GetSystemTimeAsFileTime(&fstart);
1497 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1498 GetSystemTimeAsFileTime(&fend);
1499 diff = (int) tdiff(fstart, fend);
1500 milliseconds = Adjust(milliseconds, diff);
1502 if (!isImmed && milliseconds <= 0)
1505 if (rc == WAIT_OBJECT_0) {
1507 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1508 if (b && nRead > 0) {
1509 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1510 if (b && nRead > 0) {
1511 switch (inp_rec.EventType) {
1513 if (mode & TW_INPUT) {
1514 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1515 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1517 if (inp_rec.Event.KeyEvent.bKeyDown) {
1519 int nKey = MapKey(vk);
1520 if ((nKey < 0) || FALSE == sp->_keypad_on) {
1533 if (decode_mouse(sp,
1534 (inp_rec.Event.MouseEvent.dwButtonState
1535 & BUTTON_MASK)) == 0) {
1537 } else if (mode & TW_MOUSE) {
1542 /* e.g., FOCUS_EVENT */
1545 selectActiveHandle();
1553 if (rc != WAIT_TIMEOUT) {
1564 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1565 code, errno, milliseconds));
1568 *timeleft = milliseconds;
1574 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1578 EVENTLIST_2nd(_nc_eventlist * evl))
1586 code = console_twait(sp,
1590 timeleft EVENTLIST_2nd(_nc_eventlist * evl));
1595 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1598 bool result = FALSE;
1602 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1603 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1606 * We're only interested if the button is pressed or released.
1607 * FIXME: implement continuous event-tracking.
1609 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1611 memset(&work, 0, sizeof(work));
1613 if (sp->_drv_mouse_new_buttons) {
1615 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1619 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1620 work.bstate |= (mmask_t) (decode_mouse(sp,
1621 sp->_drv_mouse_old_buttons)
1627 work.x = mer.dwMousePosition.X;
1628 work.y = mer.dwMousePosition.Y - AdjustY();
1630 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1631 sp->_drv_mouse_tail += 1;
1638 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1647 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1648 n = _nc_mingw_console_read(sp, CON.inp, buf);
1653 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1655 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1661 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1664 CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1665 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1668 this_CI.bVisible = FALSE;
1673 this_CI.dwSize = 100;
1676 SetConsoleCursorInfo(CON.hdl, &this_CI);
1681 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1686 LONG key = GenMap(0, (WORD) keycode);
1688 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1691 (size_t) (N_INI + FKEYS),
1695 key = *((LONG *) res);
1697 if (!(nKey & 0x8000))
1704 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1712 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1720 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1729 LONG key = GenMap(0, (WORD) keycode);
1731 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1739 (size_t) (N_INI + FKEYS),
1743 key = *((LONG *) res);
1745 nKey = (LOWORD(key)) & 0x7fff;
1748 *(LONG *) res = GenMap(vKey, nKey);
1754 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1756 wcon_name, /* Name */
1757 wcon_CanHandle, /* CanHandle */
1758 wcon_init, /* init */
1759 wcon_release, /* release */
1760 wcon_size, /* size */
1761 wcon_sgmode, /* sgmode */
1762 wcon_conattr, /* conattr */
1763 wcon_mvcur, /* hwcur */
1764 wcon_mode, /* mode */
1765 wcon_rescol, /* rescol */
1766 wcon_rescolors, /* rescolors */
1767 wcon_setcolor, /* color */
1768 wcon_dobeepflash, /* DoBeepFlash */
1769 wcon_initpair, /* initpair */
1770 wcon_initcolor, /* initcolor */
1771 wcon_do_color, /* docolor */
1772 wcon_initmouse, /* initmouse */
1773 wcon_testmouse, /* testmouse */
1774 wcon_setfilter, /* setfilter */
1775 wcon_hwlabel, /* hwlabel */
1776 wcon_hwlabelOnOff, /* hwlabelOnOff */
1777 wcon_doupdate, /* update */
1778 wcon_defaultcolors, /* defaultcolors */
1779 wcon_print, /* print */
1780 wcon_size, /* getsize */
1781 wcon_setsize, /* setsize */
1782 wcon_initacs, /* initacs */
1783 wcon_screen_init, /* scinit */
1784 wcon_wrap, /* scexit */
1785 wcon_twait, /* twait */
1786 wcon_read, /* read */
1788 wcon_kpad, /* kpad */
1789 wcon_keyok, /* kyOk */
1790 wcon_kyExist, /* kyExist */
1791 wcon_cursorSet /* cursorSet */
1794 /* --------------------------------------------------------- */
1799 intptr_t value = _get_osfhandle(fd);
1800 return (HANDLE) value;
1803 #if WINVER >= 0x0600
1804 /* This function tests, whether or not the ncurses application
1805 is running as a descendant of MSYS2/cygwin mintty terminal
1806 application. mintty doesn't use Windows Console for it's screen
1807 I/O, so the native Windows _isatty doesn't recognize it as
1808 character device. But we can discover we are at the end of an
1809 Pipe and can query to server side of the pipe, looking whether
1810 or not this is mintty.
1813 _ismintty(int fd, LPHANDLE pMinTTY)
1815 HANDLE handle = get_handle(fd);
1819 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1821 if (handle != INVALID_HANDLE_VALUE) {
1822 dw = GetFileType(handle);
1823 if (dw == FILE_TYPE_PIPE) {
1824 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1827 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1828 TCHAR buf[MAX_PATH];
1830 /* These security attributes may allow us to
1831 create a remote thread in mintty to manipulate
1832 the terminal state remotely */
1833 HANDLE pHandle = OpenProcess(
1834 PROCESS_CREATE_THREAD
1835 | PROCESS_QUERY_INFORMATION
1836 | PROCESS_VM_OPERATION
1842 *pMinTTY = INVALID_HANDLE_VALUE;
1843 if (pHandle != INVALID_HANDLE_VALUE) {
1844 if ((len = GetProcessImageFileName(
1848 array_length(buf)))) {
1849 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1852 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1869 /* Borrowed from ansicon project.
1870 Check whether or not an I/O handle is associated with
1874 IsConsoleHandle(HANDLE hdl)
1879 if (!GetConsoleMode(hdl, &dwFlag)) {
1880 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1882 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1887 /* Our replacement for the systems _isatty to include also
1888 a test for mintty. This is called from the NC_ISATTY macro
1889 defined in curses.priv.h
1892 _nc_mingw_isatty(int fd)
1899 #if WINVER >= 0x0600
1900 result = _ismintty(fd, NULL);
1906 /* This is used when running in terminfo mode to discover,
1907 whether or not the "terminal" is actually a Windows
1908 Console. It's the responsibilty of the console to deal
1909 with the terminal escape sequences that are sent by
1913 _nc_mingw_isconsole(int fd)
1915 HANDLE hdl = get_handle(fd);
1918 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1920 code = (int) IsConsoleHandle(hdl);
1925 #define TC_PROLOGUE(fd) \
1927 TERMINAL *term = 0; \
1929 if (_nc_screen_chain == 0) \
1931 for (each_screen(sp)) { \
1932 if (sp->_term && (sp->_term->Filedes == fd)) { \
1940 _nc_mingw_tcsetattr(
1942 int optional_action GCC_UNUSED,
1943 const struct termios *arg)
1947 if (_nc_mingw_isconsole(fd)) {
1949 HANDLE ofd = get_handle(fd);
1950 if (ofd != INVALID_HANDLE_VALUE) {
1952 if (arg->c_lflag & ICANON)
1953 dwFlag |= ENABLE_LINE_INPUT;
1955 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
1957 if (arg->c_lflag & ECHO)
1958 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
1960 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
1962 if (arg->c_iflag & BRKINT)
1963 dwFlag |= ENABLE_PROCESSED_INPUT;
1965 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
1967 dwFlag |= ENABLE_MOUSE_INPUT;
1968 SetConsoleMode(ofd, dwFlag);
1979 _nc_mingw_tcgetattr(int fd, struct termios *arg)
1983 if (_nc_mingw_isconsole(fd)) {
1991 _nc_mingw_tcflush(int fd, int queue)
1996 if (_nc_mingw_isconsole(fd)) {
1997 if (queue == TCIFLUSH) {
1998 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2000 return (int) GetLastError();
2007 _nc_mingw_testmouse(
2016 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2019 rc = console_twait(sp,
2024 EVENTLIST_2nd(evl));
2030 _nc_mingw_console_read(
2036 INPUT_RECORD inp_rec;
2044 memset(&inp_rec, 0, sizeof(inp_rec));
2046 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2048 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2049 if (b && nRead > 0) {
2050 if (inp_rec.EventType == KEY_EVENT) {
2051 if (!inp_rec.Event.KeyEvent.bKeyDown)
2053 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2054 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2056 if (sp->_keypad_on) {
2064 } else { /* *buf != 0 */
2067 } else if (inp_rec.EventType == MOUSE_EVENT) {
2068 if (handle_mouse(sp,
2069 inp_rec.Event.MouseEvent)) {
2081 __attribute__((constructor))
2082 void _enter_console(void)
2084 if (!console_initialized) {
2088 BOOL buffered = TRUE;
2092 if (_nc_mingw_isatty(0)) {
2093 CON.isMinTTY = TRUE;
2096 for (i = 0; i < (N_INI + FKEYS); i++) {
2098 CON.rmap[i] = CON.map[i] =
2101 CON.rmap[i] = CON.map[i] =
2102 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2103 (KEY_F(1) + (i - N_INI)));
2114 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2115 CON.numButtons = (int) num_buttons;
2120 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2121 for (i = 0; i < NUMPAIRS; i++)
2124 CON.inp = GetStdHandle(STD_INPUT_HANDLE);
2125 CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
2130 b = AttachConsole(ATTACH_PARENT_PROCESS);
2132 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2133 T(("... will not buffer console"));
2137 T(("... creating console buffer"));
2138 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2141 CONSOLE_TEXTMODE_BUFFER,
2145 if (CON.hdl != INVALID_HANDLE_VALUE) {
2146 CON.buffered = buffered;
2148 CON.save_SBI = CON.SBI;
2150 save_original_screen();
2151 set_scrollback(FALSE, &CON.SBI);
2153 GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
2154 T(("... initial cursor is %svisible, %d%%",
2155 (CON.save_CI.bVisible ? "" : "not-"),
2156 (int) CON.save_CI.dwSize));
2159 console_initialized = TRUE;