xref: /freebsd/contrib/ncurses/ncurses/tinfo/lib_win32con.c (revision 68ad2b0d7af2a3571c4abac9afa712f9b09b721c)
1 /****************************************************************************
2  * Copyright 2020-2024,2025 Thomas E. Dickey                                *
3  * Copyright 1998-2009,2010 Free Software Foundation, Inc.                  *
4  *                                                                          *
5  * Permission is hereby granted, free of charge, to any person obtaining a  *
6  * copy of this software and associated documentation files (the            *
7  * "Software"), to deal in the Software without restriction, including      *
8  * without limitation the rights to use, copy, modify, merge, publish,      *
9  * distribute, distribute with modifications, sublicense, and/or sell       *
10  * copies of the Software, and to permit persons to whom the Software is    *
11  * furnished to do so, subject to the following conditions:                 *
12  *                                                                          *
13  * The above copyright notice and this permission notice shall be included  *
14  * in all copies or substantial portions of the Software.                   *
15  *                                                                          *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
17  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
18  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
19  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
20  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
21  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
22  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
23  *                                                                          *
24  * Except as contained in this notice, the name(s) of the above copyright   *
25  * holders shall not be used in advertising or otherwise to promote the     *
26  * sale, use or other dealings in this Software without prior written       *
27  * authorization.                                                           *
28  ****************************************************************************/
29 
30 /****************************************************************************
31  *  Author: Juergen Pfeifer                                                 *
32  *     and: Thomas E. Dickey                                                *
33  ****************************************************************************/
34 
35 /*
36  * TODO - GetMousePos(POINT * result) from ntconio.c
37  */
38 
39 #define TTY int			/* FIXME: TTY originalMode */
40 #include <curses.priv.h>
41 #include <nc_win32.h>
42 
43 #ifndef _O_BINARY
44 #define _O_BINARY 0		/* FIXME: not defined in MSYS2 base */
45 #endif
46 
47 MODULE_ID("$Id: lib_win32con.c,v 1.50 2025/12/27 21:49:45 tom Exp $")
48 
49 #if defined(_NC_WINDOWS)
50 
51 #define CONTROL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
52 
53 static bool read_screen_data(void);
54 
55 #define GenMap(vKey,key) MAKELONG(key, vKey)
56 /* *INDENT-OFF* */
57 static const LONG keylist[] =
58 {
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)
69 };
70 static const LONG ansi_keys[] =
71 {
72     GenMap(VK_PRIOR,  'I'),
73     GenMap(VK_NEXT,   'Q'),
74     GenMap(VK_END,    'O'),
75     GenMap(VK_HOME,   'H'),
76     GenMap(VK_LEFT,   'K'),
77     GenMap(VK_UP,     'H'),
78     GenMap(VK_RIGHT,  'M'),
79     GenMap(VK_DOWN,   'P'),
80     GenMap(VK_DELETE, 'S'),
81     GenMap(VK_INSERT, 'R')
82 };
83 /* *INDENT-ON* */
84 #define array_length(a) (sizeof(a)/sizeof(a[0]))
85 #define N_INI ((int)array_length(keylist))
86 #define FKEYS 24
87 #define MAPSIZE (FKEYS + N_INI)
88 
89 static bool console_initialized = FALSE;
90 
91 /*   A process can only have a single console, so it is safe
92      to maintain all the information about it in a single
93      static structure.
94  */
95 NCURSES_EXPORT_VAR(ConsoleInfo) _nc_CONSOLE;
96 
97 #define EnsureInit() (void)(console_initialized ? TRUE : _nc_console_checkinit(USE_NAMED_PIPES))
98 
99 #define REQUIRED_MAX_V (DWORD)10
100 #define REQUIRED_MIN_V (DWORD)0
101 #define REQUIRED_BUILD (DWORD)17763
102 /*
103   This function returns 0 if the Windows version has no support for
104   the modern Console interface, otherwise it returns 1
105  */
106 NCURSES_EXPORT(int)
_nc_console_vt_supported(void)107 _nc_console_vt_supported(void)
108 {
109     OSVERSIONINFO osvi;
110     int res = 0;
111 
112     T((T_CALLED("lib_win32con::_nc_console_vt_supported")));
113     ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
114     osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
115 
116     GetVersionEx(&osvi);
117     T(("GetVersionEx returnedMajor=%lu, Minor=%lu, Build=%lu",
118        (unsigned long) osvi.dwMajorVersion,
119        (unsigned long) osvi.dwMinorVersion,
120        (unsigned long) osvi.dwBuildNumber));
121     if (osvi.dwMajorVersion >= REQUIRED_MAX_V) {
122 	if (osvi.dwMajorVersion == REQUIRED_MAX_V) {
123 	    if (((osvi.dwMinorVersion == REQUIRED_MIN_V) &&
124 		 (osvi.dwBuildNumber >= REQUIRED_BUILD)) ||
125 		((osvi.dwMinorVersion > REQUIRED_MIN_V)))
126 		res = 1;
127 	} else
128 	    res = 1;
129     }
130     returnCode(res);
131 }
132 
133 NCURSES_EXPORT(void)
_nc_console_size(int * Lines,int * Cols)134 _nc_console_size(int *Lines, int *Cols)
135 {
136     EnsureInit();
137     if (Lines != NULL && Cols != NULL) {
138 	if (WINCONSOLE.buffered) {
139 	    *Lines = (int) (WINCONSOLE.SBI.dwSize.Y);
140 	    *Cols = (int) (WINCONSOLE.SBI.dwSize.X);
141 	} else {
142 	    *Lines = (int) (WINCONSOLE.SBI.srWindow.Bottom + 1 -
143 			    WINCONSOLE.SBI.srWindow.Top);
144 	    *Cols = (int) (WINCONSOLE.SBI.srWindow.Right + 1 -
145 			   WINCONSOLE.SBI.srWindow.Left);
146 	}
147     }
148 }
149 
150 /* Convert a file descriptor into a HANDLE
151    That's not necessarily a console HANDLE
152 */
153 NCURSES_EXPORT(HANDLE)
_nc_console_handle(int fd)154 _nc_console_handle(int fd)
155 {
156     intptr_t value = _get_osfhandle(fd);
157     return (HANDLE) value;
158 }
159 
160 /* Validate that a HANDLE is actually a
161    console HANDLE
162 */
163 static BOOL
IsConsoleHandle(HANDLE hdl)164 IsConsoleHandle(HANDLE hdl)
165 {
166     DWORD dwFlag = 0;
167     BOOL result = FALSE;
168 
169     T((T_CALLED("lib_win32con::IsConsoleHandle(HANDLE=%p"), hdl));
170 
171     EnsureInit();
172 
173     if (!GetConsoleMode(hdl, &dwFlag)) {
174 	T(("GetConsoleMode failed"));
175     } else {
176 	result = TRUE;
177     }
178 
179     returnBool(result);
180 }
181 
182 /*   This is used when running in terminfo mode to discover,
183      whether or not the "terminal" is actually a Windows
184      Console. It is the responsibility of the console to deal
185      with the terminal escape sequences that are sent by
186      terminfo.
187  */
188 NCURSES_EXPORT(int)
_nc_console_test(int fd)189 _nc_console_test(int fd)
190 {
191     int code = 0;
192     HANDLE hdl = INVALID_HANDLE_VALUE;
193     T((T_CALLED("lib_win32con::_nc_console_test(%d)"), fd));
194     hdl = _nc_console_handle(fd);
195     code = (int) IsConsoleHandle(hdl);
196     returnCode(code);
197 }
198 
199 #define OutHandle() ((WINCONSOLE.isTermInfoConsole || WINCONSOLE.progMode) ? WINCONSOLE.hdl : WINCONSOLE.out)
200 
201 NCURSES_EXPORT(void)
_nc_console_selectActiveHandle(void)202 _nc_console_selectActiveHandle(void)
203 {
204     if (WINCONSOLE.lastOut != WINCONSOLE.hdl) {
205 	WINCONSOLE.lastOut = WINCONSOLE.hdl;
206 	SetConsoleActiveScreenBuffer(WINCONSOLE.lastOut);
207     }
208 }
209 
210 NCURSES_EXPORT(HANDLE)
_nc_console_fd2handle(int fd)211 _nc_console_fd2handle(int fd)
212 {
213     HANDLE hdl = _nc_console_handle(fd);
214     if (hdl == WINCONSOLE.inp) {
215 	T(("lib_win32con:validateHandle %d -> WINCONSOLE.inp", fd));
216     } else if (hdl == WINCONSOLE.hdl) {
217 	T(("lib_win32con:validateHandle %d -> WINCONSOLE.hdl", fd));
218     } else if (hdl == WINCONSOLE.out) {
219 	T(("lib_win32con:validateHandle %d -> WINCONSOLE.out", fd));
220     } else if (hdl == GetStdHandle(STD_INPUT_HANDLE)) {
221 	T(("lib_win32con:validateHandle %d -> STD_INPUT_HANDLE", fd));
222 	if (!WINCONSOLE.isTermInfoConsole && WINCONSOLE.progMode) {
223 	    hdl = WINCONSOLE.inp;
224 	}
225     } else {
226 	T(("lib_win32con:validateHandle %d maps to unknown HANDLE", fd));
227 	hdl = INVALID_HANDLE_VALUE;
228     }
229     if (hdl != INVALID_HANDLE_VALUE) {
230 	if (hdl != WINCONSOLE.inp && (!WINCONSOLE.isTermInfoConsole && WINCONSOLE.progMode)) {
231 	    if (hdl == WINCONSOLE.out && hdl != WINCONSOLE.hdl) {
232 		T(("lib_win32con:validateHandle forcing WINCONSOLE.out -> WINCONSOLE.hdl"));
233 		hdl = WINCONSOLE.hdl;
234 	    }
235 	}
236     }
237     return hdl;
238 }
239 
240 #if defined(_NC_WINDOWS) && USE_WINCONMODE
241 NCURSES_EXPORT(int)
_nc_console_setmode(HANDLE hdl,const TTY * arg)242 _nc_console_setmode(HANDLE hdl, const TTY * arg)
243 {
244     DWORD dwFlag = 0;
245     int code = ERR;
246     HANDLE alt;
247 
248     if (arg) {
249 #ifdef TRACE
250 	TTY TRCTTY;
251 #define TRCTTYOUT(flag) TRCTTY.dwFlagOut = flag
252 #define TRCTTYIN(flag)  TRCTTY.dwFlagIn = flag
253 #else
254 #define TRCTTYOUT(flag)
255 #define TRCTTYIN(flag)
256 #endif
257 	T(("lib_win32con:_nc_console_setmode %s", _nc_trace_ttymode(arg)));
258 	if (hdl == WINCONSOLE.inp) {
259 	    dwFlag = arg->dwFlagIn | ENABLE_MOUSE_INPUT | VT_FLAG_IN;
260 	    TRCTTYIN(dwFlag);
261 	    SetConsoleMode(hdl, dwFlag);
262 
263 	    alt = OutHandle();
264 	    dwFlag = arg->dwFlagOut;
265 	    TRCTTYOUT(dwFlag);
266 	    SetConsoleMode(alt, dwFlag);
267 	} else {
268 	    dwFlag = arg->dwFlagOut;
269 	    TRCTTYOUT(dwFlag);
270 	    SetConsoleMode(hdl, dwFlag);
271 
272 	    alt = WINCONSOLE.inp;
273 	    dwFlag = arg->dwFlagIn | ENABLE_MOUSE_INPUT;
274 	    TRCTTYIN(dwFlag);
275 	    SetConsoleMode(alt, dwFlag);
276 	    T(("effective mode set %s", _nc_trace_ttymode(&TRCTTY)));
277 	}
278 	code = OK;
279     }
280     return (code);
281 }
282 
283 NCURSES_EXPORT(int)
_nc_console_getmode(HANDLE hdl,TTY * arg)284 _nc_console_getmode(HANDLE hdl, TTY * arg)
285 {
286     int code = ERR;
287 
288     if (arg) {
289 	DWORD dwFlag = 0;
290 	HANDLE alt;
291 
292 	if (hdl == WINCONSOLE.inp) {
293 	    if (GetConsoleMode(hdl, &dwFlag)) {
294 		arg->dwFlagIn = dwFlag;
295 		alt = OutHandle();
296 		if (GetConsoleMode(alt, &dwFlag)) {
297 		    arg->dwFlagOut = dwFlag;
298 		    code = OK;
299 		}
300 	    }
301 	} else {
302 	    if (GetConsoleMode(hdl, &dwFlag)) {
303 		arg->dwFlagOut = dwFlag;
304 		alt = WINCONSOLE.inp;
305 		if (GetConsoleMode(alt, &dwFlag)) {
306 		    arg->dwFlagIn = dwFlag;
307 		    code = OK;
308 		}
309 	    }
310 	}
311     }
312     T(("lib_win32con:_nc_console_getmode %s", _nc_trace_ttymode(arg)));
313     return (code);
314 }
315 #endif /* defined(_NC_WINDOWS) && USE_WINCONMODE */
316 
317 NCURSES_EXPORT(int)
_nc_console_flush(HANDLE hdl)318 _nc_console_flush(HANDLE hdl)
319 {
320     int code = OK;
321 
322     T((T_CALLED("lib_win32con::_nc_console_flush(hdl=%p"), hdl));
323 
324     if (hdl != INVALID_HANDLE_VALUE) {
325 	if (hdl == WINCONSOLE.hdl ||
326 	    hdl == WINCONSOLE.inp ||
327 	    hdl == WINCONSOLE.out) {
328 	    if (!FlushConsoleInputBuffer(WINCONSOLE.inp))
329 		code = ERR;
330 	} else {
331 	    code = ERR;
332 	    T(("_nc_console_flush not requesting a handle owned by console."));
333 	}
334     }
335     returnCode(code);
336 }
337 
338 NCURSES_EXPORT(WORD)
_nc_console_MapColor(bool fore,int color)339 _nc_console_MapColor(bool fore, int color)
340 {
341     static const int _cmap[] =
342     {0, 4, 2, 6, 1, 5, 3, 7};
343     int a;
344     if (color < 0 || color > 7)
345 	a = fore ? 7 : 0;
346     else
347 	a = _cmap[color];
348     if (!fore)
349 	a = a << 4;
350     return (WORD) a;
351 }
352 
353 /*
354  * Attempt to save the screen contents.  PDCurses does this if
355  * PDC_RESTORE_SCREEN is set, giving the same visual appearance on
356  * restoration as if the library had allocated a console buffer.  MSDN
357  * says that the data which can be read is limited to 64Kb (and may be
358  * less).
359  */
360 static bool
save_original_screen(void)361 save_original_screen(void)
362 {
363     bool result = FALSE;
364 
365     WINCONSOLE.save_region.Top = 0;
366     WINCONSOLE.save_region.Left = 0;
367     WINCONSOLE.save_region.Bottom = (SHORT) (WINCONSOLE.SBI.dwSize.Y - 1);
368     WINCONSOLE.save_region.Right = (SHORT) (WINCONSOLE.SBI.dwSize.X - 1);
369 
370     if (read_screen_data()) {
371 	result = TRUE;
372     } else {
373 
374 	WINCONSOLE.save_region.Top = WINCONSOLE.SBI.srWindow.Top;
375 	WINCONSOLE.save_region.Left = WINCONSOLE.SBI.srWindow.Left;
376 	WINCONSOLE.save_region.Bottom = WINCONSOLE.SBI.srWindow.Bottom;
377 	WINCONSOLE.save_region.Right = WINCONSOLE.SBI.srWindow.Right;
378 
379 	WINCONSOLE.window_only = TRUE;
380 
381 	if (read_screen_data()) {
382 	    result = TRUE;
383 	}
384     }
385 
386     T(("... save original screen contents %s", result ? "ok" : "err"));
387     return result;
388 }
389 
390 #if defined(_NC_WINDOWS)
391 static bool
restore_original_screen(void)392 restore_original_screen(void)
393 {
394     COORD bufferCoord;
395     bool result = FALSE;
396     SMALL_RECT save_region = WINCONSOLE.save_region;
397 
398     T(("... restoring %s",
399        WINCONSOLE.window_only ? "window" : "entire buffer"));
400 
401     bufferCoord.X = (SHORT) (WINCONSOLE.window_only ?
402 			     WINCONSOLE.SBI.srWindow.Left : 0);
403     bufferCoord.Y = (SHORT) (WINCONSOLE.window_only ?
404 			     WINCONSOLE.SBI.srWindow.Top : 0);
405 
406     if (write_screen(WINCONSOLE.hdl,
407 		     WINCONSOLE.save_screen,
408 		     WINCONSOLE.save_size,
409 		     bufferCoord,
410 		     &save_region)) {
411 	result = TRUE;
412 	SetConsoleCursorPosition(WINCONSOLE.hdl, WINCONSOLE.save_SBI.dwCursorPosition);
413 	T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
414 	   WINCONSOLE.save_size.Y,
415 	   WINCONSOLE.save_size.X,
416 	   save_region.Top,
417 	   save_region.Left,
418 	   save_region.Bottom,
419 	   save_region.Right));
420     } else {
421 	T(("... restore original screen contents err"));
422     }
423     return result;
424 }
425 #endif
426 
427 static bool
read_screen_data(void)428 read_screen_data(void)
429 {
430     bool result = FALSE;
431     COORD bufferCoord;
432     size_t want;
433 
434     WINCONSOLE.save_size.X = (SHORT) (WINCONSOLE.save_region.Right
435 				      - WINCONSOLE.save_region.Left + 1);
436     WINCONSOLE.save_size.Y = (SHORT) (WINCONSOLE.save_region.Bottom
437 				      - WINCONSOLE.save_region.Top + 1);
438 
439     want = (size_t) (WINCONSOLE.save_size.X * WINCONSOLE.save_size.Y);
440 
441     if ((WINCONSOLE.save_screen = malloc(want * sizeof(CHAR_INFO))) != NULL) {
442 	bufferCoord.X = (SHORT) (WINCONSOLE.window_only
443 				 ? WINCONSOLE.SBI.srWindow.Left
444 				 : 0);
445 	bufferCoord.Y = (SHORT) (WINCONSOLE.window_only
446 				 ? WINCONSOLE.SBI.srWindow.Top
447 				 : 0);
448 
449 	T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d",
450 	   WINCONSOLE.window_only ? "window" : "buffer",
451 	   WINCONSOLE.save_size.Y, WINCONSOLE.save_size.X,
452 	   WINCONSOLE.save_region.Top,
453 	   WINCONSOLE.save_region.Left,
454 	   WINCONSOLE.save_region.Bottom,
455 	   WINCONSOLE.save_region.Right,
456 	   bufferCoord.Y,
457 	   bufferCoord.X));
458 
459 	if (read_screen(WINCONSOLE.hdl,
460 			WINCONSOLE.save_screen,
461 			WINCONSOLE.save_size,
462 			bufferCoord,
463 			&WINCONSOLE.save_region)) {
464 	    result = TRUE;
465 	} else {
466 	    T((" error %#lx", (unsigned long) GetLastError()));
467 	    FreeAndNull(WINCONSOLE.save_screen);
468 	}
469     }
470 
471     return result;
472 }
473 
474 NCURSES_EXPORT(bool)
_nc_console_get_SBI(void)475 _nc_console_get_SBI(void)
476 {
477     bool rc = FALSE;
478     if (GetConsoleScreenBufferInfo(WINCONSOLE.hdl, &(WINCONSOLE.SBI))) {
479 	T(("GetConsoleScreenBufferInfo"));
480 	T(("... buffer(X:%d Y:%d)",
481 	   WINCONSOLE.SBI.dwSize.X,
482 	   WINCONSOLE.SBI.dwSize.Y));
483 	T(("... window(X:%d Y:%d)",
484 	   WINCONSOLE.SBI.dwMaximumWindowSize.X,
485 	   WINCONSOLE.SBI.dwMaximumWindowSize.Y));
486 	T(("... cursor(X:%d Y:%d)",
487 	   WINCONSOLE.SBI.dwCursorPosition.X,
488 	   WINCONSOLE.SBI.dwCursorPosition.Y));
489 	T(("... display(Top:%d Bottom:%d Left:%d Right:%d)",
490 	   WINCONSOLE.SBI.srWindow.Top,
491 	   WINCONSOLE.SBI.srWindow.Bottom,
492 	   WINCONSOLE.SBI.srWindow.Left,
493 	   WINCONSOLE.SBI.srWindow.Right));
494 	if (WINCONSOLE.buffered) {
495 	    WINCONSOLE.origin.X = 0;
496 	    WINCONSOLE.origin.Y = 0;
497 	} else {
498 	    WINCONSOLE.origin.X = WINCONSOLE.SBI.srWindow.Left;
499 	    WINCONSOLE.origin.Y = WINCONSOLE.SBI.srWindow.Top;
500 	}
501 	rc = TRUE;
502     } else {
503 	T(("GetConsoleScreenBufferInfo ERR"));
504     }
505     return rc;
506 }
507 
508 #define MIN_WIDE 80
509 #define MIN_HIGH 24
510 
511 /*
512  * In "normal" mode, reset the buffer- and window-sizes back to their original values.
513  */
514 NCURSES_EXPORT(void)
_nc_console_set_scrollback(bool normal,CONSOLE_SCREEN_BUFFER_INFO * info)515 _nc_console_set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
516 {
517     SMALL_RECT rect;
518     COORD coord;
519     bool changed = FALSE;
520 
521     T((T_CALLED("lib_win32con::_nc_console_set_scrollback(%s)"),
522        (normal
523 	? "normal"
524 	: "application")));
525 
526     T(("... SBI.srWindow %d,%d .. %d,%d",
527        info->srWindow.Top,
528        info->srWindow.Left,
529        info->srWindow.Bottom,
530        info->srWindow.Right));
531     T(("... SBI.dwSize %dx%d",
532        info->dwSize.Y,
533        info->dwSize.X));
534 
535     if (normal) {
536 	rect = info->srWindow;
537 	coord = info->dwSize;
538 	if (memcmp(info, &WINCONSOLE.SBI, sizeof(*info)) != 0) {
539 	    changed = TRUE;
540 	    WINCONSOLE.SBI = *info;
541 	}
542     } else {
543 	int high = info->srWindow.Bottom - info->srWindow.Top + 1;
544 	int wide = info->srWindow.Right - info->srWindow.Left + 1;
545 
546 	if (high < MIN_HIGH) {
547 	    T(("... height %d < %d", high, MIN_HIGH));
548 	    high = MIN_HIGH;
549 	    changed = TRUE;
550 	}
551 	if (wide < MIN_WIDE) {
552 	    T(("... width %d < %d", wide, MIN_WIDE));
553 	    wide = MIN_WIDE;
554 	    changed = TRUE;
555 	}
556 
557 	rect.Left =
558 	    rect.Top = 0;
559 	rect.Right = (SHORT) (wide - 1);
560 	rect.Bottom = (SHORT) (high - 1);
561 
562 	coord.X = (SHORT) wide;
563 	coord.Y = (SHORT) high;
564 
565 	if (info->dwSize.Y != high ||
566 	    info->dwSize.X != wide ||
567 	    info->srWindow.Top != 0 ||
568 	    info->srWindow.Left != 0) {
569 	    changed = TRUE;
570 	}
571 
572     }
573 
574     if (changed) {
575 	T(("... coord %d,%d", coord.Y, coord.X));
576 	T(("... rect %d,%d - %d,%d",
577 	   rect.Top, rect.Left,
578 	   rect.Bottom, rect.Right));
579 	SetConsoleScreenBufferSize(WINCONSOLE.hdl, coord);	/* dwSize */
580 	SetConsoleWindowInfo(WINCONSOLE.hdl, TRUE, &rect);	/* srWindow */
581 	_nc_console_get_SBI();
582     }
583     returnVoid;
584 }
585 
586 static ULONGLONG
tdiff(FILETIME fstart,FILETIME fend)587 tdiff(FILETIME fstart, FILETIME fend)
588 {
589     ULARGE_INTEGER ustart;
590     ULARGE_INTEGER uend;
591     ULONGLONG diff;
592 
593     ustart.LowPart = fstart.dwLowDateTime;
594     ustart.HighPart = fstart.dwHighDateTime;
595     uend.LowPart = fend.dwLowDateTime;
596     uend.HighPart = fend.dwHighDateTime;
597 
598     diff = (uend.QuadPart - ustart.QuadPart) / 10000;
599     return diff;
600 }
601 
602 static int
Adjust(int milliseconds,int diff)603 Adjust(int milliseconds, int diff)
604 {
605     if (milliseconds != NC_INFINITY) {
606 	milliseconds -= diff;
607 	if (milliseconds < 0)
608 	    milliseconds = 0;
609     }
610     return milliseconds;
611 }
612 
613 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \
614                      FROM_LEFT_2ND_BUTTON_PRESSED | \
615                      FROM_LEFT_3RD_BUTTON_PRESSED | \
616                      FROM_LEFT_4TH_BUTTON_PRESSED | \
617                      RIGHTMOST_BUTTON_PRESSED)
618 
619 static mmask_t
decode_mouse(const SCREEN * sp,int mask)620 decode_mouse(const SCREEN *sp, int mask)
621 {
622     mmask_t result = 0;
623 
624     (void) sp;
625     assert(sp && console_initialized);
626 
627     if (mask & FROM_LEFT_1ST_BUTTON_PRESSED)
628 	result |= BUTTON1_PRESSED;
629     if (mask & FROM_LEFT_2ND_BUTTON_PRESSED)
630 	result |= BUTTON2_PRESSED;
631     if (mask & FROM_LEFT_3RD_BUTTON_PRESSED)
632 	result |= BUTTON3_PRESSED;
633     if (mask & FROM_LEFT_4TH_BUTTON_PRESSED)
634 	result |= BUTTON4_PRESSED;
635 
636     if (mask & RIGHTMOST_BUTTON_PRESSED) {
637 	switch (WINCONSOLE.numButtons) {
638 	case 1:
639 	    result |= BUTTON1_PRESSED;
640 	    break;
641 	case 2:
642 	    result |= BUTTON2_PRESSED;
643 	    break;
644 	case 3:
645 	    result |= BUTTON3_PRESSED;
646 	    break;
647 	case 4:
648 	    result |= BUTTON4_PRESSED;
649 	    break;
650 	}
651     }
652 
653     return result;
654 }
655 
656 #define AdjustY() (WINCONSOLE.buffered \
657                    ? 0 \
658                    : (int) WINCONSOLE.SBI.srWindow.Top)
659 
660 static bool
handle_mouse(SCREEN * sp,MOUSE_EVENT_RECORD mer)661 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
662 {
663     MEVENT work;
664     bool result = FALSE;
665 
666     assert(sp);
667 
668     sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
669     sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
670 
671     /*
672      * We're only interested if the button is pressed or released.
673      * FIXME: implement continuous event-tracking.
674      */
675     if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
676 	memset(&work, 0, sizeof(work));
677 
678 	if (sp->_drv_mouse_new_buttons) {
679 	    work.bstate |= decode_mouse(sp, sp->_drv_mouse_new_buttons);
680 	} else {
681 	    /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
682 	    work.bstate |= (decode_mouse(sp, sp->_drv_mouse_old_buttons)
683 			    >> 1);
684 	    result = TRUE;
685 	}
686 
687 	work.x = mer.dwMousePosition.X;
688 	work.y = mer.dwMousePosition.Y - AdjustY();
689 
690 	sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
691 	sp->_drv_mouse_tail += 1;
692     }
693     return result;
694 }
695 
696 static int
rkeycompare(const void * el1,const void * el2)697 rkeycompare(const void *el1, const void *el2)
698 {
699     WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
700     WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
701 
702     return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
703 }
704 
705 static int
keycompare(const void * el1,const void * el2)706 keycompare(const void *el1, const void *el2)
707 {
708     WORD key1 = HIWORD((*((const LONG *) el1)));
709     WORD key2 = HIWORD((*((const LONG *) el2)));
710 
711     return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
712 }
713 
714 static int
MapKey(WORD vKey)715 MapKey(WORD vKey)
716 {
717     int code = -1;
718 
719     if (!WINCONSOLE.isTermInfoConsole) {
720 	WORD nKey = 0;
721 	void *res;
722 	LONG key = GenMap(vKey, 0);
723 
724 	res = bsearch(&key,
725 		      WINCONSOLE.map,
726 		      (size_t) (N_INI + FKEYS),
727 		      sizeof(keylist[0]),
728 		      keycompare);
729 	if (res) {
730 	    key = *((LONG *) res);
731 	    nKey = LOWORD(key);
732 	    code = (int) (nKey & 0x7fff);
733 	    if (nKey & 0x8000)
734 		code = -code;
735 	}
736     }
737     return code;
738 }
739 
740 static int
AnsiKey(WORD vKey)741 AnsiKey(WORD vKey)
742 {
743     int code = -1;
744 
745     if (!WINCONSOLE.isTermInfoConsole) {
746 	WORD nKey = 0;
747 	void *res;
748 	LONG key = GenMap(vKey, 0);
749 
750 	res = bsearch(&key,
751 		      WINCONSOLE.ansi_map,
752 		      (size_t) (N_INI + FKEYS),
753 		      sizeof(keylist[0]),
754 		      keycompare);
755 	if (res) {
756 	    key = *((LONG *) res);
757 	    nKey = LOWORD(key);
758 	    code = (int) (nKey & 0x7fff);
759 	    if (nKey & 0x8000)
760 		code = -code;
761 	}
762     }
763     return code;
764 }
765 
766 NCURSES_EXPORT(int)
_nc_console_keyok(int keycode,int flag)767 _nc_console_keyok(int keycode, int flag)
768 {
769     int code = ERR;
770     WORD nKey;
771     WORD vKey;
772     void *res;
773     LONG key = GenMap(0, (WORD) keycode);
774 
775     T((T_CALLED("lib_win32con::_nc_console_keyok(%d, %d)"), keycode, flag));
776 
777     res = bsearch(&key,
778 		  WINCONSOLE.rmap,
779 		  (size_t) (N_INI + FKEYS),
780 		  sizeof(keylist[0]),
781 		  rkeycompare);
782     if (res) {
783 	key = *((LONG *) res);
784 	vKey = HIWORD(key);
785 	nKey = (LOWORD(key)) & 0x7fff;
786 	if (!flag)
787 	    nKey |= 0x8000;
788 	*(LONG *) res = GenMap(vKey, nKey);
789     }
790     returnCode(code);
791 }
792 
793 NCURSES_EXPORT(bool)
_nc_console_keyExist(int keycode)794 _nc_console_keyExist(int keycode)
795 {
796     WORD nKey;
797     void *res;
798     bool found = FALSE;
799     LONG key = GenMap(0, (WORD) keycode);
800 
801     T((T_CALLED("lib_win32con::_nc_console_keyExist(%d)"), keycode));
802     res = bsearch(&key,
803 		  WINCONSOLE.rmap,
804 		  (size_t) (N_INI + FKEYS),
805 		  sizeof(keylist[0]),
806 		  rkeycompare);
807     if (res) {
808 	key = *((LONG *) res);
809 	nKey = LOWORD(key);
810 	if (!(nKey & 0x8000))
811 	    found = TRUE;
812     }
813     returnCode(found);
814 }
815 
816 NCURSES_EXPORT(int)
_nc_console_twait(const SCREEN * sp,HANDLE hdl,int mode,int milliseconds,int * timeleft EVENTLIST_2nd (_nc_eventlist * evl))817 _nc_console_twait(
818 		     const SCREEN *sp,
819 		     HANDLE hdl,
820 		     int mode,
821 		     int milliseconds,
822 		     int *timeleft
823 		     EVENTLIST_2nd(_nc_eventlist * evl))
824 {
825     INPUT_RECORD inp_rec;
826     BOOL b;
827     DWORD nRead = 0, rc = WAIT_FAILED;
828     int code = 0;
829     FILETIME fstart;
830     FILETIME fend;
831     int diff;
832     bool isNoDelay = (milliseconds == 0);
833 
834 #ifdef NCURSES_WGETCH_EVENTS
835     (void) evl;			/* TODO: implement wgetch-events */
836 #endif
837 
838 #define IGNORE_CTRL_KEYS (SHIFT_PRESSED | \
839                           LEFT_ALT_PRESSED | RIGHT_ALT_PRESSED | \
840                           LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED)
841 #define CONSUME() read_keycode(hdl, &inp_rec, 1, &nRead)
842 
843     assert(sp);
844 
845     TR(TRACE_IEVENT, ("start twait: hdl=%p, %d milliseconds, mode: %d",
846 		      hdl, milliseconds, mode));
847 
848     if (milliseconds < 0)
849 	milliseconds = NC_INFINITY;
850 
851     memset(&inp_rec, 0, sizeof(inp_rec));
852 
853     while (true) {
854 	if (!isNoDelay) {
855 	    GetSystemTimeAsFileTime(&fstart);
856 	    rc = WaitForSingleObject(hdl, (DWORD) milliseconds);
857 	    GetSystemTimeAsFileTime(&fend);
858 	    diff = (int) tdiff(fstart, fend);
859 	    milliseconds = Adjust(milliseconds, diff);
860 	    if (milliseconds < 0)
861 		break;
862 	}
863 
864 	if (isNoDelay || (rc == WAIT_OBJECT_0)) {
865 	    if (mode) {
866 		nRead = 0;
867 		b = GetNumberOfConsoleInputEvents(hdl, &nRead);
868 		if (!b) {
869 		    T(("twait:err GetNumberOfConsoleInputEvents"));
870 		}
871 		if (isNoDelay && b) {
872 		    T(("twait: Events Available: %lu", (unsigned long) nRead));
873 		    if (nRead == 0) {
874 			code = 0;
875 			goto end;
876 		    } else {
877 			DWORD n = 0;
878 			MakeArray(pInpRec, INPUT_RECORD, nRead);
879 			if (pInpRec != NULL) {
880 			    DWORD i;
881 			    BOOL f;
882 			    memset(pInpRec, 0, sizeof(INPUT_RECORD) * nRead);
883 			    f = PeekConsoleInput(hdl, pInpRec, nRead, &n);
884 			    if (f) {
885 				for (i = 0; i < n; i++) {
886 				    if (pInpRec[i].EventType == KEY_EVENT) {
887 					if (pInpRec[i].Event.KeyEvent.bKeyDown) {
888 					    DWORD ctrlMask =
889 					    (pInpRec[i].Event.KeyEvent.dwControlKeyState &
890 					     IGNORE_CTRL_KEYS);
891 					    if (!ctrlMask) {
892 						code = TW_INPUT;
893 						goto end;
894 					    }
895 					}
896 				    }
897 				}
898 			    } else {
899 				T(("twait:err PeekConsoleInput"));
900 			    }
901 			    code = 0;
902 			    goto end;
903 			} else {
904 			    T(("twait:err could not alloca input records"));
905 			}
906 		    }
907 		}
908 		if (b && nRead > 0) {
909 		    b = PeekConsoleInput(hdl, &inp_rec, 1, &nRead);
910 		    if (!b) {
911 			T(("twait:err PeekConsoleInput"));
912 		    }
913 		    if (b && nRead > 0) {
914 			switch (inp_rec.EventType) {
915 			case KEY_EVENT:
916 			    if (mode & TW_INPUT) {
917 				WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
918 				WORD ch = inp_rec.Event.KeyEventChar;
919 
920 				T(("twait:event KEY_EVENT"));
921 				T(("twait vk=%d, ch=%d, keydown=%d",
922 				   vk, ch, inp_rec.Event.KeyEvent.bKeyDown));
923 
924 				if (inp_rec.Event.KeyEvent.bKeyDown) {
925 				    T(("twait:event KeyDown"));
926 				    if (!WINCONSOLE.isTermInfoConsole &&
927 					(0 == ch)) {
928 					int nKey = MapKey(vk);
929 					if (nKey < 0) {
930 					    CONSUME();
931 					    continue;
932 					}
933 				    }
934 				    code = TW_INPUT;
935 				    goto end;
936 				} else {
937 				    CONSUME();
938 				}
939 			    }
940 			    continue;
941 			case MOUSE_EVENT:
942 			    T(("twait:event MOUSE_EVENT"));
943 			    if (decode_mouse(sp,
944 					     (inp_rec.Event.MouseEvent.dwButtonState
945 					      & BUTTON_MASK)) == 0) {
946 				CONSUME();
947 			    } else if (mode & TW_MOUSE) {
948 				code = TW_MOUSE;
949 				goto end;
950 			    }
951 			    continue;
952 			    /* e.g., FOCUS_EVENT */
953 			default:
954 			    T(("twait:event Type %d", inp_rec.EventType));
955 			    CONSUME();
956 			    _nc_console_selectActiveHandle();
957 			    continue;
958 			}
959 		    }
960 		}
961 	    }
962 	    continue;
963 	} else {
964 	    if (rc != WAIT_TIMEOUT) {
965 		code = -1;
966 		break;
967 	    } else {
968 		code = 0;
969 		break;
970 	    }
971 	}
972     }
973   end:
974 
975     TR(TRACE_IEVENT, ("end twait: returned %d (%lu), remaining time %d msec",
976 		      code, (unsigned long) GetLastError(), milliseconds));
977 
978     if (timeleft)
979 	*timeleft = milliseconds;
980 
981     return code;
982 }
983 
984 NCURSES_EXPORT(int)
_nc_console_testmouse(const SCREEN * sp,HANDLE hdl,int delay EVENTLIST_2nd (_nc_eventlist * evl))985 _nc_console_testmouse(
986 			 const SCREEN *sp,
987 			 HANDLE hdl,
988 			 int delay
989 			 EVENTLIST_2nd(_nc_eventlist * evl))
990 {
991     int rc = 0;
992 
993     assert(sp);
994 
995     if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
996 	rc = TW_MOUSE;
997     } else {
998 	rc = _nc_console_twait(sp,
999 			       hdl,
1000 			       TWAIT_MASK,
1001 			       delay,
1002 			       (int *) 0
1003 			       EVENTLIST_2nd(evl));
1004     }
1005     return rc;
1006 }
1007 
1008 NCURSES_EXPORT(int)
_nc_console_read(SCREEN * sp,HANDLE hdl,int * buf)1009 _nc_console_read(
1010 		    SCREEN *sp,
1011 		    HANDLE hdl,
1012 		    int *buf)
1013 {
1014     int rc = -1;
1015     INPUT_RECORD inp_rec;
1016     BOOL b;
1017     DWORD nRead;
1018     WORD vk;
1019 
1020     assert(sp);
1021     assert(buf);
1022 
1023     memset(&inp_rec, 0, sizeof(inp_rec));
1024 
1025     T((T_CALLED("lib_win32con::_nc_console_read(%p)"), sp));
1026 
1027     while ((b = read_keycode(hdl, &inp_rec, 1, &nRead))) {
1028 	if (b && nRead > 0) {
1029 	    if (rc < 0)
1030 		rc = 0;
1031 	    rc = rc + (int) nRead;
1032 	    if (inp_rec.EventType == KEY_EVENT) {
1033 		if (!inp_rec.Event.KeyEvent.bKeyDown)
1034 		    continue;
1035 		*buf = (int) inp_rec.Event.KeyEventChar;
1036 		vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1037 		/*
1038 		 * There are 24 virtual function-keys, and typically
1039 		 * 12 function-keys on a keyboard.  Use the shift-modifier
1040 		 * to provide the remaining 12 keys.
1041 		 */
1042 		if (vk >= VK_F1 && vk <= VK_F12) {
1043 		    if (inp_rec.Event.KeyEvent.dwControlKeyState &
1044 			SHIFT_PRESSED) {
1045 			vk = (WORD) (vk + 12);
1046 		    }
1047 		}
1048 		if (*buf == 0) {
1049 		    int key = MapKey(vk);
1050 		    if (key < 0)
1051 			continue;
1052 		    if (sp->_keypad_on) {
1053 			*buf = key;
1054 		    } else {
1055 			ungetch('\0');
1056 			*buf = AnsiKey(vk);
1057 		    }
1058 		} else if (vk == VK_BACK) {
1059 		    if (!(inp_rec.Event.KeyEvent.dwControlKeyState
1060 			  & (SHIFT_PRESSED | CONTROL_PRESSED))) {
1061 			*buf = KEY_BACKSPACE;
1062 		    }
1063 		} else if (vk == VK_TAB) {
1064 		    if ((inp_rec.Event.KeyEvent.dwControlKeyState
1065 			 & (SHIFT_PRESSED | CONTROL_PRESSED))) {
1066 			*buf = KEY_BTAB;
1067 		    }
1068 		}
1069 		break;
1070 	    } else if (inp_rec.EventType == MOUSE_EVENT) {
1071 		if (handle_mouse(sp,
1072 				 inp_rec.Event.MouseEvent)) {
1073 		    *buf = KEY_MOUSE;
1074 		    break;
1075 		}
1076 	    }
1077 	    continue;
1078 	}
1079     }
1080     returnCode(rc);
1081 }
1082 
1083 #if USE_TERM_DRIVER && (USE_NAMED_PIPES || defined(USE_WIN32CON_DRIVER))
1084 /*   Our replacement for the systems _isatty to include also
1085      a test for mintty. This is called from the NC_ISATTY macro
1086      defined in curses.priv.h
1087 
1088      Return codes:
1089      - 0 : Not a TTY
1090      - 1 : A Windows character device detected by _isatty
1091      - 2 : A future implementation may return 2 for mintty
1092  */
1093 NCURSES_EXPORT(int)
_nc_console_isatty(int fd)1094 _nc_console_isatty(int fd)
1095 {
1096     int result = 0;
1097     T((T_CALLED("lib_win32con::_nc_console_isatty(%d"), fd));
1098 
1099     if (isatty(fd))
1100 	result = 1;
1101 #ifdef _NC_CHECK_MINTTY
1102     else {
1103 	if (_nc_console_checkmintty(fd, NULL)) {
1104 	    result = 2;
1105 	    fprintf(stderr,
1106 		    "ncurses on Windows must run in a Windows console.\n"
1107 		    "On newer versions of Windows, the calling program should create a PTY-like.\n"
1108 		    "device using the CreatePseudoConsole Windows API call.\n");
1109 	    exit(EXIT_FAILURE);
1110 	}
1111     }
1112 #endif
1113     returnCode(result);
1114 }
1115 #endif /* USE_TERM_DRIVER && (USE_NAMED_PIPES || defined(USE_WIN32CON_DRIVER)) */
1116 
1117 #if USE_WINCONMODE
1118 NCURSES_EXPORT(bool)
_nc_console_checkinit(bool assumeTermInfo)1119 _nc_console_checkinit(bool assumeTermInfo)
1120 {
1121     bool res = FALSE;
1122 
1123     T((T_CALLED("lib_win32con::_nc_console_checkinit(assumeTermInfo=%d)"),
1124        assumeTermInfo));
1125 
1126     /* initialize once, or not at all */
1127     if (!console_initialized) {
1128 	int i;
1129 	DWORD num_buttons;
1130 	WORD a;
1131 	BOOL buffered = FALSE;
1132 	BOOL b;
1133 
1134 	START_TRACE();
1135 	WINCONSOLE.isTermInfoConsole = assumeTermInfo;
1136 
1137 	WINCONSOLE.map = (LPDWORD) malloc(sizeof(DWORD) * MAPSIZE);
1138 	WINCONSOLE.rmap = (LPDWORD) malloc(sizeof(DWORD) * MAPSIZE);
1139 	WINCONSOLE.ansi_map = (LPDWORD) malloc(sizeof(DWORD) * MAPSIZE);
1140 
1141 	for (i = 0; i < (N_INI + FKEYS); i++) {
1142 	    if (i < N_INI) {
1143 		WINCONSOLE.rmap[i] = WINCONSOLE.map[i] =
1144 		    (DWORD) keylist[i];
1145 		WINCONSOLE.ansi_map[i] = (DWORD) ansi_keys[i];
1146 	    } else {
1147 		WINCONSOLE.rmap[i] = WINCONSOLE.map[i] =
1148 		    (DWORD) GenMap((VK_F1 + (i - N_INI)),
1149 				   (KEY_F(1) + (i - N_INI)));
1150 		WINCONSOLE.ansi_map[i] =
1151 		    (DWORD) GenMap((VK_F1 + (i - N_INI)),
1152 				   (';' + (i - N_INI)));
1153 	    }
1154 	}
1155 	qsort(WINCONSOLE.ansi_map,
1156 	      (size_t) (MAPSIZE),
1157 	      sizeof(keylist[0]),
1158 	      keycompare);
1159 	qsort(WINCONSOLE.map,
1160 	      (size_t) (MAPSIZE),
1161 	      sizeof(keylist[0]),
1162 	      keycompare);
1163 	qsort(WINCONSOLE.rmap,
1164 	      (size_t) (MAPSIZE),
1165 	      sizeof(keylist[0]),
1166 	      rkeycompare);
1167 
1168 	if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
1169 	    WINCONSOLE.numButtons = (int) num_buttons;
1170 	} else {
1171 	    WINCONSOLE.numButtons = 1;
1172 	}
1173 
1174 	a = _nc_console_MapColor(true, COLOR_WHITE) |
1175 	    _nc_console_MapColor(false, COLOR_BLACK);
1176 	for (i = 0; i < CON_NUMPAIRS; i++)
1177 	    WINCONSOLE.pairs[i] = a;
1178 
1179 #define SaveConsoleMode(handle, value) \
1180 	GetConsoleMode(WINCONSOLE.handle, &WINCONSOLE.originalMode.value)
1181 
1182 	if (WINCONSOLE.isTermInfoConsole) {
1183 	    WINCONSOLE.inp = GetStdHandle(STD_INPUT_HANDLE);
1184 	    WINCONSOLE.out = GetStdHandle(STD_OUTPUT_HANDLE);
1185 	    WINCONSOLE.hdl = WINCONSOLE.out;
1186 
1187 	    SaveConsoleMode(inp, dwFlagIn);
1188 	    SaveConsoleMode(out, dwFlagOut);
1189 
1190 	} else {
1191 	    b = AllocConsole();
1192 
1193 	    if (!b)
1194 		b = AttachConsole(ATTACH_PARENT_PROCESS);
1195 
1196 	    WINCONSOLE.inp = GetDirectHandle("CONIN$", FILE_SHARE_READ);
1197 	    WINCONSOLE.out = GetDirectHandle("CONOUT$", FILE_SHARE_WRITE);
1198 
1199 	    SaveConsoleMode(inp, dwFlagIn);
1200 	    SaveConsoleMode(out, dwFlagOut);
1201 
1202 	    if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
1203 		WINCONSOLE.hdl = WINCONSOLE.out;
1204 		buffered = FALSE;
1205 		T(("... will not buffer console"));
1206 	    } else {
1207 		T(("... creating console buffer"));
1208 		WINCONSOLE.hdl =
1209 		    CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
1210 					      FILE_SHARE_READ | FILE_SHARE_WRITE,
1211 					      NULL,
1212 					      CONSOLE_TEXTMODE_BUFFER,
1213 					      NULL);
1214 		buffered = TRUE;
1215 	    }
1216 	}
1217 
1218 	/* We set binary I/O even when using the console
1219 	   driver to cover the situation, that the
1220 	   TERM variable is set to #win32con, but actually
1221 	   Windows supports virtual terminal processing.
1222 	   So if terminfo functions are used in this setup,
1223 	   they actually may work.
1224 	 */
1225 	_setmode(fileno(stdin), _O_BINARY);
1226 	_setmode(fileno(stdout), _O_BINARY);
1227 
1228 	if (WINCONSOLE.hdl != INVALID_HANDLE_VALUE) {
1229 	    WINCONSOLE.buffered = buffered;
1230 	    _nc_console_get_SBI();
1231 	    WINCONSOLE.save_SBI = WINCONSOLE.SBI;
1232 	    if (!buffered) {
1233 		save_original_screen();
1234 		_nc_console_set_scrollback(FALSE, &WINCONSOLE.SBI);
1235 	    }
1236 	    GetConsoleCursorInfo(WINCONSOLE.hdl, &WINCONSOLE.save_CI);
1237 	    T(("... initial cursor is %svisible, %d%%",
1238 	       (WINCONSOLE.save_CI.bVisible ? "" : "not-"),
1239 	       (int) WINCONSOLE.save_CI.dwSize));
1240 	}
1241 
1242 	WINCONSOLE.initialized = TRUE;
1243 	console_initialized = TRUE;
1244     }
1245     res = (WINCONSOLE.hdl != INVALID_HANDLE_VALUE);
1246     returnBool(res);
1247 }
1248 #endif /* USE_WINCONMODE */
1249 
1250 NCURSES_EXPORT(bool)
_nc_console_restore(void)1251 _nc_console_restore(void)
1252 {
1253     bool res = FALSE;
1254 
1255     T((T_CALLED("lib_win32con::_nc_console_restore")));
1256     if (WINCONSOLE.hdl != INVALID_HANDLE_VALUE) {
1257 	res = TRUE;
1258 	if (!WINCONSOLE.buffered) {
1259 	    _nc_console_set_scrollback(TRUE, &WINCONSOLE.save_SBI);
1260 	    if (!restore_original_screen())
1261 		res = FALSE;
1262 	}
1263 	SetConsoleCursorInfo(WINCONSOLE.hdl, &WINCONSOLE.save_CI);
1264     }
1265     returnBool(res);
1266 }
1267 
1268 #endif // _NC_WINDOWS
1269