blob: 78ccfeda1b8289f472ccbf72084121a6919d3e8e [file] [log] [blame]
Steve Kondikae271bc2015-11-15 02:50:53 +01001/****************************************************************************
2 * Copyright (c) 1998-2014,2015 Free Software Foundation, Inc. *
3 * *
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: *
11 * *
12 * The above copyright notice and this permission notice shall be included *
13 * in all copies or substantial portions of the Software. *
14 * *
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. *
22 * *
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 *
26 * authorization. *
27 ****************************************************************************/
28
29/****************************************************************************
30 * Author: Juergen Pfeifer *
31 * and: Thomas E. Dickey *
32 ****************************************************************************/
33
34/*
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
39 */
40
41#include <curses.priv.h>
42
43#ifdef __MINGW32__
44#include <tchar.h>
45#else
46#include <windows.h>
47#include <wchar.h>
48#endif
49
50#include <io.h>
51
52#define PSAPI_VERSION 2
53#include <psapi.h>
54
55#define CUR my_term.type.
56
57MODULE_ID("$Id: win_driver.c,v 1.55 2015/02/28 21:30:23 tom Exp $")
58
59#ifndef __GNUC__
60# error We need GCC to compile for MinGW
61#endif
62
63#define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
64
65#define EXP_OPTIMIZE 0
66
67#define array_length(a) (sizeof(a)/sizeof(a[0]))
68
69static bool InitConsole(void);
70static bool okConsoleHandle(TERMINAL_CONTROL_BLOCK *);
71
72#define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC))
73#define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp
74
75#define GenMap(vKey,key) MAKELONG(key, vKey)
76
77#define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top)
78
79#if USE_WIDEC_SUPPORT
80#define write_screen WriteConsoleOutputW
81#define read_screen ReadConsoleOutputW
82#else
83#define write_screen WriteConsoleOutput
84#define read_screen ReadConsoleOutput
85#endif
86
87static const LONG keylist[] =
88{
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)
99};
100static const LONG ansi_keys[] =
101{
102 GenMap(VK_PRIOR, 'I'),
103 GenMap(VK_NEXT, 'Q'),
104 GenMap(VK_END, 'O'),
105 GenMap(VK_HOME, 'H'),
106 GenMap(VK_LEFT, 'K'),
107 GenMap(VK_UP, 'H'),
108 GenMap(VK_RIGHT, 'M'),
109 GenMap(VK_DOWN, 'P'),
110 GenMap(VK_DELETE, 'S'),
111 GenMap(VK_INSERT, 'R')
112};
113#define N_INI ((int)array_length(keylist))
114#define FKEYS 24
115#define MAPSIZE (FKEYS + N_INI)
116#define NUMPAIRS 64
117
118/* A process can only have a single console, so it's safe
119 to maintain all the information about it in a single
120 static structure.
121 */
122static struct {
123 BOOL initialized;
124 BOOL buffered;
125 BOOL window_only;
126 BOOL progMode;
127 BOOL isMinTTY;
128 BOOL isTermInfoConsole;
129 HANDLE out;
130 HANDLE inp;
131 HANDLE hdl;
132 HANDLE lastOut;
133 int numButtons;
134 DWORD ansi_map[MAPSIZE];
135 DWORD map[MAPSIZE];
136 DWORD rmap[MAPSIZE];
137 WORD pairs[NUMPAIRS];
138 COORD origin;
139 CHAR_INFO *save_screen;
140 COORD save_size;
141 SMALL_RECT save_region;
142 CONSOLE_SCREEN_BUFFER_INFO SBI;
143 CONSOLE_SCREEN_BUFFER_INFO save_SBI;
144 CONSOLE_CURSOR_INFO save_CI;
145} CON;
146
147static BOOL console_initialized = FALSE;
148
149static WORD
150MapColor(bool fore, int color)
151{
152 static const int _cmap[] =
153 {0, 4, 2, 6, 1, 5, 3, 7};
154 int a;
155 if (color < 0 || color > 7)
156 a = fore ? 7 : 0;
157 else
158 a = _cmap[color];
159 if (!fore)
160 a = a << 4;
161 return (WORD) a;
162}
163
164#define RevAttr(attr) \
165 (WORD) (((attr) & 0xff00) | \
166 ((((attr) & 0x07) << 4) | \
167 (((attr) & 0x70) >> 4)))
168
169static WORD
170MapAttr(WORD res, attr_t ch)
171{
172 if (ch & A_COLOR) {
173 int p;
174
175 p = PairNumber(ch);
176 if (p > 0 && p < NUMPAIRS) {
177 WORD a;
178 a = CON.pairs[p];
179 res = (WORD) ((res & 0xff00) | a);
180 }
181 }
182
183 if (ch & A_REVERSE) {
184 res = RevAttr(res);
185 }
186
187 if (ch & A_STANDOUT) {
188 res = RevAttr(res) | BACKGROUND_INTENSITY;
189 }
190
191 if (ch & A_BOLD)
192 res |= FOREGROUND_INTENSITY;
193
194 if (ch & A_DIM)
195 res |= BACKGROUND_INTENSITY;
196
197 return res;
198}
199
200#if 0 /* def TRACE */
201static void
202dump_screen(const char *fn, int ln)
203{
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];
207 COORD save_size;
208 SMALL_RECT save_region;
209 COORD bufferCoord;
210
211 T(("dump_screen %s@%d", fn, ln));
212
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;
217
218 save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
219 save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
220
221 bufferCoord.X = bufferCoord.Y = 0;
222
223 if (read_screen(CON.hdl,
224 save_screen,
225 save_size,
226 bufferCoord,
227 &save_region)) {
228 int i, j;
229 int ij = 0;
230 int k = 0;
231
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;
235 }
236 output[k++] = '\n';
237 }
238 output[k] = 0;
239
240 T(("DUMP: %d,%d - %d,%d",
241 save_region.Top,
242 save_region.Left,
243 save_region.Bottom,
244 save_region.Right));
245 T(("%s", output));
246 }
247}
248
249#else
250#define dump_screen(fn,ln) /* nothing */
251#endif
252
253#if USE_WIDEC_SUPPORT
254/*
255 * TODO: support surrogate pairs
256 * TODO: support combining characters
257 * TODO: support acsc
258 * TODO: _nc_wacs should be part of sp.
259 */
260static BOOL
261con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit)
262{
263 int actual = 0;
264 CHAR_INFO ci[limit];
265 COORD loc, siz;
266 SMALL_RECT rec;
267 int i;
268 cchar_t ch;
269 SCREEN *sp;
270
271 AssertTCB();
272 SetSP();
273
274 for (i = actual = 0; i < limit; i++) {
275 ch = str[i];
276 if (isWidecExt(ch))
277 continue;
278 ci[actual].Char.UnicodeChar = CharOf(ch);
279 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes,
280 AttrOf(ch));
281 if (AttrOf(ch) & A_ALTCHARSET) {
282 if (_nc_wacs) {
283 int which = CharOf(ch);
284 if (which > 0
285 && which < ACS_LEN
286 && CharOf(_nc_wacs[which]) != 0) {
287 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]);
288 } else {
289 ci[actual].Char.UnicodeChar = ' ';
290 }
291 }
292 }
293 ++actual;
294 }
295
296 loc.X = (SHORT) 0;
297 loc.Y = (SHORT) 0;
298 siz.X = (SHORT) actual;
299 siz.Y = 1;
300
301 rec.Left = (SHORT) x;
302 rec.Top = (SHORT) (y + AdjustY());
303 rec.Right = (SHORT) (x + limit - 1);
304 rec.Bottom = rec.Top;
305
306 return write_screen(CON.hdl, ci, siz, loc, &rec);
307}
308#define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
309#else
310static BOOL
311con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
312{
313 CHAR_INFO ci[n];
314 COORD loc, siz;
315 SMALL_RECT rec;
316 int i;
317 chtype ch;
318 SCREEN *sp;
319
320 AssertTCB();
321 SetSP();
322
323 for (i = 0; i < n; i++) {
324 ch = str[i];
325 ci[i].Char.AsciiChar = ChCharOf(ch);
326 ci[i].Attributes = MapAttr(CON.SBI.wAttributes,
327 ChAttrOf(ch));
328 if (ChAttrOf(ch) & A_ALTCHARSET) {
329 if (sp->_acs_map)
330 ci[i].Char.AsciiChar =
331 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
332 }
333 }
334
335 loc.X = (short) 0;
336 loc.Y = (short) 0;
337 siz.X = (short) n;
338 siz.Y = 1;
339
340 rec.Left = (short) x;
341 rec.Top = (short) y;
342 rec.Right = (short) (x + n - 1);
343 rec.Bottom = rec.Top;
344
345 return write_screen(CON.hdl, ci, siz, loc, &rec);
346}
347#define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
348#endif
349
350#if EXP_OPTIMIZE
351/*
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.
355 */
356static int
357find_end_of_change(SCREEN *sp, int row, int col)
358{
359 int result = col;
360 struct ldat *curdat = CurScreen(sp)->_line + row;
361 struct ldat *newdat = NewScreen(sp)->_line + row;
362
363 while (col <= newdat->lastchar) {
364#if USE_WIDEC_SUPPORT
365 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) {
366 result = col;
367 } else if (memcmp(&curdat->text[col],
368 &newdat->text[col],
369 sizeof(curdat->text[0]))) {
370 result = col;
371 } else {
372 break;
373 }
374#else
375 if (curdat->text[col] != newdat->text[col]) {
376 result = col;
377 } else {
378 break;
379 }
380#endif
381 ++col;
382 }
383 return result;
384}
385
386/*
387 * Given a row,col position at the end of a change-chunk, look for the
388 * beginning of the next change-chunk.
389 */
390static int
391find_next_change(SCREEN *sp, int row, int col)
392{
393 struct ldat *curdat = CurScreen(sp)->_line + row;
394 struct ldat *newdat = NewScreen(sp)->_line + row;
395 int result = newdat->lastchar + 1;
396
397 while (++col <= newdat->lastchar) {
398#if USE_WIDEC_SUPPORT
399 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) {
400 result = col;
401 break;
402 } else if (memcmp(&curdat->text[col],
403 &newdat->text[col],
404 sizeof(curdat->text[0]))) {
405 result = col;
406 break;
407 }
408#else
409 if (curdat->text[col] != newdat->text[col]) {
410 result = col;
411 break;
412 }
413#endif
414 }
415 return result;
416}
417
418#define EndChange(first) \
419 find_end_of_change(sp, y, first)
420#define NextChange(last) \
421 find_next_change(sp, y, last)
422
423#endif /* EXP_OPTIMIZE */
424
425#define MARK_NOCHANGE(win,row) \
426 win->_line[row].firstchar = _NOCHANGE; \
427 win->_line[row].lastchar = _NOCHANGE
428
429static void
430selectActiveHandle(void)
431{
432 if (CON.lastOut != CON.hdl) {
433 CON.lastOut = CON.hdl;
434 SetConsoleActiveScreenBuffer(CON.lastOut);
435 }
436}
437
438static bool
439restore_original_screen(void)
440{
441 COORD bufferCoord;
442 bool result = FALSE;
443 SMALL_RECT save_region = CON.save_region;
444
445 T(("... restoring %s", CON.window_only ? "window" : "entire buffer"));
446
447 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0);
448 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0);
449
450 if (write_screen(CON.hdl,
451 CON.save_screen,
452 CON.save_size,
453 bufferCoord,
454 &save_region)) {
455 result = TRUE;
456 mvcur(-1, -1, LINES - 2, 0);
457 T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
458 CON.save_size.Y,
459 CON.save_size.X,
460 save_region.Top,
461 save_region.Left,
462 save_region.Bottom,
463 save_region.Right));
464 } else {
465 T(("... restore original screen contents err"));
466 }
467 return result;
468}
469
470static const char *
471wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
472{
473 (void) TCB;
474 return "win32console";
475}
476
477static int
478wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
479{
480 int result = ERR;
481 int y, nonempty, n, x0, x1, Width, Height;
482 SCREEN *sp;
483
484 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
485 if (okConsoleHandle(TCB)) {
486 SetSP();
487
488 Width = screen_columns(sp);
489 Height = screen_lines(sp);
490 nonempty = min(Height, NewScreen(sp)->_maxy + 1);
491
492 T(("... %dx%d clear cur:%d new:%d",
493 Height, Width,
494 CurScreen(sp)->_clear,
495 NewScreen(sp)->_clear));
496
497 if (SP_PARM->_endwin) {
498
499 T(("coming back from shell mode"));
500 NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
501
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);
505
506 SP_PARM->_endwin = FALSE;
507 }
508
509 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
510 int x;
511#if USE_WIDEC_SUPPORT
512 cchar_t empty[Width];
513 wchar_t blank[2] =
514 {
515 L' ', L'\0'
516 };
517
518 for (x = 0; x < Width; x++)
519 setcchar(&empty[x], blank, 0, 0, 0);
520#else
521 chtype empty[Width];
522
523 for (x = 0; x < Width; x++)
524 empty[x] = ' ';
525#endif
526
527 for (y = 0; y < nonempty; y++) {
528 con_write(TCB, y, 0, empty, Width);
529 memcpy(empty,
530 CurScreen(sp)->_line[y].text,
531 (size_t) Width * sizeof(empty[0]));
532 }
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,
537 AdjustY()));
538 }
539
540 for (y = 0; y < nonempty; y++) {
541 x0 = NewScreen(sp)->_line[y].firstchar;
542 if (x0 != _NOCHANGE) {
543#if EXP_OPTIMIZE
544 int x2;
545 int limit = NewScreen(sp)->_line[y].lastchar;
546 while ((x1 = EndChange(x0)) <= limit) {
547 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) {
548 x1 = x2;
549 }
550 n = x1 - x0 + 1;
551 memcpy(&CurScreen(sp)->_line[y].text[x0],
552 &NewScreen(sp)->_line[y].text[x0],
553 n * sizeof(CurScreen(sp)->_line[y].text[x0]));
554 con_write(TCB,
555 y,
556 x0,
557 &CurScreen(sp)->_line[y].text[x0], n);
558 x0 = NextChange(x1);
559 }
560
561 /* mark line changed successfully */
562 if (y <= NewScreen(sp)->_maxy) {
563 MARK_NOCHANGE(NewScreen(sp), y);
564 }
565 if (y <= CurScreen(sp)->_maxy) {
566 MARK_NOCHANGE(CurScreen(sp), y);
567 }
568#else
569 x1 = NewScreen(sp)->_line[y].lastchar;
570 n = x1 - x0 + 1;
571 if (n > 0) {
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]));
575 con_write(TCB,
576 y,
577 x0,
578 &CurScreen(sp)->_line[y].text[x0], n);
579
580 /* mark line changed successfully */
581 if (y <= NewScreen(sp)->_maxy) {
582 MARK_NOCHANGE(NewScreen(sp), y);
583 }
584 if (y <= CurScreen(sp)->_maxy) {
585 MARK_NOCHANGE(CurScreen(sp), y);
586 }
587 }
588#endif
589 }
590 }
591
592 /* put everything back in sync */
593 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
594 MARK_NOCHANGE(NewScreen(sp), y);
595 }
596 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
597 MARK_NOCHANGE(CurScreen(sp), y);
598 }
599
600 if (!NewScreen(sp)->_leaveok) {
601 CurScreen(sp)->_curx = NewScreen(sp)->_curx;
602 CurScreen(sp)->_cury = NewScreen(sp)->_cury;
603
604 TCB->drv->td_hwcur(TCB,
605 0, 0,
606 CurScreen(sp)->_cury, CurScreen(sp)->_curx);
607 }
608 selectActiveHandle();
609 result = OK;
610 }
611 returnCode(result);
612}
613
614static bool
615wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
616 const char *tname,
617 int *errret GCC_UNUSED)
618{
619 bool code = FALSE;
620
621 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB));
622
623 assert((TCB != 0) && (tname != 0));
624
625 TCB->magic = WINMAGIC;
626
627 if (tname == 0 || *tname == 0)
628 code = TRUE;
629 else if (tname != 0 && *tname == '#') {
630 /*
631 * Use "#" (a character which cannot begin a terminal's name) to
632 * select specific driver from the table.
633 *
634 * In principle, we could have more than one non-terminfo driver,
635 * e.g., "win32gui".
636 */
637 size_t n = strlen(tname + 1);
638 if (n != 0
639 && ((strncmp(tname + 1, "win32console", n) == 0)
640 || (strncmp(tname + 1, "win32con", n) == 0))) {
641 code = TRUE;
642 }
643 } else if (tname != 0 && stricmp(tname, "unknown") == 0) {
644 code = TRUE;
645 }
646
647 /*
648 * This is intentional, to avoid unnecessary breakage of applications
649 * using <term.h> symbols.
650 */
651 if (code && (TCB->term.type.Booleans == 0)) {
652 _nc_init_termtype(&(TCB->term.type));
653 }
654
655 if (!code) {
656 if (_nc_mingw_isconsole(0))
657 CON.isTermInfoConsole = TRUE;
658 }
659 returnBool(code);
660}
661
662static int
663wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
664 int beepFlag)
665{
666 SCREEN *sp;
667 int res = ERR;
668
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);
672 int i;
673
674 CHAR_INFO this_screen[max_cells];
675 CHAR_INFO that_screen[max_cells];
676 COORD this_size;
677 SMALL_RECT this_region;
678 COORD bufferCoord;
679
680 if (okConsoleHandle(TCB)) {
681 SetSP();
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;
686
687 this_size.X = (SHORT) wide;
688 this_size.Y = (SHORT) high;
689
690 bufferCoord.X = this_region.Left;
691 bufferCoord.Y = this_region.Top;
692
693 if (!beepFlag &&
694 read_screen(CON.hdl,
695 this_screen,
696 this_size,
697 bufferCoord,
698 &this_region)) {
699
700 memcpy(that_screen, this_screen, sizeof(that_screen));
701
702 for (i = 0; i < max_cells; i++) {
703 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes);
704 }
705
706 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region);
707 Sleep(200);
708 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region);
709
710 } else {
711 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */
712 }
713 res = OK;
714 }
715 return res;
716}
717
718static int
719wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
720 char *data GCC_UNUSED,
721 int len GCC_UNUSED)
722{
723 SCREEN *sp;
724
725 AssertTCB();
726 SetSP();
727
728 return ERR;
729}
730
731static int
732wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
733 int fg GCC_UNUSED,
734 int bg GCC_UNUSED)
735{
736 SCREEN *sp;
737 int code = ERR;
738
739 AssertTCB();
740 SetSP();
741
742 return (code);
743}
744
745static bool
746get_SBI(void)
747{
748 bool rc = FALSE;
749 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) {
750 T(("GetConsoleScreenBufferInfo"));
751 T(("... buffer(X:%d Y:%d)",
752 CON.SBI.dwSize.X,
753 CON.SBI.dwSize.Y));
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));
765 if (CON.buffered) {
766 CON.origin.X = 0;
767 CON.origin.Y = 0;
768 } else {
769 CON.origin.X = CON.SBI.srWindow.Left;
770 CON.origin.Y = CON.SBI.srWindow.Top;
771 }
772 rc = TRUE;
773 } else {
774 T(("GetConsoleScreenBufferInfo ERR"));
775 }
776 return rc;
777}
778
779static void
780wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
781 int fore,
782 int color,
783 int (*outc) (SCREEN *, int) GCC_UNUSED)
784{
785 if (okConsoleHandle(TCB)) {
786 WORD a = MapColor(fore, color);
787 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
788 SetConsoleTextAttribute(CON.hdl, a);
789 get_SBI();
790 }
791}
792
793static bool
794wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
795{
796 bool res = FALSE;
797
798 if (okConsoleHandle(TCB)) {
799 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
800 SetConsoleTextAttribute(CON.hdl, a);
801 get_SBI();
802 res = TRUE;
803 }
804 return res;
805}
806
807static bool
808wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
809{
810 int result = FALSE;
811 SCREEN *sp;
812
813 AssertTCB();
814 SetSP();
815
816 return result;
817}
818
819static int
820wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
821{
822 int result = ERR;
823
824 T((T_CALLED("win32con::wcon_size(%p)"), TCB));
825
826 if (okConsoleHandle(TCB) &&
827 Lines != NULL &&
828 Cols != NULL) {
829 if (CON.buffered) {
830 *Lines = (int) (CON.SBI.dwSize.Y);
831 *Cols = (int) (CON.SBI.dwSize.X);
832 } else {
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);
837 }
838 result = OK;
839 }
840 returnCode(result);
841}
842
843static int
844wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
845 int l GCC_UNUSED,
846 int c GCC_UNUSED)
847{
848 AssertTCB();
849 return ERR;
850}
851
852static int
853wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
854{
855 DWORD dwFlag = 0;
856 tcflag_t iflag;
857 tcflag_t lflag;
858 int result = ERR;
859
860 if (buf != NULL && okConsoleHandle(TCB)) {
861
862 if (setFlag) {
863 iflag = buf->c_iflag;
864 lflag = buf->c_lflag;
865
866 GetConsoleMode(CON.inp, &dwFlag);
867
868 if (lflag & ICANON)
869 dwFlag |= ENABLE_LINE_INPUT;
870 else
871 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT);
872
873 if (lflag & ECHO)
874 dwFlag |= ENABLE_ECHO_INPUT;
875 else
876 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT);
877
878 if (iflag & BRKINT)
879 dwFlag |= ENABLE_PROCESSED_INPUT;
880 else
881 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT);
882
883 dwFlag |= ENABLE_MOUSE_INPUT;
884
885 buf->c_iflag = iflag;
886 buf->c_lflag = lflag;
887 SetConsoleMode(CON.inp, dwFlag);
888 TCB->term.Nttyb = *buf;
889 } else {
890 iflag = TCB->term.Nttyb.c_iflag;
891 lflag = TCB->term.Nttyb.c_lflag;
892 GetConsoleMode(CON.inp, &dwFlag);
893
894 if (dwFlag & ENABLE_LINE_INPUT)
895 lflag |= ICANON;
896 else
897 lflag &= (tcflag_t) (~ICANON);
898
899 if (dwFlag & ENABLE_ECHO_INPUT)
900 lflag |= ECHO;
901 else
902 lflag &= (tcflag_t) (~ECHO);
903
904 if (dwFlag & ENABLE_PROCESSED_INPUT)
905 iflag |= BRKINT;
906 else
907 iflag &= (tcflag_t) (~BRKINT);
908
909 TCB->term.Nttyb.c_iflag = iflag;
910 TCB->term.Nttyb.c_lflag = lflag;
911
912 *buf = TCB->term.Nttyb;
913 }
914 result = OK;
915 }
916 return result;
917}
918
919#define MIN_WIDE 80
920#define MIN_HIGH 24
921
922/*
923 * In "normal" mode, reset the buffer- and window-sizes back to their original values.
924 */
925static void
926set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info)
927{
928 SMALL_RECT rect;
929 COORD coord;
930 bool changed = FALSE;
931
932 T((T_CALLED("win32con::set_scrollback(%s)"),
933 (normal
934 ? "normal"
935 : "application")));
936
937 T(("... SBI.srWindow %d,%d .. %d,%d",
938 info->srWindow.Top,
939 info->srWindow.Left,
940 info->srWindow.Bottom,
941 info->srWindow.Right));
942 T(("... SBI.dwSize %dx%d",
943 info->dwSize.Y,
944 info->dwSize.X));
945
946 if (normal) {
947 rect = info->srWindow;
948 coord = info->dwSize;
949 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) {
950 changed = TRUE;
951 CON.SBI = *info;
952 }
953 } else {
954 int high = info->srWindow.Bottom - info->srWindow.Top + 1;
955 int wide = info->srWindow.Right - info->srWindow.Left + 1;
956
957 if (high < MIN_HIGH) {
958 T(("... height %d < %d", high, MIN_HIGH));
959 high = MIN_HIGH;
960 changed = TRUE;
961 }
962 if (wide < MIN_WIDE) {
963 T(("... width %d < %d", wide, MIN_WIDE));
964 wide = MIN_WIDE;
965 changed = TRUE;
966 }
967
968 rect.Left =
969 rect.Top = 0;
970 rect.Right = (SHORT) (wide - 1);
971 rect.Bottom = (SHORT) (high - 1);
972
973 coord.X = (SHORT) wide;
974 coord.Y = (SHORT) high;
975
976 if (info->dwSize.Y != high ||
977 info->dwSize.X != wide ||
978 info->srWindow.Top != 0 ||
979 info->srWindow.Left != 0) {
980 changed = TRUE;
981 }
982
983 }
984
985 if (changed) {
986 T(("... coord %d,%d", coord.Y, coord.X));
987 T(("... rect %d,%d - %d,%d",
988 rect.Top, rect.Left,
989 rect.Bottom, rect.Right));
990 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */
991 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */
992 get_SBI();
993 }
994 returnVoid;
995}
996
997static int
998wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
999{
1000 SCREEN *sp;
1001 TERMINAL *_term = (TERMINAL *) TCB;
1002 int code = ERR;
1003
1004 if (okConsoleHandle(TCB)) {
1005 sp = TCB->csp;
1006
1007 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"),
1008 TCB, progFlag, defFlag));
1009
1010 CON.progMode = progFlag;
1011 CON.lastOut = progFlag ? CON.hdl : CON.out;
1012 SetConsoleActiveScreenBuffer(CON.lastOut);
1013
1014 if (progFlag) /* prog mode */ {
1015 if (defFlag) {
1016 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
1017 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS);
1018 code = OK;
1019 }
1020 } else {
1021 /* reset_prog_mode */
1022 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
1023 if (sp) {
1024 if (sp->_keypad_on)
1025 _nc_keypad(sp, TRUE);
1026 }
1027 if (!CON.buffered) {
1028 set_scrollback(FALSE, &CON.SBI);
1029 }
1030 code = OK;
1031 }
1032 }
1033 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear));
1034 } else { /* shell mode */
1035 if (defFlag) {
1036 /* def_shell_mode */
1037 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
1038 code = OK;
1039 }
1040 } else {
1041 /* reset_shell_mode */
1042 if (sp) {
1043 _nc_keypad(sp, FALSE);
1044 NCURSES_SP_NAME(_nc_flush) (sp);
1045 }
1046 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
1047 if (!CON.buffered) {
1048 set_scrollback(TRUE, &CON.save_SBI);
1049 if (!restore_original_screen())
1050 code = ERR;
1051 }
1052 SetConsoleCursorInfo(CON.hdl, &CON.save_CI);
1053 }
1054 }
1055
1056 }
1057 returnCode(code);
1058}
1059
1060static void
1061wcon_screen_init(SCREEN *sp GCC_UNUSED)
1062{
1063}
1064
1065static void
1066wcon_wrap(SCREEN *sp GCC_UNUSED)
1067{
1068}
1069
1070static int
1071rkeycompare(const void *el1, const void *el2)
1072{
1073 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff;
1074 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff;
1075
1076 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1077}
1078
1079static int
1080keycompare(const void *el1, const void *el2)
1081{
1082 WORD key1 = HIWORD((*((const LONG *) el1)));
1083 WORD key2 = HIWORD((*((const LONG *) el2)));
1084
1085 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1));
1086}
1087
1088static int
1089MapKey(WORD vKey)
1090{
1091 WORD nKey = 0;
1092 void *res;
1093 LONG key = GenMap(vKey, 0);
1094 int code = -1;
1095
1096 res = bsearch(&key,
1097 CON.map,
1098 (size_t) (N_INI + FKEYS),
1099 sizeof(keylist[0]),
1100 keycompare);
1101 if (res) {
1102 key = *((LONG *) res);
1103 nKey = LOWORD(key);
1104 code = (int) (nKey & 0x7fff);
1105 if (nKey & 0x8000)
1106 code = -code;
1107 }
1108 return code;
1109}
1110
1111static int
1112AnsiKey(WORD vKey)
1113{
1114 WORD nKey = 0;
1115 void *res;
1116 LONG key = GenMap(vKey, 0);
1117 int code = -1;
1118
1119 res = bsearch(&key,
1120 CON.ansi_map,
1121 (size_t) (N_INI + FKEYS),
1122 sizeof(keylist[0]),
1123 keycompare);
1124 if (res) {
1125 key = *((LONG *) res);
1126 nKey = LOWORD(key);
1127 code = (int) (nKey & 0x7fff);
1128 if (nKey & 0x8000)
1129 code = -code;
1130 }
1131 return code;
1132}
1133
1134static void
1135wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
1136{
1137 T((T_CALLED("win32con::wcon_release(%p)"), TCB));
1138
1139 AssertTCB();
1140 if (TCB->prop)
1141 free(TCB->prop);
1142
1143 returnVoid;
1144}
1145
1146static bool
1147read_screen_data(void)
1148{
1149 bool result = FALSE;
1150 COORD bufferCoord;
1151 size_t want;
1152
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);
1157
1158 want = (size_t) (CON.save_size.X * CON.save_size.Y);
1159
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);
1163
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,
1171 bufferCoord.Y,
1172 bufferCoord.X));
1173
1174 if (read_screen(CON.hdl,
1175 CON.save_screen,
1176 CON.save_size,
1177 bufferCoord,
1178 &CON.save_region)) {
1179 result = TRUE;
1180 } else {
1181 T((" error %#lx", (unsigned long) GetLastError()));
1182 FreeAndNull(CON.save_screen);
1183 }
1184 }
1185
1186 return result;
1187}
1188
1189/*
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
1194 * less).
1195 */
1196static bool
1197save_original_screen(void)
1198{
1199 bool result = FALSE;
1200
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);
1205
1206 if (read_screen_data()) {
1207 result = TRUE;
1208 } else {
1209
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;
1214
1215 CON.window_only = TRUE;
1216
1217 if (read_screen_data()) {
1218 result = TRUE;
1219 }
1220 }
1221
1222 T(("... save original screen contents %s", result ? "ok" : "err"));
1223 return result;
1224}
1225
1226static void
1227wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
1228{
1229 T((T_CALLED("win32con::wcon_init(%p)"), TCB));
1230
1231 AssertTCB();
1232
1233 if (TCB) {
1234 if (!InitConsole()) {
1235 returnVoid;
1236 }
1237
1238 TCB->info.initcolor = TRUE;
1239 TCB->info.canchange = FALSE;
1240 TCB->info.hascolor = TRUE;
1241 TCB->info.caninit = TRUE;
1242
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;
1250
1251 TCB->info.numbuttons = CON.numButtons;
1252 TCB->info.defaultPalette = _nc_cga_palette;
1253
1254 }
1255 returnVoid;
1256}
1257
1258static void
1259wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
1260 int pair,
1261 int f,
1262 int b)
1263{
1264 SCREEN *sp;
1265
1266 if (okConsoleHandle(TCB)) {
1267 SetSP();
1268
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);
1272 }
1273 }
1274}
1275
1276static void
1277wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
1278 int color GCC_UNUSED,
1279 int r GCC_UNUSED,
1280 int g GCC_UNUSED,
1281 int b GCC_UNUSED)
1282{
1283 SCREEN *sp;
1284
1285 AssertTCB();
1286 SetSP();
1287}
1288
1289static void
1290wcon_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
1295)
1296{
1297 SCREEN *sp;
1298
1299 AssertTCB();
1300 SetSP();
1301}
1302
1303static void
1304wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
1305{
1306 SCREEN *sp;
1307
1308 if (okConsoleHandle(TCB)) {
1309 SetSP();
1310
1311 sp->_mouse_type = M_TERM_DRIVER;
1312 }
1313}
1314
1315static int
1316wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay)
1317{
1318 int rc = 0;
1319 SCREEN *sp;
1320
1321 if (okConsoleHandle(TCB)) {
1322 SetSP();
1323
1324 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
1325 rc = TW_MOUSE;
1326 } else {
1327 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
1328 TWAIT_MASK,
1329 delay,
1330 (int *) 0
1331 EVENTLIST_2nd(evl));
1332 }
1333 }
1334
1335 return rc;
1336}
1337
1338static int
1339wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
1340 int yold GCC_UNUSED, int xold GCC_UNUSED,
1341 int y, int x)
1342{
1343 int ret = ERR;
1344 if (okConsoleHandle(TCB)) {
1345 COORD loc;
1346 loc.X = (short) x;
1347 loc.Y = (short) (y + AdjustY());
1348 SetConsoleCursorPosition(CON.hdl, loc);
1349 ret = OK;
1350 }
1351 return ret;
1352}
1353
1354static void
1355wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
1356 int labnum GCC_UNUSED,
1357 char *text GCC_UNUSED)
1358{
1359 SCREEN *sp;
1360
1361 AssertTCB();
1362 SetSP();
1363}
1364
1365static void
1366wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
1367 int OnFlag GCC_UNUSED)
1368{
1369 SCREEN *sp;
1370
1371 AssertTCB();
1372 SetSP();
1373}
1374
1375static chtype
1376wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
1377{
1378 chtype res = A_NORMAL;
1379 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
1380 return res;
1381}
1382
1383static void
1384wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1385{
1386 SCREEN *sp;
1387
1388 AssertTCB();
1389 SetSP();
1390}
1391
1392static void
1393wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1394 chtype *real_map GCC_UNUSED,
1395 chtype *fake_map GCC_UNUSED)
1396{
1397#define DATA(a,b) { a, b }
1398 static struct {
1399 int acs_code;
1400 int use_code;
1401 } table[] = {
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 */
1424 };
1425#undef DATA
1426 unsigned n;
1427
1428 SCREEN *sp;
1429 if (okConsoleHandle(TCB)) {
1430 SetSP();
1431
1432 for (n = 0; n < SIZEOF(table); ++n) {
1433 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET;
1434 if (sp != 0)
1435 sp->_screen_acs_map[table[n].acs_code] = TRUE;
1436 }
1437 }
1438}
1439
1440static ULONGLONG
1441tdiff(FILETIME fstart, FILETIME fend)
1442{
1443 ULARGE_INTEGER ustart;
1444 ULARGE_INTEGER uend;
1445 ULONGLONG diff;
1446
1447 ustart.LowPart = fstart.dwLowDateTime;
1448 ustart.HighPart = fstart.dwHighDateTime;
1449 uend.LowPart = fend.dwLowDateTime;
1450 uend.HighPart = fend.dwHighDateTime;
1451
1452 diff = (uend.QuadPart - ustart.QuadPart) / 10000;
1453 return diff;
1454}
1455
1456static int
1457Adjust(int milliseconds, int diff)
1458{
1459 if (milliseconds != INFINITY) {
1460 milliseconds -= diff;
1461 if (milliseconds < 0)
1462 milliseconds = 0;
1463 }
1464 return milliseconds;
1465}
1466
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)
1472
1473static int
1474decode_mouse(SCREEN *sp, int mask)
1475{
1476 int result = 0;
1477
1478 (void) sp;
1479 assert(sp && console_initialized);
1480
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;
1489
1490 if (mask & RIGHTMOST_BUTTON_PRESSED) {
1491 switch (CON.numButtons) {
1492 case 1:
1493 result |= BUTTON1_PRESSED;
1494 break;
1495 case 2:
1496 result |= BUTTON2_PRESSED;
1497 break;
1498 case 3:
1499 result |= BUTTON3_PRESSED;
1500 break;
1501 case 4:
1502 result |= BUTTON4_PRESSED;
1503 break;
1504 }
1505 }
1506
1507 return result;
1508}
1509
1510static int
1511console_twait(
1512 SCREEN *sp,
1513 HANDLE fd,
1514 int mode,
1515 int milliseconds,
1516 int *timeleft
1517 EVENTLIST_2nd(_nc_eventlist * evl))
1518{
1519 INPUT_RECORD inp_rec;
1520 BOOL b;
1521 DWORD nRead = 0, rc = (DWORD) (-1);
1522 int code = 0;
1523 FILETIME fstart;
1524 FILETIME fend;
1525 int diff;
1526 bool isImmed = (milliseconds == 0);
1527
1528#define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead)
1529
1530 assert(sp);
1531
1532 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d",
1533 milliseconds, mode));
1534
1535 if (milliseconds < 0)
1536 milliseconds = INFINITY;
1537
1538 memset(&inp_rec, 0, sizeof(inp_rec));
1539
1540 while (true) {
1541 GetSystemTimeAsFileTime(&fstart);
1542 rc = WaitForSingleObject(fd, (DWORD) milliseconds);
1543 GetSystemTimeAsFileTime(&fend);
1544 diff = (int) tdiff(fstart, fend);
1545 milliseconds = Adjust(milliseconds, diff);
1546
1547 if (!isImmed && milliseconds <= 0)
1548 break;
1549
1550 if (rc == WAIT_OBJECT_0) {
1551 if (mode) {
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) {
1557 case KEY_EVENT:
1558 if (mode & TW_INPUT) {
1559 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
1560 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar;
1561
1562 if (inp_rec.Event.KeyEvent.bKeyDown) {
1563 if (0 == ch) {
1564 int nKey = MapKey(vk);
1565 if (nKey < 0) {
1566 CONSUME();
1567 continue;
1568 }
1569 }
1570 code = TW_INPUT;
1571 goto end;
1572 } else {
1573 CONSUME();
1574 }
1575 }
1576 continue;
1577 case MOUSE_EVENT:
1578 if (decode_mouse(sp,
1579 (inp_rec.Event.MouseEvent.dwButtonState
1580 & BUTTON_MASK)) == 0) {
1581 CONSUME();
1582 } else if (mode & TW_MOUSE) {
1583 code = TW_MOUSE;
1584 goto end;
1585 }
1586 continue;
1587 /* e.g., FOCUS_EVENT */
1588 default:
1589 CONSUME();
1590 selectActiveHandle();
1591 continue;
1592 }
1593 }
1594 }
1595 }
1596 continue;
1597 } else {
1598 if (rc != WAIT_TIMEOUT) {
1599 code = -1;
1600 break;
1601 } else {
1602 code = 0;
1603 break;
1604 }
1605 }
1606 }
1607 end:
1608
1609 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec",
1610 code, errno, milliseconds));
1611
1612 if (timeleft)
1613 *timeleft = milliseconds;
1614
1615 return code;
1616}
1617
1618static int
1619wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1620 int mode,
1621 int milliseconds,
1622 int *timeleft
1623 EVENTLIST_2nd(_nc_eventlist * evl))
1624{
1625 SCREEN *sp;
1626 int code = 0;
1627
1628 if (okConsoleHandle(TCB)) {
1629 SetSP();
1630
1631 code = console_twait(sp,
1632 CON.inp,
1633 mode,
1634 milliseconds,
1635 timeleft EVENTLIST_2nd(_nc_eventlist * evl));
1636 }
1637 return code;
1638}
1639
1640static bool
1641handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer)
1642{
1643 MEVENT work;
1644 bool result = FALSE;
1645
1646 assert(sp);
1647
1648 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons;
1649 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK;
1650
1651 /*
1652 * We're only interested if the button is pressed or released.
1653 * FIXME: implement continuous event-tracking.
1654 */
1655 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) {
1656
1657 memset(&work, 0, sizeof(work));
1658
1659 if (sp->_drv_mouse_new_buttons) {
1660
1661 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons);
1662
1663 } else {
1664
1665 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */
1666 work.bstate |= (mmask_t) (decode_mouse(sp,
1667 sp->_drv_mouse_old_buttons)
1668 >> 1);
1669
1670 result = TRUE;
1671 }
1672
1673 work.x = mer.dwMousePosition.X;
1674 work.y = mer.dwMousePosition.Y - AdjustY();
1675
1676 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work;
1677 sp->_drv_mouse_tail += 1;
1678 }
1679
1680 return result;
1681}
1682
1683static int
1684wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1685{
1686 SCREEN *sp;
1687 int n = -1;
1688
1689 T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1690
1691 assert(buf);
1692 if (okConsoleHandle(TCB)) {
1693 SetSP();
1694
1695 n = _nc_mingw_console_read(sp, CON.inp, buf);
1696 }
1697 returnCode(n);
1698}
1699
1700static int
1701wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1702{
1703 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1704 Sleep((DWORD) ms);
1705 returnCode(OK);
1706}
1707
1708static int
1709wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1710{
1711 int res = -1;
1712
1713 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1714 if (okConsoleHandle(TCB)) {
1715 CONSOLE_CURSOR_INFO this_CI = CON.save_CI;
1716 switch (mode) {
1717 case 0:
1718 this_CI.bVisible = FALSE;
1719 break;
1720 case 1:
1721 break;
1722 case 2:
1723 this_CI.dwSize = 100;
1724 break;
1725 }
1726 SetConsoleCursorInfo(CON.hdl, &this_CI);
1727 }
1728 returnCode(res);
1729}
1730
1731static bool
1732wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1733{
1734 WORD nKey;
1735 void *res;
1736 bool found = FALSE;
1737 LONG key = GenMap(0, (WORD) keycode);
1738
1739 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1740 res = bsearch(&key,
1741 CON.rmap,
1742 (size_t) (N_INI + FKEYS),
1743 sizeof(keylist[0]),
1744 rkeycompare);
1745 if (res) {
1746 key = *((LONG *) res);
1747 nKey = LOWORD(key);
1748 if (!(nKey & 0x8000))
1749 found = TRUE;
1750 }
1751 returnCode(found);
1752}
1753
1754static int
1755wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1756{
1757 SCREEN *sp;
1758 int code = ERR;
1759
1760 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1761
1762 if (okConsoleHandle(TCB)) {
1763 SetSP();
1764
1765 if (sp) {
1766 code = OK;
1767 }
1768 }
1769 returnCode(code);
1770}
1771
1772static int
1773wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1774 int keycode,
1775 int flag)
1776{
1777 int code = ERR;
1778 SCREEN *sp;
1779 WORD nKey;
1780 WORD vKey;
1781 void *res;
1782 LONG key = GenMap(0, (WORD) keycode);
1783
1784 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1785
1786 if (okConsoleHandle(TCB)) {
1787 SetSP();
1788
1789 if (sp) {
1790 res = bsearch(&key,
1791 CON.rmap,
1792 (size_t) (N_INI + FKEYS),
1793 sizeof(keylist[0]),
1794 rkeycompare);
1795 if (res) {
1796 key = *((LONG *) res);
1797 vKey = HIWORD(key);
1798 nKey = (LOWORD(key)) & 0x7fff;
1799 if (!flag)
1800 nKey |= 0x8000;
1801 *(LONG *) res = GenMap(vKey, nKey);
1802 }
1803 }
1804 }
1805 returnCode(code);
1806}
1807
1808NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1809 FALSE,
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 */
1841 wcon_nap, /* nap */
1842 wcon_kpad, /* kpad */
1843 wcon_keyok, /* kyOk */
1844 wcon_kyExist, /* kyExist */
1845 wcon_cursorSet /* cursorSet */
1846};
1847
1848/* --------------------------------------------------------- */
1849
1850static HANDLE
1851get_handle(int fd)
1852{
1853 intptr_t value = _get_osfhandle(fd);
1854 return (HANDLE) value;
1855}
1856
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.
1865 */
1866static int
1867_ismintty(int fd, LPHANDLE pMinTTY)
1868{
1869 HANDLE handle = get_handle(fd);
1870 DWORD dw;
1871 int code = 0;
1872
1873 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY));
1874
1875 if (handle != INVALID_HANDLE_VALUE) {
1876 dw = GetFileType(handle);
1877 if (dw == FILE_TYPE_PIPE) {
1878 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) {
1879 ULONG pPid;
1880 /* Requires NT6 */
1881 if (GetNamedPipeServerProcessId(handle, &pPid)) {
1882 TCHAR buf[MAX_PATH];
1883 DWORD len = 0;
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
1891 | PROCESS_VM_WRITE
1892 | PROCESS_VM_READ,
1893 FALSE,
1894 pPid);
1895 if (pMinTTY)
1896 *pMinTTY = INVALID_HANDLE_VALUE;
1897 if (pHandle != INVALID_HANDLE_VALUE) {
1898 if ((len = GetProcessImageFileName(
1899 pHandle,
1900 buf,
1901 (DWORD)
1902 array_length(buf)))) {
1903 TCHAR *pos = _tcsrchr(buf, _T('\\'));
1904 if (pos) {
1905 pos++;
1906 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10)
1907 == 0) {
1908 if (pMinTTY)
1909 *pMinTTY = pHandle;
1910 code = 1;
1911 }
1912 }
1913 }
1914 }
1915 }
1916 }
1917 }
1918 }
1919 returnCode(code);
1920}
1921#endif
1922
1923/* Borrowed from ansicon project.
1924 Check whether or not an I/O handle is associated with
1925 a Windows console.
1926*/
1927static BOOL
1928IsConsoleHandle(HANDLE hdl)
1929{
1930 DWORD dwFlag = 0;
1931 BOOL result;
1932
1933 if (!GetConsoleMode(hdl, &dwFlag)) {
1934 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL);
1935 } else {
1936 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT);
1937 }
1938 return result;
1939}
1940
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
1944 */
1945int
1946_nc_mingw_isatty(int fd)
1947{
1948 int result = 0;
1949
1950#ifdef __MING32__
1951#define SysISATTY(fd) _isatty(fd)
1952#else
1953#define SysISATTY(fd) isatty(fd)
1954#endif
1955 if (SysISATTY(fd)) {
1956 result = 1;
1957 } else {
1958#if WINVER >= 0x0600
1959 result = _ismintty(fd, NULL);
1960#endif
1961 }
1962 return result;
1963}
1964
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
1969 terminfo.
1970 */
1971int
1972_nc_mingw_isconsole(int fd)
1973{
1974 HANDLE hdl = get_handle(fd);
1975 int code = 0;
1976
1977 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd));
1978
1979 code = (int) IsConsoleHandle(hdl);
1980
1981 returnCode(code);
1982}
1983
1984#define TC_PROLOGUE(fd) \
1985 SCREEN *sp; \
1986 TERMINAL *term = 0; \
1987 int code = ERR; \
1988 if (_nc_screen_chain == 0) \
1989 return 0; \
1990 for (each_screen(sp)) { \
1991 if (sp->_term && (sp->_term->Filedes == fd)) { \
1992 term = sp->_term; \
1993 break; \
1994 } \
1995 } \
1996 assert(term != 0)
1997
1998int
1999_nc_mingw_tcsetattr(
2000 int fd,
2001 int optional_action GCC_UNUSED,
2002 const struct termios *arg)
2003{
2004 TC_PROLOGUE(fd);
2005
2006 if (_nc_mingw_isconsole(fd)) {
2007 DWORD dwFlag = 0;
2008 HANDLE ofd = get_handle(fd);
2009 if (ofd != INVALID_HANDLE_VALUE) {
2010 if (arg) {
2011 if (arg->c_lflag & ICANON)
2012 dwFlag |= ENABLE_LINE_INPUT;
2013 else
2014 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT);
2015
2016 if (arg->c_lflag & ECHO)
2017 dwFlag = dwFlag | ENABLE_ECHO_INPUT;
2018 else
2019 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT);
2020
2021 if (arg->c_iflag & BRKINT)
2022 dwFlag |= ENABLE_PROCESSED_INPUT;
2023 else
2024 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT);
2025 }
2026 dwFlag |= ENABLE_MOUSE_INPUT;
2027 SetConsoleMode(ofd, dwFlag);
2028 code = OK;
2029 }
2030 }
2031 if (arg)
2032 term->Nttyb = *arg;
2033
2034 return code;
2035}
2036
2037int
2038_nc_mingw_tcgetattr(int fd, struct termios *arg)
2039{
2040 TC_PROLOGUE(fd);
2041
2042 if (_nc_mingw_isconsole(fd)) {
2043 if (arg)
2044 *arg = term->Nttyb;
2045 }
2046 return code;
2047}
2048
2049int
2050_nc_mingw_tcflush(int fd, int queue)
2051{
2052 TC_PROLOGUE(fd);
2053 (void) term;
2054
2055 if (_nc_mingw_isconsole(fd)) {
2056 if (queue == TCIFLUSH) {
2057 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));
2058 if (!b)
2059 return (int) GetLastError();
2060 }
2061 }
2062 return code;
2063}
2064
2065int
2066_nc_mingw_testmouse(
2067 SCREEN *sp,
2068 HANDLE fd,
2069 int delay)
2070{
2071 int rc = 0;
2072
2073 assert(sp);
2074
2075 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
2076 rc = TW_MOUSE;
2077 } else {
2078 rc = console_twait(sp,
2079 fd,
2080 TWAIT_MASK,
2081 delay,
2082 (int *) 0
2083 EVENTLIST_2nd(evl));
2084 }
2085 return rc;
2086}
2087
2088int
2089_nc_mingw_console_read(
2090 SCREEN *sp,
2091 HANDLE fd,
2092 int *buf)
2093{
2094 int rc = -1;
2095 INPUT_RECORD inp_rec;
2096 BOOL b;
2097 DWORD nRead;
2098 WORD vk;
2099
2100 assert(sp);
2101 assert(buf);
2102
2103 memset(&inp_rec, 0, sizeof(inp_rec));
2104
2105 T((T_CALLED("_nc_mingw_console_read(%p)"), sp));
2106
2107 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) {
2108 if (b && nRead > 0) {
2109 if (rc < 0)
2110 rc = 0;
2111 rc += nRead;
2112 if (inp_rec.EventType == KEY_EVENT) {
2113 if (!inp_rec.Event.KeyEvent.bKeyDown)
2114 continue;
2115 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar;
2116 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode;
2117 /*
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.
2121 */
2122 if (vk >= VK_F1 && vk <= VK_F12) {
2123 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) {
2124 vk = (WORD) (vk + 12);
2125 }
2126 }
2127 if (*buf == 0) {
2128 int key = MapKey(vk);
2129 if (key < 0)
2130 continue;
2131 if (sp->_keypad_on) {
2132 *buf = key;
2133 } else {
2134 ungetch('\0');
2135 *buf = AnsiKey(vk);
2136 }
2137 }
2138 break;
2139 } else if (inp_rec.EventType == MOUSE_EVENT) {
2140 if (handle_mouse(sp,
2141 inp_rec.Event.MouseEvent)) {
2142 *buf = KEY_MOUSE;
2143 break;
2144 }
2145 }
2146 continue;
2147 }
2148 }
2149 returnCode(rc);
2150}
2151
2152static bool
2153InitConsole(void)
2154{
2155 /* initalize once, or not at all */
2156 if (!console_initialized) {
2157 int i;
2158 DWORD num_buttons;
2159 WORD a;
2160 BOOL buffered = TRUE;
2161 BOOL b;
2162
2163 START_TRACE();
2164 if (_nc_mingw_isatty(0)) {
2165 CON.isMinTTY = TRUE;
2166 }
2167
2168 for (i = 0; i < (N_INI + FKEYS); i++) {
2169 if (i < N_INI) {
2170 CON.rmap[i] = CON.map[i] =
2171 (DWORD) keylist[i];
2172 CON.ansi_map[i] = (DWORD) ansi_keys[i];
2173 } else {
2174 CON.rmap[i] = CON.map[i] =
2175 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2176 (KEY_F(1) + (i - N_INI)));
2177 CON.ansi_map[i] =
2178 (DWORD) GenMap((VK_F1 + (i - N_INI)),
2179 (';' + (i - N_INI)));
2180 }
2181 }
2182 qsort(CON.ansi_map,
2183 (size_t) (MAPSIZE),
2184 sizeof(keylist[0]),
2185 keycompare);
2186 qsort(CON.map,
2187 (size_t) (MAPSIZE),
2188 sizeof(keylist[0]),
2189 keycompare);
2190 qsort(CON.rmap,
2191 (size_t) (MAPSIZE),
2192 sizeof(keylist[0]),
2193 rkeycompare);
2194
2195 if (GetNumberOfConsoleMouseButtons(&num_buttons)) {
2196 CON.numButtons = (int) num_buttons;
2197 } else {
2198 CON.numButtons = 1;
2199 }
2200
2201 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK);
2202 for (i = 0; i < NUMPAIRS; i++)
2203 CON.pairs[i] = a;
2204
2205 CON.inp = GetStdHandle(STD_INPUT_HANDLE);
2206 CON.out = GetStdHandle(STD_OUTPUT_HANDLE);
2207
2208 b = AllocConsole();
2209
2210 if (!b)
2211 b = AttachConsole(ATTACH_PARENT_PROCESS);
2212
2213 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) {
2214 T(("... will not buffer console"));
2215 buffered = FALSE;
2216 CON.hdl = CON.out;
2217 } else {
2218 T(("... creating console buffer"));
2219 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE,
2220 0,
2221 NULL,
2222 CONSOLE_TEXTMODE_BUFFER,
2223 NULL);
2224 }
2225
2226 if (CON.hdl != INVALID_HANDLE_VALUE) {
2227 CON.buffered = buffered;
2228 get_SBI();
2229 CON.save_SBI = CON.SBI;
2230 if (!buffered) {
2231 save_original_screen();
2232 set_scrollback(FALSE, &CON.SBI);
2233 }
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));
2238 }
2239
2240 console_initialized = TRUE;
2241 }
2242 return (CON.hdl != INVALID_HANDLE_VALUE);
2243}
2244
2245static bool
2246okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB)
2247{
2248 return ((TCB != 0) &&
2249 (TCB->magic == WINMAGIC) &&
2250 InitConsole());
2251}
2252
2253/*
2254 * While a constructor would ensure that this module is initialized, that will
2255 * interfere with applications that may combine this with GUI interfaces.
2256 */
2257#if 0
2258static
2259__attribute__((constructor))
2260 void _enter_console(void)
2261{
2262 (void) InitConsole();
2263}
2264#endif