1 /****************************************************************************
2 * Copyright (c) 1998-2013,2014 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
39 #include <curses.priv.h>
43 #define PSAPI_VERSION 2
46 #define CUR my_term.type.
48 MODULE_ID("$Id: win_driver.c,v 1.38 2014/05/10 21:50:00 tom Exp $")
51 # error We need GCC to compile for MinGW
54 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
56 #define EXP_OPTIMIZE 0
58 #define array_length(a) (sizeof(a)/sizeof(a[0]))
60 #define okConsoleHandle(TCB) (TCB != 0 && CON.hdl != INVALID_HANDLE_VALUE)
62 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
63 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
65 #define GenMap(vKey,key) MAKELONG(key, vKey)
67 #define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
69 static const LONG keylist[] =
71 GenMap(VK_PRIOR, KEY_PPAGE),
72 GenMap(VK_NEXT, KEY_NPAGE),
73 GenMap(VK_END, KEY_END),
74 GenMap(VK_HOME, KEY_HOME),
75 GenMap(VK_LEFT, KEY_LEFT),
76 GenMap(VK_UP, KEY_UP),
77 GenMap(VK_RIGHT, KEY_RIGHT),
78 GenMap(VK_DOWN, KEY_DOWN),
79 GenMap(VK_DELETE, KEY_DC),
80 GenMap(VK_INSERT, KEY_IC)
82 #define N_INI ((int)array_length(keylist))
84 #define MAPSIZE (FKEYS + N_INI)
87 /* A process can only have a single console, so it's save
88 to maintain all the information about it in a single
97 BOOL isTermInfoConsole;
105 WORD pairs[NUMPAIRS];
107 CHAR_INFO *save_screen;
108 CONSOLE_SCREEN_BUFFER_INFO SBI;
111 static BOOL console_initialized = FALSE;
114 MapColor(bool fore, int color)
116 static const int _cmap[] =
117 {0, 4, 2, 6, 1, 5, 3, 7};
119 if (color < 0 || color > 7)
129 MapAttr(WORD res, attr_t ch)
135 if (p > 0 && p < NUMPAIRS) {
138 res = (WORD) ((res & 0xff00) | a);
142 if (ch & A_REVERSE) {
143 res = (WORD) ((res & 0xff00) |
144 (((res & 0x07) << 4) |
145 ((res & 0x70) >> 4)));
148 if (ch & A_STANDOUT) {
149 res = (WORD) ((res & 0xff00) |
150 (((res & 0x07) << 4) |
151 ((res & 0x70) >> 4)) |
152 BACKGROUND_INTENSITY);
156 res |= FOREGROUND_INTENSITY;
159 res |= BACKGROUND_INTENSITY;
164 #if USE_WIDEC_SUPPORT
166 * TODO: support surrogate pairs
167 * TODO: support combining characters
169 * TODO: check wcwidth of base character, fill if needed for double-width
170 * TODO: _nc_wacs should be part of sp.
173 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
186 for (i = actual = 0; i < limit; i++) {
190 ci[actual].Char.UnicodeChar = CharOf(ch);
191 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
193 if (AttrOf(ch) & A_ALTCHARSET) {
195 int which = CharOf(ch);
198 && CharOf(_nc_wacs[which]) != 0) {
199 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
201 ci[actual].Char.UnicodeChar = ' ';
210 siz.X = (short) actual;
213 rec.Left = (short) x;
214 rec.Top = (SHORT) (y + AdjustY());
215 rec.Right = (short) (x + limit - 1);
216 rec.Bottom = rec.Top;
218 return WriteConsoleOutputW(CON.hdl, ci, siz, loc, &rec);
220 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
223 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
235 for (i = 0; i < n; i++) {
237 ci[i].Char.AsciiChar = ChCharOf(ch);
238 ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
240 if (ChAttrOf(ch) & A_ALTCHARSET) {
242 ci[i].Char.AsciiChar =
243 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
252 rec.Left = (short) x;
254 rec.Right = (short) (x + n - 1);
255 rec.Bottom = rec.Top;
257 return WriteConsoleOutput(CON.hdl, ci, siz, loc, &rec);
259 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
264 * Comparing new/current screens, determine the last column-index for a change
265 * beginning on the given row,col position. Unlike a serial terminal, there is
266 * no cost for "moving" the "cursor" on the line as we update it.
269 find_end_of_change(SCREEN *sp, int row, int col)
272 struct ldat *curdat = CurScreen(sp)->_line + row;
273 struct ldat *newdat = NewScreen(sp)->_line + row;
275 while (col <= newdat->lastchar) {
276 #if USE_WIDEC_SUPPORT
277 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
279 } else if (memcmp(&curdat->text[col],
281 sizeof(curdat->text[0]))) {
287 if (curdat->text[col] != newdat->text[col]) {
299 * Given a row,col position at the end of a change-chunk, look for the
300 * beginning of the next change-chunk.
303 find_next_change(SCREEN *sp, int row, int col)
305 struct ldat *curdat = CurScreen(sp)->_line + row;
306 struct ldat *newdat = NewScreen(sp)->_line + row;
307 int result = newdat->lastchar + 1;
309 while (++col <= newdat->lastchar) {
310 #if USE_WIDEC_SUPPORT
311 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
314 } else if (memcmp(&curdat->text[col],
316 sizeof(curdat->text[0]))) {
321 if (curdat->text[col] != newdat->text[col]) {
330 #define EndChange(first) \
331 find_end_of_change(sp, y, first)
332 #define NextChange(last) \
333 find_next_change(sp, y, last)
335 #endif /* EXP_OPTIMIZE */
337 #define MARK_NOCHANGE(win,row) \
338 win->_line[row].firstchar = _NOCHANGE; \
339 win->_line[row].lastchar = _NOCHANGE
342 selectActiveHandle(void)
344 if (CON.lastOut != CON.hdl) {
345 CON.lastOut = CON.hdl;
346 SetConsoleActiveScreenBuffer(CON.lastOut);
351 restore_original_screen(void)
354 SMALL_RECT writeRegion;
357 if (CON.window_only) {
358 writeRegion.Top = CON.SBI.srWindow.Top;
359 writeRegion.Left = CON.SBI.srWindow.Left;
360 writeRegion.Bottom = CON.SBI.srWindow.Bottom;
361 writeRegion.Right = CON.SBI.srWindow.Right;
362 T(("... restoring window"));
365 writeRegion.Left = 0;
366 writeRegion.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1);
367 writeRegion.Right = (SHORT) (CON.SBI.dwSize.X - 1);
368 T(("... restoring entire buffer"));
371 bufferCoord.X = bufferCoord.Y = 0;
373 if (WriteConsoleOutput(CON.hdl,
379 mvcur(-1, -1, LINES - 2, 0);
381 T(("... restore original screen contents %s", result ? "ok" : "err"));
386 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
389 return "win32console";
393 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
396 int y, nonempty, n, x0, x1, Width, Height;
402 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
403 if (okConsoleHandle(TCB)) {
405 Width = screen_columns(sp);
406 Height = screen_lines(sp);
407 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
409 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
411 #if USE_WIDEC_SUPPORT
412 cchar_t empty[Width];
418 for (x = 0; x < Width; x++)
419 setcchar(&empty[x], blank, 0, 0, 0);
423 for (x = 0; x < Width; x++)
427 for (y = 0; y < nonempty; y++) {
428 con_write(TCB, y, 0, empty, Width);
430 CurScreen(sp)->_line[y].text,
431 (size_t) Width * sizeof(empty[0]));
433 CurScreen(sp)->_clear = FALSE;
434 NewScreen(sp)->_clear = FALSE;
435 touchwin(NewScreen(sp));
438 for (y = 0; y < nonempty; y++) {
439 x0 = NewScreen(sp)->_line[y].firstchar;
440 if (x0 != _NOCHANGE) {
443 int limit = NewScreen(sp)->_line[y].lastchar;
444 while ((x1 = EndChange(x0)) <= limit) {
445 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
449 memcpy(&CurScreen(sp)->_line[y].text[x0],
450 &NewScreen(sp)->_line[y].text[x0],
451 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
455 &CurScreen(sp)->_line[y].text[x0], n);
459 /* mark line changed successfully */
460 if (y <= NewScreen(sp)->_maxy) {
461 MARK_NOCHANGE(NewScreen(sp), y);
463 if (y <= CurScreen(sp)->_maxy) {
464 MARK_NOCHANGE(CurScreen(sp), y);
467 x1 = NewScreen(sp)->_line[y].lastchar;
470 memcpy(&CurScreen(sp)->_line[y].text[x0],
471 &NewScreen(sp)->_line[y].text[x0],
472 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0]));
476 &CurScreen(sp)->_line[y].text[x0], n);
478 /* mark line changed successfully */
479 if (y <= NewScreen(sp)->_maxy) {
480 MARK_NOCHANGE(NewScreen(sp), y);
482 if (y <= CurScreen(sp)->_maxy) {
483 MARK_NOCHANGE(CurScreen(sp), y);
490 /* put everything back in sync */
491 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
492 MARK_NOCHANGE(NewScreen(sp), y);
494 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
495 MARK_NOCHANGE(CurScreen(sp), y);
498 if (!NewScreen(sp)->_leaveok) {
499 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
500 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
502 TCB->drv->td_hwcur(TCB,
504 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
506 selectActiveHandle();
513 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
515 int *errret GCC_UNUSED)
519 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
521 assert((TCB != 0) && (tname != 0));
523 TCB->magic = WINMAGIC;
525 if (tname == 0 || *tname == 0)
527 else if (tname != 0 && *tname == '#') {
529 * Use "#" (a character which cannot begin a terminal's name) to
530 * select specific driver from the table.
532 * In principle, we could have more than one non-terminfo driver,
535 size_t n = strlen(tname + 1);
537 && ((strncmp(tname + 1, "win32console", n) == 0)
538 || (strncmp(tname + 1, "win32con", n) == 0))) {
541 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
546 * This is intentional, to avoid unnecessary breakage of applications
547 * using <term.h> symbols.
549 if (code && (TCB->term.type.Booleans == 0)) {
550 _nc_init_termtype(&(TCB->term.type));
554 if (_nc_mingw_isconsole(0))
555 CON.isTermInfoConsole = TRUE;
561 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
562 int beepFlag GCC_UNUSED)
574 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
575 char *data GCC_UNUSED,
587 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
604 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
605 T(("GetConsoleScreenBufferInfo"));
606 T(("... buffer(X:%d Y:%d)",
609 T(("... window(X:%d Y:%d)",
610 CON.SBI.dwMaximumWindowSize.X,
611 CON.SBI.dwMaximumWindowSize.Y));
612 T(("... cursor(X:%d Y:%d)",
613 CON.SBI.dwCursorPosition.X,
614 CON.SBI.dwCursorPosition.Y));
615 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
616 CON.SBI.srWindow.Top,
617 CON.SBI.srWindow.Bottom,
618 CON.SBI.srWindow.Left,
619 CON.SBI.srWindow.Right));
624 CON.origin.X = CON.SBI.srWindow.Left;
625 CON.origin.Y = CON.SBI.srWindow.Top;
629 T(("GetConsoleScreenBufferInfo ERR"));
635 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
638 int (*outc) (SCREEN *, int) GCC_UNUSED)
642 if (okConsoleHandle(TCB)) {
643 WORD a = MapColor(fore, color);
644 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
645 SetConsoleTextAttribute(CON.hdl, a);
651 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
656 if (okConsoleHandle(TCB)) {
657 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
658 SetConsoleTextAttribute(CON.hdl, a);
666 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
678 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
684 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
686 if (okConsoleHandle(TCB) &&
690 *Lines = (int) (CON.SBI.dwSize.Y);
691 *Cols = (int) (CON.SBI.dwSize.X);
693 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 -
694 CON.SBI.srWindow.Top);
695 *Cols = (int) (CON.SBI.srWindow.Right + 1 -
696 CON.SBI.srWindow.Left);
704 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
713 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
721 if (TCB == 0 || buf == NULL)
725 iflag = buf->c_iflag;
726 lflag = buf->c_lflag;
728 GetConsoleMode(CON.inp, &dwFlag);
731 dwFlag |= ENABLE_LINE_INPUT;
733 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
736 dwFlag |= ENABLE_ECHO_INPUT;
738 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
741 dwFlag |= ENABLE_PROCESSED_INPUT;
743 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
745 dwFlag |= ENABLE_MOUSE_INPUT;
747 buf->c_iflag = iflag;
748 buf->c_lflag = lflag;
749 SetConsoleMode(CON.inp, dwFlag);
750 TCB->term.Nttyb = *buf;
752 iflag = TCB->term.Nttyb.c_iflag;
753 lflag = TCB->term.Nttyb.c_lflag;
754 GetConsoleMode(CON.inp, &dwFlag);
756 if (dwFlag & ENABLE_LINE_INPUT)
759 lflag &= (tcflag_t) (~ICANON);
761 if (dwFlag & ENABLE_ECHO_INPUT)
764 lflag &= (tcflag_t) (~ECHO);
766 if (dwFlag & ENABLE_PROCESSED_INPUT)
769 iflag &= (tcflag_t) (~BRKINT);
771 TCB->term.Nttyb.c_iflag = iflag;
772 TCB->term.Nttyb.c_lflag = lflag;
774 *buf = TCB->term.Nttyb;
780 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
783 TERMINAL *_term = (TERMINAL *) TCB;
789 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"), TCB, progFlag, defFlag));
790 CON.progMode = progFlag;
791 CON.lastOut = progFlag ? CON.hdl : CON.out;
792 SetConsoleActiveScreenBuffer(CON.lastOut);
794 if (progFlag) /* prog mode */ {
796 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
797 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
801 /* reset_prog_mode */
802 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
805 _nc_keypad(sp, TRUE);
810 } else { /* shell mode */
813 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
817 /* reset_shell_mode */
819 _nc_keypad(sp, FALSE);
820 NCURSES_SP_NAME(_nc_flush) (sp);
822 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
824 if (!restore_original_screen())
834 wcon_screen_init(SCREEN *sp GCC_UNUSED)
839 wcon_wrap(SCREEN *sp GCC_UNUSED)
844 rkeycompare(const void *el1, const void *el2)
846 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
847 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
849 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
853 keycompare(const void *el1, const void *el2)
855 WORD key1 = HIWORD((*((const LONG *) el1)));
856 WORD key2 = HIWORD((*((const LONG *) el2)));
858 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
866 LONG key = GenMap(vKey, 0);
871 (size_t) (N_INI + FKEYS),
875 key = *((LONG *) res);
877 code = (int) (nKey & 0x7fff);
885 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
887 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
897 * Attempt to save the screen contents. PDCurses does this if
898 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on restoration
899 * as if the library had allocated a console buffer.
902 save_original_screen(void)
907 SMALL_RECT readRegion;
910 bufferSize.X = CON.SBI.dwSize.X;
911 bufferSize.Y = CON.SBI.dwSize.Y;
912 want = (size_t) (bufferSize.X * bufferSize.Y);
914 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
915 bufferCoord.X = bufferCoord.Y = 0;
919 readRegion.Bottom = (SHORT) (bufferSize.Y - 1);
920 readRegion.Right = (SHORT) (bufferSize.X - 1);
922 T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d",
923 bufferSize.Y, bufferSize.X,
931 if (ReadConsoleOutput(CON.hdl,
938 T((" error %#lx", (unsigned long) GetLastError()));
939 FreeAndNull(CON.save_screen);
941 bufferSize.X = (SHORT) (CON.SBI.srWindow.Right
942 - CON.SBI.srWindow.Left + 1);
943 bufferSize.Y = (SHORT) (CON.SBI.srWindow.Bottom
944 - CON.SBI.srWindow.Top + 1);
945 want = (size_t) (bufferSize.X * bufferSize.Y);
947 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
948 bufferCoord.X = bufferCoord.Y = 0;
950 readRegion.Top = CON.SBI.srWindow.Top;
951 readRegion.Left = CON.SBI.srWindow.Left;
952 readRegion.Bottom = CON.SBI.srWindow.Bottom;
953 readRegion.Right = CON.SBI.srWindow.Right;
955 T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d",
956 bufferSize.Y, bufferSize.X,
964 if (ReadConsoleOutput(CON.hdl,
970 CON.window_only = TRUE;
972 T((" error %#lx", (unsigned long) GetLastError()));
978 T(("... save original screen contents %s", result ? "ok" : "err"));
983 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
985 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
990 if (CON.hdl == INVALID_HANDLE_VALUE) {
994 TCB->info.initcolor = TRUE;
995 TCB->info.canchange = FALSE;
996 TCB->info.hascolor = TRUE;
997 TCB->info.caninit = TRUE;
999 TCB->info.maxpairs = NUMPAIRS;
1000 TCB->info.maxcolors = 8;
1001 TCB->info.numlabels = 0;
1002 TCB->info.labelwidth = 0;
1003 TCB->info.labelheight = 0;
1004 TCB->info.nocolorvideo = 1;
1005 TCB->info.tabsize = 8;
1007 TCB->info.numbuttons = CON.numButtons;
1008 TCB->info.defaultPalette = _nc_cga_palette;
1015 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1025 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1026 && (b >= 0) && (b < 8)) {
1027 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b);
1032 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1033 int color GCC_UNUSED,
1045 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1046 int old_pair GCC_UNUSED,
1047 int pair GCC_UNUSED,
1048 int reverse GCC_UNUSED,
1049 int (*outc) (SCREEN *, int) GCC_UNUSED
1059 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1066 sp->_mouse_type = M_TERM_DRIVER;
1070 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
1078 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1081 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1085 EVENTLIST_2nd(evl));
1092 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1093 int yold GCC_UNUSED, int xold GCC_UNUSED,
1097 if (okConsoleHandle(TCB)) {
1100 loc.Y = (short) (y + AdjustY());
1101 SetConsoleCursorPosition(CON.hdl, loc);
1108 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1109 int labnum GCC_UNUSED,
1110 char *text GCC_UNUSED)
1119 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1120 int OnFlag GCC_UNUSED)
1129 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1131 chtype res = A_NORMAL;
1132 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1137 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1146 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1147 chtype *real_map GCC_UNUSED,
1148 chtype *fake_map GCC_UNUSED)
1150 #define DATA(a,b) { a, b }
1155 DATA('a', 0xb1), /* ACS_CKBOARD */
1156 DATA('f', 0xf8), /* ACS_DEGREE */
1157 DATA('g', 0xf1), /* ACS_PLMINUS */
1158 DATA('j', 0xd9), /* ACS_LRCORNER */
1159 DATA('l', 0xda), /* ACS_ULCORNER */
1160 DATA('k', 0xbf), /* ACS_URCORNER */
1161 DATA('m', 0xc0), /* ACS_LLCORNER */
1162 DATA('n', 0xc5), /* ACS_PLUS */
1163 DATA('q', 0xc4), /* ACS_HLINE */
1164 DATA('t', 0xc3), /* ACS_LTEE */
1165 DATA('u', 0xb4), /* ACS_RTEE */
1166 DATA('v', 0xc1), /* ACS_BTEE */
1167 DATA('w', 0xc2), /* ACS_TTEE */
1168 DATA('x', 0xb3), /* ACS_VLINE */
1169 DATA('y', 0xf3), /* ACS_LEQUAL */
1170 DATA('z', 0xf2), /* ACS_GEQUAL */
1171 DATA('0', 0xdb), /* ACS_BLOCK */
1172 DATA('{', 0xe3), /* ACS_PI */
1173 DATA('}', 0x9c), /* ACS_STERLING */
1174 DATA(',', 0xae), /* ACS_LARROW */
1175 DATA('+', 0xaf), /* ACS_RARROW */
1176 DATA('~', 0xf9), /* ACS_BULLET */
1185 for (n = 0; n < SIZEOF(table); ++n) {
1186 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1188 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1193 tdiff(FILETIME fstart, FILETIME fend)
1195 ULARGE_INTEGER ustart;
1196 ULARGE_INTEGER uend;
1199 ustart.LowPart = fstart.dwLowDateTime;
1200 ustart.HighPart = fstart.dwHighDateTime;
1201 uend.LowPart = fend.dwLowDateTime;
1202 uend.HighPart = fend.dwHighDateTime;
1204 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1209 Adjust(int milliseconds, int diff)
1211 if (milliseconds == INFINITY)
1212 return milliseconds;
1213 milliseconds -= diff;
1214 if (milliseconds < 0)
1216 return milliseconds;
1219 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1220 FROM_LEFT_2ND_BUTTON_PRESSED | \
1221 FROM_LEFT_3RD_BUTTON_PRESSED | \
1222 FROM_LEFT_4TH_BUTTON_PRESSED | \
1223 RIGHTMOST_BUTTON_PRESSED)
1226 decode_mouse(SCREEN *sp, int mask)
1231 assert(sp && console_initialized);
1233 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1234 result |= BUTTON1_PRESSED;
1235 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1236 result |= BUTTON2_PRESSED;
1237 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1238 result |= BUTTON3_PRESSED;
1239 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1240 result |= BUTTON4_PRESSED;
1242 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1243 switch (CON.numButtons) {
1245 result |= BUTTON1_PRESSED;
1248 result |= BUTTON2_PRESSED;
1251 result |= BUTTON3_PRESSED;
1254 result |= BUTTON4_PRESSED;
1269 EVENTLIST_2nd(_nc_eventlist * evl))
1271 INPUT_RECORD inp_rec;
1273 DWORD nRead = 0, rc = (DWORD) (-1);
1278 bool isImmed = (milliseconds == 0);
1280 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1284 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1285 milliseconds, mode));
1287 if (milliseconds < 0)
1288 milliseconds = INFINITY;
1290 memset(&inp_rec, 0, sizeof(inp_rec));
1293 GetSystemTimeAsFileTime(&fstart);
1294 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1295 GetSystemTimeAsFileTime(&fend);
1296 diff = (int) tdiff(fstart, fend);
1297 milliseconds = Adjust(milliseconds, diff);
1299 if (!isImmed && milliseconds == 0)
1302 if (rc == WAIT_OBJECT_0) {
1304 b = GetNumberOfConsoleInputEvents(fd, &nRead);
1305 if (b && nRead > 0) {
1306 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead);
1307 if (b && nRead > 0) {
1308 switch (inp_rec.EventType) {
1310 if (mode & TW_INPUT) {
1311 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1312 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1314 if (inp_rec.Event.KeyEvent.bKeyDown) {
1316 int nKey = MapKey(vk);
1317 if ((nKey < 0) || FALSE == sp->_keypad_on) {
1330 if (decode_mouse(sp,
1331 (inp_rec.Event.MouseEvent.dwButtonState
1332 & BUTTON_MASK)) == 0) {
1334 } else if (mode & TW_MOUSE) {
1340 selectActiveHandle();
1348 if (rc != WAIT_TIMEOUT) {
1359 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1360 code, errno, milliseconds));
1363 *timeleft = milliseconds;
1369 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1373 EVENTLIST_2nd(_nc_eventlist * evl))
1381 code = console_twait(sp,
1385 timeleft EVENTLIST_2nd(_nc_eventlist * evl));
1390 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1393 bool result = FALSE;
1397 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1398 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1401 * We're only interested if the button is pressed or released.
1402 * FIXME: implement continuous event-tracking.
1404 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1406 memset(&work, 0, sizeof(work));
1408 if (sp->_drv_mouse_new_buttons) {
1410 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1414 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1415 work.bstate |= (mmask_t) (decode_mouse(sp,
1416 sp->_drv_mouse_old_buttons)
1422 work.x = mer.dwMousePosition.X;
1423 work.y = mer.dwMousePosition.Y - AdjustY();
1425 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1426 sp->_drv_mouse_tail += 1;
1433 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1442 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1443 n = _nc_mingw_console_read(sp, CON.inp, buf);
1448 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1450 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1456 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1461 LONG key = GenMap(0, (WORD) keycode);
1463 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1466 (size_t) (N_INI + FKEYS),
1470 key = *((LONG *) res);
1472 if (!(nKey & 0x8000))
1479 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1487 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1495 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1504 LONG key = GenMap(0, (WORD) keycode);
1506 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1514 (size_t) (N_INI + FKEYS),
1518 key = *((LONG *) res);
1520 nKey = (LOWORD(key)) & 0x7fff;
1523 *(LONG *) res = GenMap(vKey, nKey);
1529 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1531 wcon_name, /* Name */
1532 wcon_CanHandle, /* CanHandle */
1533 wcon_init, /* init */
1534 wcon_release, /* release */
1535 wcon_size, /* size */
1536 wcon_sgmode, /* sgmode */
1537 wcon_conattr, /* conattr */
1538 wcon_mvcur, /* hwcur */
1539 wcon_mode, /* mode */
1540 wcon_rescol, /* rescol */
1541 wcon_rescolors, /* rescolors */
1542 wcon_setcolor, /* color */
1543 wcon_dobeepflash, /* DoBeepFlash */
1544 wcon_initpair, /* initpair */
1545 wcon_initcolor, /* initcolor */
1546 wcon_do_color, /* docolor */
1547 wcon_initmouse, /* initmouse */
1548 wcon_testmouse, /* testmouse */
1549 wcon_setfilter, /* setfilter */
1550 wcon_hwlabel, /* hwlabel */
1551 wcon_hwlabelOnOff, /* hwlabelOnOff */
1552 wcon_doupdate, /* update */
1553 wcon_defaultcolors, /* defaultcolors */
1554 wcon_print, /* print */
1555 wcon_size, /* getsize */
1556 wcon_setsize, /* setsize */
1557 wcon_initacs, /* initacs */
1558 wcon_screen_init, /* scinit */
1559 wcon_wrap, /* scexit */
1560 wcon_twait, /* twait */
1561 wcon_read, /* read */
1563 wcon_kpad, /* kpad */
1564 wcon_keyok, /* kyOk */
1565 wcon_kyExist /* kyExist */
1568 /* --------------------------------------------------------- */
1573 intptr_t value = _get_osfhandle(fd);
1574 return (HANDLE) value;
1577 #if WINVER >= 0x0600
1578 /* This function tests, whether or not the ncurses application
1579 is running as a descendant of MSYS2/cygwin mintty terminal
1580 application. mintty doesn't use Windows Console for it's screen
1581 I/O, so the native Windows _isatty doesn't recognize it as
1582 character device. But we can discover we are at the end of an
1583 Pipe and can query to server side of the pipe, looking whether
1584 or not this is mintty.
1587 _ismintty(int fd, LPHANDLE pMinTTY)
1589 HANDLE handle = get_handle(fd);
1593 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1595 if (handle != INVALID_HANDLE_VALUE) {
1596 dw = GetFileType(handle);
1597 if (dw == FILE_TYPE_PIPE) {
1598 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1601 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1602 TCHAR buf[MAX_PATH];
1604 /* These security attributes may allow us to
1605 create a remote thread in mintty to manipulate
1606 the terminal state remotely */
1607 HANDLE pHandle = OpenProcess(
1608 PROCESS_CREATE_THREAD
1609 | PROCESS_QUERY_INFORMATION
1610 | PROCESS_VM_OPERATION
1616 *pMinTTY = INVALID_HANDLE_VALUE;
1617 if (pHandle != INVALID_HANDLE_VALUE) {
1618 if ((len = GetProcessImageFileName(
1622 array_length(buf)))) {
1623 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1626 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1643 /* Borrowed from ansicon project.
1644 Check wether or not a I/O handle is associated with
1648 IsConsoleHandle(HANDLE hdl)
1651 if (!GetConsoleMode(hdl, &dwFlag)) {
1652 return (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1654 return (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1657 /* Our replacement for the systems _isatty to include also
1658 a test for mintty. This is called from the NC_ISATTY macro
1659 defined in curses.priv.h
1662 _nc_mingw_isatty(int fd)
1669 return _ismintty(fd, NULL);
1673 /* This is used when running in terminfo mode to discover,
1674 whether or not the "terminal" is actually a Windows
1675 Console. It's the responsibilty of the console to deal
1676 with the terminal escape sequences that are sent by
1680 _nc_mingw_isconsole(int fd)
1682 HANDLE hdl = get_handle(fd);
1685 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1687 code = (int) IsConsoleHandle(hdl);
1692 #define TC_PROLOGUE(fd) \
1694 TERMINAL *term = 0; \
1696 if (_nc_screen_chain==0) \
1698 for (each_screen(sp)) { \
1699 if (sp->_term && sp->_term->Filedes==fd) { \
1707 _nc_mingw_tcsetattr(
1709 int optional_action GCC_UNUSED,
1710 const struct termios *arg)
1714 if (_nc_mingw_isconsole(fd)) {
1716 HANDLE ofd = get_handle(fd);
1717 if (ofd != INVALID_HANDLE_VALUE) {
1719 if (arg->c_lflag & ICANON)
1720 dwFlag |= ENABLE_LINE_INPUT;
1722 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
1724 if (arg->c_lflag & ECHO)
1725 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
1727 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
1729 if (arg->c_iflag & BRKINT)
1730 dwFlag |= ENABLE_PROCESSED_INPUT;
1732 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
1734 dwFlag |= ENABLE_MOUSE_INPUT;
1735 SetConsoleMode(ofd, dwFlag);
1746 _nc_mingw_tcgetattr(int fd, struct termios *arg)
1750 if (_nc_mingw_isconsole(fd)) {
1758 _nc_mingw_tcflush(int fd, int queue)
1763 if (_nc_mingw_isconsole(fd)) {
1764 if (queue == TCIFLUSH) {
1765 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
1767 return (int) GetLastError();
1774 _nc_mingw_testmouse(
1783 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1786 rc = console_twait(sp,
1791 EVENTLIST_2nd(evl));
1797 _nc_mingw_console_read(
1803 INPUT_RECORD inp_rec;
1811 memset(&inp_rec, 0, sizeof(inp_rec));
1813 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
1815 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
1816 if (b && nRead > 0) {
1817 if (inp_rec.EventType == KEY_EVENT) {
1818 if (!inp_rec.Event.KeyEvent.bKeyDown)
1820 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
1821 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1823 if (sp->_keypad_on) {
1831 } else { /* *buf != 0 */
1834 } else if (inp_rec.EventType == MOUSE_EVENT) {
1835 if (handle_mouse(sp,
1836 inp_rec.Event.MouseEvent)) {
1848 __attribute__((constructor))
1849 void _enter_console(void)
1851 if (!console_initialized) {
1855 BOOL buffered = TRUE;
1858 if (_nc_mingw_isatty(0)) {
1859 CON.isMinTTY = TRUE;
1862 for (i = 0; i < (N_INI + FKEYS); i++) {
1864 CON.rmap[i] = CON.map[i] =
1867 CON.rmap[i] = CON.map[i] =
1868 (DWORD) GenMap((VK_F1 + (i - N_INI)),
1869 (KEY_F(1) + (i - N_INI)));
1880 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
1881 CON.numButtons = (int) num_buttons;
1886 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
1887 for (i = 0; i < NUMPAIRS; i++)
1890 CON.inp = GetStdHandle(STD_INPUT_HANDLE);
1891 CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
1896 b = AttachConsole(ATTACH_PARENT_PROCESS);
1898 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
1902 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1905 CONSOLE_TEXTMODE_BUFFER,
1909 if (CON.hdl != INVALID_HANDLE_VALUE) {
1910 CON.buffered = buffered;
1913 save_original_screen();
1917 console_initialized = TRUE;