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.73 2023/08/05 19:02:24 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
129 BOOL isTermInfoConsole;
135 DWORD ansi_map[MAPSIZE];
138 WORD pairs[NUMPAIRS];
140 CHAR_INFO *save_screen;
142 SMALL_RECT save_region;
143 CONSOLE_SCREEN_BUFFER_INFO SBI;
144 CONSOLE_SCREEN_BUFFER_INFO save_SBI;
145 CONSOLE_CURSOR_INFO save_CI;
148 static BOOL console_initialized = FALSE;
151 MapColor(bool fore, int color)
153 static const int _cmap[] =
154 {0, 4, 2, 6, 1, 5, 3, 7};
156 if (color < 0 || color > 7)
165 #define RevAttr(attr) \
166 (WORD) (((attr) & 0xff00) | \
167 ((((attr) & 0x07) << 4) | \
168 (((attr) & 0x70) >> 4)))
171 MapAttr(WORD res, attr_t ch)
177 if (p > 0 && p < NUMPAIRS) {
180 res = (WORD) ((res & 0xff00) | a);
184 if (ch & A_REVERSE) {
188 if (ch & A_STANDOUT) {
189 res = RevAttr(res) | BACKGROUND_INTENSITY;
193 res |= FOREGROUND_INTENSITY;
196 res |= BACKGROUND_INTENSITY;
201 #if 0 /* def TRACE */
203 dump_screen(const char *fn, int ln)
205 int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1;
206 char output[max_cells];
207 CHAR_INFO save_screen[max_cells];
209 SMALL_RECT save_region;
212 T(("dump_screen %s@%d", fn, ln));
214 save_region.Top = CON.SBI.srWindow.Top;
215 save_region.Left = CON.SBI.srWindow.Left;
216 save_region.Bottom = CON.SBI.srWindow.Bottom;
217 save_region.Right = CON.SBI.srWindow.Right;
219 save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
220 save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
222 bufferCoord.X = bufferCoord.Y = 0;
224 if (read_screen(CON.hdl,
233 for (i = save_region.Top; i <= save_region.Bottom; ++i) {
234 for (j = save_region.Left; j <= save_region.Right; ++j) {
235 output[k++] = save_screen[ij++].Char.AsciiChar;
241 T(("DUMP: %d,%d - %d,%d",
251 #define dump_screen(fn,ln) /* nothing */
254 #if USE_WIDEC_SUPPORT
256 * TODO: support surrogate pairs
257 * TODO: support combining characters
259 * TODO: _nc_wacs should be part of sp.
262 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
265 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, limit);
275 for (i = actual = 0; i < limit; i++) {
279 ci[actual].Char.UnicodeChar = CharOf(ch);
280 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
282 if (AttrOf(ch) & A_ALTCHARSET) {
284 int which = CharOf(ch);
287 && CharOf(_nc_wacs[which]) != 0) {
288 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
290 ci[actual].Char.UnicodeChar = ' ';
299 siz.X = (SHORT) actual;
302 rec.Left = (SHORT) x;
303 rec.Top = (SHORT) (y + AdjustY());
304 rec.Right = (SHORT) (x + limit - 1);
305 rec.Bottom = rec.Top;
307 return write_screen(CON.hdl, ci, siz, loc, &rec);
309 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
312 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
314 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, n);
324 for (i = 0; i < n; i++) {
326 ci[i].Char.AsciiChar = ChCharOf(ch);
327 ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
329 if (ChAttrOf(ch) & A_ALTCHARSET) {
331 ci[i].Char.AsciiChar =
332 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
341 rec.Left = (short) x;
343 rec.Right = (short) (x + n - 1);
344 rec.Bottom = rec.Top;
346 return write_screen(CON.hdl, ci, siz, loc, &rec);
348 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
353 * Comparing new/current screens, determine the last column-index for a change
354 * beginning on the given row,col position. Unlike a serial terminal, there is
355 * no cost for "moving" the "cursor" on the line as we update it.
358 find_end_of_change(SCREEN *sp, int row, int col)
361 struct ldat *curdat = CurScreen(sp)->_line + row;
362 struct ldat *newdat = NewScreen(sp)->_line + row;
364 while (col <= newdat->lastchar) {
365 #if USE_WIDEC_SUPPORT
366 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
368 } else if (memcmp(&curdat->text[col],
370 sizeof(curdat->text[0]))) {
376 if (curdat->text[col] != newdat->text[col]) {
388 * Given a row,col position at the end of a change-chunk, look for the
389 * beginning of the next change-chunk.
392 find_next_change(SCREEN *sp, int row, int col)
394 struct ldat *curdat = CurScreen(sp)->_line + row;
395 struct ldat *newdat = NewScreen(sp)->_line + row;
396 int result = newdat->lastchar + 1;
398 while (++col <= newdat->lastchar) {
399 #if USE_WIDEC_SUPPORT
400 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
403 } else if (memcmp(&curdat->text[col],
405 sizeof(curdat->text[0]))) {
410 if (curdat->text[col] != newdat->text[col]) {
419 #define EndChange(first) \
420 find_end_of_change(sp, y, first)
421 #define NextChange(last) \
422 find_next_change(sp, y, last)
424 #endif /* EXP_OPTIMIZE */
426 #define MARK_NOCHANGE(win,row) \
427 win->_line[row].firstchar = _NOCHANGE; \
428 win->_line[row].lastchar = _NOCHANGE
431 selectActiveHandle(void)
433 if (CON.lastOut != CON.hdl) {
434 CON.lastOut = CON.hdl;
435 SetConsoleActiveScreenBuffer(CON.lastOut);
440 restore_original_screen(void)
444 SMALL_RECT save_region = CON.save_region;
446 T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
448 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
449 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
451 if (write_screen(CON.hdl,
457 mvcur(-1, -1, LINES - 2, 0);
458 T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
466 T(("... restore original screen contents err"));
472 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
475 return "win32console";
479 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
482 int y, nonempty, n, x0, x1, Width, Height;
485 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
486 if (okConsoleHandle(TCB)) {
489 Width = screen_columns(sp);
490 Height = screen_lines(sp);
491 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
493 T(("... %dx%d clear cur:%d new:%d",
495 CurScreen(sp)->_clear,
496 NewScreen(sp)->_clear));
498 if (SP_PARM->_endwin == ewSuspend) {
500 T(("coming back from shell mode"));
501 NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
503 NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
504 NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
505 SP_PARM->_mouse_resume(SP_PARM);
507 SP_PARM->_endwin = ewRunning;
510 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
512 #if USE_WIDEC_SUPPORT
513 cchar_t *empty = TypeAlloca(cchar_t, Width);
519 for (x = 0; x < Width; x++)
520 setcchar(&empty[x], blank, 0, 0, 0);
522 chtype *empty = TypeAlloca(chtype, Width);
524 for (x = 0; x < Width; x++)
528 for (y = 0; y < nonempty; y++) {
529 con_write(TCB, y, 0, empty, Width);
531 CurScreen(sp)->_line[y].text,
532 (size_t) Width * sizeof(empty[0]));
534 CurScreen(sp)->_clear = FALSE;
535 NewScreen(sp)->_clear = FALSE;
536 touchwin(NewScreen(sp));
537 T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
541 for (y = 0; y < nonempty; y++) {
542 x0 = NewScreen(sp)->_line[y].firstchar;
543 if (x0 != _NOCHANGE) {
546 int limit = NewScreen(sp)->_line[y].lastchar;
547 while ((x1 = EndChange(x0)) <= limit) {
548 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
552 memcpy(&CurScreen(sp)->_line[y].text[x0],
553 &NewScreen(sp)->_line[y].text[x0],
554 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
558 &CurScreen(sp)->_line[y].text[x0], n);
562 /* mark line changed successfully */
563 if (y <= NewScreen(sp)->_maxy) {
564 MARK_NOCHANGE(NewScreen(sp), y);
566 if (y <= CurScreen(sp)->_maxy) {
567 MARK_NOCHANGE(CurScreen(sp), y);
570 x1 = NewScreen(sp)->_line[y].lastchar;
573 memcpy(&CurScreen(sp)->_line[y].text[x0],
574 &NewScreen(sp)->_line[y].text[x0],
575 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
579 &CurScreen(sp)->_line[y].text[x0], n);
581 /* mark line changed successfully */
582 if (y <= NewScreen(sp)->_maxy) {
583 MARK_NOCHANGE(NewScreen(sp), y);
585 if (y <= CurScreen(sp)->_maxy) {
586 MARK_NOCHANGE(CurScreen(sp), y);
593 /* put everything back in sync */
594 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
595 MARK_NOCHANGE(NewScreen(sp), y);
597 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
598 MARK_NOCHANGE(CurScreen(sp), y);
601 if (!NewScreen(sp)->_leaveok) {
602 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
603 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
605 TCB->drv->td_hwcur(TCB,
607 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
609 selectActiveHandle();
616 #define SysISATTY(fd) _isatty(fd)
618 #define SysISATTY(fd) isatty(fd)
622 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
624 int *errret GCC_UNUSED)
628 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
630 assert((TCB != 0) && (tname != 0));
632 TCB->magic = WINMAGIC;
634 if (tname == 0 || *tname == 0)
636 else if (tname != 0 && *tname == '#') {
638 * Use "#" (a character which cannot begin a terminal's name) to
639 * select specific driver from the table.
641 * In principle, we could have more than one non-terminfo driver,
644 size_t n = strlen(tname + 1);
646 && ((strncmp(tname + 1, "win32console", n) == 0)
647 || (strncmp(tname + 1, "win32con", n) == 0))) {
650 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
652 } else if (SysISATTY(TCB->term.Filedes)) {
657 * This is intentional, to avoid unnecessary breakage of applications
658 * using <term.h> symbols.
660 if (code && (TerminalType(&TCB->term).Booleans == 0)) {
661 _nc_init_termtype(&TerminalType(&TCB->term));
662 #if NCURSES_EXT_NUMBERS
663 _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
668 if (_nc_mingw_isconsole(0))
669 CON.isTermInfoConsole = TRUE;
675 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
681 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
682 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
683 int max_cells = (high * wide);
686 CHAR_INFO *this_screen = TypeAlloca(CHAR_INFO, max_cells);
687 CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells);
689 SMALL_RECT this_region;
692 if (okConsoleHandle(TCB)) {
694 this_region.Top = CON.SBI.srWindow.Top;
695 this_region.Left = CON.SBI.srWindow.Left;
696 this_region.Bottom = CON.SBI.srWindow.Bottom;
697 this_region.Right = CON.SBI.srWindow.Right;
699 this_size.X = (SHORT) wide;
700 this_size.Y = (SHORT) high;
702 bufferCoord.X = this_region.Left;
703 bufferCoord.Y = this_region.Top;
714 sizeof(CHAR_INFO) * (size_t) max_cells);
716 for (i = 0; i < max_cells; i++) {
717 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
720 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
722 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
725 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */
733 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
734 char *data GCC_UNUSED,
746 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
763 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
764 T(("GetConsoleScreenBufferInfo"));
765 T(("... buffer(X:%d Y:%d)",
768 T(("... window(X:%d Y:%d)",
769 CON.SBI.dwMaximumWindowSize.X,
770 CON.SBI.dwMaximumWindowSize.Y));
771 T(("... cursor(X:%d Y:%d)",
772 CON.SBI.dwCursorPosition.X,
773 CON.SBI.dwCursorPosition.Y));
774 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
775 CON.SBI.srWindow.Top,
776 CON.SBI.srWindow.Bottom,
777 CON.SBI.srWindow.Left,
778 CON.SBI.srWindow.Right));
783 CON.origin.X = CON.SBI.srWindow.Left;
784 CON.origin.Y = CON.SBI.srWindow.Top;
788 T(("GetConsoleScreenBufferInfo ERR"));
794 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
797 int (*outc) (SCREEN *, int) GCC_UNUSED)
799 if (okConsoleHandle(TCB)) {
800 WORD a = MapColor(fore, color);
801 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
802 SetConsoleTextAttribute(CON.hdl, a);
808 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
812 if (okConsoleHandle(TCB)) {
813 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
814 SetConsoleTextAttribute(CON.hdl, a);
822 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
834 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
838 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
840 if (okConsoleHandle(TCB) &&
844 *Lines = (int) (CON.SBI.dwSize.Y);
845 *Cols = (int) (CON.SBI.dwSize.X);
847 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
848 CON.SBI.srWindow.Top);
849 *Cols = (int) (CON.SBI.srWindow.Right + 1 -
850 CON.SBI.srWindow.Left);
858 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
867 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
874 if (buf != NULL && okConsoleHandle(TCB)) {
877 iflag = buf->c_iflag;
878 lflag = buf->c_lflag;
880 GetConsoleMode(CON.inp, &dwFlag);
883 dwFlag |= ENABLE_LINE_INPUT;
885 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
888 dwFlag |= ENABLE_ECHO_INPUT;
890 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
893 dwFlag |= ENABLE_PROCESSED_INPUT;
895 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
897 dwFlag |= ENABLE_MOUSE_INPUT;
899 buf->c_iflag = iflag;
900 buf->c_lflag = lflag;
901 SetConsoleMode(CON.inp, dwFlag);
902 TCB->term.Nttyb = *buf;
904 iflag = TCB->term.Nttyb.c_iflag;
905 lflag = TCB->term.Nttyb.c_lflag;
906 GetConsoleMode(CON.inp, &dwFlag);
908 if (dwFlag & ENABLE_LINE_INPUT)
911 lflag &= (tcflag_t) (~ICANON);
913 if (dwFlag & ENABLE_ECHO_INPUT)
916 lflag &= (tcflag_t) (~ECHO);
918 if (dwFlag & ENABLE_PROCESSED_INPUT)
921 iflag &= (tcflag_t) (~BRKINT);
923 TCB->term.Nttyb.c_iflag = iflag;
924 TCB->term.Nttyb.c_lflag = lflag;
926 *buf = TCB->term.Nttyb;
937 * In "normal" mode, reset the buffer- and window-sizes back to their original values.
940 set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
944 bool changed = FALSE;
946 T((T_CALLED("win32con::set_scrollback(%s)"),
951 T(("... SBI.srWindow %d,%d .. %d,%d",
954 info->srWindow.Bottom,
955 info->srWindow.Right));
956 T(("... SBI.dwSize %dx%d",
961 rect = info->srWindow;
962 coord = info->dwSize;
963 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
968 int high = info->srWindow.Bottom - info->srWindow.Top + 1;
969 int wide = info->srWindow.Right - info->srWindow.Left + 1;
971 if (high < MIN_HIGH) {
972 T(("... height %d < %d", high, MIN_HIGH));
976 if (wide < MIN_WIDE) {
977 T(("... width %d < %d", wide, MIN_WIDE));
984 rect.Right = (SHORT) (wide - 1);
985 rect.Bottom = (SHORT) (high - 1);
987 coord.X = (SHORT) wide;
988 coord.Y = (SHORT) high;
990 if (info->dwSize.Y != high ||
991 info->dwSize.X != wide ||
992 info->srWindow.Top != 0 ||
993 info->srWindow.Left != 0) {
1000 T(("... coord %d,%d", coord.Y, coord.X));
1001 T(("... rect %d,%d - %d,%d",
1002 rect.Top, rect.Left,
1003 rect.Bottom, rect.Right));
1004 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */
1005 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */
1012 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
1015 TERMINAL *_term = (TERMINAL *) TCB;
1018 if (okConsoleHandle(TCB)) {
1021 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"),
1022 TCB, progFlag, defFlag));
1024 CON.progMode = progFlag;
1025 CON.lastOut = progFlag ? CON.hdl : CON.out;
1026 SetConsoleActiveScreenBuffer(CON.lastOut);
1028 if (progFlag) /* prog mode */ {
1030 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
1031 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
1035 /* reset_prog_mode */
1036 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
1039 _nc_keypad(sp, TRUE);
1041 if (!CON.buffered) {
1042 set_scrollback(FALSE, &CON.SBI);
1047 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
1048 } else { /* shell mode */
1050 /* def_shell_mode */
1051 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
1055 /* reset_shell_mode */
1057 _nc_keypad(sp, FALSE);
1058 NCURSES_SP_NAME(_nc_flush) (sp);
1060 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
1061 if (!CON.buffered) {
1062 set_scrollback(TRUE, &CON.save_SBI);
1063 if (!restore_original_screen())
1066 SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
1075 wcon_screen_init(SCREEN *sp GCC_UNUSED)
1080 wcon_wrap(SCREEN *sp GCC_UNUSED)
1085 rkeycompare(const void *el1, const void *el2)
1087 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
1088 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
1090 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1094 keycompare(const void *el1, const void *el2)
1096 WORD key1 = HIWORD((*((const LONG *) el1)));
1097 WORD key2 = HIWORD((*((const LONG *) el2)));
1099 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1107 LONG key = GenMap(vKey, 0);
1112 (size_t) (N_INI + FKEYS),
1116 key = *((LONG *) res);
1118 code = (int) (nKey & 0x7fff);
1130 LONG key = GenMap(vKey, 0);
1135 (size_t) (N_INI + FKEYS),
1139 key = *((LONG *) res);
1141 code = (int) (nKey & 0x7fff);
1149 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
1151 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
1161 read_screen_data(void)
1163 bool result = FALSE;
1167 CON.save_size.X = (SHORT) (CON.save_region.Right
1168 - CON.save_region.Left + 1);
1169 CON.save_size.Y = (SHORT) (CON.save_region.Bottom
1170 - CON.save_region.Top + 1);
1172 want = (size_t) (CON.save_size.X * CON.save_size.Y);
1174 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1175 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
1176 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
1178 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
1179 CON.window_only ? "window" : "buffer",
1180 CON.save_size.Y, CON.save_size.X,
1181 CON.save_region.Top,
1182 CON.save_region.Left,
1183 CON.save_region.Bottom,
1184 CON.save_region.Right,
1188 if (read_screen(CON.hdl,
1192 &CON.save_region)) {
1195 T((" error %#lx", (unsigned long) GetLastError()));
1196 FreeAndNull(CON.save_screen);
1204 * Attempt to save the screen contents. PDCurses does this if
1205 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
1206 * restoration as if the library had allocated a console buffer. MSDN
1207 * says that the data which can be read is limited to 64Kb (and may be
1211 save_original_screen(void)
1213 bool result = FALSE;
1215 CON.save_region.Top = 0;
1216 CON.save_region.Left = 0;
1217 CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
1218 CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
1220 if (read_screen_data()) {
1224 CON.save_region.Top = CON.SBI.srWindow.Top;
1225 CON.save_region.Left = CON.SBI.srWindow.Left;
1226 CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
1227 CON.save_region.Right = CON.SBI.srWindow.Right;
1229 CON.window_only = TRUE;
1231 if (read_screen_data()) {
1236 T(("... save original screen contents %s", result ? "ok" : "err"));
1241 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1243 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1248 if (!InitConsole()) {
1252 TCB->info.initcolor = TRUE;
1253 TCB->info.canchange = FALSE;
1254 TCB->info.hascolor = TRUE;
1255 TCB->info.caninit = TRUE;
1257 TCB->info.maxpairs = NUMPAIRS;
1258 TCB->info.maxcolors = 8;
1259 TCB->info.numlabels = 0;
1260 TCB->info.labelwidth = 0;
1261 TCB->info.labelheight = 0;
1262 TCB->info.nocolorvideo = 1;
1263 TCB->info.tabsize = 8;
1265 TCB->info.numbuttons = CON.numButtons;
1266 TCB->info.defaultPalette = _nc_cga_palette;
1273 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1280 if (okConsoleHandle(TCB)) {
1283 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1284 && (b >= 0) && (b < 8)) {
1285 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
1291 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1292 int color GCC_UNUSED,
1304 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1305 int old_pair GCC_UNUSED,
1306 int pair GCC_UNUSED,
1307 int reverse GCC_UNUSED,
1308 int (*outc) (SCREEN *, int) GCC_UNUSED
1318 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1322 if (okConsoleHandle(TCB)) {
1325 sp->_mouse_type = M_TERM_DRIVER;
1330 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
1332 EVENTLIST_2nd(_nc_eventlist * evl))
1337 if (okConsoleHandle(TCB)) {
1340 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1343 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1347 EVENTLIST_2nd(evl));
1355 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1356 int yold GCC_UNUSED, int xold GCC_UNUSED,
1360 if (okConsoleHandle(TCB)) {
1363 loc.Y = (short) (y + AdjustY());
1364 SetConsoleCursorPosition(CON.hdl, loc);
1371 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1372 int labnum GCC_UNUSED,
1373 char *text GCC_UNUSED)
1382 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1383 int OnFlag GCC_UNUSED)
1392 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1394 chtype res = A_NORMAL;
1395 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1400 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1409 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1410 chtype *real_map GCC_UNUSED,
1411 chtype *fake_map GCC_UNUSED)
1413 #define DATA(a,b) { a, b }
1418 DATA('a', 0xb1), /* ACS_CKBOARD */
1419 DATA('f', 0xf8), /* ACS_DEGREE */
1420 DATA('g', 0xf1), /* ACS_PLMINUS */
1421 DATA('j', 0xd9), /* ACS_LRCORNER */
1422 DATA('l', 0xda), /* ACS_ULCORNER */
1423 DATA('k', 0xbf), /* ACS_URCORNER */
1424 DATA('m', 0xc0), /* ACS_LLCORNER */
1425 DATA('n', 0xc5), /* ACS_PLUS */
1426 DATA('q', 0xc4), /* ACS_HLINE */
1427 DATA('t', 0xc3), /* ACS_LTEE */
1428 DATA('u', 0xb4), /* ACS_RTEE */
1429 DATA('v', 0xc1), /* ACS_BTEE */
1430 DATA('w', 0xc2), /* ACS_TTEE */
1431 DATA('x', 0xb3), /* ACS_VLINE */
1432 DATA('y', 0xf3), /* ACS_LEQUAL */
1433 DATA('z', 0xf2), /* ACS_GEQUAL */
1434 DATA('0', 0xdb), /* ACS_BLOCK */
1435 DATA('{', 0xe3), /* ACS_PI */
1436 DATA('}', 0x9c), /* ACS_STERLING */
1437 DATA(',', 0xae), /* ACS_LARROW */
1438 DATA('+', 0xaf), /* ACS_RARROW */
1439 DATA('~', 0xf9), /* ACS_BULLET */
1445 if (okConsoleHandle(TCB)) {
1448 for (n = 0; n < SIZEOF(table); ++n) {
1449 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1451 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1457 tdiff(FILETIME fstart, FILETIME fend)
1459 ULARGE_INTEGER ustart;
1460 ULARGE_INTEGER uend;
1463 ustart.LowPart = fstart.dwLowDateTime;
1464 ustart.HighPart = fstart.dwHighDateTime;
1465 uend.LowPart = fend.dwLowDateTime;
1466 uend.HighPart = fend.dwHighDateTime;
1468 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1473 Adjust(int milliseconds, int diff)
1475 if (milliseconds != INFINITY) {
1476 milliseconds -= diff;
1477 if (milliseconds < 0)
1480 return milliseconds;
1483 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1484 FROM_LEFT_2ND_BUTTON_PRESSED | \
1485 FROM_LEFT_3RD_BUTTON_PRESSED | \
1486 FROM_LEFT_4TH_BUTTON_PRESSED | \
1487 RIGHTMOST_BUTTON_PRESSED)
1490 decode_mouse(SCREEN *sp, int mask)
1495 assert(sp && console_initialized);
1497 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1498 result |= BUTTON1_PRESSED;
1499 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1500 result |= BUTTON2_PRESSED;
1501 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1502 result |= BUTTON3_PRESSED;
1503 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1504 result |= BUTTON4_PRESSED;
1506 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1507 switch (CON.numButtons) {
1509 result |= BUTTON1_PRESSED;
1512 result |= BUTTON2_PRESSED;
1515 result |= BUTTON3_PRESSED;
1518 result |= BUTTON4_PRESSED;
1533 EVENTLIST_2nd(_nc_eventlist * evl))
1535 INPUT_RECORD inp_rec;
1537 DWORD nRead = 0, rc = (DWORD) (-1);
1542 bool isImmed = (milliseconds == 0);
1544 #ifdef NCURSES_WGETCH_EVENTS
1545 (void) evl; /* TODO: implement wgetch-events */
1548 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1552 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1553 milliseconds, mode));
1555 if (milliseconds < 0)
1556 milliseconds = INFINITY;
1558 memset(&inp_rec, 0, sizeof(inp_rec));
1561 GetSystemTimeAsFileTime(&fstart);
1562 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1563 GetSystemTimeAsFileTime(&fend);
1564 diff = (int) tdiff(fstart, fend);
1565 milliseconds = Adjust(milliseconds, diff);
1567 if (!isImmed && milliseconds <= 0)
1570 if (rc == WAIT_OBJECT_0) {
1572 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1573 if (b && nRead > 0) {
1574 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1575 if (b && nRead > 0) {
1576 switch (inp_rec.EventType) {
1578 if (mode & TW_INPUT) {
1579 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1580 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1582 if (inp_rec.Event.KeyEvent.bKeyDown) {
1584 int nKey = MapKey(vk);
1598 if (decode_mouse(sp,
1599 (inp_rec.Event.MouseEvent.dwButtonState
1600 & BUTTON_MASK)) == 0) {
1602 } else if (mode & TW_MOUSE) {
1607 /* e.g., FOCUS_EVENT */
1610 selectActiveHandle();
1618 if (rc != WAIT_TIMEOUT) {
1629 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1630 code, errno, milliseconds));
1633 *timeleft = milliseconds;
1639 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1643 EVENTLIST_2nd(_nc_eventlist * evl))
1648 if (okConsoleHandle(TCB)) {
1651 code = console_twait(sp,
1655 timeleft EVENTLIST_2nd(evl));
1661 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1664 bool result = FALSE;
1668 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1669 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1672 * We're only interested if the button is pressed or released.
1673 * FIXME: implement continuous event-tracking.
1675 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1677 memset(&work, 0, sizeof(work));
1679 if (sp->_drv_mouse_new_buttons) {
1681 work.bstate |= decode_mouse(sp, sp->_drv_mouse_new_buttons);
1685 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1686 work.bstate |= (decode_mouse(sp,
1687 sp->_drv_mouse_old_buttons)
1693 work.x = mer.dwMousePosition.X;
1694 work.y = mer.dwMousePosition.Y - AdjustY();
1696 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1697 sp->_drv_mouse_tail += 1;
1704 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1709 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1712 if (okConsoleHandle(TCB)) {
1715 n = _nc_mingw_console_read(sp, CON.inp, buf);
1721 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1723 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1729 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1733 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1734 if (okConsoleHandle(TCB)) {
1735 CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1738 this_CI.bVisible = FALSE;
1743 this_CI.dwSize = 100;
1746 SetConsoleCursorInfo(CON.hdl, &this_CI);
1752 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1757 LONG key = GenMap(0, (WORD) keycode);
1759 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1762 (size_t) (N_INI + FKEYS),
1766 key = *((LONG *) res);
1768 if (!(nKey & 0x8000))
1775 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1780 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1782 if (okConsoleHandle(TCB)) {
1793 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1802 LONG key = GenMap(0, (WORD) keycode);
1804 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1806 if (okConsoleHandle(TCB)) {
1812 (size_t) (N_INI + FKEYS),
1816 key = *((LONG *) res);
1818 nKey = (LOWORD(key)) & 0x7fff;
1821 *(LONG *) res = GenMap(vKey, nKey);
1828 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1830 wcon_name, /* Name */
1831 wcon_CanHandle, /* CanHandle */
1832 wcon_init, /* init */
1833 wcon_release, /* release */
1834 wcon_size, /* size */
1835 wcon_sgmode, /* sgmode */
1836 wcon_conattr, /* conattr */
1837 wcon_mvcur, /* hwcur */
1838 wcon_mode, /* mode */
1839 wcon_rescol, /* rescol */
1840 wcon_rescolors, /* rescolors */
1841 wcon_setcolor, /* color */
1842 wcon_dobeepflash, /* DoBeepFlash */
1843 wcon_initpair, /* initpair */
1844 wcon_initcolor, /* initcolor */
1845 wcon_do_color, /* docolor */
1846 wcon_initmouse, /* initmouse */
1847 wcon_testmouse, /* testmouse */
1848 wcon_setfilter, /* setfilter */
1849 wcon_hwlabel, /* hwlabel */
1850 wcon_hwlabelOnOff, /* hwlabelOnOff */
1851 wcon_doupdate, /* update */
1852 wcon_defaultcolors, /* defaultcolors */
1853 wcon_print, /* print */
1854 wcon_size, /* getsize */
1855 wcon_setsize, /* setsize */
1856 wcon_initacs, /* initacs */
1857 wcon_screen_init, /* scinit */
1858 wcon_wrap, /* scexit */
1859 wcon_twait, /* twait */
1860 wcon_read, /* read */
1862 wcon_kpad, /* kpad */
1863 wcon_keyok, /* kyOk */
1864 wcon_kyExist, /* kyExist */
1865 wcon_cursorSet /* cursorSet */
1868 /* --------------------------------------------------------- */
1873 intptr_t value = _get_osfhandle(fd);
1874 return (HANDLE) value;
1877 #if WINVER >= 0x0600
1878 /* This function tests, whether or not the ncurses application
1879 is running as a descendant of MSYS2/cygwin mintty terminal
1880 application. mintty doesn't use Windows Console for its screen
1881 I/O, so the native Windows _isatty doesn't recognize it as
1882 character device. But we can discover we are at the end of an
1883 Pipe and can query to server side of the pipe, looking whether
1884 or not this is mintty.
1887 _ismintty(int fd, LPHANDLE pMinTTY)
1889 HANDLE handle = get_handle(fd);
1893 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1895 if (handle != INVALID_HANDLE_VALUE) {
1896 dw = GetFileType(handle);
1897 if (dw == FILE_TYPE_PIPE) {
1898 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1901 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1902 TCHAR buf[MAX_PATH];
1904 /* These security attributes may allow us to
1905 create a remote thread in mintty to manipulate
1906 the terminal state remotely */
1907 HANDLE pHandle = OpenProcess(
1908 PROCESS_CREATE_THREAD
1909 | PROCESS_QUERY_INFORMATION
1910 | PROCESS_VM_OPERATION
1916 *pMinTTY = INVALID_HANDLE_VALUE;
1917 if (pHandle != INVALID_HANDLE_VALUE) {
1918 if ((len = GetProcessImageFileName(
1922 array_length(buf)))) {
1923 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1926 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1943 /* Borrowed from ansicon project.
1944 Check whether or not an I/O handle is associated with
1948 IsConsoleHandle(HANDLE hdl)
1953 if (!GetConsoleMode(hdl, &dwFlag)) {
1954 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1956 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1961 /* Our replacement for the systems _isatty to include also
1962 a test for mintty. This is called from the NC_ISATTY macro
1963 defined in curses.priv.h
1966 _nc_mingw_isatty(int fd)
1970 if (SysISATTY(fd)) {
1973 #if WINVER >= 0x0600
1974 result = _ismintty(fd, NULL);
1980 /* This is used when running in terminfo mode to discover,
1981 whether or not the "terminal" is actually a Windows
1982 Console. It is the responsibility of the console to deal
1983 with the terminal escape sequences that are sent by
1987 _nc_mingw_isconsole(int fd)
1989 HANDLE hdl = get_handle(fd);
1992 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1994 code = (int) IsConsoleHandle(hdl);
1999 #define TC_PROLOGUE(fd) \
2001 TERMINAL *term = 0; \
2003 if (_nc_screen_chain == 0) \
2005 for (each_screen(sp)) { \
2006 if (sp->_term && (sp->_term->Filedes == fd)) { \
2014 _nc_mingw_tcsetattr(
2016 int optional_action GCC_UNUSED,
2017 const struct termios *arg)
2021 if (_nc_mingw_isconsole(fd)) {
2023 HANDLE ofd = get_handle(fd);
2024 if (ofd != INVALID_HANDLE_VALUE) {
2026 if (arg->c_lflag & ICANON)
2027 dwFlag |= ENABLE_LINE_INPUT;
2029 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
2031 if (arg->c_lflag & ECHO)
2032 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
2034 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
2036 if (arg->c_iflag & BRKINT)
2037 dwFlag |= ENABLE_PROCESSED_INPUT;
2039 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
2041 dwFlag |= ENABLE_MOUSE_INPUT;
2042 SetConsoleMode(ofd, dwFlag);
2053 _nc_mingw_tcgetattr(int fd, struct termios *arg)
2057 if (_nc_mingw_isconsole(fd)) {
2065 _nc_mingw_tcflush(int fd, int queue)
2070 if (_nc_mingw_isconsole(fd)) {
2071 if (queue == TCIFLUSH) {
2072 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2074 return (int) GetLastError();
2081 _nc_mingw_testmouse(
2085 EVENTLIST_2nd(_nc_eventlist * evl))
2091 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2094 rc = console_twait(sp,
2099 EVENTLIST_2nd(evl));
2105 _nc_mingw_console_read(
2111 INPUT_RECORD inp_rec;
2119 memset(&inp_rec, 0, sizeof(inp_rec));
2121 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2123 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2124 if (b && nRead > 0) {
2127 rc = rc + (int) nRead;
2128 if (inp_rec.EventType == KEY_EVENT) {
2129 if (!inp_rec.Event.KeyEvent.bKeyDown)
2131 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2132 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2134 * There are 24 virtual function-keys (defined in winuser.h),
2135 * and typically 12 function-keys on a keyboard. Use the
2136 * shift-modifier to provide the remaining keys.
2138 if (vk >= VK_F1 && vk <= VK_F12) {
2139 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
2140 vk = (WORD) (vk + 12);
2144 int key = MapKey(vk);
2147 if (sp->_keypad_on) {
2153 } else if (vk == VK_BACK) {
2154 if (!(inp_rec.Event.KeyEvent.dwControlKeyState
2155 & (SHIFT_PRESSED | CONTROL_PRESSED))) {
2156 *buf = KEY_BACKSPACE;
2160 } else if (inp_rec.EventType == MOUSE_EVENT) {
2161 if (handle_mouse(sp,
2162 inp_rec.Event.MouseEvent)) {
2176 /* initialize once, or not at all */
2177 if (!console_initialized) {
2181 BOOL buffered = TRUE;
2186 for (i = 0; i < (N_INI + FKEYS); i++) {
2188 CON.rmap[i] = CON.map[i] =
2190 CON.ansi_map[i] = (DWORD) ansi_keys[i];
2192 CON.rmap[i] = CON.map[i] =
2193 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2194 (KEY_F(1) + (i - N_INI)));
2196 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2197 (';' + (i - N_INI)));
2213 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2214 CON.numButtons = (int) num_buttons;
2219 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2220 for (i = 0; i < NUMPAIRS; i++)
2226 b = AttachConsole(ATTACH_PARENT_PROCESS);
2228 CON.inp = GetDirectHandle("CONIN$", FILE_SHARE_READ);
2229 CON.out = GetDirectHandle("CONOUT$", FILE_SHARE_WRITE);
2231 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2232 T(("... will not buffer console"));
2236 T(("... creating console buffer"));
2237 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2238 FILE_SHARE_READ | FILE_SHARE_WRITE,
2240 CONSOLE_TEXTMODE_BUFFER,
2244 if (CON.hdl != INVALID_HANDLE_VALUE) {
2245 CON.buffered = buffered;
2247 CON.save_SBI = CON.SBI;
2249 save_original_screen();
2250 set_scrollback(FALSE, &CON.SBI);
2252 GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
2253 T(("... initial cursor is %svisible, %d%%",
2254 (CON.save_CI.bVisible ? "" : "not-"),
2255 (int) CON.save_CI.dwSize));
2258 console_initialized = TRUE;
2260 return (CON.hdl != INVALID_HANDLE_VALUE);
2264 okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB)
2266 return ((TCB != 0) &&
2267 (TCB->magic == WINMAGIC) &&
2272 * While a constructor would ensure that this module is initialized, that will
2273 * interfere with applications that may combine this with GUI interfaces.
2277 __attribute__((constructor))
2278 void _enter_console(void)
2280 (void) InitConsole();