1 /****************************************************************************
2 * Copyright (c) 1998-2016,2017 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.59 2017/07/22 21:10:28 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, int delay)
1324 if (okConsoleHandle(TCB)) {
1327 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1330 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1334 EVENTLIST_2nd(evl));
1342 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1343 int yold GCC_UNUSED, int xold GCC_UNUSED,
1347 if (okConsoleHandle(TCB)) {
1350 loc.Y = (short) (y + AdjustY());
1351 SetConsoleCursorPosition(CON.hdl, loc);
1358 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1359 int labnum GCC_UNUSED,
1360 char *text GCC_UNUSED)
1369 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1370 int OnFlag GCC_UNUSED)
1379 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1381 chtype res = A_NORMAL;
1382 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1387 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1396 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1397 chtype *real_map GCC_UNUSED,
1398 chtype *fake_map GCC_UNUSED)
1400 #define DATA(a,b) { a, b }
1405 DATA('a', 0xb1), /* ACS_CKBOARD */
1406 DATA('f', 0xf8), /* ACS_DEGREE */
1407 DATA('g', 0xf1), /* ACS_PLMINUS */
1408 DATA('j', 0xd9), /* ACS_LRCORNER */
1409 DATA('l', 0xda), /* ACS_ULCORNER */
1410 DATA('k', 0xbf), /* ACS_URCORNER */
1411 DATA('m', 0xc0), /* ACS_LLCORNER */
1412 DATA('n', 0xc5), /* ACS_PLUS */
1413 DATA('q', 0xc4), /* ACS_HLINE */
1414 DATA('t', 0xc3), /* ACS_LTEE */
1415 DATA('u', 0xb4), /* ACS_RTEE */
1416 DATA('v', 0xc1), /* ACS_BTEE */
1417 DATA('w', 0xc2), /* ACS_TTEE */
1418 DATA('x', 0xb3), /* ACS_VLINE */
1419 DATA('y', 0xf3), /* ACS_LEQUAL */
1420 DATA('z', 0xf2), /* ACS_GEQUAL */
1421 DATA('0', 0xdb), /* ACS_BLOCK */
1422 DATA('{', 0xe3), /* ACS_PI */
1423 DATA('}', 0x9c), /* ACS_STERLING */
1424 DATA(',', 0xae), /* ACS_LARROW */
1425 DATA('+', 0xaf), /* ACS_RARROW */
1426 DATA('~', 0xf9), /* ACS_BULLET */
1432 if (okConsoleHandle(TCB)) {
1435 for (n = 0; n < SIZEOF(table); ++n) {
1436 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1438 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1444 tdiff(FILETIME fstart, FILETIME fend)
1446 ULARGE_INTEGER ustart;
1447 ULARGE_INTEGER uend;
1450 ustart.LowPart = fstart.dwLowDateTime;
1451 ustart.HighPart = fstart.dwHighDateTime;
1452 uend.LowPart = fend.dwLowDateTime;
1453 uend.HighPart = fend.dwHighDateTime;
1455 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1460 Adjust(int milliseconds, int diff)
1462 if (milliseconds != INFINITY) {
1463 milliseconds -= diff;
1464 if (milliseconds < 0)
1467 return milliseconds;
1470 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1471 FROM_LEFT_2ND_BUTTON_PRESSED | \
1472 FROM_LEFT_3RD_BUTTON_PRESSED | \
1473 FROM_LEFT_4TH_BUTTON_PRESSED | \
1474 RIGHTMOST_BUTTON_PRESSED)
1477 decode_mouse(SCREEN *sp, int mask)
1482 assert(sp && console_initialized);
1484 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1485 result |= BUTTON1_PRESSED;
1486 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1487 result |= BUTTON2_PRESSED;
1488 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1489 result |= BUTTON3_PRESSED;
1490 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1491 result |= BUTTON4_PRESSED;
1493 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1494 switch (CON.numButtons) {
1496 result |= BUTTON1_PRESSED;
1499 result |= BUTTON2_PRESSED;
1502 result |= BUTTON3_PRESSED;
1505 result |= BUTTON4_PRESSED;
1520 EVENTLIST_2nd(_nc_eventlist * evl))
1522 INPUT_RECORD inp_rec;
1524 DWORD nRead = 0, rc = (DWORD) (-1);
1529 bool isImmed = (milliseconds == 0);
1531 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1535 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1536 milliseconds, mode));
1538 if (milliseconds < 0)
1539 milliseconds = INFINITY;
1541 memset(&inp_rec, 0, sizeof(inp_rec));
1544 GetSystemTimeAsFileTime(&fstart);
1545 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1546 GetSystemTimeAsFileTime(&fend);
1547 diff = (int) tdiff(fstart, fend);
1548 milliseconds = Adjust(milliseconds, diff);
1550 if (!isImmed && milliseconds <= 0)
1553 if (rc == WAIT_OBJECT_0) {
1555 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1556 if (b && nRead > 0) {
1557 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1558 if (b && nRead > 0) {
1559 switch (inp_rec.EventType) {
1561 if (mode & TW_INPUT) {
1562 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1563 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1565 if (inp_rec.Event.KeyEvent.bKeyDown) {
1567 int nKey = MapKey(vk);
1581 if (decode_mouse(sp,
1582 (inp_rec.Event.MouseEvent.dwButtonState
1583 & BUTTON_MASK)) == 0) {
1585 } else if (mode & TW_MOUSE) {
1590 /* e.g., FOCUS_EVENT */
1593 selectActiveHandle();
1601 if (rc != WAIT_TIMEOUT) {
1612 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1613 code, errno, milliseconds));
1616 *timeleft = milliseconds;
1622 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1626 EVENTLIST_2nd(_nc_eventlist * evl))
1631 if (okConsoleHandle(TCB)) {
1634 code = console_twait(sp,
1638 timeleft EVENTLIST_2nd(_nc_eventlist * evl));
1644 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1647 bool result = FALSE;
1651 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1652 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1655 * We're only interested if the button is pressed or released.
1656 * FIXME: implement continuous event-tracking.
1658 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1660 memset(&work, 0, sizeof(work));
1662 if (sp->_drv_mouse_new_buttons) {
1664 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1668 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1669 work.bstate |= (mmask_t) (decode_mouse(sp,
1670 sp->_drv_mouse_old_buttons)
1676 work.x = mer.dwMousePosition.X;
1677 work.y = mer.dwMousePosition.Y - AdjustY();
1679 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1680 sp->_drv_mouse_tail += 1;
1687 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1692 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1695 if (okConsoleHandle(TCB)) {
1698 n = _nc_mingw_console_read(sp, CON.inp, buf);
1704 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1706 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1712 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1716 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1717 if (okConsoleHandle(TCB)) {
1718 CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1721 this_CI.bVisible = FALSE;
1726 this_CI.dwSize = 100;
1729 SetConsoleCursorInfo(CON.hdl, &this_CI);
1735 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1740 LONG key = GenMap(0, (WORD) keycode);
1742 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1745 (size_t) (N_INI + FKEYS),
1749 key = *((LONG *) res);
1751 if (!(nKey & 0x8000))
1758 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1763 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1765 if (okConsoleHandle(TCB)) {
1776 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1785 LONG key = GenMap(0, (WORD) keycode);
1787 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1789 if (okConsoleHandle(TCB)) {
1795 (size_t) (N_INI + FKEYS),
1799 key = *((LONG *) res);
1801 nKey = (LOWORD(key)) & 0x7fff;
1804 *(LONG *) res = GenMap(vKey, nKey);
1811 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1813 wcon_name, /* Name */
1814 wcon_CanHandle, /* CanHandle */
1815 wcon_init, /* init */
1816 wcon_release, /* release */
1817 wcon_size, /* size */
1818 wcon_sgmode, /* sgmode */
1819 wcon_conattr, /* conattr */
1820 wcon_mvcur, /* hwcur */
1821 wcon_mode, /* mode */
1822 wcon_rescol, /* rescol */
1823 wcon_rescolors, /* rescolors */
1824 wcon_setcolor, /* color */
1825 wcon_dobeepflash, /* DoBeepFlash */
1826 wcon_initpair, /* initpair */
1827 wcon_initcolor, /* initcolor */
1828 wcon_do_color, /* docolor */
1829 wcon_initmouse, /* initmouse */
1830 wcon_testmouse, /* testmouse */
1831 wcon_setfilter, /* setfilter */
1832 wcon_hwlabel, /* hwlabel */
1833 wcon_hwlabelOnOff, /* hwlabelOnOff */
1834 wcon_doupdate, /* update */
1835 wcon_defaultcolors, /* defaultcolors */
1836 wcon_print, /* print */
1837 wcon_size, /* getsize */
1838 wcon_setsize, /* setsize */
1839 wcon_initacs, /* initacs */
1840 wcon_screen_init, /* scinit */
1841 wcon_wrap, /* scexit */
1842 wcon_twait, /* twait */
1843 wcon_read, /* read */
1845 wcon_kpad, /* kpad */
1846 wcon_keyok, /* kyOk */
1847 wcon_kyExist, /* kyExist */
1848 wcon_cursorSet /* cursorSet */
1851 /* --------------------------------------------------------- */
1856 intptr_t value = _get_osfhandle(fd);
1857 return (HANDLE) value;
1860 #if WINVER >= 0x0600
1861 /* This function tests, whether or not the ncurses application
1862 is running as a descendant of MSYS2/cygwin mintty terminal
1863 application. mintty doesn't use Windows Console for it's screen
1864 I/O, so the native Windows _isatty doesn't recognize it as
1865 character device. But we can discover we are at the end of an
1866 Pipe and can query to server side of the pipe, looking whether
1867 or not this is mintty.
1870 _ismintty(int fd, LPHANDLE pMinTTY)
1872 HANDLE handle = get_handle(fd);
1876 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1878 if (handle != INVALID_HANDLE_VALUE) {
1879 dw = GetFileType(handle);
1880 if (dw == FILE_TYPE_PIPE) {
1881 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1884 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1885 TCHAR buf[MAX_PATH];
1887 /* These security attributes may allow us to
1888 create a remote thread in mintty to manipulate
1889 the terminal state remotely */
1890 HANDLE pHandle = OpenProcess(
1891 PROCESS_CREATE_THREAD
1892 | PROCESS_QUERY_INFORMATION
1893 | PROCESS_VM_OPERATION
1899 *pMinTTY = INVALID_HANDLE_VALUE;
1900 if (pHandle != INVALID_HANDLE_VALUE) {
1901 if ((len = GetProcessImageFileName(
1905 array_length(buf)))) {
1906 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1909 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1926 /* Borrowed from ansicon project.
1927 Check whether or not an I/O handle is associated with
1931 IsConsoleHandle(HANDLE hdl)
1936 if (!GetConsoleMode(hdl, &dwFlag)) {
1937 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1939 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1944 /* Our replacement for the systems _isatty to include also
1945 a test for mintty. This is called from the NC_ISATTY macro
1946 defined in curses.priv.h
1949 _nc_mingw_isatty(int fd)
1954 #define SysISATTY(fd) _isatty(fd)
1956 #define SysISATTY(fd) isatty(fd)
1958 if (SysISATTY(fd)) {
1961 #if WINVER >= 0x0600
1962 result = _ismintty(fd, NULL);
1968 /* This is used when running in terminfo mode to discover,
1969 whether or not the "terminal" is actually a Windows
1970 Console. It's the responsibilty of the console to deal
1971 with the terminal escape sequences that are sent by
1975 _nc_mingw_isconsole(int fd)
1977 HANDLE hdl = get_handle(fd);
1980 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1982 code = (int) IsConsoleHandle(hdl);
1987 #define TC_PROLOGUE(fd) \
1989 TERMINAL *term = 0; \
1991 if (_nc_screen_chain == 0) \
1993 for (each_screen(sp)) { \
1994 if (sp->_term && (sp->_term->Filedes == fd)) { \
2002 _nc_mingw_tcsetattr(
2004 int optional_action GCC_UNUSED,
2005 const struct termios *arg)
2009 if (_nc_mingw_isconsole(fd)) {
2011 HANDLE ofd = get_handle(fd);
2012 if (ofd != INVALID_HANDLE_VALUE) {
2014 if (arg->c_lflag & ICANON)
2015 dwFlag |= ENABLE_LINE_INPUT;
2017 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
2019 if (arg->c_lflag & ECHO)
2020 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
2022 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
2024 if (arg->c_iflag & BRKINT)
2025 dwFlag |= ENABLE_PROCESSED_INPUT;
2027 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
2029 dwFlag |= ENABLE_MOUSE_INPUT;
2030 SetConsoleMode(ofd, dwFlag);
2041 _nc_mingw_tcgetattr(int fd, struct termios *arg)
2045 if (_nc_mingw_isconsole(fd)) {
2053 _nc_mingw_tcflush(int fd, int queue)
2058 if (_nc_mingw_isconsole(fd)) {
2059 if (queue == TCIFLUSH) {
2060 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2062 return (int) GetLastError();
2069 _nc_mingw_testmouse(
2078 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2081 rc = console_twait(sp,
2086 EVENTLIST_2nd(evl));
2092 _nc_mingw_console_read(
2098 INPUT_RECORD inp_rec;
2106 memset(&inp_rec, 0, sizeof(inp_rec));
2108 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2110 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2111 if (b && nRead > 0) {
2114 rc = rc + (int) nRead;
2115 if (inp_rec.EventType == KEY_EVENT) {
2116 if (!inp_rec.Event.KeyEvent.bKeyDown)
2118 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2119 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2121 * There are 24 virtual function-keys, and typically
2122 * 12 function-keys on a keyboard. Use the shift-modifier
2123 * to provide the remaining 12 keys.
2125 if (vk >= VK_F1 && vk <= VK_F12) {
2126 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
2127 vk = (WORD) (vk + 12);
2131 int key = MapKey(vk);
2134 if (sp->_keypad_on) {
2142 } else if (inp_rec.EventType == MOUSE_EVENT) {
2143 if (handle_mouse(sp,
2144 inp_rec.Event.MouseEvent)) {
2158 /* initalize once, or not at all */
2159 if (!console_initialized) {
2163 BOOL buffered = TRUE;
2167 if (_nc_mingw_isatty(0)) {
2168 CON.isMinTTY = TRUE;
2171 for (i = 0; i < (N_INI + FKEYS); i++) {
2173 CON.rmap[i] = CON.map[i] =
2175 CON.ansi_map[i] = (DWORD) ansi_keys[i];
2177 CON.rmap[i] = CON.map[i] =
2178 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2179 (KEY_F(1) + (i - N_INI)));
2181 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2182 (';' + (i - N_INI)));
2198 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2199 CON.numButtons = (int) num_buttons;
2204 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2205 for (i = 0; i < NUMPAIRS; i++)
2208 CON.inp = GetStdHandle(STD_INPUT_HANDLE);
2209 CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
2214 b = AttachConsole(ATTACH_PARENT_PROCESS);
2216 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2217 T(("... will not buffer console"));
2221 T(("... creating console buffer"));
2222 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2225 CONSOLE_TEXTMODE_BUFFER,
2229 if (CON.hdl != INVALID_HANDLE_VALUE) {
2230 CON.buffered = buffered;
2232 CON.save_SBI = CON.SBI;
2234 save_original_screen();
2235 set_scrollback(FALSE, &CON.SBI);
2237 GetConsoleCursorInfo(CON.hdl, &CON.save_CI);
2238 T(("... initial cursor is %svisible, %d%%",
2239 (CON.save_CI.bVisible ? "" : "not-"),
2240 (int) CON.save_CI.dwSize));
2243 console_initialized = TRUE;
2245 return (CON.hdl != INVALID_HANDLE_VALUE);
2249 okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB)
2251 return ((TCB != 0) &&
2252 (TCB->magic == WINMAGIC) &&
2257 * While a constructor would ensure that this module is initialized, that will
2258 * interfere with applications that may combine this with GUI interfaces.
2262 __attribute__((constructor))
2263 void _enter_console(void)
2265 (void) InitConsole();