1 /****************************************************************************
2 * Copyright 2018,2020 Thomas E. Dickey *
3 * Copyright 2008-2016,2017 Free Software Foundation, Inc. *
5 * Permission is hereby granted, free of charge, to any person obtaining a *
6 * copy of this software and associated documentation files (the *
7 * "Software"), to deal in the Software without restriction, including *
8 * without limitation the rights to use, copy, modify, merge, publish, *
9 * distribute, distribute with modifications, sublicense, and/or sell *
10 * copies of the Software, and to permit persons to whom the Software is *
11 * furnished to do so, subject to the following conditions: *
13 * The above copyright notice and this permission notice shall be included *
14 * in all copies or substantial portions of the Software. *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
17 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
18 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
19 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
20 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
21 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
22 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
24 * Except as contained in this notice, the name(s) of the above copyright *
25 * holders shall not be used in advertising or otherwise to promote the *
26 * sale, use or other dealings in this Software without prior written *
28 ****************************************************************************/
30 /****************************************************************************
31 * Author: Juergen Pfeifer *
32 * and: Thomas E. Dickey *
33 ****************************************************************************/
36 * TODO - GetMousePos(POINT * result) from ntconio.c
37 * TODO - implement nodelay
38 * TODO - improve screen-repainting performance, using implied wraparound to reduce write's
39 * TODO - make it optional whether screen is restored or not when non-buffered
42 #include <curses.priv.h>
53 #define PSAPI_VERSION 2
56 #define CUR TerminalType(my_term).
58 MODULE_ID("$Id: win_driver.c,v 1.63 2020/02/02 23:34:34 tom Exp $")
61 # error We need GCC to compile for MinGW
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')
114 #define N_INI ((int)array_length(keylist))
116 #define MAPSIZE (FKEYS + N_INI)
119 /* A process can only have a single console, so it's safe
120 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)
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)
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[Width];
519 for (x = 0; x < Width; x++)
520 setcchar(&empty[x], blank, 0, 0, 0);
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 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
618 int *errret GCC_UNUSED)
622 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
624 assert((TCB != 0) && (tname != 0));
626 TCB->magic = WINMAGIC;
628 if (tname == 0 || *tname == 0)
630 else if (tname != 0 && *tname == '#') {
632 * Use "#" (a character which cannot begin a terminal's name) to
633 * select specific driver from the table.
635 * In principle, we could have more than one non-terminfo driver,
638 size_t n = strlen(tname + 1);
640 && ((strncmp(tname + 1, "win32console", n) == 0)
641 || (strncmp(tname + 1, "win32con", n) == 0))) {
644 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
649 * This is intentional, to avoid unnecessary breakage of applications
650 * using <term.h> symbols.
652 if (code && (TerminalType(&TCB->term).Booleans == 0)) {
653 _nc_init_termtype(&TerminalType(&TCB->term));
654 #if NCURSES_EXT_NUMBERS
655 _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
660 if (_nc_mingw_isconsole(0))
661 CON.isTermInfoConsole = TRUE;
667 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
673 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1);
674 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1);
675 int max_cells = (high * wide);
678 CHAR_INFO this_screen[max_cells];
679 CHAR_INFO that_screen[max_cells];
681 SMALL_RECT this_region;
684 if (okConsoleHandle(TCB)) {
686 this_region.Top = CON.SBI.srWindow.Top;
687 this_region.Left = CON.SBI.srWindow.Left;
688 this_region.Bottom = CON.SBI.srWindow.Bottom;
689 this_region.Right = CON.SBI.srWindow.Right;
691 this_size.X = (SHORT) wide;
692 this_size.Y = (SHORT) high;
694 bufferCoord.X = this_region.Left;
695 bufferCoord.Y = this_region.Top;
704 memcpy(that_screen, this_screen, sizeof(that_screen));
706 for (i = 0; i < max_cells; i++) {
707 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
710 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
712 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
715 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */
723 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
724 char *data GCC_UNUSED,
736 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
753 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
754 T(("GetConsoleScreenBufferInfo"));
755 T(("... buffer(X:%d Y:%d)",
758 T(("... window(X:%d Y:%d)",
759 CON.SBI.dwMaximumWindowSize.X,
760 CON.SBI.dwMaximumWindowSize.Y));
761 T(("... cursor(X:%d Y:%d)",
762 CON.SBI.dwCursorPosition.X,
763 CON.SBI.dwCursorPosition.Y));
764 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
765 CON.SBI.srWindow.Top,
766 CON.SBI.srWindow.Bottom,
767 CON.SBI.srWindow.Left,
768 CON.SBI.srWindow.Right));
773 CON.origin.X = CON.SBI.srWindow.Left;
774 CON.origin.Y = CON.SBI.srWindow.Top;
778 T(("GetConsoleScreenBufferInfo ERR"));
784 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
787 int (*outc) (SCREEN *, int) GCC_UNUSED)
789 if (okConsoleHandle(TCB)) {
790 WORD a = MapColor(fore, color);
791 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
792 SetConsoleTextAttribute(CON.hdl, a);
798 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
802 if (okConsoleHandle(TCB)) {
803 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
804 SetConsoleTextAttribute(CON.hdl, a);
812 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
824 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
828 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
830 if (okConsoleHandle(TCB) &&
834 *Lines = (int) (CON.SBI.dwSize.Y);
835 *Cols = (int) (CON.SBI.dwSize.X);
837 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
838 CON.SBI.srWindow.Top);
839 *Cols = (int) (CON.SBI.srWindow.Right + 1 -
840 CON.SBI.srWindow.Left);
848 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
857 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
864 if (buf != NULL && okConsoleHandle(TCB)) {
867 iflag = buf->c_iflag;
868 lflag = buf->c_lflag;
870 GetConsoleMode(CON.inp, &dwFlag);
873 dwFlag |= ENABLE_LINE_INPUT;
875 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
878 dwFlag |= ENABLE_ECHO_INPUT;
880 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
883 dwFlag |= ENABLE_PROCESSED_INPUT;
885 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
887 dwFlag |= ENABLE_MOUSE_INPUT;
889 buf->c_iflag = iflag;
890 buf->c_lflag = lflag;
891 SetConsoleMode(CON.inp, dwFlag);
892 TCB->term.Nttyb = *buf;
894 iflag = TCB->term.Nttyb.c_iflag;
895 lflag = TCB->term.Nttyb.c_lflag;
896 GetConsoleMode(CON.inp, &dwFlag);
898 if (dwFlag & ENABLE_LINE_INPUT)
901 lflag &= (tcflag_t) (~ICANON);
903 if (dwFlag & ENABLE_ECHO_INPUT)
906 lflag &= (tcflag_t) (~ECHO);
908 if (dwFlag & ENABLE_PROCESSED_INPUT)
911 iflag &= (tcflag_t) (~BRKINT);
913 TCB->term.Nttyb.c_iflag = iflag;
914 TCB->term.Nttyb.c_lflag = lflag;
916 *buf = TCB->term.Nttyb;
927 * In "normal" mode, reset the buffer- and window-sizes back to their original values.
930 set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
934 bool changed = FALSE;
936 T((T_CALLED("win32con::set_scrollback(%s)"),
941 T(("... SBI.srWindow %d,%d .. %d,%d",
944 info->srWindow.Bottom,
945 info->srWindow.Right));
946 T(("... SBI.dwSize %dx%d",
951 rect = info->srWindow;
952 coord = info->dwSize;
953 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
958 int high = info->srWindow.Bottom - info->srWindow.Top + 1;
959 int wide = info->srWindow.Right - info->srWindow.Left + 1;
961 if (high < MIN_HIGH) {
962 T(("... height %d < %d", high, MIN_HIGH));
966 if (wide < MIN_WIDE) {
967 T(("... width %d < %d", wide, MIN_WIDE));
974 rect.Right = (SHORT) (wide - 1);
975 rect.Bottom = (SHORT) (high - 1);
977 coord.X = (SHORT) wide;
978 coord.Y = (SHORT) high;
980 if (info->dwSize.Y != high ||
981 info->dwSize.X != wide ||
982 info->srWindow.Top != 0 ||
983 info->srWindow.Left != 0) {
990 T(("... coord %d,%d", coord.Y, coord.X));
991 T(("... rect %d,%d - %d,%d",
993 rect.Bottom, rect.Right));
994 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */
995 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */
1002 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
1005 TERMINAL *_term = (TERMINAL *) TCB;
1008 if (okConsoleHandle(TCB)) {
1011 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"),
1012 TCB, progFlag, defFlag));
1014 CON.progMode = progFlag;
1015 CON.lastOut = progFlag ? CON.hdl : CON.out;
1016 SetConsoleActiveScreenBuffer(CON.lastOut);
1018 if (progFlag) /* prog mode */ {
1020 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
1021 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
1025 /* reset_prog_mode */
1026 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
1029 _nc_keypad(sp, TRUE);
1031 if (!CON.buffered) {
1032 set_scrollback(FALSE, &CON.SBI);
1037 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
1038 } else { /* shell mode */
1040 /* def_shell_mode */
1041 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
1045 /* reset_shell_mode */
1047 _nc_keypad(sp, FALSE);
1048 NCURSES_SP_NAME(_nc_flush) (sp);
1050 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
1051 if (!CON.buffered) {
1052 set_scrollback(TRUE, &CON.save_SBI);
1053 if (!restore_original_screen())
1056 SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
1065 wcon_screen_init(SCREEN *sp GCC_UNUSED)
1070 wcon_wrap(SCREEN *sp GCC_UNUSED)
1075 rkeycompare(const void *el1, const void *el2)
1077 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
1078 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
1080 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1084 keycompare(const void *el1, const void *el2)
1086 WORD key1 = HIWORD((*((const LONG *) el1)));
1087 WORD key2 = HIWORD((*((const LONG *) el2)));
1089 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1097 LONG key = GenMap(vKey, 0);
1102 (size_t) (N_INI + FKEYS),
1106 key = *((LONG *) res);
1108 code = (int) (nKey & 0x7fff);
1120 LONG key = GenMap(vKey, 0);
1125 (size_t) (N_INI + FKEYS),
1129 key = *((LONG *) res);
1131 code = (int) (nKey & 0x7fff);
1139 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
1141 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
1151 read_screen_data(void)
1153 bool result = FALSE;
1157 CON.save_size.X = (SHORT) (CON.save_region.Right
1158 - CON.save_region.Left + 1);
1159 CON.save_size.Y = (SHORT) (CON.save_region.Bottom
1160 - CON.save_region.Top + 1);
1162 want = (size_t) (CON.save_size.X * CON.save_size.Y);
1164 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1165 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
1166 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
1168 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
1169 CON.window_only ? "window" : "buffer",
1170 CON.save_size.Y, CON.save_size.X,
1171 CON.save_region.Top,
1172 CON.save_region.Left,
1173 CON.save_region.Bottom,
1174 CON.save_region.Right,
1178 if (read_screen(CON.hdl,
1182 &CON.save_region)) {
1185 T((" error %#lx", (unsigned long) GetLastError()));
1186 FreeAndNull(CON.save_screen);
1194 * Attempt to save the screen contents. PDCurses does this if
1195 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
1196 * restoration as if the library had allocated a console buffer. MSDN
1197 * says that the data which can be read is limited to 64Kb (and may be
1201 save_original_screen(void)
1203 bool result = FALSE;
1205 CON.save_region.Top = 0;
1206 CON.save_region.Left = 0;
1207 CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
1208 CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1);
1210 if (read_screen_data()) {
1214 CON.save_region.Top = CON.SBI.srWindow.Top;
1215 CON.save_region.Left = CON.SBI.srWindow.Left;
1216 CON.save_region.Bottom = CON.SBI.srWindow.Bottom;
1217 CON.save_region.Right = CON.SBI.srWindow.Right;
1219 CON.window_only = TRUE;
1221 if (read_screen_data()) {
1226 T(("... save original screen contents %s", result ? "ok" : "err"));
1231 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1233 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1238 if (!InitConsole()) {
1242 TCB->info.initcolor = TRUE;
1243 TCB->info.canchange = FALSE;
1244 TCB->info.hascolor = TRUE;
1245 TCB->info.caninit = TRUE;
1247 TCB->info.maxpairs = NUMPAIRS;
1248 TCB->info.maxcolors = 8;
1249 TCB->info.numlabels = 0;
1250 TCB->info.labelwidth = 0;
1251 TCB->info.labelheight = 0;
1252 TCB->info.nocolorvideo = 1;
1253 TCB->info.tabsize = 8;
1255 TCB->info.numbuttons = CON.numButtons;
1256 TCB->info.defaultPalette = _nc_cga_palette;
1263 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1270 if (okConsoleHandle(TCB)) {
1273 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1274 && (b >= 0) && (b < 8)) {
1275 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
1281 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1282 int color GCC_UNUSED,
1294 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1295 int old_pair GCC_UNUSED,
1296 int pair GCC_UNUSED,
1297 int reverse GCC_UNUSED,
1298 int (*outc) (SCREEN *, int) GCC_UNUSED
1308 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1312 if (okConsoleHandle(TCB)) {
1315 sp->_mouse_type = M_TERM_DRIVER;
1320 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
1322 EVENTLIST_2nd(_nc_eventlist * evl))
1327 if (okConsoleHandle(TCB)) {
1330 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1333 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1337 EVENTLIST_2nd(evl));
1345 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1346 int yold GCC_UNUSED, int xold GCC_UNUSED,
1350 if (okConsoleHandle(TCB)) {
1353 loc.Y = (short) (y + AdjustY());
1354 SetConsoleCursorPosition(CON.hdl, loc);
1361 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1362 int labnum GCC_UNUSED,
1363 char *text GCC_UNUSED)
1372 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1373 int OnFlag GCC_UNUSED)
1382 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1384 chtype res = A_NORMAL;
1385 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1390 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1399 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1400 chtype *real_map GCC_UNUSED,
1401 chtype *fake_map GCC_UNUSED)
1403 #define DATA(a,b) { a, b }
1408 DATA('a', 0xb1), /* ACS_CKBOARD */
1409 DATA('f', 0xf8), /* ACS_DEGREE */
1410 DATA('g', 0xf1), /* ACS_PLMINUS */
1411 DATA('j', 0xd9), /* ACS_LRCORNER */
1412 DATA('l', 0xda), /* ACS_ULCORNER */
1413 DATA('k', 0xbf), /* ACS_URCORNER */
1414 DATA('m', 0xc0), /* ACS_LLCORNER */
1415 DATA('n', 0xc5), /* ACS_PLUS */
1416 DATA('q', 0xc4), /* ACS_HLINE */
1417 DATA('t', 0xc3), /* ACS_LTEE */
1418 DATA('u', 0xb4), /* ACS_RTEE */
1419 DATA('v', 0xc1), /* ACS_BTEE */
1420 DATA('w', 0xc2), /* ACS_TTEE */
1421 DATA('x', 0xb3), /* ACS_VLINE */
1422 DATA('y', 0xf3), /* ACS_LEQUAL */
1423 DATA('z', 0xf2), /* ACS_GEQUAL */
1424 DATA('0', 0xdb), /* ACS_BLOCK */
1425 DATA('{', 0xe3), /* ACS_PI */
1426 DATA('}', 0x9c), /* ACS_STERLING */
1427 DATA(',', 0xae), /* ACS_LARROW */
1428 DATA('+', 0xaf), /* ACS_RARROW */
1429 DATA('~', 0xf9), /* ACS_BULLET */
1435 if (okConsoleHandle(TCB)) {
1438 for (n = 0; n < SIZEOF(table); ++n) {
1439 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1441 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1447 tdiff(FILETIME fstart, FILETIME fend)
1449 ULARGE_INTEGER ustart;
1450 ULARGE_INTEGER uend;
1453 ustart.LowPart = fstart.dwLowDateTime;
1454 ustart.HighPart = fstart.dwHighDateTime;
1455 uend.LowPart = fend.dwLowDateTime;
1456 uend.HighPart = fend.dwHighDateTime;
1458 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1463 Adjust(int milliseconds, int diff)
1465 if (milliseconds != INFINITY) {
1466 milliseconds -= diff;
1467 if (milliseconds < 0)
1470 return milliseconds;
1473 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1474 FROM_LEFT_2ND_BUTTON_PRESSED | \
1475 FROM_LEFT_3RD_BUTTON_PRESSED | \
1476 FROM_LEFT_4TH_BUTTON_PRESSED | \
1477 RIGHTMOST_BUTTON_PRESSED)
1480 decode_mouse(SCREEN *sp, int mask)
1485 assert(sp && console_initialized);
1487 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1488 result |= BUTTON1_PRESSED;
1489 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1490 result |= BUTTON2_PRESSED;
1491 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1492 result |= BUTTON3_PRESSED;
1493 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1494 result |= BUTTON4_PRESSED;
1496 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1497 switch (CON.numButtons) {
1499 result |= BUTTON1_PRESSED;
1502 result |= BUTTON2_PRESSED;
1505 result |= BUTTON3_PRESSED;
1508 result |= BUTTON4_PRESSED;
1523 EVENTLIST_2nd(_nc_eventlist * evl))
1525 INPUT_RECORD inp_rec;
1527 DWORD nRead = 0, rc = (DWORD) (-1);
1532 bool isImmed = (milliseconds == 0);
1534 #ifdef NCURSES_WGETCH_EVENTS
1535 (void) evl; /* TODO: implement wgetch-events */
1538 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1542 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1543 milliseconds, mode));
1545 if (milliseconds < 0)
1546 milliseconds = INFINITY;
1548 memset(&inp_rec, 0, sizeof(inp_rec));
1551 GetSystemTimeAsFileTime(&fstart);
1552 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1553 GetSystemTimeAsFileTime(&fend);
1554 diff = (int) tdiff(fstart, fend);
1555 milliseconds = Adjust(milliseconds, diff);
1557 if (!isImmed && milliseconds <= 0)
1560 if (rc == WAIT_OBJECT_0) {
1562 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1563 if (b && nRead > 0) {
1564 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1565 if (b && nRead > 0) {
1566 switch (inp_rec.EventType) {
1568 if (mode & TW_INPUT) {
1569 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1570 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1572 if (inp_rec.Event.KeyEvent.bKeyDown) {
1574 int nKey = MapKey(vk);
1588 if (decode_mouse(sp,
1589 (inp_rec.Event.MouseEvent.dwButtonState
1590 & BUTTON_MASK)) == 0) {
1592 } else if (mode & TW_MOUSE) {
1597 /* e.g., FOCUS_EVENT */
1600 selectActiveHandle();
1608 if (rc != WAIT_TIMEOUT) {
1619 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1620 code, errno, milliseconds));
1623 *timeleft = milliseconds;
1629 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1633 EVENTLIST_2nd(_nc_eventlist * evl))
1638 if (okConsoleHandle(TCB)) {
1641 code = console_twait(sp,
1645 timeleft EVENTLIST_2nd(evl));
1651 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1654 bool result = FALSE;
1658 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1659 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1662 * We're only interested if the button is pressed or released.
1663 * FIXME: implement continuous event-tracking.
1665 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1667 memset(&work, 0, sizeof(work));
1669 if (sp->_drv_mouse_new_buttons) {
1671 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1675 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1676 work.bstate |= (mmask_t) (decode_mouse(sp,
1677 sp->_drv_mouse_old_buttons)
1683 work.x = mer.dwMousePosition.X;
1684 work.y = mer.dwMousePosition.Y - AdjustY();
1686 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1687 sp->_drv_mouse_tail += 1;
1694 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1699 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1702 if (okConsoleHandle(TCB)) {
1705 n = _nc_mingw_console_read(sp, CON.inp, buf);
1711 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1713 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1719 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1723 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1724 if (okConsoleHandle(TCB)) {
1725 CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1728 this_CI.bVisible = FALSE;
1733 this_CI.dwSize = 100;
1736 SetConsoleCursorInfo(CON.hdl, &this_CI);
1742 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1747 LONG key = GenMap(0, (WORD) keycode);
1749 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1752 (size_t) (N_INI + FKEYS),
1756 key = *((LONG *) res);
1758 if (!(nKey & 0x8000))
1765 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1770 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1772 if (okConsoleHandle(TCB)) {
1783 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1792 LONG key = GenMap(0, (WORD) keycode);
1794 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1796 if (okConsoleHandle(TCB)) {
1802 (size_t) (N_INI + FKEYS),
1806 key = *((LONG *) res);
1808 nKey = (LOWORD(key)) & 0x7fff;
1811 *(LONG *) res = GenMap(vKey, nKey);
1818 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1820 wcon_name, /* Name */
1821 wcon_CanHandle, /* CanHandle */
1822 wcon_init, /* init */
1823 wcon_release, /* release */
1824 wcon_size, /* size */
1825 wcon_sgmode, /* sgmode */
1826 wcon_conattr, /* conattr */
1827 wcon_mvcur, /* hwcur */
1828 wcon_mode, /* mode */
1829 wcon_rescol, /* rescol */
1830 wcon_rescolors, /* rescolors */
1831 wcon_setcolor, /* color */
1832 wcon_dobeepflash, /* DoBeepFlash */
1833 wcon_initpair, /* initpair */
1834 wcon_initcolor, /* initcolor */
1835 wcon_do_color, /* docolor */
1836 wcon_initmouse, /* initmouse */
1837 wcon_testmouse, /* testmouse */
1838 wcon_setfilter, /* setfilter */
1839 wcon_hwlabel, /* hwlabel */
1840 wcon_hwlabelOnOff, /* hwlabelOnOff */
1841 wcon_doupdate, /* update */
1842 wcon_defaultcolors, /* defaultcolors */
1843 wcon_print, /* print */
1844 wcon_size, /* getsize */
1845 wcon_setsize, /* setsize */
1846 wcon_initacs, /* initacs */
1847 wcon_screen_init, /* scinit */
1848 wcon_wrap, /* scexit */
1849 wcon_twait, /* twait */
1850 wcon_read, /* read */
1852 wcon_kpad, /* kpad */
1853 wcon_keyok, /* kyOk */
1854 wcon_kyExist, /* kyExist */
1855 wcon_cursorSet /* cursorSet */
1858 /* --------------------------------------------------------- */
1863 intptr_t value = _get_osfhandle(fd);
1864 return (HANDLE) value;
1867 #if WINVER >= 0x0600
1868 /* This function tests, whether or not the ncurses application
1869 is running as a descendant of MSYS2/cygwin mintty terminal
1870 application. mintty doesn't use Windows Console for it's screen
1871 I/O, so the native Windows _isatty doesn't recognize it as
1872 character device. But we can discover we are at the end of an
1873 Pipe and can query to server side of the pipe, looking whether
1874 or not this is mintty.
1877 _ismintty(int fd, LPHANDLE pMinTTY)
1879 HANDLE handle = get_handle(fd);
1883 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1885 if (handle != INVALID_HANDLE_VALUE) {
1886 dw = GetFileType(handle);
1887 if (dw == FILE_TYPE_PIPE) {
1888 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1891 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1892 TCHAR buf[MAX_PATH];
1894 /* These security attributes may allow us to
1895 create a remote thread in mintty to manipulate
1896 the terminal state remotely */
1897 HANDLE pHandle = OpenProcess(
1898 PROCESS_CREATE_THREAD
1899 | PROCESS_QUERY_INFORMATION
1900 | PROCESS_VM_OPERATION
1906 *pMinTTY = INVALID_HANDLE_VALUE;
1907 if (pHandle != INVALID_HANDLE_VALUE) {
1908 if ((len = GetProcessImageFileName(
1912 array_length(buf)))) {
1913 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1916 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1933 /* Borrowed from ansicon project.
1934 Check whether or not an I/O handle is associated with
1938 IsConsoleHandle(HANDLE hdl)
1943 if (!GetConsoleMode(hdl, &dwFlag)) {
1944 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1946 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1951 /* Our replacement for the systems _isatty to include also
1952 a test for mintty. This is called from the NC_ISATTY macro
1953 defined in curses.priv.h
1956 _nc_mingw_isatty(int fd)
1961 #define SysISATTY(fd) _isatty(fd)
1963 #define SysISATTY(fd) isatty(fd)
1965 if (SysISATTY(fd)) {
1968 #if WINVER >= 0x0600
1969 result = _ismintty(fd, NULL);
1975 /* This is used when running in terminfo mode to discover,
1976 whether or not the "terminal" is actually a Windows
1977 Console. It's the responsibility of the console to deal
1978 with the terminal escape sequences that are sent by
1982 _nc_mingw_isconsole(int fd)
1984 HANDLE hdl = get_handle(fd);
1987 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1989 code = (int) IsConsoleHandle(hdl);
1994 #define TC_PROLOGUE(fd) \
1996 TERMINAL *term = 0; \
1998 if (_nc_screen_chain == 0) \
2000 for (each_screen(sp)) { \
2001 if (sp->_term && (sp->_term->Filedes == fd)) { \
2009 _nc_mingw_tcsetattr(
2011 int optional_action GCC_UNUSED,
2012 const struct termios *arg)
2016 if (_nc_mingw_isconsole(fd)) {
2018 HANDLE ofd = get_handle(fd);
2019 if (ofd != INVALID_HANDLE_VALUE) {
2021 if (arg->c_lflag & ICANON)
2022 dwFlag |= ENABLE_LINE_INPUT;
2024 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
2026 if (arg->c_lflag & ECHO)
2027 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
2029 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
2031 if (arg->c_iflag & BRKINT)
2032 dwFlag |= ENABLE_PROCESSED_INPUT;
2034 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
2036 dwFlag |= ENABLE_MOUSE_INPUT;
2037 SetConsoleMode(ofd, dwFlag);
2048 _nc_mingw_tcgetattr(int fd, struct termios *arg)
2052 if (_nc_mingw_isconsole(fd)) {
2060 _nc_mingw_tcflush(int fd, int queue)
2065 if (_nc_mingw_isconsole(fd)) {
2066 if (queue == TCIFLUSH) {
2067 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2069 return (int) GetLastError();
2076 _nc_mingw_testmouse(
2080 EVENTLIST_2nd(_nc_eventlist * evl))
2086 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2089 rc = console_twait(sp,
2094 EVENTLIST_2nd(evl));
2100 _nc_mingw_console_read(
2106 INPUT_RECORD inp_rec;
2114 memset(&inp_rec, 0, sizeof(inp_rec));
2116 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2118 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2119 if (b && nRead > 0) {
2122 rc = rc + (int) nRead;
2123 if (inp_rec.EventType == KEY_EVENT) {
2124 if (!inp_rec.Event.KeyEvent.bKeyDown)
2126 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2127 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2129 * There are 24 virtual function-keys, and typically
2130 * 12 function-keys on a keyboard. Use the shift-modifier
2131 * to provide the remaining 12 keys.
2133 if (vk >= VK_F1 && vk <= VK_F12) {
2134 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
2135 vk = (WORD) (vk + 12);
2139 int key = MapKey(vk);
2142 if (sp->_keypad_on) {
2150 } else if (inp_rec.EventType == MOUSE_EVENT) {
2151 if (handle_mouse(sp,
2152 inp_rec.Event.MouseEvent)) {
2166 /* initialize once, or not at all */
2167 if (!console_initialized) {
2171 BOOL buffered = TRUE;
2175 if (_nc_mingw_isatty(0)) {
2176 CON.isMinTTY = TRUE;
2179 for (i = 0; i < (N_INI + FKEYS); i++) {
2181 CON.rmap[i] = CON.map[i] =
2183 CON.ansi_map[i] = (DWORD) ansi_keys[i];
2185 CON.rmap[i] = CON.map[i] =
2186 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2187 (KEY_F(1) + (i - N_INI)));
2189 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2190 (';' + (i - N_INI)));
2206 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2207 CON.numButtons = (int) num_buttons;
2212 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2213 for (i = 0; i < NUMPAIRS; i++)
2216 CON.inp = GetStdHandle(STD_INPUT_HANDLE);
2217 CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
2222 b = AttachConsole(ATTACH_PARENT_PROCESS);
2224 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2225 T(("... will not buffer console"));
2229 T(("... creating console buffer"));
2230 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2233 CONSOLE_TEXTMODE_BUFFER,
2237 if (CON.hdl != INVALID_HANDLE_VALUE) {
2238 CON.buffered = buffered;
2240 CON.save_SBI = CON.SBI;
2242 save_original_screen();
2243 set_scrollback(FALSE, &CON.SBI);
2245 GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
2246 T(("... initial cursor is %svisible, %d%%",
2247 (CON.save_CI.bVisible ? "" : "not-"),
2248 (int) CON.save_CI.dwSize));
2251 console_initialized = TRUE;
2253 return (CON.hdl != INVALID_HANDLE_VALUE);
2257 okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB)
2259 return ((TCB != 0) &&
2260 (TCB->magic == WINMAGIC) &&
2265 * While a constructor would ensure that this module is initialized, that will
2266 * interfere with applications that may combine this with GUI interfaces.
2270 __attribute__((constructor))
2271 void _enter_console(void)
2273 (void) InitConsole();