1 /****************************************************************************
2 * Copyright (c) 1998-2014,2015 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 my_term.type.
57 MODULE_ID("$Id: win_driver.c,v 1.55 2015/02/28 21:30:23 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
) {
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
= FALSE
;
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
&& (TCB
->term
.type
.Booleans
== 0)) {
652 _nc_init_termtype(&(TCB
->term
.type
));
656 if (_nc_mingw_isconsole(0))
657 CON
.isTermInfoConsole
= TRUE
;
663 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK
* TCB
,
669 int high
= (CON
.SBI
.srWindow
.Bottom
- CON
.SBI
.srWindow
.Top
+ 1);
670 int wide
= (CON
.SBI
.srWindow
.Right
- CON
.SBI
.srWindow
.Left
+ 1);
671 int max_cells
= (high
* wide
);
674 CHAR_INFO this_screen
[max_cells
];
675 CHAR_INFO that_screen
[max_cells
];
677 SMALL_RECT this_region
;
680 if (okConsoleHandle(TCB
)) {
682 this_region
.Top
= CON
.SBI
.srWindow
.Top
;
683 this_region
.Left
= CON
.SBI
.srWindow
.Left
;
684 this_region
.Bottom
= CON
.SBI
.srWindow
.Bottom
;
685 this_region
.Right
= CON
.SBI
.srWindow
.Right
;
687 this_size
.X
= (SHORT
) wide
;
688 this_size
.Y
= (SHORT
) high
;
690 bufferCoord
.X
= this_region
.Left
;
691 bufferCoord
.Y
= this_region
.Top
;
700 memcpy(that_screen
, this_screen
, sizeof(that_screen
));
702 for (i
= 0; i
< max_cells
; i
++) {
703 that_screen
[i
].Attributes
= RevAttr(that_screen
[i
].Attributes
);
706 write_screen(CON
.hdl
, that_screen
, this_size
, bufferCoord
, &this_region
);
708 write_screen(CON
.hdl
, this_screen
, this_size
, bufferCoord
, &this_region
);
711 MessageBeep(MB_ICONWARNING
); /* MB_OK might be better */
719 wcon_print(TERMINAL_CONTROL_BLOCK
* TCB
,
720 char *data GCC_UNUSED
,
732 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK
* TCB
,
749 if (GetConsoleScreenBufferInfo(CON
.hdl
, &(CON
.SBI
))) {
750 T(("GetConsoleScreenBufferInfo"));
751 T(("... buffer(X:%d Y:%d)",
754 T(("... window(X:%d Y:%d)",
755 CON
.SBI
.dwMaximumWindowSize
.X
,
756 CON
.SBI
.dwMaximumWindowSize
.Y
));
757 T(("... cursor(X:%d Y:%d)",
758 CON
.SBI
.dwCursorPosition
.X
,
759 CON
.SBI
.dwCursorPosition
.Y
));
760 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
761 CON
.SBI
.srWindow
.Top
,
762 CON
.SBI
.srWindow
.Bottom
,
763 CON
.SBI
.srWindow
.Left
,
764 CON
.SBI
.srWindow
.Right
));
769 CON
.origin
.X
= CON
.SBI
.srWindow
.Left
;
770 CON
.origin
.Y
= CON
.SBI
.srWindow
.Top
;
774 T(("GetConsoleScreenBufferInfo ERR"));
780 wcon_setcolor(TERMINAL_CONTROL_BLOCK
* TCB
,
783 int (*outc
) (SCREEN
*, int) GCC_UNUSED
)
785 if (okConsoleHandle(TCB
)) {
786 WORD a
= MapColor(fore
, color
);
787 a
|= (WORD
) ((CON
.SBI
.wAttributes
) & (fore
? 0xfff8 : 0xff8f));
788 SetConsoleTextAttribute(CON
.hdl
, a
);
794 wcon_rescol(TERMINAL_CONTROL_BLOCK
* TCB
)
798 if (okConsoleHandle(TCB
)) {
799 WORD a
= FOREGROUND_BLUE
| FOREGROUND_RED
| FOREGROUND_GREEN
;
800 SetConsoleTextAttribute(CON
.hdl
, a
);
808 wcon_rescolors(TERMINAL_CONTROL_BLOCK
* TCB
)
820 wcon_size(TERMINAL_CONTROL_BLOCK
* TCB
, int *Lines
, int *Cols
)
824 T((T_CALLED("win32con::wcon_size(%p)"), TCB
));
826 if (okConsoleHandle(TCB
) &&
830 *Lines
= (int) (CON
.SBI
.dwSize
.Y
);
831 *Cols
= (int) (CON
.SBI
.dwSize
.X
);
833 *Lines
= (int) (CON
.SBI
.srWindow
.Bottom
+ 1 -
834 CON
.SBI
.srWindow
.Top
);
835 *Cols
= (int) (CON
.SBI
.srWindow
.Right
+ 1 -
836 CON
.SBI
.srWindow
.Left
);
844 wcon_setsize(TERMINAL_CONTROL_BLOCK
* TCB GCC_UNUSED
,
853 wcon_sgmode(TERMINAL_CONTROL_BLOCK
* TCB
, int setFlag
, TTY
* buf
)
860 if (buf
!= NULL
&& okConsoleHandle(TCB
)) {
863 iflag
= buf
->c_iflag
;
864 lflag
= buf
->c_lflag
;
866 GetConsoleMode(CON
.inp
, &dwFlag
);
869 dwFlag
|= ENABLE_LINE_INPUT
;
871 dwFlag
&= (DWORD
) (~ENABLE_LINE_INPUT
);
874 dwFlag
|= ENABLE_ECHO_INPUT
;
876 dwFlag
&= (DWORD
) (~ENABLE_ECHO_INPUT
);
879 dwFlag
|= ENABLE_PROCESSED_INPUT
;
881 dwFlag
&= (DWORD
) (~ENABLE_PROCESSED_INPUT
);
883 dwFlag
|= ENABLE_MOUSE_INPUT
;
885 buf
->c_iflag
= iflag
;
886 buf
->c_lflag
= lflag
;
887 SetConsoleMode(CON
.inp
, dwFlag
);
888 TCB
->term
.Nttyb
= *buf
;
890 iflag
= TCB
->term
.Nttyb
.c_iflag
;
891 lflag
= TCB
->term
.Nttyb
.c_lflag
;
892 GetConsoleMode(CON
.inp
, &dwFlag
);
894 if (dwFlag
& ENABLE_LINE_INPUT
)
897 lflag
&= (tcflag_t
) (~ICANON
);
899 if (dwFlag
& ENABLE_ECHO_INPUT
)
902 lflag
&= (tcflag_t
) (~ECHO
);
904 if (dwFlag
& ENABLE_PROCESSED_INPUT
)
907 iflag
&= (tcflag_t
) (~BRKINT
);
909 TCB
->term
.Nttyb
.c_iflag
= iflag
;
910 TCB
->term
.Nttyb
.c_lflag
= lflag
;
912 *buf
= TCB
->term
.Nttyb
;
923 * In "normal" mode, reset the buffer- and window-sizes back to their original values.
926 set_scrollback(bool normal
, CONSOLE_SCREEN_BUFFER_INFO
* info
)
930 bool changed
= FALSE
;
932 T((T_CALLED("win32con::set_scrollback(%s)"),
937 T(("... SBI.srWindow %d,%d .. %d,%d",
940 info
->srWindow
.Bottom
,
941 info
->srWindow
.Right
));
942 T(("... SBI.dwSize %dx%d",
947 rect
= info
->srWindow
;
948 coord
= info
->dwSize
;
949 if (memcmp(info
, &CON
.SBI
, sizeof(*info
)) != 0) {
954 int high
= info
->srWindow
.Bottom
- info
->srWindow
.Top
+ 1;
955 int wide
= info
->srWindow
.Right
- info
->srWindow
.Left
+ 1;
957 if (high
< MIN_HIGH
) {
958 T(("... height %d < %d", high
, MIN_HIGH
));
962 if (wide
< MIN_WIDE
) {
963 T(("... width %d < %d", wide
, MIN_WIDE
));
970 rect
.Right
= (SHORT
) (wide
- 1);
971 rect
.Bottom
= (SHORT
) (high
- 1);
973 coord
.X
= (SHORT
) wide
;
974 coord
.Y
= (SHORT
) high
;
976 if (info
->dwSize
.Y
!= high
||
977 info
->dwSize
.X
!= wide
||
978 info
->srWindow
.Top
!= 0 ||
979 info
->srWindow
.Left
!= 0) {
986 T(("... coord %d,%d", coord
.Y
, coord
.X
));
987 T(("... rect %d,%d - %d,%d",
989 rect
.Bottom
, rect
.Right
));
990 SetConsoleScreenBufferSize(CON
.hdl
, coord
); /* dwSize */
991 SetConsoleWindowInfo(CON
.hdl
, TRUE
, &rect
); /* srWindow */
998 wcon_mode(TERMINAL_CONTROL_BLOCK
* TCB
, int progFlag
, int defFlag
)
1001 TERMINAL
*_term
= (TERMINAL
*) TCB
;
1004 if (okConsoleHandle(TCB
)) {
1007 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"),
1008 TCB
, progFlag
, defFlag
));
1010 CON
.progMode
= progFlag
;
1011 CON
.lastOut
= progFlag
? CON
.hdl
: CON
.out
;
1012 SetConsoleActiveScreenBuffer(CON
.lastOut
);
1014 if (progFlag
) /* prog mode */ {
1016 if ((wcon_sgmode(TCB
, FALSE
, &(_term
->Nttyb
)) == OK
)) {
1017 _term
->Nttyb
.c_oflag
&= (tcflag_t
) (~OFLAGS_TABS
);
1021 /* reset_prog_mode */
1022 if (wcon_sgmode(TCB
, TRUE
, &(_term
->Nttyb
)) == OK
) {
1025 _nc_keypad(sp
, TRUE
);
1027 if (!CON
.buffered
) {
1028 set_scrollback(FALSE
, &CON
.SBI
);
1033 T(("... buffered:%d, clear:%d", CON
.buffered
, CurScreen(sp
)->_clear
));
1034 } else { /* shell mode */
1036 /* def_shell_mode */
1037 if (wcon_sgmode(TCB
, FALSE
, &(_term
->Ottyb
)) == OK
) {
1041 /* reset_shell_mode */
1043 _nc_keypad(sp
, FALSE
);
1044 NCURSES_SP_NAME(_nc_flush
) (sp
);
1046 code
= wcon_sgmode(TCB
, TRUE
, &(_term
->Ottyb
));
1047 if (!CON
.buffered
) {
1048 set_scrollback(TRUE
, &CON
.save_SBI
);
1049 if (!restore_original_screen())
1052 SetConsoleCursorInfo(CON
.hdl
, &CON
.save_CI
);
1061 wcon_screen_init(SCREEN
*sp GCC_UNUSED
)
1066 wcon_wrap(SCREEN
*sp GCC_UNUSED
)
1071 rkeycompare(const void *el1
, const void *el2
)
1073 WORD key1
= (LOWORD((*((const LONG
*) el1
)))) & 0x7fff;
1074 WORD key2
= (LOWORD((*((const LONG
*) el2
)))) & 0x7fff;
1076 return ((key1
< key2
) ? -1 : ((key1
== key2
) ? 0 : 1));
1080 keycompare(const void *el1
, const void *el2
)
1082 WORD key1
= HIWORD((*((const LONG
*) el1
)));
1083 WORD key2
= HIWORD((*((const LONG
*) el2
)));
1085 return ((key1
< key2
) ? -1 : ((key1
== key2
) ? 0 : 1));
1093 LONG key
= GenMap(vKey
, 0);
1098 (size_t) (N_INI
+ FKEYS
),
1102 key
= *((LONG
*) res
);
1104 code
= (int) (nKey
& 0x7fff);
1116 LONG key
= GenMap(vKey
, 0);
1121 (size_t) (N_INI
+ FKEYS
),
1125 key
= *((LONG
*) res
);
1127 code
= (int) (nKey
& 0x7fff);
1135 wcon_release(TERMINAL_CONTROL_BLOCK
* TCB
)
1137 T((T_CALLED("win32con::wcon_release(%p)"), TCB
));
1147 read_screen_data(void)
1149 bool result
= FALSE
;
1153 CON
.save_size
.X
= (SHORT
) (CON
.save_region
.Right
1154 - CON
.save_region
.Left
+ 1);
1155 CON
.save_size
.Y
= (SHORT
) (CON
.save_region
.Bottom
1156 - CON
.save_region
.Top
+ 1);
1158 want
= (size_t) (CON
.save_size
.X
* CON
.save_size
.Y
);
1160 if ((CON
.save_screen
= malloc(want
* sizeof(CHAR_INFO
))) != 0) {
1161 bufferCoord
.X
= (SHORT
) (CON
.window_only
? CON
.SBI
.srWindow
.Left
: 0);
1162 bufferCoord
.Y
= (SHORT
) (CON
.window_only
? CON
.SBI
.srWindow
.Top
: 0);
1164 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
1165 CON
.window_only
? "window" : "buffer",
1166 CON
.save_size
.Y
, CON
.save_size
.X
,
1167 CON
.save_region
.Top
,
1168 CON
.save_region
.Left
,
1169 CON
.save_region
.Bottom
,
1170 CON
.save_region
.Right
,
1174 if (read_screen(CON
.hdl
,
1178 &CON
.save_region
)) {
1181 T((" error %#lx", (unsigned long) GetLastError()));
1182 FreeAndNull(CON
.save_screen
);
1190 * Attempt to save the screen contents. PDCurses does this if
1191 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
1192 * restoration as if the library had allocated a console buffer. MSDN
1193 * says that the data which can be read is limited to 64Kb (and may be
1197 save_original_screen(void)
1199 bool result
= FALSE
;
1201 CON
.save_region
.Top
= 0;
1202 CON
.save_region
.Left
= 0;
1203 CON
.save_region
.Bottom
= (SHORT
) (CON
.SBI
.dwSize
.Y
- 1);
1204 CON
.save_region
.Right
= (SHORT
) (CON
.SBI
.dwSize
.X
- 1);
1206 if (read_screen_data()) {
1210 CON
.save_region
.Top
= CON
.SBI
.srWindow
.Top
;
1211 CON
.save_region
.Left
= CON
.SBI
.srWindow
.Left
;
1212 CON
.save_region
.Bottom
= CON
.SBI
.srWindow
.Bottom
;
1213 CON
.save_region
.Right
= CON
.SBI
.srWindow
.Right
;
1215 CON
.window_only
= TRUE
;
1217 if (read_screen_data()) {
1222 T(("... save original screen contents %s", result
? "ok" : "err"));
1227 wcon_init(TERMINAL_CONTROL_BLOCK
* TCB
)
1229 T((T_CALLED("win32con::wcon_init(%p)"), TCB
));
1234 if (!InitConsole()) {
1238 TCB
->info
.initcolor
= TRUE
;
1239 TCB
->info
.canchange
= FALSE
;
1240 TCB
->info
.hascolor
= TRUE
;
1241 TCB
->info
.caninit
= TRUE
;
1243 TCB
->info
.maxpairs
= NUMPAIRS
;
1244 TCB
->info
.maxcolors
= 8;
1245 TCB
->info
.numlabels
= 0;
1246 TCB
->info
.labelwidth
= 0;
1247 TCB
->info
.labelheight
= 0;
1248 TCB
->info
.nocolorvideo
= 1;
1249 TCB
->info
.tabsize
= 8;
1251 TCB
->info
.numbuttons
= CON
.numButtons
;
1252 TCB
->info
.defaultPalette
= _nc_cga_palette
;
1259 wcon_initpair(TERMINAL_CONTROL_BLOCK
* TCB
,
1266 if (okConsoleHandle(TCB
)) {
1269 if ((pair
> 0) && (pair
< NUMPAIRS
) && (f
>= 0) && (f
< 8)
1270 && (b
>= 0) && (b
< 8)) {
1271 CON
.pairs
[pair
] = MapColor(true, f
) | MapColor(false, b
);
1277 wcon_initcolor(TERMINAL_CONTROL_BLOCK
* TCB
,
1278 int color GCC_UNUSED
,
1290 wcon_do_color(TERMINAL_CONTROL_BLOCK
* TCB
,
1291 int old_pair GCC_UNUSED
,
1292 int pair GCC_UNUSED
,
1293 int reverse GCC_UNUSED
,
1294 int (*outc
) (SCREEN
*, int) GCC_UNUSED
1304 wcon_initmouse(TERMINAL_CONTROL_BLOCK
* TCB
)
1308 if (okConsoleHandle(TCB
)) {
1311 sp
->_mouse_type
= M_TERM_DRIVER
;
1316 wcon_testmouse(TERMINAL_CONTROL_BLOCK
* TCB
, int delay
)
1321 if (okConsoleHandle(TCB
)) {
1324 if (sp
->_drv_mouse_head
< sp
->_drv_mouse_tail
) {
1327 rc
= TCBOf(sp
)->drv
->td_twait(TCBOf(sp
),
1331 EVENTLIST_2nd(evl
));
1339 wcon_mvcur(TERMINAL_CONTROL_BLOCK
* TCB
,
1340 int yold GCC_UNUSED
, int xold GCC_UNUSED
,
1344 if (okConsoleHandle(TCB
)) {
1347 loc
.Y
= (short) (y
+ AdjustY());
1348 SetConsoleCursorPosition(CON
.hdl
, loc
);
1355 wcon_hwlabel(TERMINAL_CONTROL_BLOCK
* TCB
,
1356 int labnum GCC_UNUSED
,
1357 char *text GCC_UNUSED
)
1366 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK
* TCB
,
1367 int OnFlag GCC_UNUSED
)
1376 wcon_conattr(TERMINAL_CONTROL_BLOCK
* TCB GCC_UNUSED
)
1378 chtype res
= A_NORMAL
;
1379 res
|= (A_BOLD
| A_DIM
| A_REVERSE
| A_STANDOUT
| A_COLOR
);
1384 wcon_setfilter(TERMINAL_CONTROL_BLOCK
* TCB
)
1393 wcon_initacs(TERMINAL_CONTROL_BLOCK
* TCB
,
1394 chtype
*real_map GCC_UNUSED
,
1395 chtype
*fake_map GCC_UNUSED
)
1397 #define DATA(a,b) { a, b }
1402 DATA('a', 0xb1), /* ACS_CKBOARD */
1403 DATA('f', 0xf8), /* ACS_DEGREE */
1404 DATA('g', 0xf1), /* ACS_PLMINUS */
1405 DATA('j', 0xd9), /* ACS_LRCORNER */
1406 DATA('l', 0xda), /* ACS_ULCORNER */
1407 DATA('k', 0xbf), /* ACS_URCORNER */
1408 DATA('m', 0xc0), /* ACS_LLCORNER */
1409 DATA('n', 0xc5), /* ACS_PLUS */
1410 DATA('q', 0xc4), /* ACS_HLINE */
1411 DATA('t', 0xc3), /* ACS_LTEE */
1412 DATA('u', 0xb4), /* ACS_RTEE */
1413 DATA('v', 0xc1), /* ACS_BTEE */
1414 DATA('w', 0xc2), /* ACS_TTEE */
1415 DATA('x', 0xb3), /* ACS_VLINE */
1416 DATA('y', 0xf3), /* ACS_LEQUAL */
1417 DATA('z', 0xf2), /* ACS_GEQUAL */
1418 DATA('0', 0xdb), /* ACS_BLOCK */
1419 DATA('{', 0xe3), /* ACS_PI */
1420 DATA('}', 0x9c), /* ACS_STERLING */
1421 DATA(',', 0xae), /* ACS_LARROW */
1422 DATA('+', 0xaf), /* ACS_RARROW */
1423 DATA('~', 0xf9), /* ACS_BULLET */
1429 if (okConsoleHandle(TCB
)) {
1432 for (n
= 0; n
< SIZEOF(table
); ++n
) {
1433 real_map
[table
[n
].acs_code
] = (chtype
) table
[n
].use_code
| A_ALTCHARSET
;
1435 sp
->_screen_acs_map
[table
[n
].acs_code
] = TRUE
;
1441 tdiff(FILETIME fstart
, FILETIME fend
)
1443 ULARGE_INTEGER ustart
;
1444 ULARGE_INTEGER uend
;
1447 ustart
.LowPart
= fstart
.dwLowDateTime
;
1448 ustart
.HighPart
= fstart
.dwHighDateTime
;
1449 uend
.LowPart
= fend
.dwLowDateTime
;
1450 uend
.HighPart
= fend
.dwHighDateTime
;
1452 diff
= (uend
.QuadPart
- ustart
.QuadPart
) / 10000;
1457 Adjust(int milliseconds
, int diff
)
1459 if (milliseconds
!= INFINITY
) {
1460 milliseconds
-= diff
;
1461 if (milliseconds
< 0)
1464 return milliseconds
;
1467 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
1468 FROM_LEFT_2ND_BUTTON_PRESSED | \
1469 FROM_LEFT_3RD_BUTTON_PRESSED | \
1470 FROM_LEFT_4TH_BUTTON_PRESSED | \
1471 RIGHTMOST_BUTTON_PRESSED)
1474 decode_mouse(SCREEN
*sp
, int mask
)
1479 assert(sp
&& console_initialized
);
1481 if (mask
& FROM_LEFT_1ST_BUTTON_PRESSED
)
1482 result
|= BUTTON1_PRESSED
;
1483 if (mask
& FROM_LEFT_2ND_BUTTON_PRESSED
)
1484 result
|= BUTTON2_PRESSED
;
1485 if (mask
& FROM_LEFT_3RD_BUTTON_PRESSED
)
1486 result
|= BUTTON3_PRESSED
;
1487 if (mask
& FROM_LEFT_4TH_BUTTON_PRESSED
)
1488 result
|= BUTTON4_PRESSED
;
1490 if (mask
& RIGHTMOST_BUTTON_PRESSED
) {
1491 switch (CON
.numButtons
) {
1493 result
|= BUTTON1_PRESSED
;
1496 result
|= BUTTON2_PRESSED
;
1499 result
|= BUTTON3_PRESSED
;
1502 result
|= BUTTON4_PRESSED
;
1517 EVENTLIST_2nd(_nc_eventlist
* evl
))
1519 INPUT_RECORD inp_rec
;
1521 DWORD nRead
= 0, rc
= (DWORD
) (-1);
1526 bool isImmed
= (milliseconds
== 0);
1528 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1532 TR(TRACE_IEVENT
, ("start twait: %d milliseconds, mode: %d",
1533 milliseconds
, mode
));
1535 if (milliseconds
< 0)
1536 milliseconds
= INFINITY
;
1538 memset(&inp_rec
, 0, sizeof(inp_rec
));
1541 GetSystemTimeAsFileTime(&fstart
);
1542 rc
= WaitForSingleObject(fd
, (DWORD
) milliseconds
);
1543 GetSystemTimeAsFileTime(&fend
);
1544 diff
= (int) tdiff(fstart
, fend
);
1545 milliseconds
= Adjust(milliseconds
, diff
);
1547 if (!isImmed
&& milliseconds
<= 0)
1550 if (rc
== WAIT_OBJECT_0
) {
1552 b
= GetNumberOfConsoleInputEvents(fd
, &nRead
);
1553 if (b
&& nRead
> 0) {
1554 b
= PeekConsoleInput(fd
, &inp_rec
, 1, &nRead
);
1555 if (b
&& nRead
> 0) {
1556 switch (inp_rec
.EventType
) {
1558 if (mode
& TW_INPUT
) {
1559 WORD vk
= inp_rec
.Event
.KeyEvent
.wVirtualKeyCode
;
1560 char ch
= inp_rec
.Event
.KeyEvent
.uChar
.AsciiChar
;
1562 if (inp_rec
.Event
.KeyEvent
.bKeyDown
) {
1564 int nKey
= MapKey(vk
);
1578 if (decode_mouse(sp
,
1579 (inp_rec
.Event
.MouseEvent
.dwButtonState
1580 & BUTTON_MASK
)) == 0) {
1582 } else if (mode
& TW_MOUSE
) {
1587 /* e.g., FOCUS_EVENT */
1590 selectActiveHandle();
1598 if (rc
!= WAIT_TIMEOUT
) {
1609 TR(TRACE_IEVENT
, ("end twait: returned %d (%d), remaining time %d msec",
1610 code
, errno
, milliseconds
));
1613 *timeleft
= milliseconds
;
1619 wcon_twait(TERMINAL_CONTROL_BLOCK
* TCB
,
1623 EVENTLIST_2nd(_nc_eventlist
* evl
))
1628 if (okConsoleHandle(TCB
)) {
1631 code
= console_twait(sp
,
1635 timeleft
EVENTLIST_2nd(_nc_eventlist
* evl
));
1641 handle_mouse(SCREEN
*sp
, MOUSE_EVENT_RECORD mer
)
1644 bool result
= FALSE
;
1648 sp
->_drv_mouse_old_buttons
= sp
->_drv_mouse_new_buttons
;
1649 sp
->_drv_mouse_new_buttons
= mer
.dwButtonState
& BUTTON_MASK
;
1652 * We're only interested if the button is pressed or released.
1653 * FIXME: implement continuous event-tracking.
1655 if (sp
->_drv_mouse_new_buttons
!= sp
->_drv_mouse_old_buttons
) {
1657 memset(&work
, 0, sizeof(work
));
1659 if (sp
->_drv_mouse_new_buttons
) {
1661 work
.bstate
|= (mmask_t
) decode_mouse(sp
, sp
->_drv_mouse_new_buttons
);
1665 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1666 work
.bstate
|= (mmask_t
) (decode_mouse(sp
,
1667 sp
->_drv_mouse_old_buttons
)
1673 work
.x
= mer
.dwMousePosition
.X
;
1674 work
.y
= mer
.dwMousePosition
.Y
- AdjustY();
1676 sp
->_drv_mouse_fifo
[sp
->_drv_mouse_tail
] = work
;
1677 sp
->_drv_mouse_tail
+= 1;
1684 wcon_read(TERMINAL_CONTROL_BLOCK
* TCB
, int *buf
)
1689 T((T_CALLED("win32con::wcon_read(%p)"), TCB
));
1692 if (okConsoleHandle(TCB
)) {
1695 n
= _nc_mingw_console_read(sp
, CON
.inp
, buf
);
1701 wcon_nap(TERMINAL_CONTROL_BLOCK
* TCB GCC_UNUSED
, int ms
)
1703 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB
, ms
));
1709 wcon_cursorSet(TERMINAL_CONTROL_BLOCK
* TCB GCC_UNUSED
, int mode
)
1713 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode
));
1714 if (okConsoleHandle(TCB
)) {
1715 CONSOLE_CURSOR_INFO this_CI
= CON
.save_CI
;
1718 this_CI
.bVisible
= FALSE
;
1723 this_CI
.dwSize
= 100;
1726 SetConsoleCursorInfo(CON
.hdl
, &this_CI
);
1732 wcon_kyExist(TERMINAL_CONTROL_BLOCK
* TCB GCC_UNUSED
, int keycode
)
1737 LONG key
= GenMap(0, (WORD
) keycode
);
1739 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode
));
1742 (size_t) (N_INI
+ FKEYS
),
1746 key
= *((LONG
*) res
);
1748 if (!(nKey
& 0x8000))
1755 wcon_kpad(TERMINAL_CONTROL_BLOCK
* TCB
, int flag GCC_UNUSED
)
1760 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB
, flag
));
1762 if (okConsoleHandle(TCB
)) {
1773 wcon_keyok(TERMINAL_CONTROL_BLOCK
* TCB
,
1782 LONG key
= GenMap(0, (WORD
) keycode
);
1784 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB
, keycode
, flag
));
1786 if (okConsoleHandle(TCB
)) {
1792 (size_t) (N_INI
+ FKEYS
),
1796 key
= *((LONG
*) res
);
1798 nKey
= (LOWORD(key
)) & 0x7fff;
1801 *(LONG
*) res
= GenMap(vKey
, nKey
);
1808 NCURSES_EXPORT_VAR (TERM_DRIVER
) _nc_WIN_DRIVER
= {
1810 wcon_name
, /* Name */
1811 wcon_CanHandle
, /* CanHandle */
1812 wcon_init
, /* init */
1813 wcon_release
, /* release */
1814 wcon_size
, /* size */
1815 wcon_sgmode
, /* sgmode */
1816 wcon_conattr
, /* conattr */
1817 wcon_mvcur
, /* hwcur */
1818 wcon_mode
, /* mode */
1819 wcon_rescol
, /* rescol */
1820 wcon_rescolors
, /* rescolors */
1821 wcon_setcolor
, /* color */
1822 wcon_dobeepflash
, /* DoBeepFlash */
1823 wcon_initpair
, /* initpair */
1824 wcon_initcolor
, /* initcolor */
1825 wcon_do_color
, /* docolor */
1826 wcon_initmouse
, /* initmouse */
1827 wcon_testmouse
, /* testmouse */
1828 wcon_setfilter
, /* setfilter */
1829 wcon_hwlabel
, /* hwlabel */
1830 wcon_hwlabelOnOff
, /* hwlabelOnOff */
1831 wcon_doupdate
, /* update */
1832 wcon_defaultcolors
, /* defaultcolors */
1833 wcon_print
, /* print */
1834 wcon_size
, /* getsize */
1835 wcon_setsize
, /* setsize */
1836 wcon_initacs
, /* initacs */
1837 wcon_screen_init
, /* scinit */
1838 wcon_wrap
, /* scexit */
1839 wcon_twait
, /* twait */
1840 wcon_read
, /* read */
1842 wcon_kpad
, /* kpad */
1843 wcon_keyok
, /* kyOk */
1844 wcon_kyExist
, /* kyExist */
1845 wcon_cursorSet
/* cursorSet */
1848 /* --------------------------------------------------------- */
1853 intptr_t value
= _get_osfhandle(fd
);
1854 return (HANDLE
) value
;
1857 #if WINVER >= 0x0600
1858 /* This function tests, whether or not the ncurses application
1859 is running as a descendant of MSYS2/cygwin mintty terminal
1860 application. mintty doesn't use Windows Console for it's screen
1861 I/O, so the native Windows _isatty doesn't recognize it as
1862 character device. But we can discover we are at the end of an
1863 Pipe and can query to server side of the pipe, looking whether
1864 or not this is mintty.
1867 _ismintty(int fd
, LPHANDLE pMinTTY
)
1869 HANDLE handle
= get_handle(fd
);
1873 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd
, pMinTTY
));
1875 if (handle
!= INVALID_HANDLE_VALUE
) {
1876 dw
= GetFileType(handle
);
1877 if (dw
== FILE_TYPE_PIPE
) {
1878 if (GetNamedPipeInfo(handle
, 0, 0, 0, 0)) {
1881 if (GetNamedPipeServerProcessId(handle
, &pPid
)) {
1882 TCHAR buf
[MAX_PATH
];
1884 /* These security attributes may allow us to
1885 create a remote thread in mintty to manipulate
1886 the terminal state remotely */
1887 HANDLE pHandle
= OpenProcess(
1888 PROCESS_CREATE_THREAD
1889 | PROCESS_QUERY_INFORMATION
1890 | PROCESS_VM_OPERATION
1896 *pMinTTY
= INVALID_HANDLE_VALUE
;
1897 if (pHandle
!= INVALID_HANDLE_VALUE
) {
1898 if ((len
= GetProcessImageFileName(
1902 array_length(buf
)))) {
1903 TCHAR
*pos
= _tcsrchr(buf
, _T('\\'));
1906 if (_tcsnicmp(pos
, _TEXT("mintty.exe"), 10)
1923 /* Borrowed from ansicon project.
1924 Check whether or not an I/O handle is associated with
1928 IsConsoleHandle(HANDLE hdl
)
1933 if (!GetConsoleMode(hdl
, &dwFlag
)) {
1934 result
= (int) WriteConsoleA(hdl
, NULL
, 0, &dwFlag
, NULL
);
1936 result
= (int) (dwFlag
& ENABLE_PROCESSED_OUTPUT
);
1941 /* Our replacement for the systems _isatty to include also
1942 a test for mintty. This is called from the NC_ISATTY macro
1943 defined in curses.priv.h
1946 _nc_mingw_isatty(int fd
)
1951 #define SysISATTY(fd) _isatty(fd)
1953 #define SysISATTY(fd) isatty(fd)
1955 if (SysISATTY(fd
)) {
1958 #if WINVER >= 0x0600
1959 result
= _ismintty(fd
, NULL
);
1965 /* This is used when running in terminfo mode to discover,
1966 whether or not the "terminal" is actually a Windows
1967 Console. It's the responsibilty of the console to deal
1968 with the terminal escape sequences that are sent by
1972 _nc_mingw_isconsole(int fd
)
1974 HANDLE hdl
= get_handle(fd
);
1977 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd
));
1979 code
= (int) IsConsoleHandle(hdl
);
1984 #define TC_PROLOGUE(fd) \
1986 TERMINAL *term = 0; \
1988 if (_nc_screen_chain == 0) \
1990 for (each_screen(sp)) { \
1991 if (sp->_term && (sp->_term->Filedes == fd)) { \
1999 _nc_mingw_tcsetattr(
2001 int optional_action GCC_UNUSED
,
2002 const struct termios
*arg
)
2006 if (_nc_mingw_isconsole(fd
)) {
2008 HANDLE ofd
= get_handle(fd
);
2009 if (ofd
!= INVALID_HANDLE_VALUE
) {
2011 if (arg
->c_lflag
& ICANON
)
2012 dwFlag
|= ENABLE_LINE_INPUT
;
2014 dwFlag
= dwFlag
& (DWORD
) (~ENABLE_LINE_INPUT
);
2016 if (arg
->c_lflag
& ECHO
)
2017 dwFlag
= dwFlag
| ENABLE_ECHO_INPUT
;
2019 dwFlag
= dwFlag
& (DWORD
) (~ENABLE_ECHO_INPUT
);
2021 if (arg
->c_iflag
& BRKINT
)
2022 dwFlag
|= ENABLE_PROCESSED_INPUT
;
2024 dwFlag
= dwFlag
& (DWORD
) (~ENABLE_PROCESSED_INPUT
);
2026 dwFlag
|= ENABLE_MOUSE_INPUT
;
2027 SetConsoleMode(ofd
, dwFlag
);
2038 _nc_mingw_tcgetattr(int fd
, struct termios
*arg
)
2042 if (_nc_mingw_isconsole(fd
)) {
2050 _nc_mingw_tcflush(int fd
, int queue
)
2055 if (_nc_mingw_isconsole(fd
)) {
2056 if (queue
== TCIFLUSH
) {
2057 BOOL b
= FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE
));
2059 return (int) GetLastError();
2066 _nc_mingw_testmouse(
2075 if (sp
->_drv_mouse_head
< sp
->_drv_mouse_tail
) {
2078 rc
= console_twait(sp
,
2083 EVENTLIST_2nd(evl
));
2089 _nc_mingw_console_read(
2095 INPUT_RECORD inp_rec
;
2103 memset(&inp_rec
, 0, sizeof(inp_rec
));
2105 T((T_CALLED("_nc_mingw_console_read(%p)"), sp
));
2107 while ((b
= ReadConsoleInput(fd
, &inp_rec
, 1, &nRead
))) {
2108 if (b
&& nRead
> 0) {
2112 if (inp_rec
.EventType
== KEY_EVENT
) {
2113 if (!inp_rec
.Event
.KeyEvent
.bKeyDown
)
2115 *buf
= (int) inp_rec
.Event
.KeyEvent
.uChar
.AsciiChar
;
2116 vk
= inp_rec
.Event
.KeyEvent
.wVirtualKeyCode
;
2118 * There are 24 virtual function-keys, and typically
2119 * 12 function-keys on a keyboard. Use the shift-modifier
2120 * to provide the remaining 12 keys.
2122 if (vk
>= VK_F1
&& vk
<= VK_F12
) {
2123 if (inp_rec
.Event
.KeyEvent
.dwControlKeyState
& SHIFT_PRESSED
) {
2124 vk
= (WORD
) (vk
+ 12);
2128 int key
= MapKey(vk
);
2131 if (sp
->_keypad_on
) {
2139 } else if (inp_rec
.EventType
== MOUSE_EVENT
) {
2140 if (handle_mouse(sp
,
2141 inp_rec
.Event
.MouseEvent
)) {
2155 /* initalize once, or not at all */
2156 if (!console_initialized
) {
2160 BOOL buffered
= TRUE
;
2164 if (_nc_mingw_isatty(0)) {
2165 CON
.isMinTTY
= TRUE
;
2168 for (i
= 0; i
< (N_INI
+ FKEYS
); i
++) {
2170 CON
.rmap
[i
] = CON
.map
[i
] =
2172 CON
.ansi_map
[i
] = (DWORD
) ansi_keys
[i
];
2174 CON
.rmap
[i
] = CON
.map
[i
] =
2175 (DWORD
) GenMap((VK_F1
+ (i
- N_INI
)),
2176 (KEY_F(1) + (i
- N_INI
)));
2178 (DWORD
) GenMap((VK_F1
+ (i
- N_INI
)),
2179 (';' + (i
- N_INI
)));
2195 if (GetNumberOfConsoleMouseButtons(&num_buttons
)) {
2196 CON
.numButtons
= (int) num_buttons
;
2201 a
= MapColor(true, COLOR_WHITE
) | MapColor(false, COLOR_BLACK
);
2202 for (i
= 0; i
< NUMPAIRS
; i
++)
2205 CON
.inp
= GetStdHandle(STD_INPUT_HANDLE
);
2206 CON
.out
= GetStdHandle(STD_OUTPUT_HANDLE
);
2211 b
= AttachConsole(ATTACH_PARENT_PROCESS
);
2213 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2214 T(("... will not buffer console"));
2218 T(("... creating console buffer"));
2219 CON
.hdl
= CreateConsoleScreenBuffer(GENERIC_READ
| GENERIC_WRITE
,
2222 CONSOLE_TEXTMODE_BUFFER
,
2226 if (CON
.hdl
!= INVALID_HANDLE_VALUE
) {
2227 CON
.buffered
= buffered
;
2229 CON
.save_SBI
= CON
.SBI
;
2231 save_original_screen();
2232 set_scrollback(FALSE
, &CON
.SBI
);
2234 GetConsoleCursorInfo(CON
.hdl
, &CON
.save_CI
);
2235 T(("... initial cursor is %svisible, %d%%",
2236 (CON
.save_CI
.bVisible
? "" : "not-"),
2237 (int) CON
.save_CI
.dwSize
));
2240 console_initialized
= TRUE
;
2242 return (CON
.hdl
!= INVALID_HANDLE_VALUE
);
2246 okConsoleHandle(TERMINAL_CONTROL_BLOCK
* TCB
)
2248 return ((TCB
!= 0) &&
2249 (TCB
->magic
== WINMAGIC
) &&
2254 * While a constructor would ensure that this module is initialized, that will
2255 * interfere with applications that may combine this with GUI interfaces.
2259 __attribute__((constructor
))
2260 void _enter_console(void)
2262 (void) InitConsole();