1 /****************************************************************************
2 * Copyright 2018-2021,2023 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 #define CONTROL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
60 MODULE_ID("$Id: win_driver.c,v 1.71 2023/07/08 19:53:51 tom Exp $")
62 #define TypeAlloca(type,count) (type*) _alloca(sizeof(type) * (size_t) (count))
64 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
66 #define EXP_OPTIMIZE 0
68 #define array_length(a) (sizeof(a)/sizeof(a[0]))
70 static bool InitConsole(void);
71 static bool okConsoleHandle(TERMINAL_CONTROL_BLOCK *);
73 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
74 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
76 #define GenMap(vKey,key) MAKELONG(key, vKey)
78 #define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
81 #define write_screen WriteConsoleOutputW
82 #define read_screen ReadConsoleOutputW
84 #define write_screen WriteConsoleOutput
85 #define read_screen ReadConsoleOutput
88 static const LONG keylist[] =
90 GenMap(VK_PRIOR, KEY_PPAGE),
91 GenMap(VK_NEXT, KEY_NPAGE),
92 GenMap(VK_END, KEY_END),
93 GenMap(VK_HOME, KEY_HOME),
94 GenMap(VK_LEFT, KEY_LEFT),
95 GenMap(VK_UP, KEY_UP),
96 GenMap(VK_RIGHT, KEY_RIGHT),
97 GenMap(VK_DOWN, KEY_DOWN),
98 GenMap(VK_DELETE, KEY_DC),
99 GenMap(VK_INSERT, KEY_IC)
101 static const LONG ansi_keys[] =
103 GenMap(VK_PRIOR, 'I'),
104 GenMap(VK_NEXT, 'Q'),
106 GenMap(VK_HOME, 'H'),
107 GenMap(VK_LEFT, 'K'),
109 GenMap(VK_RIGHT, 'M'),
110 GenMap(VK_DOWN, 'P'),
111 GenMap(VK_DELETE, 'S'),
112 GenMap(VK_INSERT, 'R')
115 #define N_INI ((int)array_length(keylist))
117 #define MAPSIZE (FKEYS + N_INI)
120 /* A process can only have a single console, so it is safe
121 to maintain all the information about it in a single
130 BOOL isTermInfoConsole;
136 DWORD ansi_map[MAPSIZE];
139 WORD pairs[NUMPAIRS];
141 CHAR_INFO *save_screen;
143 SMALL_RECT save_region;
144 CONSOLE_SCREEN_BUFFER_INFO SBI;
145 CONSOLE_SCREEN_BUFFER_INFO save_SBI;
146 CONSOLE_CURSOR_INFO save_CI;
149 static BOOL console_initialized = FALSE;
152 MapColor(bool fore, int color)
154 static const int _cmap[] =
155 {0, 4, 2, 6, 1, 5, 3, 7};
157 if (color < 0 || color > 7)
166 #define RevAttr(attr) \
167 (WORD) (((attr) & 0xff00) | \
168 ((((attr) & 0x07) << 4) | \
169 (((attr) & 0x70) >> 4)))
172 MapAttr(WORD res, attr_t ch)
178 if (p > 0 && p < NUMPAIRS) {
181 res = (WORD) ((res & 0xff00) | a);
185 if (ch & A_REVERSE) {
189 if (ch & A_STANDOUT) {
190 res = RevAttr(res) | BACKGROUND_INTENSITY;
194 res |= FOREGROUND_INTENSITY;
197 res |= BACKGROUND_INTENSITY;
202 #if 0 /* def TRACE */
204 dump_screen(const char *fn, int ln)
206 int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1;
207 char output[max_cells];
208 CHAR_INFO save_screen[max_cells];
210 SMALL_RECT save_region;
213 T(("dump_screen %s@%d", fn, ln));
215 save_region.Top = CON.SBI.srWindow.Top;
216 save_region.Left = CON.SBI.srWindow.Left;
217 save_region.Bottom = CON.SBI.srWindow.Bottom;
218 save_region.Right = CON.SBI.srWindow.Right;
220 save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
221 save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
223 bufferCoord.X = bufferCoord.Y = 0;
225 if (read_screen(CON.hdl,
234 for (i = save_region.Top; i <= save_region.Bottom; ++i) {
235 for (j = save_region.Left; j <= save_region.Right; ++j) {
236 output[k++] = save_screen[ij++].Char.AsciiChar;
242 T(("DUMP: %d,%d - %d,%d",
252 #define dump_screen(fn,ln) /* nothing */
255 #if USE_WIDEC_SUPPORT
257 * TODO: support surrogate pairs
258 * TODO: support combining characters
260 * TODO: _nc_wacs should be part of sp.
263 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
266 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, limit);
276 for (i = actual = 0; i < limit; i++) {
280 ci[actual].Char.UnicodeChar = CharOf(ch);
281 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
283 if (AttrOf(ch) & A_ALTCHARSET) {
285 int which = CharOf(ch);
288 && CharOf(_nc_wacs[which]) != 0) {
289 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
291 ci[actual].Char.UnicodeChar = ' ';
300 siz.X = (SHORT) actual;
303 rec.Left = (SHORT) x;
304 rec.Top = (SHORT) (y + AdjustY());
305 rec.Right = (SHORT) (x + limit - 1);
306 rec.Bottom = rec.Top;
308 return write_screen(CON.hdl, ci, siz, loc, &rec);
310 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
313 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
315 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, n);
325 for (i = 0; i < n; i++) {
327 ci[i].Char.AsciiChar = ChCharOf(ch);
328 ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
330 if (ChAttrOf(ch) & A_ALTCHARSET) {
332 ci[i].Char.AsciiChar =
333 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
342 rec.Left = (short) x;
344 rec.Right = (short) (x + n - 1);
345 rec.Bottom = rec.Top;
347 return write_screen(CON.hdl, ci, siz, loc, &rec);
349 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
354 * Comparing new/current screens, determine the last column-index for a change
355 * beginning on the given row,col position. Unlike a serial terminal, there is
356 * no cost for "moving" the "cursor" on the line as we update it.
359 find_end_of_change(SCREEN *sp, int row, int col)
362 struct ldat *curdat = CurScreen(sp)->_line + row;
363 struct ldat *newdat = NewScreen(sp)->_line + row;
365 while (col <= newdat->lastchar) {
366 #if USE_WIDEC_SUPPORT
367 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
369 } else if (memcmp(&curdat->text[col],
371 sizeof(curdat->text[0]))) {
377 if (curdat->text[col] != newdat->text[col]) {
389 * Given a row,col position at the end of a change-chunk, look for the
390 * beginning of the next change-chunk.
393 find_next_change(SCREEN *sp, int row, int col)
395 struct ldat *curdat = CurScreen(sp)->_line + row;
396 struct ldat *newdat = NewScreen(sp)->_line + row;
397 int result = newdat->lastchar + 1;
399 while (++col <= newdat->lastchar) {
400 #if USE_WIDEC_SUPPORT
401 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
404 } else if (memcmp(&curdat->text[col],
406 sizeof(curdat->text[0]))) {
411 if (curdat->text[col] != newdat->text[col]) {
420 #define EndChange(first) \
421 find_end_of_change(sp, y, first)
422 #define NextChange(last) \
423 find_next_change(sp, y, last)
425 #endif /* EXP_OPTIMIZE */
427 #define MARK_NOCHANGE(win,row) \
428 win->_line[row].firstchar = _NOCHANGE; \
429 win->_line[row].lastchar = _NOCHANGE
432 selectActiveHandle(void)
434 if (CON.lastOut != CON.hdl) {
435 CON.lastOut = CON.hdl;
436 SetConsoleActiveScreenBuffer(CON.lastOut);
441 restore_original_screen(void)
445 SMALL_RECT save_region = CON.save_region;
447 T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
449 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
450 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
452 if (write_screen(CON.hdl,
458 mvcur(-1, -1, LINES - 2, 0);
459 T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
467 T(("... restore original screen contents err"));
473 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
476 return "win32console";
480 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
483 int y, nonempty, n, x0, x1, Width, Height;
486 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
487 if (okConsoleHandle(TCB)) {
490 Width = screen_columns(sp);
491 Height = screen_lines(sp);
492 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
494 T(("... %dx%d clear cur:%d new:%d",
496 CurScreen(sp)->_clear,
497 NewScreen(sp)->_clear));
499 if (SP_PARM->_endwin == ewSuspend) {
501 T(("coming back from shell mode"));
502 NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
504 NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
505 NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
506 SP_PARM->_mouse_resume(SP_PARM);
508 SP_PARM->_endwin = ewRunning;
511 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
513 #if USE_WIDEC_SUPPORT
514 cchar_t *empty = TypeAlloca(cchar_t, Width);
520 for (x = 0; x < Width; x++)
521 setcchar(&empty[x], blank, 0, 0, 0);
523 chtype *empty = TypeAlloca(chtype, Width);
525 for (x = 0; x < Width; x++)
529 for (y = 0; y < nonempty; y++) {
530 con_write(TCB, y, 0, empty, Width);
532 CurScreen(sp)->_line[y].text,
533 (size_t) Width * sizeof(empty[0]));
535 CurScreen(sp)->_clear = FALSE;
536 NewScreen(sp)->_clear = FALSE;
537 touchwin(NewScreen(sp));
538 T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
542 for (y = 0; y < nonempty; y++) {
543 x0 = NewScreen(sp)->_line[y].firstchar;
544 if (x0 != _NOCHANGE) {
547 int limit = NewScreen(sp)->_line[y].lastchar;
548 while ((x1 = EndChange(x0)) <= limit) {
549 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
553 memcpy(&CurScreen(sp)->_line[y].text[x0],
554 &NewScreen(sp)->_line[y].text[x0],
555 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
559 &CurScreen(sp)->_line[y].text[x0], n);
563 /* mark line changed successfully */
564 if (y <= NewScreen(sp)->_maxy) {
565 MARK_NOCHANGE(NewScreen(sp), y);
567 if (y <= CurScreen(sp)->_maxy) {
568 MARK_NOCHANGE(CurScreen(sp), y);
571 x1 = NewScreen(sp)->_line[y].lastchar;
574 memcpy(&CurScreen(sp)->_line[y].text[x0],
575 &NewScreen(sp)->_line[y].text[x0],
576 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
580 &CurScreen(sp)->_line[y].text[x0], n);
582 /* mark line changed successfully */
583 if (y <= NewScreen(sp)->_maxy) {
584 MARK_NOCHANGE(NewScreen(sp), y);
586 if (y <= CurScreen(sp)->_maxy) {
587 MARK_NOCHANGE(CurScreen(sp), y);
594 /* put everything back in sync */
595 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
596 MARK_NOCHANGE(NewScreen(sp), y);
598 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
599 MARK_NOCHANGE(CurScreen(sp), y);
602 if (!NewScreen(sp)->_leaveok) {
603 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
604 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
606 TCB->drv->td_hwcur(TCB,
608 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
610 selectActiveHandle();
617 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
619 int *errret GCC_UNUSED)
623 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
625 assert((TCB != 0) && (tname != 0));
627 TCB->magic = WINMAGIC;
629 if (tname == 0 || *tname == 0)
631 else if (tname != 0 && *tname == '#') {
633 * Use "#" (a character which cannot begin a terminal's name) to
634 * select specific driver from the table.
636 * In principle, we could have more than one non-terminfo driver,
639 size_t n = strlen(tname + 1);
641 && ((strncmp(tname + 1, "win32console", n) == 0)
642 || (strncmp(tname + 1, "win32con", n) == 0))) {
645 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
650 * This is intentional, to avoid unnecessary breakage of applications
651 * using <term.h> symbols.
653 if (code && (TerminalType(&TCB->term).Booleans == 0)) {
654 _nc_init_termtype(&TerminalType(&TCB->term));
655 #if NCURSES_EXT_NUMBERS
656 _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
661 if (_nc_mingw_isconsole(0))
662 CON.isTermInfoConsole = TRUE;
668 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
674 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
675 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
676 int max_cells = (high * wide);
679 CHAR_INFO *this_screen = TypeAlloca(CHAR_INFO, max_cells);
680 CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells);
682 SMALL_RECT this_region;
685 if (okConsoleHandle(TCB)) {
687 this_region.Top = CON.SBI.srWindow.Top;
688 this_region.Left = CON.SBI.srWindow.Left;
689 this_region.Bottom = CON.SBI.srWindow.Bottom;
690 this_region.Right = CON.SBI.srWindow.Right;
692 this_size.X = (SHORT) wide;
693 this_size.Y = (SHORT) high;
695 bufferCoord.X = this_region.Left;
696 bufferCoord.Y = this_region.Top;
707 sizeof(CHAR_INFO) * (size_t) max_cells);
709 for (i = 0; i < max_cells; i++) {
710 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
713 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
715 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
718 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */
726 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
727 char *data GCC_UNUSED,
739 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
756 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
757 T(("GetConsoleScreenBufferInfo"));
758 T(("... buffer(X:%d Y:%d)",
761 T(("... window(X:%d Y:%d)",
762 CON.SBI.dwMaximumWindowSize.X,
763 CON.SBI.dwMaximumWindowSize.Y));
764 T(("... cursor(X:%d Y:%d)",
765 CON.SBI.dwCursorPosition.X,
766 CON.SBI.dwCursorPosition.Y));
767 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
768 CON.SBI.srWindow.Top,
769 CON.SBI.srWindow.Bottom,
770 CON.SBI.srWindow.Left,
771 CON.SBI.srWindow.Right));
776 CON.origin.X = CON.SBI.srWindow.Left;
777 CON.origin.Y = CON.SBI.srWindow.Top;
781 T(("GetConsoleScreenBufferInfo ERR"));
787 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
790 int (*outc) (SCREEN *, int) GCC_UNUSED)
792 if (okConsoleHandle(TCB)) {
793 WORD a = MapColor(fore, color);
794 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
795 SetConsoleTextAttribute(CON.hdl, a);
801 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
805 if (okConsoleHandle(TCB)) {
806 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
807 SetConsoleTextAttribute(CON.hdl, a);
815 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
827 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
831 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
833 if (okConsoleHandle(TCB) &&
837 *Lines = (int) (CON.SBI.dwSize.Y);
838 *Cols = (int) (CON.SBI.dwSize.X);
840 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
841 CON.SBI.srWindow.Top);
842 *Cols = (int) (CON.SBI.srWindow.Right + 1 -
843 CON.SBI.srWindow.Left);
851 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
860 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
867 if (buf != NULL && okConsoleHandle(TCB)) {
870 iflag = buf->c_iflag;
871 lflag = buf->c_lflag;
873 GetConsoleMode(CON.inp, &dwFlag);
876 dwFlag |= ENABLE_LINE_INPUT;
878 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
881 dwFlag |= ENABLE_ECHO_INPUT;
883 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
886 dwFlag |= ENABLE_PROCESSED_INPUT;
888 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
890 dwFlag |= ENABLE_MOUSE_INPUT;
892 buf->c_iflag = iflag;
893 buf->c_lflag = lflag;
894 SetConsoleMode(CON.inp, dwFlag);
895 TCB->term.Nttyb = *buf;
897 iflag = TCB->term.Nttyb.c_iflag;
898 lflag = TCB->term.Nttyb.c_lflag;
899 GetConsoleMode(CON.inp, &dwFlag);
901 if (dwFlag & ENABLE_LINE_INPUT)
904 lflag &= (tcflag_t) (~ICANON);
906 if (dwFlag & ENABLE_ECHO_INPUT)
909 lflag &= (tcflag_t) (~ECHO);
911 if (dwFlag & ENABLE_PROCESSED_INPUT)
914 iflag &= (tcflag_t) (~BRKINT);
916 TCB->term.Nttyb.c_iflag = iflag;
917 TCB->term.Nttyb.c_lflag = lflag;
919 *buf = TCB->term.Nttyb;
930 * In "normal" mode, reset the buffer- and window-sizes back to their original values.
933 set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
937 bool changed = FALSE;
939 T((T_CALLED("win32con::set_scrollback(%s)"),
944 T(("... SBI.srWindow %d,%d .. %d,%d",
947 info->srWindow.Bottom,
948 info->srWindow.Right));
949 T(("... SBI.dwSize %dx%d",
954 rect = info->srWindow;
955 coord = info->dwSize;
956 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
961 int high = info->srWindow.Bottom - info->srWindow.Top + 1;
962 int wide = info->srWindow.Right - info->srWindow.Left + 1;
964 if (high < MIN_HIGH) {
965 T(("... height %d < %d", high, MIN_HIGH));
969 if (wide < MIN_WIDE) {
970 T(("... width %d < %d", wide, MIN_WIDE));
977 rect.Right = (SHORT) (wide - 1);
978 rect.Bottom = (SHORT) (high - 1);
980 coord.X = (SHORT) wide;
981 coord.Y = (SHORT) high;
983 if (info->dwSize.Y != high ||
984 info->dwSize.X != wide ||
985 info->srWindow.Top != 0 ||
986 info->srWindow.Left != 0) {
993 T(("... coord %d,%d", coord.Y, coord.X));
994 T(("... rect %d,%d - %d,%d",
996 rect.Bottom, rect.Right));
997 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */
998 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */
1005 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
1008 TERMINAL *_term = (TERMINAL *) TCB;
1011 if (okConsoleHandle(TCB)) {
1014 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"),
1015 TCB, progFlag, defFlag));
1017 CON.progMode = progFlag;
1018 CON.lastOut = progFlag ? CON.hdl : CON.out;
1019 SetConsoleActiveScreenBuffer(CON.lastOut);
1021 if (progFlag) /* prog mode */ {
1023 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
1024 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
1028 /* reset_prog_mode */
1029 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
1032 _nc_keypad(sp, TRUE);
1034 if (!CON.buffered) {
1035 set_scrollback(FALSE, &CON.SBI);
1040 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
1041 } else { /* shell mode */
1043 /* def_shell_mode */
1044 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
1048 /* reset_shell_mode */
1050 _nc_keypad(sp, FALSE);
1051 NCURSES_SP_NAME(_nc_flush) (sp);
1053 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
1054 if (!CON.buffered) {
1055 set_scrollback(TRUE, &CON.save_SBI);
1056 if (!restore_original_screen())
1059 SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
1068 wcon_screen_init(SCREEN *sp GCC_UNUSED)
1073 wcon_wrap(SCREEN *sp GCC_UNUSED)
1078 rkeycompare(const void *el1, const void *el2)
1080 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
1081 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
1083 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1087 keycompare(const void *el1, const void *el2)
1089 WORD key1 = HIWORD((*((const LONG *) el1)));
1090 WORD key2 = HIWORD((*((const LONG *) el2)));
1092 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1100 LONG key = GenMap(vKey, 0);
1105 (size_t) (N_INI + FKEYS),
1109 key = *((LONG *) res);
1111 code = (int) (nKey & 0x7fff);
1123 LONG key = GenMap(vKey, 0);
1128 (size_t) (N_INI + FKEYS),
1132 key = *((LONG *) res);
1134 code = (int) (nKey & 0x7fff);
1142 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
1144 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
1154 read_screen_data(void)
1156 bool result = FALSE;
1160 CON.save_size.X = (SHORT) (CON.save_region.Right
1161 - CON.save_region.Left + 1);
1162 CON.save_size.Y = (SHORT) (CON.save_region.Bottom
1163 - CON.save_region.Top + 1);
1165 want = (size_t) (CON.save_size.X * CON.save_size.Y);
1167 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1168 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
1169 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
1171 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
1172 CON.window_only ? "window" : "buffer",
1173 CON.save_size.Y, CON.save_size.X,
1174 CON.save_region.Top,
1175 CON.save_region.Left,
1176 CON.save_region.Bottom,
1177 CON.save_region.Right,
1181 if (read_screen(CON.hdl,
1185 &CON.save_region)) {
1188 T((" error %#lx", (unsigned long) GetLastError()));
1189 FreeAndNull(CON.save_screen);
1197 * Attempt to save the screen contents. PDCurses does this if
1198 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
1199 * restoration as if the library had allocated a console buffer. MSDN
1200 * says that the data which can be read is limited to 64Kb (and may be
1204 save_original_screen(void)
1206 bool result = FALSE;
1208 CON.save_region.Top = 0;
1209 CON.save_region.Left = 0;
1210 CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
1211 CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
1213 if (read_screen_data()) {
1217 CON.save_region.Top = CON.SBI.srWindow.Top;
1218 CON.save_region.Left = CON.SBI.srWindow.Left;
1219 CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
1220 CON.save_region.Right = CON.SBI.srWindow.Right;
1222 CON.window_only = TRUE;
1224 if (read_screen_data()) {
1229 T(("... save original screen contents %s", result ? "ok" : "err"));
1234 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1236 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1241 if (!InitConsole()) {
1245 TCB->info.initcolor = TRUE;
1246 TCB->info.canchange = FALSE;
1247 TCB->info.hascolor = TRUE;
1248 TCB->info.caninit = TRUE;
1250 TCB->info.maxpairs = NUMPAIRS;
1251 TCB->info.maxcolors = 8;
1252 TCB->info.numlabels = 0;
1253 TCB->info.labelwidth = 0;
1254 TCB->info.labelheight = 0;
1255 TCB->info.nocolorvideo = 1;
1256 TCB->info.tabsize = 8;
1258 TCB->info.numbuttons = CON.numButtons;
1259 TCB->info.defaultPalette = _nc_cga_palette;
1266 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1273 if (okConsoleHandle(TCB)) {
1276 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1277 && (b >= 0) && (b < 8)) {
1278 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
1284 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1285 int color GCC_UNUSED,
1297 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1298 int old_pair GCC_UNUSED,
1299 int pair GCC_UNUSED,
1300 int reverse GCC_UNUSED,
1301 int (*outc) (SCREEN *, int) GCC_UNUSED
1311 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1315 if (okConsoleHandle(TCB)) {
1318 sp->_mouse_type = M_TERM_DRIVER;
1323 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
1325 EVENTLIST_2nd(_nc_eventlist * evl))
1330 if (okConsoleHandle(TCB)) {
1333 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1336 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1340 EVENTLIST_2nd(evl));
1348 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1349 int yold GCC_UNUSED, int xold GCC_UNUSED,
1353 if (okConsoleHandle(TCB)) {
1356 loc.Y = (short) (y + AdjustY());
1357 SetConsoleCursorPosition(CON.hdl, loc);
1364 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1365 int labnum GCC_UNUSED,
1366 char *text GCC_UNUSED)
1375 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1376 int OnFlag GCC_UNUSED)
1385 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1387 chtype res = A_NORMAL;
1388 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1393 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1402 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1403 chtype *real_map GCC_UNUSED,
1404 chtype *fake_map GCC_UNUSED)
1406 #define DATA(a,b) { a, b }
1411 DATA('a', 0xb1), /* ACS_CKBOARD */
1412 DATA('f', 0xf8), /* ACS_DEGREE */
1413 DATA('g', 0xf1), /* ACS_PLMINUS */
1414 DATA('j', 0xd9), /* ACS_LRCORNER */
1415 DATA('l', 0xda), /* ACS_ULCORNER */
1416 DATA('k', 0xbf), /* ACS_URCORNER */
1417 DATA('m', 0xc0), /* ACS_LLCORNER */
1418 DATA('n', 0xc5), /* ACS_PLUS */
1419 DATA('q', 0xc4), /* ACS_HLINE */
1420 DATA('t', 0xc3), /* ACS_LTEE */
1421 DATA('u', 0xb4), /* ACS_RTEE */
1422 DATA('v', 0xc1), /* ACS_BTEE */
1423 DATA('w', 0xc2), /* ACS_TTEE */
1424 DATA('x', 0xb3), /* ACS_VLINE */
1425 DATA('y', 0xf3), /* ACS_LEQUAL */
1426 DATA('z', 0xf2), /* ACS_GEQUAL */
1427 DATA('0', 0xdb), /* ACS_BLOCK */
1428 DATA('{', 0xe3), /* ACS_PI */
1429 DATA('}', 0x9c), /* ACS_STERLING */
1430 DATA(',', 0xae), /* ACS_LARROW */
1431 DATA('+', 0xaf), /* ACS_RARROW */
1432 DATA('~', 0xf9), /* ACS_BULLET */
1438 if (okConsoleHandle(TCB)) {
1441 for (n = 0; n < SIZEOF(table); ++n) {
1442 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1444 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1450 tdiff(FILETIME fstart, FILETIME fend)
1452 ULARGE_INTEGER ustart;
1453 ULARGE_INTEGER uend;
1456 ustart.LowPart = fstart.dwLowDateTime;
1457 ustart.HighPart = fstart.dwHighDateTime;
1458 uend.LowPart = fend.dwLowDateTime;
1459 uend.HighPart = fend.dwHighDateTime;
1461 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1466 Adjust(int milliseconds, int diff)
1468 if (milliseconds != INFINITY) {
1469 milliseconds -= diff;
1470 if (milliseconds < 0)
1473 return milliseconds;
1476 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1477 FROM_LEFT_2ND_BUTTON_PRESSED | \
1478 FROM_LEFT_3RD_BUTTON_PRESSED | \
1479 FROM_LEFT_4TH_BUTTON_PRESSED | \
1480 RIGHTMOST_BUTTON_PRESSED)
1483 decode_mouse(SCREEN *sp, int mask)
1488 assert(sp && console_initialized);
1490 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1491 result |= BUTTON1_PRESSED;
1492 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1493 result |= BUTTON2_PRESSED;
1494 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1495 result |= BUTTON3_PRESSED;
1496 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1497 result |= BUTTON4_PRESSED;
1499 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1500 switch (CON.numButtons) {
1502 result |= BUTTON1_PRESSED;
1505 result |= BUTTON2_PRESSED;
1508 result |= BUTTON3_PRESSED;
1511 result |= BUTTON4_PRESSED;
1526 EVENTLIST_2nd(_nc_eventlist * evl))
1528 INPUT_RECORD inp_rec;
1530 DWORD nRead = 0, rc = (DWORD) (-1);
1535 bool isImmed = (milliseconds == 0);
1537 #ifdef NCURSES_WGETCH_EVENTS
1538 (void) evl; /* TODO: implement wgetch-events */
1541 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1545 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1546 milliseconds, mode));
1548 if (milliseconds < 0)
1549 milliseconds = INFINITY;
1551 memset(&inp_rec, 0, sizeof(inp_rec));
1554 GetSystemTimeAsFileTime(&fstart);
1555 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1556 GetSystemTimeAsFileTime(&fend);
1557 diff = (int) tdiff(fstart, fend);
1558 milliseconds = Adjust(milliseconds, diff);
1560 if (!isImmed && milliseconds <= 0)
1563 if (rc == WAIT_OBJECT_0) {
1565 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1566 if (b && nRead > 0) {
1567 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1568 if (b && nRead > 0) {
1569 switch (inp_rec.EventType) {
1571 if (mode & TW_INPUT) {
1572 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1573 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1575 if (inp_rec.Event.KeyEvent.bKeyDown) {
1577 int nKey = MapKey(vk);
1591 if (decode_mouse(sp,
1592 (inp_rec.Event.MouseEvent.dwButtonState
1593 & BUTTON_MASK)) == 0) {
1595 } else if (mode & TW_MOUSE) {
1600 /* e.g., FOCUS_EVENT */
1603 selectActiveHandle();
1611 if (rc != WAIT_TIMEOUT) {
1622 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1623 code, errno, milliseconds));
1626 *timeleft = milliseconds;
1632 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1636 EVENTLIST_2nd(_nc_eventlist * evl))
1641 if (okConsoleHandle(TCB)) {
1644 code = console_twait(sp,
1648 timeleft EVENTLIST_2nd(evl));
1654 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1657 bool result = FALSE;
1661 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1662 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1665 * We're only interested if the button is pressed or released.
1666 * FIXME: implement continuous event-tracking.
1668 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1670 memset(&work, 0, sizeof(work));
1672 if (sp->_drv_mouse_new_buttons) {
1674 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1678 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1679 work.bstate |= (mmask_t) (decode_mouse(sp,
1680 sp->_drv_mouse_old_buttons)
1686 work.x = mer.dwMousePosition.X;
1687 work.y = mer.dwMousePosition.Y - AdjustY();
1689 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1690 sp->_drv_mouse_tail += 1;
1697 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1702 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1705 if (okConsoleHandle(TCB)) {
1708 n = _nc_mingw_console_read(sp, CON.inp, buf);
1714 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1716 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1722 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1726 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1727 if (okConsoleHandle(TCB)) {
1728 CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1731 this_CI.bVisible = FALSE;
1736 this_CI.dwSize = 100;
1739 SetConsoleCursorInfo(CON.hdl, &this_CI);
1745 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1750 LONG key = GenMap(0, (WORD) keycode);
1752 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1755 (size_t) (N_INI + FKEYS),
1759 key = *((LONG *) res);
1761 if (!(nKey & 0x8000))
1768 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1773 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1775 if (okConsoleHandle(TCB)) {
1786 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1795 LONG key = GenMap(0, (WORD) keycode);
1797 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1799 if (okConsoleHandle(TCB)) {
1805 (size_t) (N_INI + FKEYS),
1809 key = *((LONG *) res);
1811 nKey = (LOWORD(key)) & 0x7fff;
1814 *(LONG *) res = GenMap(vKey, nKey);
1821 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1823 wcon_name, /* Name */
1824 wcon_CanHandle, /* CanHandle */
1825 wcon_init, /* init */
1826 wcon_release, /* release */
1827 wcon_size, /* size */
1828 wcon_sgmode, /* sgmode */
1829 wcon_conattr, /* conattr */
1830 wcon_mvcur, /* hwcur */
1831 wcon_mode, /* mode */
1832 wcon_rescol, /* rescol */
1833 wcon_rescolors, /* rescolors */
1834 wcon_setcolor, /* color */
1835 wcon_dobeepflash, /* DoBeepFlash */
1836 wcon_initpair, /* initpair */
1837 wcon_initcolor, /* initcolor */
1838 wcon_do_color, /* docolor */
1839 wcon_initmouse, /* initmouse */
1840 wcon_testmouse, /* testmouse */
1841 wcon_setfilter, /* setfilter */
1842 wcon_hwlabel, /* hwlabel */
1843 wcon_hwlabelOnOff, /* hwlabelOnOff */
1844 wcon_doupdate, /* update */
1845 wcon_defaultcolors, /* defaultcolors */
1846 wcon_print, /* print */
1847 wcon_size, /* getsize */
1848 wcon_setsize, /* setsize */
1849 wcon_initacs, /* initacs */
1850 wcon_screen_init, /* scinit */
1851 wcon_wrap, /* scexit */
1852 wcon_twait, /* twait */
1853 wcon_read, /* read */
1855 wcon_kpad, /* kpad */
1856 wcon_keyok, /* kyOk */
1857 wcon_kyExist, /* kyExist */
1858 wcon_cursorSet /* cursorSet */
1861 /* --------------------------------------------------------- */
1866 intptr_t value = _get_osfhandle(fd);
1867 return (HANDLE) value;
1870 #if WINVER >= 0x0600
1871 /* This function tests, whether or not the ncurses application
1872 is running as a descendant of MSYS2/cygwin mintty terminal
1873 application. mintty doesn't use Windows Console for its screen
1874 I/O, so the native Windows _isatty doesn't recognize it as
1875 character device. But we can discover we are at the end of an
1876 Pipe and can query to server side of the pipe, looking whether
1877 or not this is mintty.
1880 _ismintty(int fd, LPHANDLE pMinTTY)
1882 HANDLE handle = get_handle(fd);
1886 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1888 if (handle != INVALID_HANDLE_VALUE) {
1889 dw = GetFileType(handle);
1890 if (dw == FILE_TYPE_PIPE) {
1891 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1894 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1895 TCHAR buf[MAX_PATH];
1897 /* These security attributes may allow us to
1898 create a remote thread in mintty to manipulate
1899 the terminal state remotely */
1900 HANDLE pHandle = OpenProcess(
1901 PROCESS_CREATE_THREAD
1902 | PROCESS_QUERY_INFORMATION
1903 | PROCESS_VM_OPERATION
1909 *pMinTTY = INVALID_HANDLE_VALUE;
1910 if (pHandle != INVALID_HANDLE_VALUE) {
1911 if ((len = GetProcessImageFileName(
1915 array_length(buf)))) {
1916 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1919 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1936 /* Borrowed from ansicon project.
1937 Check whether or not an I/O handle is associated with
1941 IsConsoleHandle(HANDLE hdl)
1946 if (!GetConsoleMode(hdl, &dwFlag)) {
1947 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1949 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1954 /* Our replacement for the systems _isatty to include also
1955 a test for mintty. This is called from the NC_ISATTY macro
1956 defined in curses.priv.h
1959 _nc_mingw_isatty(int fd)
1964 #define SysISATTY(fd) _isatty(fd)
1966 #define SysISATTY(fd) isatty(fd)
1968 if (SysISATTY(fd)) {
1971 #if WINVER >= 0x0600
1972 result = _ismintty(fd, NULL);
1978 /* This is used when running in terminfo mode to discover,
1979 whether or not the "terminal" is actually a Windows
1980 Console. It is the responsibility of the console to deal
1981 with the terminal escape sequences that are sent by
1985 _nc_mingw_isconsole(int fd)
1987 HANDLE hdl = get_handle(fd);
1990 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1992 code = (int) IsConsoleHandle(hdl);
1997 #define TC_PROLOGUE(fd) \
1999 TERMINAL *term = 0; \
2001 if (_nc_screen_chain == 0) \
2003 for (each_screen(sp)) { \
2004 if (sp->_term && (sp->_term->Filedes == fd)) { \
2012 _nc_mingw_tcsetattr(
2014 int optional_action GCC_UNUSED,
2015 const struct termios *arg)
2019 if (_nc_mingw_isconsole(fd)) {
2021 HANDLE ofd = get_handle(fd);
2022 if (ofd != INVALID_HANDLE_VALUE) {
2024 if (arg->c_lflag & ICANON)
2025 dwFlag |= ENABLE_LINE_INPUT;
2027 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
2029 if (arg->c_lflag & ECHO)
2030 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
2032 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
2034 if (arg->c_iflag & BRKINT)
2035 dwFlag |= ENABLE_PROCESSED_INPUT;
2037 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
2039 dwFlag |= ENABLE_MOUSE_INPUT;
2040 SetConsoleMode(ofd, dwFlag);
2051 _nc_mingw_tcgetattr(int fd, struct termios *arg)
2055 if (_nc_mingw_isconsole(fd)) {
2063 _nc_mingw_tcflush(int fd, int queue)
2068 if (_nc_mingw_isconsole(fd)) {
2069 if (queue == TCIFLUSH) {
2070 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2072 return (int) GetLastError();
2079 _nc_mingw_testmouse(
2083 EVENTLIST_2nd(_nc_eventlist * evl))
2089 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2092 rc = console_twait(sp,
2097 EVENTLIST_2nd(evl));
2103 _nc_mingw_console_read(
2109 INPUT_RECORD inp_rec;
2117 memset(&inp_rec, 0, sizeof(inp_rec));
2119 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2121 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2122 if (b && nRead > 0) {
2125 rc = rc + (int) nRead;
2126 if (inp_rec.EventType == KEY_EVENT) {
2127 if (!inp_rec.Event.KeyEvent.bKeyDown)
2129 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2130 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2132 * There are 24 virtual function-keys (defined in winuser.h),
2133 * and typically 12 function-keys on a keyboard. Use the
2134 * shift-modifier to provide the remaining keys.
2136 if (vk >= VK_F1 && vk <= VK_F12) {
2137 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
2138 vk = (WORD) (vk + 12);
2142 int key = MapKey(vk);
2145 if (sp->_keypad_on) {
2151 } else if (vk == VK_BACK) {
2152 if (!(inp_rec.Event.KeyEvent.dwControlKeyState
2153 & (SHIFT_PRESSED | CONTROL_PRESSED))) {
2154 *buf = KEY_BACKSPACE;
2158 } else if (inp_rec.EventType == MOUSE_EVENT) {
2159 if (handle_mouse(sp,
2160 inp_rec.Event.MouseEvent)) {
2174 /* initialize once, or not at all */
2175 if (!console_initialized) {
2179 BOOL buffered = TRUE;
2183 if (_nc_mingw_isatty(0)) {
2184 CON.isMinTTY = TRUE;
2187 for (i = 0; i < (N_INI + FKEYS); i++) {
2189 CON.rmap[i] = CON.map[i] =
2191 CON.ansi_map[i] = (DWORD) ansi_keys[i];
2193 CON.rmap[i] = CON.map[i] =
2194 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2195 (KEY_F(1) + (i - N_INI)));
2197 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2198 (';' + (i - N_INI)));
2214 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2215 CON.numButtons = (int) num_buttons;
2220 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2221 for (i = 0; i < NUMPAIRS; i++)
2227 b = AttachConsole(ATTACH_PARENT_PROCESS);
2229 CON.inp = GetDirectHandle("CONIN$", FILE_SHARE_READ);
2230 CON.out = GetDirectHandle("CONOUT$", FILE_SHARE_WRITE);
2232 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2233 T(("... will not buffer console"));
2237 T(("... creating console buffer"));
2238 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2239 FILE_SHARE_READ | FILE_SHARE_WRITE,
2241 CONSOLE_TEXTMODE_BUFFER,
2245 if (CON.hdl != INVALID_HANDLE_VALUE) {
2246 CON.buffered = buffered;
2248 CON.save_SBI = CON.SBI;
2250 save_original_screen();
2251 set_scrollback(FALSE, &CON.SBI);
2253 GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
2254 T(("... initial cursor is %svisible, %d%%",
2255 (CON.save_CI.bVisible ? "" : "not-"),
2256 (int) CON.save_CI.dwSize));
2259 console_initialized = TRUE;
2261 return (CON.hdl != INVALID_HANDLE_VALUE);
2265 okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB)
2267 return ((TCB != 0) &&
2268 (TCB->magic == WINMAGIC) &&
2273 * While a constructor would ensure that this module is initialized, that will
2274 * interfere with applications that may combine this with GUI interfaces.
2278 __attribute__((constructor))
2279 void _enter_console(void)
2281 (void) InitConsole();