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>
40 #define CUR my_term.type.
42 MODULE_ID("$Id: win_driver.c,v 1.33 2014/04/26 19:32:05 juergen Exp $")
44 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
46 #define EXP_OPTIMIZE 0
48 #define okConsoleHandle(TCB) (TCB != 0 && !InvalidConsoleHandle(TCB->hdl))
50 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
51 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
53 #define GenMap(vKey,key) MAKELONG(key, vKey)
55 #define AdjustY(p) ((p)->buffered ? 0 : (int) (p)->SBI.srWindow.Top)
57 static const LONG keylist[] =
59 GenMap(VK_PRIOR, KEY_PPAGE),
60 GenMap(VK_NEXT, KEY_NPAGE),
61 GenMap(VK_END, KEY_END),
62 GenMap(VK_HOME, KEY_HOME),
63 GenMap(VK_LEFT, KEY_LEFT),
64 GenMap(VK_UP, KEY_UP),
65 GenMap(VK_RIGHT, KEY_RIGHT),
66 GenMap(VK_DOWN, KEY_DOWN),
67 GenMap(VK_DELETE, KEY_DC),
68 GenMap(VK_INSERT, KEY_IC)
70 #define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0])))
72 #define MAPSIZE (FKEYS + N_INI)
74 #define HANDLE_CAST(f) (HANDLE)(intptr_t)(f)
76 typedef struct props {
77 CONSOLE_SCREEN_BUFFER_INFO SBI;
83 bool buffered; /* normally allocate console-buffer */
84 bool window_only; /* ..if not, we save buffer or window-only */
86 CHAR_INFO *save_screen;
89 #define PropOf(TCB) ((Properties*)TCB->prop)
92 /* This function tests, whether or not the ncurses application
93 is running as a descendant of MSYS2/cygwin mintty terminal
94 application. mintty doesn't use Windows Console for it's screen
95 I/O, so the native Windows _isatty doesn't recognize it as
96 character device. But we can discover we are at the end of an
97 Pipe and can query to server side of the pipe, looking whether
98 or not this is mintty.
101 _ismintty(int fd, LPHANDLE pMinTTY)
106 handle = HANDLE_CAST(_get_osfhandle(fd));
107 if (handle == INVALID_HANDLE_VALUE)
110 dw = GetFileType(handle);
111 if (dw == FILE_TYPE_PIPE) {
112 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
115 if (GetNamedPipeServerProcessId(handle, &pPid)) {
118 /* These security attributes may allow us to
119 create a remote thread in mintty to manipulate
120 the terminal state remotely */
121 HANDLE pHandle = OpenProcess(PROCESS_CREATE_THREAD
122 | PROCESS_QUERY_INFORMATION
123 | PROCESS_VM_OPERATION
129 *pMinTTY = INVALID_HANDLE_VALUE;
130 if (pHandle == INVALID_HANDLE_VALUE)
132 if (len = GetProcessImageFileName(pHandle,
134 (DWORD) (sizeof(buf) /
136 TCHAR *pos = _tcsrchr(buf, _T('\\'));
139 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10) == 0) {
153 /* Our replacement for the systems _isatty to include also
154 a test for mintty. This is called from the NC_ISATTY macro
155 defined in curses.priv.h
158 _nc_mingw_isatty(int fd)
165 return _ismintty(fd, NULL);
169 /* Borrowed from ansicon project.
170 Check whether or not a I/O handle is associated with
174 IsConsoleHandle(HANDLE hdl)
177 if (!GetConsoleMode(hdl, &dwFlag)) {
178 return (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
180 return (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
183 /* This is used when running in terminfo mode to discover,
184 whether or not the "terminal" is actually a Windows
185 Console. It's the responsibilty of the console to deal
186 with the terminal escape sequences that are sent by
190 _nc_mingw_isconsole(int fd)
192 HANDLE hdl = HANDLE_CAST(_get_osfhandle(fd));
193 return (int) IsConsoleHandle(hdl);
197 _nc_mingw_ioctl(int fd GCC_UNUSED,
198 long int request GCC_UNUSED,
199 struct termios *arg GCC_UNUSED)
203 fprintf(stderr, "TERMINFO currently not supported on Windows.\n");
208 MapColor(bool fore, int color)
210 static const int _cmap[] =
211 {0, 4, 2, 6, 1, 5, 3, 7};
213 if (color < 0 || color > 7)
223 MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch)
232 if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) {
234 a = PropOf(TCB)->pairs[p];
235 res = (WORD) ((res & 0xff00) | a);
239 if (ch & A_REVERSE) {
240 res = (WORD) ((res & 0xff00) |
241 (((res & 0x07) << 4) |
242 ((res & 0x70) >> 4)));
245 if (ch & A_STANDOUT) {
246 res = (WORD) ((res & 0xff00) |
247 (((res & 0x07) << 4) |
248 ((res & 0x70) >> 4)) |
249 BACKGROUND_INTENSITY);
253 res |= FOREGROUND_INTENSITY;
256 res |= BACKGROUND_INTENSITY;
261 #if USE_WIDEC_SUPPORT
263 * TODO: support surrogate pairs
264 * TODO: support combining characters
266 * TODO: check wcwidth of base character, fill if needed for double-width
267 * TODO: _nc_wacs should be part of sp.
270 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
279 Properties *p = PropOf(TCB);
285 for (i = actual = 0; i < limit; i++) {
289 ci[actual].Char.UnicodeChar = CharOf(ch);
290 ci[actual].Attributes = MapAttr(TCB,
291 PropOf(TCB)->SBI.wAttributes,
293 if (AttrOf(ch) & A_ALTCHARSET) {
295 int which = CharOf(ch);
298 && CharOf(_nc_wacs[which]) != 0) {
299 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
301 ci[actual].Char.UnicodeChar = ' ';
310 siz.X = (short) actual;
313 rec.Left = (short) x;
314 rec.Top = (SHORT) (y + AdjustY(p));
315 rec.Right = (short) (x + limit - 1);
316 rec.Bottom = rec.Top;
318 return WriteConsoleOutputW(TCB->hdl, ci, siz, loc, &rec);
320 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
323 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
336 for (i = 0; i < n; i++) {
338 ci[i].Char.AsciiChar = ChCharOf(ch);
339 ci[i].Attributes = MapAttr(TCB,
340 PropOf(TCB)->SBI.wAttributes,
342 if (ChAttrOf(ch) & A_ALTCHARSET) {
344 ci[i].Char.AsciiChar =
345 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
354 rec.Left = (short) x;
356 rec.Right = (short) (x + n - 1);
357 rec.Bottom = rec.Top;
359 return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec);
361 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
366 * Comparing new/current screens, determine the last column-index for a change
367 * beginning on the given row,col position. Unlike a serial terminal, there is
368 * no cost for "moving" the "cursor" on the line as we update it.
371 find_end_of_change(SCREEN *sp, int row, int col)
374 struct ldat *curdat = CurScreen(sp)->_line + row;
375 struct ldat *newdat = NewScreen(sp)->_line + row;
377 while (col <= newdat->lastchar) {
378 #if USE_WIDEC_SUPPORT
379 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
381 } else if (memcmp(&curdat->text[col],
383 sizeof(curdat->text[0]))) {
389 if (curdat->text[col] != newdat->text[col]) {
401 * Given a row,col position at the end of a change-chunk, look for the
402 * beginning of the next change-chunk.
405 find_next_change(SCREEN *sp, int row, int col)
407 struct ldat *curdat = CurScreen(sp)->_line + row;
408 struct ldat *newdat = NewScreen(sp)->_line + row;
409 int result = newdat->lastchar + 1;
411 while (++col <= newdat->lastchar) {
412 #if USE_WIDEC_SUPPORT
413 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
416 } else if (memcmp(&curdat->text[col],
418 sizeof(curdat->text[0]))) {
423 if (curdat->text[col] != newdat->text[col]) {
432 #define EndChange(first) \
433 find_end_of_change(sp, y, first)
434 #define NextChange(last) \
435 find_next_change(sp, y, last)
437 #endif /* EXP_OPTIMIZE */
439 #define MARK_NOCHANGE(win,row) \
440 win->_line[row].firstchar = _NOCHANGE; \
441 win->_line[row].lastchar = _NOCHANGE
444 selectActiveHandle(TERMINAL_CONTROL_BLOCK * TCB)
446 if (PropOf(TCB)->lastOut != TCB->hdl) {
447 PropOf(TCB)->lastOut = TCB->hdl;
448 SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
453 restore_original_screen(TERMINAL_CONTROL_BLOCK * TCB)
456 SMALL_RECT writeRegion;
457 Properties *p = PropOf(TCB);
460 if (p->window_only) {
461 writeRegion.Top = p->SBI.srWindow.Top;
462 writeRegion.Left = p->SBI.srWindow.Left;
463 writeRegion.Bottom = p->SBI.srWindow.Bottom;
464 writeRegion.Right = p->SBI.srWindow.Right;
465 T(("... restoring window"));
468 writeRegion.Left = 0;
469 writeRegion.Bottom = (SHORT) (p->SBI.dwSize.Y - 1);
470 writeRegion.Right = (SHORT) (p->SBI.dwSize.X - 1);
471 T(("... restoring entire buffer"));
474 bufferCoord.X = bufferCoord.Y = 0;
476 if (WriteConsoleOutput(TCB->hdl,
482 mvcur(-1, -1, LINES - 2, 0);
484 T(("... restore original screen contents %s", result ? "ok" : "err"));
489 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
492 return "win32console";
496 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
499 int y, nonempty, n, x0, x1, Width, Height;
505 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
506 if (okConsoleHandle(TCB)) {
508 Width = screen_columns(sp);
509 Height = screen_lines(sp);
510 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
512 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
514 #if USE_WIDEC_SUPPORT
515 cchar_t empty[Width];
521 for (x = 0; x < Width; x++)
522 setcchar(&empty[x], blank, 0, 0, 0);
526 for (x = 0; x < Width; x++)
530 for (y = 0; y < nonempty; y++) {
531 con_write(TCB, y, 0, empty, Width);
533 CurScreen(sp)->_line[y].text,
534 (size_t) Width * sizeof(empty[0]));
536 CurScreen(sp)->_clear = FALSE;
537 NewScreen(sp)->_clear = FALSE;
538 touchwin(NewScreen(sp));
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(TCB);
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)) {
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 && (TCB->term.type.Booleans == 0)) {
652 _nc_init_termtype(&(TCB->term.type));
658 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
659 int beepFlag GCC_UNUSED)
671 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
672 char *data GCC_UNUSED,
684 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
698 get_SBI(TERMINAL_CONTROL_BLOCK * TCB)
701 Properties *p = PropOf(TCB);
702 if (GetConsoleScreenBufferInfo(TCB->hdl, &(p->SBI))) {
703 T(("GetConsoleScreenBufferInfo"));
704 T(("... buffer(X:%d Y:%d)",
707 T(("... window(X:%d Y:%d)",
708 p->SBI.dwMaximumWindowSize.X,
709 p->SBI.dwMaximumWindowSize.Y));
710 T(("... cursor(X:%d Y:%d)",
711 p->SBI.dwCursorPosition.X,
712 p->SBI.dwCursorPosition.Y));
713 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
715 p->SBI.srWindow.Bottom,
716 p->SBI.srWindow.Left,
717 p->SBI.srWindow.Right));
722 p->origin.X = p->SBI.srWindow.Left;
723 p->origin.Y = p->SBI.srWindow.Top;
727 T(("GetConsoleScreenBufferInfo ERR"));
733 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
736 int (*outc) (SCREEN *, int) GCC_UNUSED)
740 if (okConsoleHandle(TCB) &&
742 WORD a = MapColor(fore, color);
743 a |= (WORD) ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
744 SetConsoleTextAttribute(TCB->hdl, a);
750 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
755 if (okConsoleHandle(TCB)) {
756 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
757 SetConsoleTextAttribute(TCB->hdl, a);
765 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
777 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
783 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
785 if (okConsoleHandle(TCB) &&
789 if (PropOf(TCB)->buffered) {
790 *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y);
791 *Cols = (int) (PropOf(TCB)->SBI.dwSize.X);
793 *Lines = (int) (PropOf(TCB)->SBI.srWindow.Bottom + 1 -
794 PropOf(TCB)->SBI.srWindow.Top);
795 *Cols = (int) (PropOf(TCB)->SBI.srWindow.Right + 1 -
796 PropOf(TCB)->SBI.srWindow.Left);
804 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
813 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
821 if (TCB == 0 || buf == NULL)
825 iflag = buf->c_iflag;
826 lflag = buf->c_lflag;
828 GetConsoleMode(TCB->inp, &dwFlag);
831 dwFlag |= ENABLE_LINE_INPUT;
833 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
836 dwFlag |= ENABLE_ECHO_INPUT;
838 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
841 dwFlag |= ENABLE_PROCESSED_INPUT;
843 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
845 dwFlag |= ENABLE_MOUSE_INPUT;
847 buf->c_iflag = iflag;
848 buf->c_lflag = lflag;
849 SetConsoleMode(TCB->inp, dwFlag);
850 TCB->term.Nttyb = *buf;
852 iflag = TCB->term.Nttyb.c_iflag;
853 lflag = TCB->term.Nttyb.c_lflag;
854 GetConsoleMode(TCB->inp, &dwFlag);
856 if (dwFlag & ENABLE_LINE_INPUT)
859 lflag &= (tcflag_t) (~ICANON);
861 if (dwFlag & ENABLE_ECHO_INPUT)
864 lflag &= (tcflag_t) (~ECHO);
866 if (dwFlag & ENABLE_PROCESSED_INPUT)
869 iflag &= (tcflag_t) (~BRKINT);
871 TCB->term.Nttyb.c_iflag = iflag;
872 TCB->term.Nttyb.c_lflag = lflag;
874 *buf = TCB->term.Nttyb;
880 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
883 TERMINAL *_term = (TERMINAL *) TCB;
889 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"), TCB, progFlag, defFlag));
890 PropOf(TCB)->progMode = progFlag;
891 PropOf(TCB)->lastOut = progFlag ? TCB->hdl : TCB->out;
892 SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut);
894 if (progFlag) /* prog mode */ {
896 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
897 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
901 /* reset_prog_mode */
902 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
905 _nc_keypad(sp, TRUE);
910 } else { /* shell mode */
913 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
917 /* reset_shell_mode */
919 _nc_keypad(sp, FALSE);
920 NCURSES_SP_NAME(_nc_flush) (sp);
922 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
923 if (!PropOf(TCB)->buffered) {
924 if (!restore_original_screen(TCB))
934 wcon_screen_init(SCREEN *sp GCC_UNUSED)
939 wcon_wrap(SCREEN *sp GCC_UNUSED)
944 rkeycompare(const void *el1, const void *el2)
946 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
947 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
949 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
953 keycompare(const void *el1, const void *el2)
955 WORD key1 = HIWORD((*((const LONG *) el1)));
956 WORD key2 = HIWORD((*((const LONG *) el2)));
958 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
962 MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey)
966 LONG key = GenMap(vKey, 0);
973 (size_t) (N_INI + FKEYS),
977 key = *((LONG *) res);
979 code = (int) (nKey & 0x7fff);
987 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
989 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
999 * Attempt to save the screen contents. PDCurses does this if
1000 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on restoration
1001 * as if the library had allocated a console buffer.
1004 save_original_screen(TERMINAL_CONTROL_BLOCK * TCB)
1006 bool result = FALSE;
1007 Properties *p = PropOf(TCB);
1010 SMALL_RECT readRegion;
1013 bufferSize.X = p->SBI.dwSize.X;
1014 bufferSize.Y = p->SBI.dwSize.Y;
1015 want = (size_t) (bufferSize.X * bufferSize.Y);
1017 if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1018 bufferCoord.X = bufferCoord.Y = 0;
1021 readRegion.Left = 0;
1022 readRegion.Bottom = (SHORT) (bufferSize.Y - 1);
1023 readRegion.Right = (SHORT) (bufferSize.X - 1);
1025 T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d",
1026 bufferSize.Y, bufferSize.X,
1034 if (ReadConsoleOutput(TCB->hdl,
1041 T((" error %#lx", (unsigned long) GetLastError()));
1042 FreeAndNull(p->save_screen);
1044 bufferSize.X = (SHORT) (p->SBI.srWindow.Right
1045 - p->SBI.srWindow.Left + 1);
1046 bufferSize.Y = (SHORT) (p->SBI.srWindow.Bottom
1047 - p->SBI.srWindow.Top + 1);
1048 want = (size_t) (bufferSize.X * bufferSize.Y);
1050 if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) {
1051 bufferCoord.X = bufferCoord.Y = 0;
1053 readRegion.Top = p->SBI.srWindow.Top;
1054 readRegion.Left = p->SBI.srWindow.Left;
1055 readRegion.Bottom = p->SBI.srWindow.Bottom;
1056 readRegion.Right = p->SBI.srWindow.Right;
1058 T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d",
1059 bufferSize.Y, bufferSize.X,
1067 if (ReadConsoleOutput(TCB->hdl,
1073 p->window_only = TRUE;
1075 T((" error %#lx", (unsigned long) GetLastError()));
1081 T(("... save original screen contents %s", result ? "ok" : "err"));
1086 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1090 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1095 BOOL b = AllocConsole();
1098 bool buffered = TRUE;
1101 b = AttachConsole(ATTACH_PARENT_PROCESS);
1103 TCB->inp = GetStdHandle(STD_INPUT_HANDLE);
1104 TCB->out = GetStdHandle(STD_OUTPUT_HANDLE);
1106 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
1107 TCB->hdl = TCB->out;
1110 TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1113 CONSOLE_TEXTMODE_BUFFER,
1117 if (InvalidConsoleHandle(TCB->hdl)) {
1119 } else if ((TCB->prop = typeCalloc(Properties, 1)) != 0) {
1120 PropOf(TCB)->buffered = buffered;
1121 PropOf(TCB)->window_only = FALSE;
1122 if (!get_SBI(TCB)) {
1123 FreeAndNull(TCB->prop); /* force error in wcon_size */
1127 if (!save_original_screen(TCB)) {
1128 FreeAndNull(TCB->prop); /* force error in wcon_size */
1134 TCB->info.initcolor = TRUE;
1135 TCB->info.canchange = FALSE;
1136 TCB->info.hascolor = TRUE;
1137 TCB->info.caninit = TRUE;
1139 TCB->info.maxpairs = NUMPAIRS;
1140 TCB->info.maxcolors = 8;
1141 TCB->info.numlabels = 0;
1142 TCB->info.labelwidth = 0;
1143 TCB->info.labelheight = 0;
1144 TCB->info.nocolorvideo = 1;
1145 TCB->info.tabsize = 8;
1147 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
1148 T(("mouse has %ld buttons", num_buttons));
1149 TCB->info.numbuttons = (int) num_buttons;
1151 TCB->info.numbuttons = 1;
1154 TCB->info.defaultPalette = _nc_cga_palette;
1156 for (i = 0; i < (N_INI + FKEYS); i++) {
1158 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = (DWORD) keylist[i];
1160 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] =
1161 (DWORD) GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI)));
1163 qsort(PropOf(TCB)->map,
1167 qsort(PropOf(TCB)->rmap,
1172 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
1173 for (i = 0; i < NUMPAIRS; i++)
1174 PropOf(TCB)->pairs[i] = a;
1180 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1190 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8)
1191 && (b >= 0) && (b < 8)) {
1192 PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b);
1197 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1198 int color GCC_UNUSED,
1210 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
1211 int old_pair GCC_UNUSED,
1212 int pair GCC_UNUSED,
1213 int reverse GCC_UNUSED,
1214 int (*outc) (SCREEN *, int) GCC_UNUSED
1224 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1231 sp->_mouse_type = M_TERM_DRIVER;
1235 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
1243 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1246 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1250 EVENTLIST_2nd(evl));
1257 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1258 int yold GCC_UNUSED, int xold GCC_UNUSED,
1262 if (okConsoleHandle(TCB)) {
1263 Properties *p = PropOf(TCB);
1266 loc.Y = (short) (y + AdjustY(p));
1267 SetConsoleCursorPosition(TCB->hdl, loc);
1274 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1275 int labnum GCC_UNUSED,
1276 char *text GCC_UNUSED)
1285 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1286 int OnFlag GCC_UNUSED)
1295 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1297 chtype res = A_NORMAL;
1298 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1303 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1312 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1313 chtype *real_map GCC_UNUSED,
1314 chtype *fake_map GCC_UNUSED)
1316 #define DATA(a,b) { a, b }
1321 DATA('a', 0xb1), /* ACS_CKBOARD */
1322 DATA('f', 0xf8), /* ACS_DEGREE */
1323 DATA('g', 0xf1), /* ACS_PLMINUS */
1324 DATA('j', 0xd9), /* ACS_LRCORNER */
1325 DATA('l', 0xda), /* ACS_ULCORNER */
1326 DATA('k', 0xbf), /* ACS_URCORNER */
1327 DATA('m', 0xc0), /* ACS_LLCORNER */
1328 DATA('n', 0xc5), /* ACS_PLUS */
1329 DATA('q', 0xc4), /* ACS_HLINE */
1330 DATA('t', 0xc3), /* ACS_LTEE */
1331 DATA('u', 0xb4), /* ACS_RTEE */
1332 DATA('v', 0xc1), /* ACS_BTEE */
1333 DATA('w', 0xc2), /* ACS_TTEE */
1334 DATA('x', 0xb3), /* ACS_VLINE */
1335 DATA('y', 0xf3), /* ACS_LEQUAL */
1336 DATA('z', 0xf2), /* ACS_GEQUAL */
1337 DATA('0', 0xdb), /* ACS_BLOCK */
1338 DATA('{', 0xe3), /* ACS_PI */
1339 DATA('}', 0x9c), /* ACS_STERLING */
1340 DATA(',', 0xae), /* ACS_LARROW */
1341 DATA('+', 0xaf), /* ACS_RARROW */
1342 DATA('~', 0xf9), /* ACS_BULLET */
1351 for (n = 0; n < SIZEOF(table); ++n) {
1352 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1354 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1359 tdiff(FILETIME fstart, FILETIME fend)
1361 ULARGE_INTEGER ustart;
1362 ULARGE_INTEGER uend;
1365 ustart.LowPart = fstart.dwLowDateTime;
1366 ustart.HighPart = fstart.dwHighDateTime;
1367 uend.LowPart = fend.dwLowDateTime;
1368 uend.HighPart = fend.dwHighDateTime;
1370 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1375 Adjust(int milliseconds, int diff)
1377 if (milliseconds == INFINITY)
1378 return milliseconds;
1379 milliseconds -= diff;
1380 if (milliseconds < 0)
1382 return milliseconds;
1385 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1386 FROM_LEFT_2ND_BUTTON_PRESSED | \
1387 FROM_LEFT_3RD_BUTTON_PRESSED | \
1388 FROM_LEFT_4TH_BUTTON_PRESSED | \
1389 RIGHTMOST_BUTTON_PRESSED)
1392 decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask)
1400 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
1401 result |= BUTTON1_PRESSED;
1402 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
1403 result |= BUTTON2_PRESSED;
1404 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
1405 result |= BUTTON3_PRESSED;
1406 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
1407 result |= BUTTON4_PRESSED;
1409 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1410 switch (TCB->info.numbuttons) {
1412 result |= BUTTON1_PRESSED;
1415 result |= BUTTON2_PRESSED;
1418 result |= BUTTON3_PRESSED;
1421 result |= BUTTON4_PRESSED;
1430 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1434 EVENTLIST_2nd(_nc_eventlist * evl))
1437 INPUT_RECORD inp_rec;
1439 DWORD nRead = 0, rc = (DWORD) (-1);
1444 bool isImmed = (milliseconds == 0);
1446 #define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead)
1451 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1452 milliseconds, mode));
1454 if (milliseconds < 0)
1455 milliseconds = INFINITY;
1457 memset(&inp_rec, 0, sizeof(inp_rec));
1460 GetSystemTimeAsFileTime(&fstart);
1461 rc = WaitForSingleObject(TCB->inp, (DWORD) milliseconds);
1462 GetSystemTimeAsFileTime(&fend);
1463 diff = (int) tdiff(fstart, fend);
1464 milliseconds = Adjust(milliseconds, diff);
1466 if (!isImmed && milliseconds == 0)
1469 if (rc == WAIT_OBJECT_0) {
1471 b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead);
1472 if (b && nRead > 0) {
1473 b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead);
1474 if (b && nRead > 0) {
1475 switch (inp_rec.EventType) {
1477 if (mode & TW_INPUT) {
1478 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1479 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1481 if (inp_rec.Event.KeyEvent.bKeyDown) {
1483 int nKey = MapKey(TCB, vk);
1484 if ((nKey < 0) || FALSE == sp->_keypad_on) {
1497 if (decode_mouse(TCB,
1498 (inp_rec.Event.MouseEvent.dwButtonState
1499 & BUTTON_MASK)) == 0) {
1501 } else if (mode & TW_MOUSE) {
1507 selectActiveHandle(TCB);
1515 if (rc != WAIT_TIMEOUT) {
1526 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1527 code, errno, milliseconds));
1530 *timeleft = milliseconds;
1536 handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer)
1540 bool result = FALSE;
1545 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1546 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1549 * We're only interested if the button is pressed or released.
1550 * FIXME: implement continuous event-tracking.
1552 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1553 Properties *p = PropOf(TCB);
1555 memset(&work, 0, sizeof(work));
1557 if (sp->_drv_mouse_new_buttons) {
1559 work.bstate |= (mmask_t) decode_mouse(TCB, sp->_drv_mouse_new_buttons);
1563 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1564 work.bstate |= (mmask_t) (decode_mouse(TCB,
1565 sp->_drv_mouse_old_buttons)
1571 work.x = mer.dwMousePosition.X;
1572 work.y = mer.dwMousePosition.Y - AdjustY(p);
1574 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1575 sp->_drv_mouse_tail += 1;
1582 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1586 INPUT_RECORD inp_rec;
1595 memset(&inp_rec, 0, sizeof(inp_rec));
1597 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1598 while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) {
1599 if (b && nRead > 0) {
1600 if (inp_rec.EventType == KEY_EVENT) {
1601 if (!inp_rec.Event.KeyEvent.bKeyDown)
1603 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
1604 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1606 if (sp->_keypad_on) {
1607 *buf = MapKey(TCB, vk);
1614 } else { /* *buf != 0 */
1617 } else if (inp_rec.EventType == MOUSE_EVENT) {
1618 if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) {
1630 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1632 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1638 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode)
1644 LONG key = GenMap(0, (WORD) keycode);
1651 T((T_CALLED("win32con::wcon_kyExist(%p, %d)"), TCB, keycode));
1654 (size_t) (N_INI + FKEYS),
1658 key = *((LONG *) res);
1660 if (!(nKey & 0x8000))
1667 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1675 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1683 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag)
1690 LONG key = GenMap(0, (WORD) keycode);
1695 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1699 (size_t) (N_INI + FKEYS),
1703 key = *((LONG *) res);
1705 nKey = (LOWORD(key)) & 0x7fff;
1708 *(LONG *) res = GenMap(vKey, nKey);
1714 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1716 wcon_name, /* Name */
1717 wcon_CanHandle, /* CanHandle */
1718 wcon_init, /* init */
1719 wcon_release, /* release */
1720 wcon_size, /* size */
1721 wcon_sgmode, /* sgmode */
1722 wcon_conattr, /* conattr */
1723 wcon_mvcur, /* hwcur */
1724 wcon_mode, /* mode */
1725 wcon_rescol, /* rescol */
1726 wcon_rescolors, /* rescolors */
1727 wcon_setcolor, /* color */
1728 wcon_dobeepflash, /* DoBeepFlash */
1729 wcon_initpair, /* initpair */
1730 wcon_initcolor, /* initcolor */
1731 wcon_do_color, /* docolor */
1732 wcon_initmouse, /* initmouse */
1733 wcon_testmouse, /* testmouse */
1734 wcon_setfilter, /* setfilter */
1735 wcon_hwlabel, /* hwlabel */
1736 wcon_hwlabelOnOff, /* hwlabelOnOff */
1737 wcon_doupdate, /* update */
1738 wcon_defaultcolors, /* defaultcolors */
1739 wcon_print, /* print */
1740 wcon_size, /* getsize */
1741 wcon_setsize, /* setsize */
1742 wcon_initacs, /* initacs */
1743 wcon_screen_init, /* scinit */
1744 wcon_wrap, /* scexit */
1745 wcon_twait, /* twait */
1746 wcon_read, /* read */
1748 wcon_kpad, /* kpad */
1749 wcon_keyok, /* kyOk */
1750 wcon_kyExist /* kyExist */