1 /****************************************************************************
2 * Copyright 2018-2020,2021 Thomas E. Dickey *
3 * Copyright 2008-2016,2017 Free Software Foundation, Inc. *
5 * Permission is hereby granted, free of charge, to any person obtaining a *
6 * copy of this software and associated documentation files (the *
7 * "Software"), to deal in the Software without restriction, including *
8 * without limitation the rights to use, copy, modify, merge, publish, *
9 * distribute, distribute with modifications, sublicense, and/or sell *
10 * copies of the Software, and to permit persons to whom the Software is *
11 * furnished to do so, subject to the following conditions: *
13 * The above copyright notice and this permission notice shall be included *
14 * in all copies or substantial portions of the Software. *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
24 * Except as contained in this notice, the name(s) of the above copyright *
25 * holders shall not be used in advertising or otherwise to promote the *
26 * sale, use or other dealings in this Software without prior written *
28 ****************************************************************************/
30 /****************************************************************************
31 * Author: Juergen Pfeifer *
32 * and: Thomas E. Dickey *
33 ****************************************************************************/
36 * TODO - GetMousePos(POINT * result) from ntconio.c
37 * TODO - implement nodelay
38 * TODO - improve screen-repainting performance, using implied wraparound to reduce write's
39 * TODO - make it optional whether screen is restored or not when non-buffered
42 #include <curses.priv.h>
53 #define PSAPI_VERSION 2
56 #define CUR TerminalType(my_term).
58 MODULE_ID("$Id: win_driver.c,v 1.67 2021/09/04 10:54:35 tom Exp $")
60 #define TypeAlloca(type,count) (type*) _alloca(sizeof(type) * (size_t) (count))
62 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
64 #define EXP_OPTIMIZE 0
66 #define array_length(a) (sizeof(a)/sizeof(a[0]))
68 static bool InitConsole(void);
69 static bool okConsoleHandle(TERMINAL_CONTROL_BLOCK *);
71 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
72 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
74 #define GenMap(vKey,key) MAKELONG(key, vKey)
76 #define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
79 #define write_screen WriteConsoleOutputW
80 #define read_screen ReadConsoleOutputW
82 #define write_screen WriteConsoleOutput
83 #define read_screen ReadConsoleOutput
86 static const LONG keylist[] =
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)
99 static const LONG ansi_keys[] =
101 GenMap(VK_PRIOR, 'I'),
102 GenMap(VK_NEXT, 'Q'),
104 GenMap(VK_HOME, 'H'),
105 GenMap(VK_LEFT, 'K'),
107 GenMap(VK_RIGHT, 'M'),
108 GenMap(VK_DOWN, 'P'),
109 GenMap(VK_DELETE, 'S'),
110 GenMap(VK_INSERT, 'R')
112 #define N_INI ((int)array_length(keylist))
114 #define MAPSIZE (FKEYS + N_INI)
117 /* A process can only have a single console, so it is safe
118 to maintain all the information about it in a single
127 BOOL isTermInfoConsole;
133 DWORD ansi_map[MAPSIZE];
136 WORD pairs[NUMPAIRS];
138 CHAR_INFO *save_screen;
140 SMALL_RECT save_region;
141 CONSOLE_SCREEN_BUFFER_INFO SBI;
142 CONSOLE_SCREEN_BUFFER_INFO save_SBI;
143 CONSOLE_CURSOR_INFO save_CI;
146 static BOOL console_initialized = FALSE;
149 MapColor(bool fore, int color)
151 static const int _cmap[] =
152 {0, 4, 2, 6, 1, 5, 3, 7};
154 if (color < 0 || color > 7)
163 #define RevAttr(attr) \
164 (WORD) (((attr) & 0xff00) | \
165 ((((attr) & 0x07) << 4) | \
166 (((attr) & 0x70) >> 4)))
169 MapAttr(WORD res, attr_t ch)
175 if (p > 0 && p < NUMPAIRS) {
178 res = (WORD) ((res & 0xff00) | a);
182 if (ch & A_REVERSE) {
186 if (ch & A_STANDOUT) {
187 res = RevAttr(res) | BACKGROUND_INTENSITY;
191 res |= FOREGROUND_INTENSITY;
194 res |= BACKGROUND_INTENSITY;
199 #if 0 /* def TRACE */
201 dump_screen(const char *fn, int ln)
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];
207 SMALL_RECT save_region;
210 T(("dump_screen %s@%d", fn, ln));
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;
217 save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
218 save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
220 bufferCoord.X = bufferCoord.Y = 0;
222 if (read_screen(CON.hdl,
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;
239 T(("DUMP: %d,%d - %d,%d",
249 #define dump_screen(fn,ln) /* nothing */
252 #if USE_WIDEC_SUPPORT
254 * TODO: support surrogate pairs
255 * TODO: support combining characters
257 * TODO: _nc_wacs should be part of sp.
260 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
263 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, limit);
273 for (i = actual = 0; i < limit; i++) {
277 ci[actual].Char.UnicodeChar = CharOf(ch);
278 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
280 if (AttrOf(ch) & A_ALTCHARSET) {
282 int which = CharOf(ch);
285 && CharOf(_nc_wacs[which]) != 0) {
286 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
288 ci[actual].Char.UnicodeChar = ' ';
297 siz.X = (SHORT) actual;
300 rec.Left = (SHORT) x;
301 rec.Top = (SHORT) (y + AdjustY());
302 rec.Right = (SHORT) (x + limit - 1);
303 rec.Bottom = rec.Top;
305 return write_screen(CON.hdl, ci, siz, loc, &rec);
307 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
310 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
312 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, n);
322 for (i = 0; i < n; i++) {
324 ci[i].Char.AsciiChar = ChCharOf(ch);
325 ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
327 if (ChAttrOf(ch) & A_ALTCHARSET) {
329 ci[i].Char.AsciiChar =
330 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
339 rec.Left = (short) x;
341 rec.Right = (short) (x + n - 1);
342 rec.Bottom = rec.Top;
344 return write_screen(CON.hdl, ci, siz, loc, &rec);
346 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
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.
356 find_end_of_change(SCREEN *sp, int row, int col)
359 struct ldat *curdat = CurScreen(sp)->_line + row;
360 struct ldat *newdat = NewScreen(sp)->_line + row;
362 while (col <= newdat->lastchar) {
363 #if USE_WIDEC_SUPPORT
364 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
366 } else if (memcmp(&curdat->text[col],
368 sizeof(curdat->text[0]))) {
374 if (curdat->text[col] != newdat->text[col]) {
386 * Given a row,col position at the end of a change-chunk, look for the
387 * beginning of the next change-chunk.
390 find_next_change(SCREEN *sp, int row, int col)
392 struct ldat *curdat = CurScreen(sp)->_line + row;
393 struct ldat *newdat = NewScreen(sp)->_line + row;
394 int result = newdat->lastchar + 1;
396 while (++col <= newdat->lastchar) {
397 #if USE_WIDEC_SUPPORT
398 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
401 } else if (memcmp(&curdat->text[col],
403 sizeof(curdat->text[0]))) {
408 if (curdat->text[col] != newdat->text[col]) {
417 #define EndChange(first) \
418 find_end_of_change(sp, y, first)
419 #define NextChange(last) \
420 find_next_change(sp, y, last)
422 #endif /* EXP_OPTIMIZE */
424 #define MARK_NOCHANGE(win,row) \
425 win->_line[row].firstchar = _NOCHANGE; \
426 win->_line[row].lastchar = _NOCHANGE
429 selectActiveHandle(void)
431 if (CON.lastOut != CON.hdl) {
432 CON.lastOut = CON.hdl;
433 SetConsoleActiveScreenBuffer(CON.lastOut);
438 restore_original_screen(void)
442 SMALL_RECT save_region = CON.save_region;
444 T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
446 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
447 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
449 if (write_screen(CON.hdl,
455 mvcur(-1, -1, LINES - 2, 0);
456 T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
464 T(("... restore original screen contents err"));
470 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
473 return "win32console";
477 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
480 int y, nonempty, n, x0, x1, Width, Height;
483 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
484 if (okConsoleHandle(TCB)) {
487 Width = screen_columns(sp);
488 Height = screen_lines(sp);
489 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
491 T(("... %dx%d clear cur:%d new:%d",
493 CurScreen(sp)->_clear,
494 NewScreen(sp)->_clear));
496 if (SP_PARM->_endwin == ewSuspend) {
498 T(("coming back from shell mode"));
499 NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
501 NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
502 NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
503 SP_PARM->_mouse_resume(SP_PARM);
505 SP_PARM->_endwin = ewRunning;
508 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
510 #if USE_WIDEC_SUPPORT
511 cchar_t *empty = TypeAlloca(cchar_t, Width);
517 for (x = 0; x < Width; x++)
518 setcchar(&empty[x], blank, 0, 0, 0);
520 chtype *empty = TypeAlloca(chtype, Width);
522 for (x = 0; x < Width; x++)
526 for (y = 0; y < nonempty; y++) {
527 con_write(TCB, y, 0, empty, Width);
529 CurScreen(sp)->_line[y].text,
530 (size_t) Width * sizeof(empty[0]));
532 CurScreen(sp)->_clear = FALSE;
533 NewScreen(sp)->_clear = FALSE;
534 touchwin(NewScreen(sp));
535 T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
539 for (y = 0; y < nonempty; y++) {
540 x0 = NewScreen(sp)->_line[y].firstchar;
541 if (x0 != _NOCHANGE) {
544 int limit = NewScreen(sp)->_line[y].lastchar;
545 while ((x1 = EndChange(x0)) <= limit) {
546 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
550 memcpy(&CurScreen(sp)->_line[y].text[x0],
551 &NewScreen(sp)->_line[y].text[x0],
552 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
556 &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);
568 x1 = NewScreen(sp)->_line[y].lastchar;
571 memcpy(&CurScreen(sp)->_line[y].text[x0],
572 &NewScreen(sp)->_line[y].text[x0],
573 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
577 &CurScreen(sp)->_line[y].text[x0], n);
579 /* mark line changed successfully */
580 if (y <= NewScreen(sp)->_maxy) {
581 MARK_NOCHANGE(NewScreen(sp), y);
583 if (y <= CurScreen(sp)->_maxy) {
584 MARK_NOCHANGE(CurScreen(sp), y);
591 /* put everything back in sync */
592 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
593 MARK_NOCHANGE(NewScreen(sp), y);
595 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
596 MARK_NOCHANGE(CurScreen(sp), y);
599 if (!NewScreen(sp)->_leaveok) {
600 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
601 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
603 TCB->drv->td_hwcur(TCB,
605 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
607 selectActiveHandle();
614 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
616 int *errret GCC_UNUSED)
620 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
622 assert((TCB != 0) && (tname != 0));
624 TCB->magic = WINMAGIC;
626 if (tname == 0 || *tname == 0)
628 else if (tname != 0 && *tname == '#') {
630 * Use "#" (a character which cannot begin a terminal's name) to
631 * select specific driver from the table.
633 * In principle, we could have more than one non-terminfo driver,
636 size_t n = strlen(tname + 1);
638 && ((strncmp(tname + 1, "win32console", n) == 0)
639 || (strncmp(tname + 1, "win32con", n) == 0))) {
642 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
647 * This is intentional, to avoid unnecessary breakage of applications
648 * using <term.h> symbols.
650 if (code && (TerminalType(&TCB->term).Booleans == 0)) {
651 _nc_init_termtype(&TerminalType(&TCB->term));
652 #if NCURSES_EXT_NUMBERS
653 _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
658 if (_nc_mingw_isconsole(0))
659 CON.isTermInfoConsole = TRUE;
665 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
671 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
672 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
673 int max_cells = (high * wide);
676 CHAR_INFO *this_screen = TypeAlloca(CHAR_INFO, max_cells);
677 CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells);
679 SMALL_RECT this_region;
682 if (okConsoleHandle(TCB)) {
684 this_region.Top = CON.SBI.srWindow.Top;
685 this_region.Left = CON.SBI.srWindow.Left;
686 this_region.Bottom = CON.SBI.srWindow.Bottom;
687 this_region.Right = CON.SBI.srWindow.Right;
689 this_size.X = (SHORT) wide;
690 this_size.Y = (SHORT) high;
692 bufferCoord.X = this_region.Left;
693 bufferCoord.Y = this_region.Top;
704 sizeof(CHAR_INFO) * (size_t) max_cells);
706 for (i = 0; i < max_cells; i++) {
707 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
710 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
712 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
715 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */
723 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
724 char *data GCC_UNUSED,
736 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
753 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
754 T(("GetConsoleScreenBufferInfo"));
755 T(("... buffer(X:%d Y:%d)",
758 T(("... window(X:%d Y:%d)",
759 CON.SBI.dwMaximumWindowSize.X,
760 CON.SBI.dwMaximumWindowSize.Y));
761 T(("... cursor(X:%d Y:%d)",
762 CON.SBI.dwCursorPosition.X,
763 CON.SBI.dwCursorPosition.Y));
764 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
765 CON.SBI.srWindow.Top,
766 CON.SBI.srWindow.Bottom,
767 CON.SBI.srWindow.Left,
768 CON.SBI.srWindow.Right));
773 CON.origin.X = CON.SBI.srWindow.Left;
774 CON.origin.Y = CON.SBI.srWindow.Top;
778 T(("GetConsoleScreenBufferInfo ERR"));
784 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
787 int (*outc) (SCREEN *, int) GCC_UNUSED)
789 if (okConsoleHandle(TCB)) {
790 WORD a = MapColor(fore, color);
791 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
792 SetConsoleTextAttribute(CON.hdl, a);
798 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
802 if (okConsoleHandle(TCB)) {
803 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
804 SetConsoleTextAttribute(CON.hdl, a);
812 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
824 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
828 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
830 if (okConsoleHandle(TCB) &&
834 *Lines = (int) (CON.SBI.dwSize.Y);
835 *Cols = (int) (CON.SBI.dwSize.X);
837 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
838 CON.SBI.srWindow.Top);
839 *Cols = (int) (CON.SBI.srWindow.Right + 1 -
840 CON.SBI.srWindow.Left);
848 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
857 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
864 if (buf != NULL && okConsoleHandle(TCB)) {
867 iflag = buf->c_iflag;
868 lflag = buf->c_lflag;
870 GetConsoleMode(CON.inp, &dwFlag);
873 dwFlag |= ENABLE_LINE_INPUT;
875 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
878 dwFlag |= ENABLE_ECHO_INPUT;
880 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
883 dwFlag |= ENABLE_PROCESSED_INPUT;
885 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
887 dwFlag |= ENABLE_MOUSE_INPUT;
889 buf->c_iflag = iflag;
890 buf->c_lflag = lflag;
891 SetConsoleMode(CON.inp, dwFlag);
892 TCB->term.Nttyb = *buf;
894 iflag = TCB->term.Nttyb.c_iflag;
895 lflag = TCB->term.Nttyb.c_lflag;
896 GetConsoleMode(CON.inp, &dwFlag);
898 if (dwFlag & ENABLE_LINE_INPUT)
901 lflag &= (tcflag_t) (~ICANON);
903 if (dwFlag & ENABLE_ECHO_INPUT)
906 lflag &= (tcflag_t) (~ECHO);
908 if (dwFlag & ENABLE_PROCESSED_INPUT)
911 iflag &= (tcflag_t) (~BRKINT);
913 TCB->term.Nttyb.c_iflag = iflag;
914 TCB->term.Nttyb.c_lflag = lflag;
916 *buf = TCB->term.Nttyb;
927 * In "normal" mode, reset the buffer- and window-sizes back to their original values.
930 set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
934 bool changed = FALSE;
936 T((T_CALLED("win32con::set_scrollback(%s)"),
941 T(("... SBI.srWindow %d,%d .. %d,%d",
944 info->srWindow.Bottom,
945 info->srWindow.Right));
946 T(("... SBI.dwSize %dx%d",
951 rect = info->srWindow;
952 coord = info->dwSize;
953 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
958 int high = info->srWindow.Bottom - info->srWindow.Top + 1;
959 int wide = info->srWindow.Right - info->srWindow.Left + 1;
961 if (high < MIN_HIGH) {
962 T(("... height %d < %d", high, MIN_HIGH));
966 if (wide < MIN_WIDE) {
967 T(("... width %d < %d", wide, MIN_WIDE));
974 rect.Right = (SHORT) (wide - 1);
975 rect.Bottom = (SHORT) (high - 1);
977 coord.X = (SHORT) wide;
978 coord.Y = (SHORT) high;
980 if (info->dwSize.Y != high ||
981 info->dwSize.X != wide ||
982 info->srWindow.Top != 0 ||
983 info->srWindow.Left != 0) {
990 T(("... coord %d,%d", coord.Y, coord.X));
991 T(("... rect %d,%d - %d,%d",
993 rect.Bottom, rect.Right));
994 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */
995 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */
1002 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
1005 TERMINAL *_term = (TERMINAL *) TCB;
1008 if (okConsoleHandle(TCB)) {
1011 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"),
1012 TCB, progFlag, defFlag));
1014 CON.progMode = progFlag;
1015 CON.lastOut = progFlag ? CON.hdl : CON.out;
1016 SetConsoleActiveScreenBuffer(CON.lastOut);
1018 if (progFlag) /* prog mode */ {
1020 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
1021 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
1025 /* reset_prog_mode */
1026 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
1029 _nc_keypad(sp, TRUE);
1031 if (!CON.buffered) {
1032 set_scrollback(FALSE, &CON.SBI);
1037 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
1038 } else { /* shell mode */
1040 /* def_shell_mode */
1041 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
1045 /* reset_shell_mode */
1047 _nc_keypad(sp, FALSE);
1048 NCURSES_SP_NAME(_nc_flush) (sp);
1050 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
1051 if (!CON.buffered) {
1052 set_scrollback(TRUE, &CON.save_SBI);
1053 if (!restore_original_screen())
1056 SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
1065 wcon_screen_init(SCREEN *sp GCC_UNUSED)
1070 wcon_wrap(SCREEN *sp GCC_UNUSED)
1075 rkeycompare(const void *el1, const void *el2)
1077 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
1078 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
1080 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1084 keycompare(const void *el1, const void *el2)
1086 WORD key1 = HIWORD((*((const LONG *) el1)));
1087 WORD key2 = HIWORD((*((const LONG *) el2)));
1089 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1097 LONG key = GenMap(vKey, 0);
1102 (size_t) (N_INI + FKEYS),
1106 key = *((LONG *) res);
1108 code = (int) (nKey & 0x7fff);
1120 LONG key = GenMap(vKey, 0);
1125 (size_t) (N_INI + FKEYS),
1129 key = *((LONG *) res);
1131 code = (int) (nKey & 0x7fff);
1139 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
1141 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
1151 read_screen_data(void)
1153 bool result = FALSE;
1157 CON.save_size.X = (SHORT) (CON.save_region.Right
1158 - CON.save_region.Left + 1);
1159 CON.save_size.Y = (SHORT) (CON.save_region.Bottom
1160 - CON.save_region.Top + 1);
1162 want = (size_t) (CON.save_size.X * CON.save_size.Y);
1164 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1165 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
1166 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
1168 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
1169 CON.window_only ? "window" : "buffer",
1170 CON.save_size.Y, CON.save_size.X,
1171 CON.save_region.Top,
1172 CON.save_region.Left,
1173 CON.save_region.Bottom,
1174 CON.save_region.Right,
1178 if (read_screen(CON.hdl,
1182 &CON.save_region)) {
1185 T((" error %#lx", (unsigned long) GetLastError()));
1186 FreeAndNull(CON.save_screen);
1194 * Attempt to save the screen contents. PDCurses does this if
1195 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
1196 * restoration as if the library had allocated a console buffer. MSDN
1197 * says that the data which can be read is limited to 64Kb (and may be
1201 save_original_screen(void)
1203 bool result = FALSE;
1205 CON.save_region.Top = 0;
1206 CON.save_region.Left = 0;
1207 CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
1208 CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
1210 if (read_screen_data()) {
1214 CON.save_region.Top = CON.SBI.srWindow.Top;
1215 CON.save_region.Left = CON.SBI.srWindow.Left;
1216 CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
1217 CON.save_region.Right = CON.SBI.srWindow.Right;
1219 CON.window_only = TRUE;
1221 if (read_screen_data()) {
1226 T(("... save original screen contents %s", result ? "ok" : "err"));
1231 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1233 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1238 if (!InitConsole()) {
1242 TCB->info.initcolor = TRUE;
1243 TCB->info.canchange = FALSE;
1244 TCB->info.hascolor = TRUE;
1245 TCB->info.caninit = TRUE;
1247 TCB->info.maxpairs = NUMPAIRS;
1248 TCB->info.maxcolors = 8;
1249 TCB->info.numlabels = 0;
1250 TCB->info.labelwidth = 0;
1251 TCB->info.labelheight = 0;
1252 TCB->info.nocolorvideo = 1;
1253 TCB->info.tabsize = 8;
1255 TCB->info.numbuttons = CON.numButtons;
1256 TCB->info.defaultPalette = _nc_cga_palette;
1263 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1270 if (okConsoleHandle(TCB)) {
1273 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1274 && (b >= 0) && (b < 8)) {
1275 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
1281 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1282 int color GCC_UNUSED,
1294 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1295 int old_pair GCC_UNUSED,
1296 int pair GCC_UNUSED,
1297 int reverse GCC_UNUSED,
1298 int (*outc) (SCREEN *, int) GCC_UNUSED
1308 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1312 if (okConsoleHandle(TCB)) {
1315 sp->_mouse_type = M_TERM_DRIVER;
1320 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
1322 EVENTLIST_2nd(_nc_eventlist * evl))
1327 if (okConsoleHandle(TCB)) {
1330 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1333 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1337 EVENTLIST_2nd(evl));
1345 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1346 int yold GCC_UNUSED, int xold GCC_UNUSED,
1350 if (okConsoleHandle(TCB)) {
1353 loc.Y = (short) (y + AdjustY());
1354 SetConsoleCursorPosition(CON.hdl, loc);
1361 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1362 int labnum GCC_UNUSED,
1363 char *text GCC_UNUSED)
1372 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1373 int OnFlag GCC_UNUSED)
1382 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1384 chtype res = A_NORMAL;
1385 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1390 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1399 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1400 chtype *real_map GCC_UNUSED,
1401 chtype *fake_map GCC_UNUSED)
1403 #define DATA(a,b) { a, b }
1408 DATA('a', 0xb1), /* ACS_CKBOARD */
1409 DATA('f', 0xf8), /* ACS_DEGREE */
1410 DATA('g', 0xf1), /* ACS_PLMINUS */
1411 DATA('j', 0xd9), /* ACS_LRCORNER */
1412 DATA('l', 0xda), /* ACS_ULCORNER */
1413 DATA('k', 0xbf), /* ACS_URCORNER */
1414 DATA('m', 0xc0), /* ACS_LLCORNER */
1415 DATA('n', 0xc5), /* ACS_PLUS */
1416 DATA('q', 0xc4), /* ACS_HLINE */
1417 DATA('t', 0xc3), /* ACS_LTEE */
1418 DATA('u', 0xb4), /* ACS_RTEE */
1419 DATA('v', 0xc1), /* ACS_BTEE */
1420 DATA('w', 0xc2), /* ACS_TTEE */
1421 DATA('x', 0xb3), /* ACS_VLINE */
1422 DATA('y', 0xf3), /* ACS_LEQUAL */
1423 DATA('z', 0xf2), /* ACS_GEQUAL */
1424 DATA('0', 0xdb), /* ACS_BLOCK */
1425 DATA('{', 0xe3), /* ACS_PI */
1426 DATA('}', 0x9c), /* ACS_STERLING */
1427 DATA(',', 0xae), /* ACS_LARROW */
1428 DATA('+', 0xaf), /* ACS_RARROW */
1429 DATA('~', 0xf9), /* ACS_BULLET */
1435 if (okConsoleHandle(TCB)) {
1438 for (n = 0; n < SIZEOF(table); ++n) {
1439 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1441 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1447 tdiff(FILETIME fstart, FILETIME fend)
1449 ULARGE_INTEGER ustart;
1450 ULARGE_INTEGER uend;
1453 ustart.LowPart = fstart.dwLowDateTime;
1454 ustart.HighPart = fstart.dwHighDateTime;
1455 uend.LowPart = fend.dwLowDateTime;
1456 uend.HighPart = fend.dwHighDateTime;
1458 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1463 Adjust(int milliseconds, int diff)
1465 if (milliseconds != INFINITY) {
1466 milliseconds -= diff;
1467 if (milliseconds < 0)
1470 return milliseconds;
1473 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1474 FROM_LEFT_2ND_BUTTON_PRESSED | \
1475 FROM_LEFT_3RD_BUTTON_PRESSED | \
1476 FROM_LEFT_4TH_BUTTON_PRESSED | \
1477 RIGHTMOST_BUTTON_PRESSED)
1480 decode_mouse(SCREEN *sp, int mask)
1485 assert(sp && console_initialized);
1487 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1488 result |= BUTTON1_PRESSED;
1489 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1490 result |= BUTTON2_PRESSED;
1491 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1492 result |= BUTTON3_PRESSED;
1493 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1494 result |= BUTTON4_PRESSED;
1496 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1497 switch (CON.numButtons) {
1499 result |= BUTTON1_PRESSED;
1502 result |= BUTTON2_PRESSED;
1505 result |= BUTTON3_PRESSED;
1508 result |= BUTTON4_PRESSED;
1523 EVENTLIST_2nd(_nc_eventlist * evl))
1525 INPUT_RECORD inp_rec;
1527 DWORD nRead = 0, rc = (DWORD) (-1);
1532 bool isImmed = (milliseconds == 0);
1534 #ifdef NCURSES_WGETCH_EVENTS
1535 (void) evl; /* TODO: implement wgetch-events */
1538 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1542 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1543 milliseconds, mode));
1545 if (milliseconds < 0)
1546 milliseconds = INFINITY;
1548 memset(&inp_rec, 0, sizeof(inp_rec));
1551 GetSystemTimeAsFileTime(&fstart);
1552 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1553 GetSystemTimeAsFileTime(&fend);
1554 diff = (int) tdiff(fstart, fend);
1555 milliseconds = Adjust(milliseconds, diff);
1557 if (!isImmed && milliseconds <= 0)
1560 if (rc == WAIT_OBJECT_0) {
1562 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1563 if (b && nRead > 0) {
1564 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1565 if (b && nRead > 0) {
1566 switch (inp_rec.EventType) {
1568 if (mode & TW_INPUT) {
1569 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1570 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1572 if (inp_rec.Event.KeyEvent.bKeyDown) {
1574 int nKey = MapKey(vk);
1588 if (decode_mouse(sp,
1589 (inp_rec.Event.MouseEvent.dwButtonState
1590 & BUTTON_MASK)) == 0) {
1592 } else if (mode & TW_MOUSE) {
1597 /* e.g., FOCUS_EVENT */
1600 selectActiveHandle();
1608 if (rc != WAIT_TIMEOUT) {
1619 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1620 code, errno, milliseconds));
1623 *timeleft = milliseconds;
1629 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1633 EVENTLIST_2nd(_nc_eventlist * evl))
1638 if (okConsoleHandle(TCB)) {
1641 code = console_twait(sp,
1645 timeleft EVENTLIST_2nd(evl));
1651 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1654 bool result = FALSE;
1658 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1659 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1662 * We're only interested if the button is pressed or released.
1663 * FIXME: implement continuous event-tracking.
1665 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1667 memset(&work, 0, sizeof(work));
1669 if (sp->_drv_mouse_new_buttons) {
1671 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1675 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1676 work.bstate |= (mmask_t) (decode_mouse(sp,
1677 sp->_drv_mouse_old_buttons)
1683 work.x = mer.dwMousePosition.X;
1684 work.y = mer.dwMousePosition.Y - AdjustY();
1686 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1687 sp->_drv_mouse_tail += 1;
1694 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1699 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1702 if (okConsoleHandle(TCB)) {
1705 n = _nc_mingw_console_read(sp, CON.inp, buf);
1711 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1713 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1719 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1723 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1724 if (okConsoleHandle(TCB)) {
1725 CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1728 this_CI.bVisible = FALSE;
1733 this_CI.dwSize = 100;
1736 SetConsoleCursorInfo(CON.hdl, &this_CI);
1742 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1747 LONG key = GenMap(0, (WORD) keycode);
1749 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1752 (size_t) (N_INI + FKEYS),
1756 key = *((LONG *) res);
1758 if (!(nKey & 0x8000))
1765 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1770 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1772 if (okConsoleHandle(TCB)) {
1783 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1792 LONG key = GenMap(0, (WORD) keycode);
1794 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1796 if (okConsoleHandle(TCB)) {
1802 (size_t) (N_INI + FKEYS),
1806 key = *((LONG *) res);
1808 nKey = (LOWORD(key)) & 0x7fff;
1811 *(LONG *) res = GenMap(vKey, nKey);
1818 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1820 wcon_name, /* Name */
1821 wcon_CanHandle, /* CanHandle */
1822 wcon_init, /* init */
1823 wcon_release, /* release */
1824 wcon_size, /* size */
1825 wcon_sgmode, /* sgmode */
1826 wcon_conattr, /* conattr */
1827 wcon_mvcur, /* hwcur */
1828 wcon_mode, /* mode */
1829 wcon_rescol, /* rescol */
1830 wcon_rescolors, /* rescolors */
1831 wcon_setcolor, /* color */
1832 wcon_dobeepflash, /* DoBeepFlash */
1833 wcon_initpair, /* initpair */
1834 wcon_initcolor, /* initcolor */
1835 wcon_do_color, /* docolor */
1836 wcon_initmouse, /* initmouse */
1837 wcon_testmouse, /* testmouse */
1838 wcon_setfilter, /* setfilter */
1839 wcon_hwlabel, /* hwlabel */
1840 wcon_hwlabelOnOff, /* hwlabelOnOff */
1841 wcon_doupdate, /* update */
1842 wcon_defaultcolors, /* defaultcolors */
1843 wcon_print, /* print */
1844 wcon_size, /* getsize */
1845 wcon_setsize, /* setsize */
1846 wcon_initacs, /* initacs */
1847 wcon_screen_init, /* scinit */
1848 wcon_wrap, /* scexit */
1849 wcon_twait, /* twait */
1850 wcon_read, /* read */
1852 wcon_kpad, /* kpad */
1853 wcon_keyok, /* kyOk */
1854 wcon_kyExist, /* kyExist */
1855 wcon_cursorSet /* cursorSet */
1858 /* --------------------------------------------------------- */
1863 intptr_t value = _get_osfhandle(fd);
1864 return (HANDLE) value;
1867 #if WINVER >= 0x0600
1868 /* This function tests, whether or not the ncurses application
1869 is running as a descendant of MSYS2/cygwin mintty terminal
1870 application. mintty doesn't use Windows Console for its screen
1871 I/O, so the native Windows _isatty doesn't recognize it as
1872 character device. But we can discover we are at the end of an
1873 Pipe and can query to server side of the pipe, looking whether
1874 or not this is mintty.
1877 _ismintty(int fd, LPHANDLE pMinTTY)
1879 HANDLE handle = get_handle(fd);
1883 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1885 if (handle != INVALID_HANDLE_VALUE) {
1886 dw = GetFileType(handle);
1887 if (dw == FILE_TYPE_PIPE) {
1888 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1891 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1892 TCHAR buf[MAX_PATH];
1894 /* These security attributes may allow us to
1895 create a remote thread in mintty to manipulate
1896 the terminal state remotely */
1897 HANDLE pHandle = OpenProcess(
1898 PROCESS_CREATE_THREAD
1899 | PROCESS_QUERY_INFORMATION
1900 | PROCESS_VM_OPERATION
1906 *pMinTTY = INVALID_HANDLE_VALUE;
1907 if (pHandle != INVALID_HANDLE_VALUE) {
1908 if ((len = GetProcessImageFileName(
1912 array_length(buf)))) {
1913 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1916 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1933 /* Borrowed from ansicon project.
1934 Check whether or not an I/O handle is associated with
1938 IsConsoleHandle(HANDLE hdl)
1943 if (!GetConsoleMode(hdl, &dwFlag)) {
1944 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1946 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1951 /* Our replacement for the systems _isatty to include also
1952 a test for mintty. This is called from the NC_ISATTY macro
1953 defined in curses.priv.h
1956 _nc_mingw_isatty(int fd)
1961 #define SysISATTY(fd) _isatty(fd)
1963 #define SysISATTY(fd) isatty(fd)
1965 if (SysISATTY(fd)) {
1968 #if WINVER >= 0x0600
1969 result = _ismintty(fd, NULL);
1975 /* This is used when running in terminfo mode to discover,
1976 whether or not the "terminal" is actually a Windows
1977 Console. It is the responsibility of the console to deal
1978 with the terminal escape sequences that are sent by
1982 _nc_mingw_isconsole(int fd)
1984 HANDLE hdl = get_handle(fd);
1987 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1989 code = (int) IsConsoleHandle(hdl);
1994 #define TC_PROLOGUE(fd) \
1996 TERMINAL *term = 0; \
1998 if (_nc_screen_chain == 0) \
2000 for (each_screen(sp)) { \
2001 if (sp->_term && (sp->_term->Filedes == fd)) { \
2009 _nc_mingw_tcsetattr(
2011 int optional_action GCC_UNUSED,
2012 const struct termios *arg)
2016 if (_nc_mingw_isconsole(fd)) {
2018 HANDLE ofd = get_handle(fd);
2019 if (ofd != INVALID_HANDLE_VALUE) {
2021 if (arg->c_lflag & ICANON)
2022 dwFlag |= ENABLE_LINE_INPUT;
2024 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
2026 if (arg->c_lflag & ECHO)
2027 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
2029 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
2031 if (arg->c_iflag & BRKINT)
2032 dwFlag |= ENABLE_PROCESSED_INPUT;
2034 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
2036 dwFlag |= ENABLE_MOUSE_INPUT;
2037 SetConsoleMode(ofd, dwFlag);
2048 _nc_mingw_tcgetattr(int fd, struct termios *arg)
2052 if (_nc_mingw_isconsole(fd)) {
2060 _nc_mingw_tcflush(int fd, int queue)
2065 if (_nc_mingw_isconsole(fd)) {
2066 if (queue == TCIFLUSH) {
2067 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2069 return (int) GetLastError();
2076 _nc_mingw_testmouse(
2080 EVENTLIST_2nd(_nc_eventlist * evl))
2086 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2089 rc = console_twait(sp,
2094 EVENTLIST_2nd(evl));
2100 _nc_mingw_console_read(
2106 INPUT_RECORD inp_rec;
2114 memset(&inp_rec, 0, sizeof(inp_rec));
2116 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2118 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2119 if (b && nRead > 0) {
2122 rc = rc + (int) nRead;
2123 if (inp_rec.EventType == KEY_EVENT) {
2124 if (!inp_rec.Event.KeyEvent.bKeyDown)
2126 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2127 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2129 * There are 24 virtual function-keys, and typically
2130 * 12 function-keys on a keyboard. Use the shift-modifier
2131 * to provide the remaining 12 keys.
2133 if (vk >= VK_F1 && vk <= VK_F12) {
2134 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
2135 vk = (WORD) (vk + 12);
2139 int key = MapKey(vk);
2142 if (sp->_keypad_on) {
2150 } else if (inp_rec.EventType == MOUSE_EVENT) {
2151 if (handle_mouse(sp,
2152 inp_rec.Event.MouseEvent)) {
2166 /* initialize once, or not at all */
2167 if (!console_initialized) {
2171 BOOL buffered = TRUE;
2175 if (_nc_mingw_isatty(0)) {
2176 CON.isMinTTY = TRUE;
2179 for (i = 0; i < (N_INI + FKEYS); i++) {
2181 CON.rmap[i] = CON.map[i] =
2183 CON.ansi_map[i] = (DWORD) ansi_keys[i];
2185 CON.rmap[i] = CON.map[i] =
2186 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2187 (KEY_F(1) + (i - N_INI)));
2189 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2190 (';' + (i - N_INI)));
2206 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2207 CON.numButtons = (int) num_buttons;
2212 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2213 for (i = 0; i < NUMPAIRS; i++)
2216 CON.inp = GetStdHandle(STD_INPUT_HANDLE);
2217 CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
2222 b = AttachConsole(ATTACH_PARENT_PROCESS);
2224 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2225 T(("... will not buffer console"));
2229 T(("... creating console buffer"));
2230 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2233 CONSOLE_TEXTMODE_BUFFER,
2237 if (CON.hdl != INVALID_HANDLE_VALUE) {
2238 CON.buffered = buffered;
2240 CON.save_SBI = CON.SBI;
2242 save_original_screen();
2243 set_scrollback(FALSE, &CON.SBI);
2245 GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
2246 T(("... initial cursor is %svisible, %d%%",
2247 (CON.save_CI.bVisible ? "" : "not-"),
2248 (int) CON.save_CI.dwSize));
2251 console_initialized = TRUE;
2253 return (CON.hdl != INVALID_HANDLE_VALUE);
2257 okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB)
2259 return ((TCB != 0) &&
2260 (TCB->magic == WINMAGIC) &&
2265 * While a constructor would ensure that this module is initialized, that will
2266 * interfere with applications that may combine this with GUI interfaces.
2270 __attribute__((constructor))
2271 void _enter_console(void)
2273 (void) InitConsole();