1 /****************************************************************************
2 * Copyright (c) 1998-2017,2018 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>
52 #define PSAPI_VERSION 2
55 #define CUR TerminalType(my_term).
57 MODULE_ID("$Id: win_driver.c,v 1.61 2018/06/23 21:35:06 tom Exp $")
60 # error We need GCC to compile for MinGW
63 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
65 #define EXP_OPTIMIZE 0
67 #define array_length(a) (sizeof(a)/sizeof(a[0]))
69 static bool InitConsole(void);
70 static bool okConsoleHandle(TERMINAL_CONTROL_BLOCK *);
72 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
73 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
75 #define GenMap(vKey,key) MAKELONG(key, vKey)
77 #define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
80 #define write_screen WriteConsoleOutputW
81 #define read_screen ReadConsoleOutputW
83 #define write_screen WriteConsoleOutput
84 #define read_screen ReadConsoleOutput
87 static const LONG keylist[] =
89 GenMap(VK_PRIOR, KEY_PPAGE),
90 GenMap(VK_NEXT, KEY_NPAGE),
91 GenMap(VK_END, KEY_END),
92 GenMap(VK_HOME, KEY_HOME),
93 GenMap(VK_LEFT, KEY_LEFT),
94 GenMap(VK_UP, KEY_UP),
95 GenMap(VK_RIGHT, KEY_RIGHT),
96 GenMap(VK_DOWN, KEY_DOWN),
97 GenMap(VK_DELETE, KEY_DC),
98 GenMap(VK_INSERT, KEY_IC)
100 static const LONG ansi_keys[] =
102 GenMap(VK_PRIOR, 'I'),
103 GenMap(VK_NEXT, 'Q'),
105 GenMap(VK_HOME, 'H'),
106 GenMap(VK_LEFT, 'K'),
108 GenMap(VK_RIGHT, 'M'),
109 GenMap(VK_DOWN, 'P'),
110 GenMap(VK_DELETE, 'S'),
111 GenMap(VK_INSERT, 'R')
113 #define N_INI ((int)array_length(keylist))
115 #define MAPSIZE (FKEYS + N_INI)
118 /* A process can only have a single console, so it's safe
119 to maintain all the information about it in a single
128 BOOL isTermInfoConsole;
134 DWORD ansi_map[MAPSIZE];
137 WORD pairs[NUMPAIRS];
139 CHAR_INFO *save_screen;
141 SMALL_RECT save_region;
142 CONSOLE_SCREEN_BUFFER_INFO SBI;
143 CONSOLE_SCREEN_BUFFER_INFO save_SBI;
144 CONSOLE_CURSOR_INFO save_CI;
147 static BOOL console_initialized = FALSE;
150 MapColor(bool fore, int color)
152 static const int _cmap[] =
153 {0, 4, 2, 6, 1, 5, 3, 7};
155 if (color < 0 || color > 7)
164 #define RevAttr(attr) \
165 (WORD) (((attr) & 0xff00) | \
166 ((((attr) & 0x07) << 4) | \
167 (((attr) & 0x70) >> 4)))
170 MapAttr(WORD res, attr_t ch)
176 if (p > 0 && p < NUMPAIRS) {
179 res = (WORD) ((res & 0xff00) | a);
183 if (ch & A_REVERSE) {
187 if (ch & A_STANDOUT) {
188 res = RevAttr(res) | BACKGROUND_INTENSITY;
192 res |= FOREGROUND_INTENSITY;
195 res |= BACKGROUND_INTENSITY;
200 #if 0 /* def TRACE */
202 dump_screen(const char *fn, int ln)
204 int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1;
205 char output[max_cells];
206 CHAR_INFO save_screen[max_cells];
208 SMALL_RECT save_region;
211 T(("dump_screen %s@%d", fn, ln));
213 save_region.Top = CON.SBI.srWindow.Top;
214 save_region.Left = CON.SBI.srWindow.Left;
215 save_region.Bottom = CON.SBI.srWindow.Bottom;
216 save_region.Right = CON.SBI.srWindow.Right;
218 save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
219 save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
221 bufferCoord.X = bufferCoord.Y = 0;
223 if (read_screen(CON.hdl,
232 for (i = save_region.Top; i <= save_region.Bottom; ++i) {
233 for (j = save_region.Left; j <= save_region.Right; ++j) {
234 output[k++] = save_screen[ij++].Char.AsciiChar;
240 T(("DUMP: %d,%d - %d,%d",
250 #define dump_screen(fn,ln) /* nothing */
253 #if USE_WIDEC_SUPPORT
255 * TODO: support surrogate pairs
256 * TODO: support combining characters
258 * TODO: _nc_wacs should be part of sp.
261 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
274 for (i = actual = 0; i < limit; i++) {
278 ci[actual].Char.UnicodeChar = CharOf(ch);
279 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
281 if (AttrOf(ch) & A_ALTCHARSET) {
283 int which = CharOf(ch);
286 && CharOf(_nc_wacs[which]) != 0) {
287 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
289 ci[actual].Char.UnicodeChar = ' ';
298 siz.X = (SHORT) actual;
301 rec.Left = (SHORT) x;
302 rec.Top = (SHORT) (y + AdjustY());
303 rec.Right = (SHORT) (x + limit - 1);
304 rec.Bottom = rec.Top;
306 return write_screen(CON.hdl, ci, siz, loc, &rec);
308 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
311 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
323 for (i = 0; i < n; i++) {
325 ci[i].Char.AsciiChar = ChCharOf(ch);
326 ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
328 if (ChAttrOf(ch) & A_ALTCHARSET) {
330 ci[i].Char.AsciiChar =
331 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
340 rec.Left = (short) x;
342 rec.Right = (short) (x + n - 1);
343 rec.Bottom = rec.Top;
345 return write_screen(CON.hdl, ci, siz, loc, &rec);
347 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
352 * Comparing new/current screens, determine the last column-index for a change
353 * beginning on the given row,col position. Unlike a serial terminal, there is
354 * no cost for "moving" the "cursor" on the line as we update it.
357 find_end_of_change(SCREEN *sp, int row, int col)
360 struct ldat *curdat = CurScreen(sp)->_line + row;
361 struct ldat *newdat = NewScreen(sp)->_line + row;
363 while (col <= newdat->lastchar) {
364 #if USE_WIDEC_SUPPORT
365 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
367 } else if (memcmp(&curdat->text[col],
369 sizeof(curdat->text[0]))) {
375 if (curdat->text[col] != newdat->text[col]) {
387 * Given a row,col position at the end of a change-chunk, look for the
388 * beginning of the next change-chunk.
391 find_next_change(SCREEN *sp, int row, int col)
393 struct ldat *curdat = CurScreen(sp)->_line + row;
394 struct ldat *newdat = NewScreen(sp)->_line + row;
395 int result = newdat->lastchar + 1;
397 while (++col <= newdat->lastchar) {
398 #if USE_WIDEC_SUPPORT
399 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
402 } else if (memcmp(&curdat->text[col],
404 sizeof(curdat->text[0]))) {
409 if (curdat->text[col] != newdat->text[col]) {
418 #define EndChange(first) \
419 find_end_of_change(sp, y, first)
420 #define NextChange(last) \
421 find_next_change(sp, y, last)
423 #endif /* EXP_OPTIMIZE */
425 #define MARK_NOCHANGE(win,row) \
426 win->_line[row].firstchar = _NOCHANGE; \
427 win->_line[row].lastchar = _NOCHANGE
430 selectActiveHandle(void)
432 if (CON.lastOut != CON.hdl) {
433 CON.lastOut = CON.hdl;
434 SetConsoleActiveScreenBuffer(CON.lastOut);
439 restore_original_screen(void)
443 SMALL_RECT save_region = CON.save_region;
445 T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
447 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
448 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
450 if (write_screen(CON.hdl,
456 mvcur(-1, -1, LINES - 2, 0);
457 T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
465 T(("... restore original screen contents err"));
471 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
474 return "win32console";
478 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
481 int y, nonempty, n, x0, x1, Width, Height;
484 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
485 if (okConsoleHandle(TCB)) {
488 Width = screen_columns(sp);
489 Height = screen_lines(sp);
490 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
492 T(("... %dx%d clear cur:%d new:%d",
494 CurScreen(sp)->_clear,
495 NewScreen(sp)->_clear));
497 if (SP_PARM->_endwin == ewSuspend) {
499 T(("coming back from shell mode"));
500 NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
502 NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
503 NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
504 SP_PARM->_mouse_resume(SP_PARM);
506 SP_PARM->_endwin = ewRunning;
509 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
511 #if USE_WIDEC_SUPPORT
512 cchar_t empty[Width];
518 for (x = 0; x < Width; x++)
519 setcchar(&empty[x], blank, 0, 0, 0);
523 for (x = 0; x < Width; x++)
527 for (y = 0; y < nonempty; y++) {
528 con_write(TCB, y, 0, empty, Width);
530 CurScreen(sp)->_line[y].text,
531 (size_t) Width * sizeof(empty[0]));
533 CurScreen(sp)->_clear = FALSE;
534 NewScreen(sp)->_clear = FALSE;
535 touchwin(NewScreen(sp));
536 T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
540 for (y = 0; y < nonempty; y++) {
541 x0 = NewScreen(sp)->_line[y].firstchar;
542 if (x0 != _NOCHANGE) {
545 int limit = NewScreen(sp)->_line[y].lastchar;
546 while ((x1 = EndChange(x0)) <= limit) {
547 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
551 memcpy(&CurScreen(sp)->_line[y].text[x0],
552 &NewScreen(sp)->_line[y].text[x0],
553 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
557 &CurScreen(sp)->_line[y].text[x0], n);
561 /* mark line changed successfully */
562 if (y <= NewScreen(sp)->_maxy) {
563 MARK_NOCHANGE(NewScreen(sp), y);
565 if (y <= CurScreen(sp)->_maxy) {
566 MARK_NOCHANGE(CurScreen(sp), y);
569 x1 = NewScreen(sp)->_line[y].lastchar;
572 memcpy(&CurScreen(sp)->_line[y].text[x0],
573 &NewScreen(sp)->_line[y].text[x0],
574 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
578 &CurScreen(sp)->_line[y].text[x0], n);
580 /* mark line changed successfully */
581 if (y <= NewScreen(sp)->_maxy) {
582 MARK_NOCHANGE(NewScreen(sp), y);
584 if (y <= CurScreen(sp)->_maxy) {
585 MARK_NOCHANGE(CurScreen(sp), y);
592 /* put everything back in sync */
593 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
594 MARK_NOCHANGE(NewScreen(sp), y);
596 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
597 MARK_NOCHANGE(CurScreen(sp), y);
600 if (!NewScreen(sp)->_leaveok) {
601 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
602 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
604 TCB->drv->td_hwcur(TCB,
606 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
608 selectActiveHandle();
615 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
617 int *errret GCC_UNUSED)
621 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
623 assert((TCB != 0) && (tname != 0));
625 TCB->magic = WINMAGIC;
627 if (tname == 0 || *tname == 0)
629 else if (tname != 0 && *tname == '#') {
631 * Use "#" (a character which cannot begin a terminal's name) to
632 * select specific driver from the table.
634 * In principle, we could have more than one non-terminfo driver,
637 size_t n = strlen(tname + 1);
639 && ((strncmp(tname + 1, "win32console", n) == 0)
640 || (strncmp(tname + 1, "win32con", n) == 0))) {
643 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
648 * This is intentional, to avoid unnecessary breakage of applications
649 * using <term.h> symbols.
651 if (code && (TerminalType(&TCB->term).Booleans == 0)) {
652 _nc_init_termtype(&TerminalType(&TCB->term));
653 #if NCURSES_EXT_NUMBERS
654 _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
659 if (_nc_mingw_isconsole(0))
660 CON.isTermInfoConsole = TRUE;
666 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
672 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
673 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
674 int max_cells = (high * wide);
677 CHAR_INFO this_screen[max_cells];
678 CHAR_INFO that_screen[max_cells];
680 SMALL_RECT this_region;
683 if (okConsoleHandle(TCB)) {
685 this_region.Top = CON.SBI.srWindow.Top;
686 this_region.Left = CON.SBI.srWindow.Left;
687 this_region.Bottom = CON.SBI.srWindow.Bottom;
688 this_region.Right = CON.SBI.srWindow.Right;
690 this_size.X = (SHORT) wide;
691 this_size.Y = (SHORT) high;
693 bufferCoord.X = this_region.Left;
694 bufferCoord.Y = this_region.Top;
703 memcpy(that_screen, this_screen, sizeof(that_screen));
705 for (i = 0; i < max_cells; i++) {
706 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
709 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
711 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
714 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */
722 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
723 char *data GCC_UNUSED,
735 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
752 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
753 T(("GetConsoleScreenBufferInfo"));
754 T(("... buffer(X:%d Y:%d)",
757 T(("... window(X:%d Y:%d)",
758 CON.SBI.dwMaximumWindowSize.X,
759 CON.SBI.dwMaximumWindowSize.Y));
760 T(("... cursor(X:%d Y:%d)",
761 CON.SBI.dwCursorPosition.X,
762 CON.SBI.dwCursorPosition.Y));
763 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
764 CON.SBI.srWindow.Top,
765 CON.SBI.srWindow.Bottom,
766 CON.SBI.srWindow.Left,
767 CON.SBI.srWindow.Right));
772 CON.origin.X = CON.SBI.srWindow.Left;
773 CON.origin.Y = CON.SBI.srWindow.Top;
777 T(("GetConsoleScreenBufferInfo ERR"));
783 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
786 int (*outc) (SCREEN *, int) GCC_UNUSED)
788 if (okConsoleHandle(TCB)) {
789 WORD a = MapColor(fore, color);
790 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
791 SetConsoleTextAttribute(CON.hdl, a);
797 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
801 if (okConsoleHandle(TCB)) {
802 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
803 SetConsoleTextAttribute(CON.hdl, a);
811 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
823 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
827 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
829 if (okConsoleHandle(TCB) &&
833 *Lines = (int) (CON.SBI.dwSize.Y);
834 *Cols = (int) (CON.SBI.dwSize.X);
836 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
837 CON.SBI.srWindow.Top);
838 *Cols = (int) (CON.SBI.srWindow.Right + 1 -
839 CON.SBI.srWindow.Left);
847 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
856 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
863 if (buf != NULL && okConsoleHandle(TCB)) {
866 iflag = buf->c_iflag;
867 lflag = buf->c_lflag;
869 GetConsoleMode(CON.inp, &dwFlag);
872 dwFlag |= ENABLE_LINE_INPUT;
874 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
877 dwFlag |= ENABLE_ECHO_INPUT;
879 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
882 dwFlag |= ENABLE_PROCESSED_INPUT;
884 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
886 dwFlag |= ENABLE_MOUSE_INPUT;
888 buf->c_iflag = iflag;
889 buf->c_lflag = lflag;
890 SetConsoleMode(CON.inp, dwFlag);
891 TCB->term.Nttyb = *buf;
893 iflag = TCB->term.Nttyb.c_iflag;
894 lflag = TCB->term.Nttyb.c_lflag;
895 GetConsoleMode(CON.inp, &dwFlag);
897 if (dwFlag & ENABLE_LINE_INPUT)
900 lflag &= (tcflag_t) (~ICANON);
902 if (dwFlag & ENABLE_ECHO_INPUT)
905 lflag &= (tcflag_t) (~ECHO);
907 if (dwFlag & ENABLE_PROCESSED_INPUT)
910 iflag &= (tcflag_t) (~BRKINT);
912 TCB->term.Nttyb.c_iflag = iflag;
913 TCB->term.Nttyb.c_lflag = lflag;
915 *buf = TCB->term.Nttyb;
926 * In "normal" mode, reset the buffer- and window-sizes back to their original values.
929 set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
933 bool changed = FALSE;
935 T((T_CALLED("win32con::set_scrollback(%s)"),
940 T(("... SBI.srWindow %d,%d .. %d,%d",
943 info->srWindow.Bottom,
944 info->srWindow.Right));
945 T(("... SBI.dwSize %dx%d",
950 rect = info->srWindow;
951 coord = info->dwSize;
952 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
957 int high = info->srWindow.Bottom - info->srWindow.Top + 1;
958 int wide = info->srWindow.Right - info->srWindow.Left + 1;
960 if (high < MIN_HIGH) {
961 T(("... height %d < %d", high, MIN_HIGH));
965 if (wide < MIN_WIDE) {
966 T(("... width %d < %d", wide, MIN_WIDE));
973 rect.Right = (SHORT) (wide - 1);
974 rect.Bottom = (SHORT) (high - 1);
976 coord.X = (SHORT) wide;
977 coord.Y = (SHORT) high;
979 if (info->dwSize.Y != high ||
980 info->dwSize.X != wide ||
981 info->srWindow.Top != 0 ||
982 info->srWindow.Left != 0) {
989 T(("... coord %d,%d", coord.Y, coord.X));
990 T(("... rect %d,%d - %d,%d",
992 rect.Bottom, rect.Right));
993 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */
994 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */
1001 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
1004 TERMINAL *_term = (TERMINAL *) TCB;
1007 if (okConsoleHandle(TCB)) {
1010 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"),
1011 TCB, progFlag, defFlag));
1013 CON.progMode = progFlag;
1014 CON.lastOut = progFlag ? CON.hdl : CON.out;
1015 SetConsoleActiveScreenBuffer(CON.lastOut);
1017 if (progFlag) /* prog mode */ {
1019 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
1020 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
1024 /* reset_prog_mode */
1025 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
1028 _nc_keypad(sp, TRUE);
1030 if (!CON.buffered) {
1031 set_scrollback(FALSE, &CON.SBI);
1036 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
1037 } else { /* shell mode */
1039 /* def_shell_mode */
1040 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
1044 /* reset_shell_mode */
1046 _nc_keypad(sp, FALSE);
1047 NCURSES_SP_NAME(_nc_flush) (sp);
1049 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
1050 if (!CON.buffered) {
1051 set_scrollback(TRUE, &CON.save_SBI);
1052 if (!restore_original_screen())
1055 SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
1064 wcon_screen_init(SCREEN *sp GCC_UNUSED)
1069 wcon_wrap(SCREEN *sp GCC_UNUSED)
1074 rkeycompare(const void *el1, const void *el2)
1076 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
1077 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
1079 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1083 keycompare(const void *el1, const void *el2)
1085 WORD key1 = HIWORD((*((const LONG *) el1)));
1086 WORD key2 = HIWORD((*((const LONG *) el2)));
1088 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1096 LONG key = GenMap(vKey, 0);
1101 (size_t) (N_INI + FKEYS),
1105 key = *((LONG *) res);
1107 code = (int) (nKey & 0x7fff);
1119 LONG key = GenMap(vKey, 0);
1124 (size_t) (N_INI + FKEYS),
1128 key = *((LONG *) res);
1130 code = (int) (nKey & 0x7fff);
1138 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
1140 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
1150 read_screen_data(void)
1152 bool result = FALSE;
1156 CON.save_size.X = (SHORT) (CON.save_region.Right
1157 - CON.save_region.Left + 1);
1158 CON.save_size.Y = (SHORT) (CON.save_region.Bottom
1159 - CON.save_region.Top + 1);
1161 want = (size_t) (CON.save_size.X * CON.save_size.Y);
1163 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1164 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
1165 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
1167 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
1168 CON.window_only ? "window" : "buffer",
1169 CON.save_size.Y, CON.save_size.X,
1170 CON.save_region.Top,
1171 CON.save_region.Left,
1172 CON.save_region.Bottom,
1173 CON.save_region.Right,
1177 if (read_screen(CON.hdl,
1181 &CON.save_region)) {
1184 T((" error %#lx", (unsigned long) GetLastError()));
1185 FreeAndNull(CON.save_screen);
1193 * Attempt to save the screen contents. PDCurses does this if
1194 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
1195 * restoration as if the library had allocated a console buffer. MSDN
1196 * says that the data which can be read is limited to 64Kb (and may be
1200 save_original_screen(void)
1202 bool result = FALSE;
1204 CON.save_region.Top = 0;
1205 CON.save_region.Left = 0;
1206 CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
1207 CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
1209 if (read_screen_data()) {
1213 CON.save_region.Top = CON.SBI.srWindow.Top;
1214 CON.save_region.Left = CON.SBI.srWindow.Left;
1215 CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
1216 CON.save_region.Right = CON.SBI.srWindow.Right;
1218 CON.window_only = TRUE;
1220 if (read_screen_data()) {
1225 T(("... save original screen contents %s", result ? "ok" : "err"));
1230 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1232 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1237 if (!InitConsole()) {
1241 TCB->info.initcolor = TRUE;
1242 TCB->info.canchange = FALSE;
1243 TCB->info.hascolor = TRUE;
1244 TCB->info.caninit = TRUE;
1246 TCB->info.maxpairs = NUMPAIRS;
1247 TCB->info.maxcolors = 8;
1248 TCB->info.numlabels = 0;
1249 TCB->info.labelwidth = 0;
1250 TCB->info.labelheight = 0;
1251 TCB->info.nocolorvideo = 1;
1252 TCB->info.tabsize = 8;
1254 TCB->info.numbuttons = CON.numButtons;
1255 TCB->info.defaultPalette = _nc_cga_palette;
1262 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1269 if (okConsoleHandle(TCB)) {
1272 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1273 && (b >= 0) && (b < 8)) {
1274 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
1280 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1281 int color GCC_UNUSED,
1293 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1294 int old_pair GCC_UNUSED,
1295 int pair GCC_UNUSED,
1296 int reverse GCC_UNUSED,
1297 int (*outc) (SCREEN *, int) GCC_UNUSED
1307 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1311 if (okConsoleHandle(TCB)) {
1314 sp->_mouse_type = M_TERM_DRIVER;
1319 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
1321 EVENTLIST_2nd(_nc_eventlist * evl))
1326 if (okConsoleHandle(TCB)) {
1329 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1332 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1336 EVENTLIST_2nd(evl));
1344 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1345 int yold GCC_UNUSED, int xold GCC_UNUSED,
1349 if (okConsoleHandle(TCB)) {
1352 loc.Y = (short) (y + AdjustY());
1353 SetConsoleCursorPosition(CON.hdl, loc);
1360 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1361 int labnum GCC_UNUSED,
1362 char *text GCC_UNUSED)
1371 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1372 int OnFlag GCC_UNUSED)
1381 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1383 chtype res = A_NORMAL;
1384 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1389 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1398 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1399 chtype *real_map GCC_UNUSED,
1400 chtype *fake_map GCC_UNUSED)
1402 #define DATA(a,b) { a, b }
1407 DATA('a', 0xb1), /* ACS_CKBOARD */
1408 DATA('f', 0xf8), /* ACS_DEGREE */
1409 DATA('g', 0xf1), /* ACS_PLMINUS */
1410 DATA('j', 0xd9), /* ACS_LRCORNER */
1411 DATA('l', 0xda), /* ACS_ULCORNER */
1412 DATA('k', 0xbf), /* ACS_URCORNER */
1413 DATA('m', 0xc0), /* ACS_LLCORNER */
1414 DATA('n', 0xc5), /* ACS_PLUS */
1415 DATA('q', 0xc4), /* ACS_HLINE */
1416 DATA('t', 0xc3), /* ACS_LTEE */
1417 DATA('u', 0xb4), /* ACS_RTEE */
1418 DATA('v', 0xc1), /* ACS_BTEE */
1419 DATA('w', 0xc2), /* ACS_TTEE */
1420 DATA('x', 0xb3), /* ACS_VLINE */
1421 DATA('y', 0xf3), /* ACS_LEQUAL */
1422 DATA('z', 0xf2), /* ACS_GEQUAL */
1423 DATA('0', 0xdb), /* ACS_BLOCK */
1424 DATA('{', 0xe3), /* ACS_PI */
1425 DATA('}', 0x9c), /* ACS_STERLING */
1426 DATA(',', 0xae), /* ACS_LARROW */
1427 DATA('+', 0xaf), /* ACS_RARROW */
1428 DATA('~', 0xf9), /* ACS_BULLET */
1434 if (okConsoleHandle(TCB)) {
1437 for (n = 0; n < SIZEOF(table); ++n) {
1438 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1440 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1446 tdiff(FILETIME fstart, FILETIME fend)
1448 ULARGE_INTEGER ustart;
1449 ULARGE_INTEGER uend;
1452 ustart.LowPart = fstart.dwLowDateTime;
1453 ustart.HighPart = fstart.dwHighDateTime;
1454 uend.LowPart = fend.dwLowDateTime;
1455 uend.HighPart = fend.dwHighDateTime;
1457 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1462 Adjust(int milliseconds, int diff)
1464 if (milliseconds != INFINITY) {
1465 milliseconds -= diff;
1466 if (milliseconds < 0)
1469 return milliseconds;
1472 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1473 FROM_LEFT_2ND_BUTTON_PRESSED | \
1474 FROM_LEFT_3RD_BUTTON_PRESSED | \
1475 FROM_LEFT_4TH_BUTTON_PRESSED | \
1476 RIGHTMOST_BUTTON_PRESSED)
1479 decode_mouse(SCREEN *sp, int mask)
1484 assert(sp && console_initialized);
1486 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1487 result |= BUTTON1_PRESSED;
1488 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1489 result |= BUTTON2_PRESSED;
1490 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1491 result |= BUTTON3_PRESSED;
1492 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1493 result |= BUTTON4_PRESSED;
1495 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1496 switch (CON.numButtons) {
1498 result |= BUTTON1_PRESSED;
1501 result |= BUTTON2_PRESSED;
1504 result |= BUTTON3_PRESSED;
1507 result |= BUTTON4_PRESSED;
1522 EVENTLIST_2nd(_nc_eventlist * evl))
1524 INPUT_RECORD inp_rec;
1526 DWORD nRead = 0, rc = (DWORD) (-1);
1531 bool isImmed = (milliseconds == 0);
1533 #ifdef NCURSES_WGETCH_EVENTS
1534 (void) evl; /* TODO: implement wgetch-events */
1537 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1541 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1542 milliseconds, mode));
1544 if (milliseconds < 0)
1545 milliseconds = INFINITY;
1547 memset(&inp_rec, 0, sizeof(inp_rec));
1550 GetSystemTimeAsFileTime(&fstart);
1551 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1552 GetSystemTimeAsFileTime(&fend);
1553 diff = (int) tdiff(fstart, fend);
1554 milliseconds = Adjust(milliseconds, diff);
1556 if (!isImmed && milliseconds <= 0)
1559 if (rc == WAIT_OBJECT_0) {
1561 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1562 if (b && nRead > 0) {
1563 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1564 if (b && nRead > 0) {
1565 switch (inp_rec.EventType) {
1567 if (mode & TW_INPUT) {
1568 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1569 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1571 if (inp_rec.Event.KeyEvent.bKeyDown) {
1573 int nKey = MapKey(vk);
1587 if (decode_mouse(sp,
1588 (inp_rec.Event.MouseEvent.dwButtonState
1589 & BUTTON_MASK)) == 0) {
1591 } else if (mode & TW_MOUSE) {
1596 /* e.g., FOCUS_EVENT */
1599 selectActiveHandle();
1607 if (rc != WAIT_TIMEOUT) {
1618 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1619 code, errno, milliseconds));
1622 *timeleft = milliseconds;
1628 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1632 EVENTLIST_2nd(_nc_eventlist * evl))
1637 if (okConsoleHandle(TCB)) {
1640 code = console_twait(sp,
1644 timeleft EVENTLIST_2nd(evl));
1650 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1653 bool result = FALSE;
1657 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1658 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1661 * We're only interested if the button is pressed or released.
1662 * FIXME: implement continuous event-tracking.
1664 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1666 memset(&work, 0, sizeof(work));
1668 if (sp->_drv_mouse_new_buttons) {
1670 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1674 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1675 work.bstate |= (mmask_t) (decode_mouse(sp,
1676 sp->_drv_mouse_old_buttons)
1682 work.x = mer.dwMousePosition.X;
1683 work.y = mer.dwMousePosition.Y - AdjustY();
1685 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1686 sp->_drv_mouse_tail += 1;
1693 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1698 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1701 if (okConsoleHandle(TCB)) {
1704 n = _nc_mingw_console_read(sp, CON.inp, buf);
1710 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1712 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1718 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1722 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1723 if (okConsoleHandle(TCB)) {
1724 CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1727 this_CI.bVisible = FALSE;
1732 this_CI.dwSize = 100;
1735 SetConsoleCursorInfo(CON.hdl, &this_CI);
1741 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1746 LONG key = GenMap(0, (WORD) keycode);
1748 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1751 (size_t) (N_INI + FKEYS),
1755 key = *((LONG *) res);
1757 if (!(nKey & 0x8000))
1764 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1769 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1771 if (okConsoleHandle(TCB)) {
1782 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1791 LONG key = GenMap(0, (WORD) keycode);
1793 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1795 if (okConsoleHandle(TCB)) {
1801 (size_t) (N_INI + FKEYS),
1805 key = *((LONG *) res);
1807 nKey = (LOWORD(key)) & 0x7fff;
1810 *(LONG *) res = GenMap(vKey, nKey);
1817 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1819 wcon_name, /* Name */
1820 wcon_CanHandle, /* CanHandle */
1821 wcon_init, /* init */
1822 wcon_release, /* release */
1823 wcon_size, /* size */
1824 wcon_sgmode, /* sgmode */
1825 wcon_conattr, /* conattr */
1826 wcon_mvcur, /* hwcur */
1827 wcon_mode, /* mode */
1828 wcon_rescol, /* rescol */
1829 wcon_rescolors, /* rescolors */
1830 wcon_setcolor, /* color */
1831 wcon_dobeepflash, /* DoBeepFlash */
1832 wcon_initpair, /* initpair */
1833 wcon_initcolor, /* initcolor */
1834 wcon_do_color, /* docolor */
1835 wcon_initmouse, /* initmouse */
1836 wcon_testmouse, /* testmouse */
1837 wcon_setfilter, /* setfilter */
1838 wcon_hwlabel, /* hwlabel */
1839 wcon_hwlabelOnOff, /* hwlabelOnOff */
1840 wcon_doupdate, /* update */
1841 wcon_defaultcolors, /* defaultcolors */
1842 wcon_print, /* print */
1843 wcon_size, /* getsize */
1844 wcon_setsize, /* setsize */
1845 wcon_initacs, /* initacs */
1846 wcon_screen_init, /* scinit */
1847 wcon_wrap, /* scexit */
1848 wcon_twait, /* twait */
1849 wcon_read, /* read */
1851 wcon_kpad, /* kpad */
1852 wcon_keyok, /* kyOk */
1853 wcon_kyExist, /* kyExist */
1854 wcon_cursorSet /* cursorSet */
1857 /* --------------------------------------------------------- */
1862 intptr_t value = _get_osfhandle(fd);
1863 return (HANDLE) value;
1866 #if WINVER >= 0x0600
1867 /* This function tests, whether or not the ncurses application
1868 is running as a descendant of MSYS2/cygwin mintty terminal
1869 application. mintty doesn't use Windows Console for it's screen
1870 I/O, so the native Windows _isatty doesn't recognize it as
1871 character device. But we can discover we are at the end of an
1872 Pipe and can query to server side of the pipe, looking whether
1873 or not this is mintty.
1876 _ismintty(int fd, LPHANDLE pMinTTY)
1878 HANDLE handle = get_handle(fd);
1882 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1884 if (handle != INVALID_HANDLE_VALUE) {
1885 dw = GetFileType(handle);
1886 if (dw == FILE_TYPE_PIPE) {
1887 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1890 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1891 TCHAR buf[MAX_PATH];
1893 /* These security attributes may allow us to
1894 create a remote thread in mintty to manipulate
1895 the terminal state remotely */
1896 HANDLE pHandle = OpenProcess(
1897 PROCESS_CREATE_THREAD
1898 | PROCESS_QUERY_INFORMATION
1899 | PROCESS_VM_OPERATION
1905 *pMinTTY = INVALID_HANDLE_VALUE;
1906 if (pHandle != INVALID_HANDLE_VALUE) {
1907 if ((len = GetProcessImageFileName(
1911 array_length(buf)))) {
1912 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1915 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1932 /* Borrowed from ansicon project.
1933 Check whether or not an I/O handle is associated with
1937 IsConsoleHandle(HANDLE hdl)
1942 if (!GetConsoleMode(hdl, &dwFlag)) {
1943 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1945 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1950 /* Our replacement for the systems _isatty to include also
1951 a test for mintty. This is called from the NC_ISATTY macro
1952 defined in curses.priv.h
1955 _nc_mingw_isatty(int fd)
1960 #define SysISATTY(fd) _isatty(fd)
1962 #define SysISATTY(fd) isatty(fd)
1964 if (SysISATTY(fd)) {
1967 #if WINVER >= 0x0600
1968 result = _ismintty(fd, NULL);
1974 /* This is used when running in terminfo mode to discover,
1975 whether or not the "terminal" is actually a Windows
1976 Console. It's the responsibilty of the console to deal
1977 with the terminal escape sequences that are sent by
1981 _nc_mingw_isconsole(int fd)
1983 HANDLE hdl = get_handle(fd);
1986 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1988 code = (int) IsConsoleHandle(hdl);
1993 #define TC_PROLOGUE(fd) \
1995 TERMINAL *term = 0; \
1997 if (_nc_screen_chain == 0) \
1999 for (each_screen(sp)) { \
2000 if (sp->_term && (sp->_term->Filedes == fd)) { \
2008 _nc_mingw_tcsetattr(
2010 int optional_action GCC_UNUSED,
2011 const struct termios *arg)
2015 if (_nc_mingw_isconsole(fd)) {
2017 HANDLE ofd = get_handle(fd);
2018 if (ofd != INVALID_HANDLE_VALUE) {
2020 if (arg->c_lflag & ICANON)
2021 dwFlag |= ENABLE_LINE_INPUT;
2023 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
2025 if (arg->c_lflag & ECHO)
2026 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
2028 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
2030 if (arg->c_iflag & BRKINT)
2031 dwFlag |= ENABLE_PROCESSED_INPUT;
2033 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
2035 dwFlag |= ENABLE_MOUSE_INPUT;
2036 SetConsoleMode(ofd, dwFlag);
2047 _nc_mingw_tcgetattr(int fd, struct termios *arg)
2051 if (_nc_mingw_isconsole(fd)) {
2059 _nc_mingw_tcflush(int fd, int queue)
2064 if (_nc_mingw_isconsole(fd)) {
2065 if (queue == TCIFLUSH) {
2066 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2068 return (int) GetLastError();
2075 _nc_mingw_testmouse(
2079 EVENTLIST_2nd(_nc_eventlist * evl))
2085 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2088 rc = console_twait(sp,
2093 EVENTLIST_2nd(evl));
2099 _nc_mingw_console_read(
2105 INPUT_RECORD inp_rec;
2113 memset(&inp_rec, 0, sizeof(inp_rec));
2115 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2117 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2118 if (b && nRead > 0) {
2121 rc = rc + (int) nRead;
2122 if (inp_rec.EventType == KEY_EVENT) {
2123 if (!inp_rec.Event.KeyEvent.bKeyDown)
2125 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2126 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2128 * There are 24 virtual function-keys, and typically
2129 * 12 function-keys on a keyboard. Use the shift-modifier
2130 * to provide the remaining 12 keys.
2132 if (vk >= VK_F1 && vk <= VK_F12) {
2133 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
2134 vk = (WORD) (vk + 12);
2138 int key = MapKey(vk);
2141 if (sp->_keypad_on) {
2149 } else if (inp_rec.EventType == MOUSE_EVENT) {
2150 if (handle_mouse(sp,
2151 inp_rec.Event.MouseEvent)) {
2165 /* initalize once, or not at all */
2166 if (!console_initialized) {
2170 BOOL buffered = TRUE;
2174 if (_nc_mingw_isatty(0)) {
2175 CON.isMinTTY = TRUE;
2178 for (i = 0; i < (N_INI + FKEYS); i++) {
2180 CON.rmap[i] = CON.map[i] =
2182 CON.ansi_map[i] = (DWORD) ansi_keys[i];
2184 CON.rmap[i] = CON.map[i] =
2185 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2186 (KEY_F(1) + (i - N_INI)));
2188 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2189 (';' + (i - N_INI)));
2205 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2206 CON.numButtons = (int) num_buttons;
2211 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2212 for (i = 0; i < NUMPAIRS; i++)
2215 CON.inp = GetStdHandle(STD_INPUT_HANDLE);
2216 CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
2221 b = AttachConsole(ATTACH_PARENT_PROCESS);
2223 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2224 T(("... will not buffer console"));
2228 T(("... creating console buffer"));
2229 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2232 CONSOLE_TEXTMODE_BUFFER,
2236 if (CON.hdl != INVALID_HANDLE_VALUE) {
2237 CON.buffered = buffered;
2239 CON.save_SBI = CON.SBI;
2241 save_original_screen();
2242 set_scrollback(FALSE, &CON.SBI);
2244 GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
2245 T(("... initial cursor is %svisible, %d%%",
2246 (CON.save_CI.bVisible ? "" : "not-"),
2247 (int) CON.save_CI.dwSize));
2250 console_initialized = TRUE;
2252 return (CON.hdl != INVALID_HANDLE_VALUE);
2256 okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB)
2258 return ((TCB != 0) &&
2259 (TCB->magic == WINMAGIC) &&
2264 * While a constructor would ensure that this module is initialized, that will
2265 * interfere with applications that may combine this with GUI interfaces.
2269 __attribute__((constructor))
2270 void _enter_console(void)
2272 (void) InitConsole();