xref: /freebsd/contrib/ncurses/ncurses/win32con/win32_driver.c (revision 68ad2b0d7af2a3571c4abac9afa712f9b09b721c)
1 /****************************************************************************
2  * Copyright 2018-2024,2025 Thomas E. Dickey                                *
3  * Copyright 2008-2016,2017 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 - improve screen-repainting performance, using implied wraparound to reduce write's
37  * TODO - make it optional whether screen is restored or not when non-buffered
38  */
39 
40 #include <curses.priv.h>
41 
42 #define CUR TerminalType(my_term).
43 
44 MODULE_ID("$Id: win32_driver.c,v 1.20 2025/12/30 19:34:50 tom Exp $")
45 
46 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE)
47 #define EXP_OPTIMIZE 0
48 
49 #define AssertTCB() assert(TCB != NULL && (TCB->magic == WINMAGIC))
50 #define validateConsoleHandle() (AssertTCB(), console_initialized || \
51                                  (console_initialized = \
52                                   _nc_console_checkinit(USE_NAMED_PIPES)))
53 #define SetSP() assert(TCB->csp != NULL); sp = TCB->csp; (void) sp
54 
55 #define AdjustY() (WINCONSOLE.buffered \
56                    ? 0 \
57                    : (int) WINCONSOLE.SBI.srWindow.Top)
58 
59 #define RevAttr(attr) (WORD) (((attr) & 0xff00) | \
60 		      ((((attr) & 0x07) << 4) | \
61 		       (((attr) & 0x70) >> 4)))
62 
63 static bool console_initialized = FALSE;
64 
65 static WORD
MapAttr(WORD res,attr_t ch)66 MapAttr(WORD res, attr_t ch)
67 {
68     if (ch & A_COLOR) {
69 	int p;
70 
71 	p = PairNumber(ch);
72 	if (p > 0 && p < CON_NUMPAIRS) {
73 	    WORD a;
74 	    a = WINCONSOLE.pairs[p];
75 	    res = (WORD) ((res & 0xff00) | a);
76 	}
77     }
78 
79     if (ch & A_REVERSE) {
80 	res = RevAttr(res);
81     }
82 
83     if (ch & A_STANDOUT) {
84 	res = RevAttr(res) | BACKGROUND_INTENSITY;
85     }
86 
87     if (ch & A_BOLD)
88 	res |= FOREGROUND_INTENSITY;
89 
90     if (ch & A_DIM)
91 	res |= BACKGROUND_INTENSITY;
92 
93     return res;
94 }
95 
96 #if 0				/* def TRACE */
97 static void
98 dump_screen(const char *fn, int ln)
99 {
100     int max_cells = (WINCONSOLE.SBI.dwSize.Y *
101 		     (1 + WINCONSOLE.SBI.dwSize.X)) + 1;
102     char output[max_cells];
103     CHAR_INFO save_screen[max_cells];
104     COORD save_size;
105     SMALL_RECT save_region;
106     COORD bufferCoord;
107 
108     T(("dump_screen %s@%d", fn, ln));
109 
110     save_region.Top = WINCONSOLE.SBI.srWindow.Top;
111     save_region.Left = WINCONSOLE.SBI.srWindow.Left;
112     save_region.Bottom = WINCONSOLE.SBI.srWindow.Bottom;
113     save_region.Right = WINCONSOLE.SBI.srWindow.Right;
114 
115     save_size.X = (SHORT) (save_region.Right - save_region.Left + 1);
116     save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1);
117 
118     bufferCoord.X = bufferCoord.Y = 0;
119 
120     if (read_screen(WINCONSOLE.hdl,
121 		    save_screen,
122 		    save_size,
123 		    bufferCoord,
124 		    &save_region)) {
125 	int i, j;
126 	int ij = 0;
127 	int k = 0;
128 
129 	for (i = save_region.Top; i <= save_region.Bottom; ++i) {
130 	    for (j = save_region.Left; j <= save_region.Right; ++j) {
131 		output[k++] = save_screen[ij++].CharInfoChar;
132 	    }
133 	    output[k++] = '\n';
134 	}
135 	output[k] = 0;
136 
137 	T(("DUMP: %d,%d - %d,%d",
138 	   save_region.Top,
139 	   save_region.Left,
140 	   save_region.Bottom,
141 	   save_region.Right));
142 	T(("%s", output));
143     }
144 }
145 
146 #else
147 #define dump_screen(fn,ln)	/* nothing */
148 #endif
149 
150 #if USE_WIDEC_SUPPORT
151 /*
152  * TODO: support surrogate pairs
153  * TODO: support combining characters
154  * TODO: support acsc
155  * TODO: _nc_wacs should be part of sp.
156  */
157 static BOOL
con_write16(TERMINAL_CONTROL_BLOCK * TCB,int y,int x,cchar_t * str,int limit)158 con_write16(TERMINAL_CONTROL_BLOCK * TCB,
159 	    int y, int x, cchar_t *str, int limit)
160 {
161     int actual = 0;
162     MakeArray(ci, CHAR_INFO, limit);
163     COORD loc, siz;
164     SMALL_RECT rec;
165     int i;
166     cchar_t ch;
167     SCREEN *sp;
168 
169     AssertTCB();
170     SetSP();
171 
172     for (i = actual = 0; i < limit; i++) {
173 	ch = str[i];
174 	if (isWidecExt(ch))
175 	    continue;
176 	ci[actual].CharInfoChar = CharOf(ch);
177 	ci[actual].Attributes = MapAttr(WINCONSOLE.SBI.wAttributes,
178 					AttrOf(ch));
179 	if (AttrOf(ch) & A_ALTCHARSET) {
180 	    if (_nc_wacs) {
181 		int which = CharOf(ch);
182 		if (which > 0
183 		    && which < ACS_LEN
184 		    && CharOf(_nc_wacs[which]) != 0) {
185 		    ci[actual].CharInfoChar = CharOf(_nc_wacs[which]);
186 		} else {
187 		    ci[actual].CharInfoChar = ' ';
188 		}
189 	    }
190 	}
191 	++actual;
192     }
193 
194     loc.X = (SHORT) 0;
195     loc.Y = (SHORT) 0;
196     siz.X = (SHORT) actual;
197     siz.Y = 1;
198 
199     rec.Left = (SHORT) x;
200     rec.Top = (SHORT) (y + AdjustY());
201     rec.Right = (SHORT) (x + limit - 1);
202     rec.Bottom = rec.Top;
203 
204     return write_screen(WINCONSOLE.hdl, ci, siz, loc, &rec);
205 }
206 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n)
207 #else
208 static BOOL
con_write8(TERMINAL_CONTROL_BLOCK * TCB,int y,int x,chtype * str,int n)209 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n)
210 {
211     MakeArray(ci, CHAR_INFO, n);
212     COORD loc, siz;
213     SMALL_RECT rec;
214     int i;
215     chtype ch;
216     SCREEN *sp;
217 
218     AssertTCB();
219     SetSP();
220 
221     for (i = 0; i < n; i++) {
222 	ch = str[i];
223 	ci[i].CharInfoChar = ChCharOf(ch);
224 	ci[i].Attributes = MapAttr(WINCONSOLE.SBI.wAttributes,
225 				   ChAttrOf(ch));
226 	if (ChAttrOf(ch) & A_ALTCHARSET) {
227 	    if (sp->_acs_map)
228 		ci[i].CharInfoChar =
229 		    ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch)));
230 	}
231     }
232 
233     loc.X = (short) 0;
234     loc.Y = (short) 0;
235     siz.X = (short) n;
236     siz.Y = 1;
237 
238     rec.Left = (short) x;
239     rec.Top = (short) y;
240     rec.Right = (short) (x + n - 1);
241     rec.Bottom = rec.Top;
242 
243     return write_screen(WINCONSOLE.hdl, ci, siz, loc, &rec);
244 }
245 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n)
246 #endif
247 
248 #if EXP_OPTIMIZE
249 /*
250  * Comparing new/current screens, determine the last column-index for a change
251  * beginning on the given row,col position.  Unlike a serial terminal, there is
252  * no cost for "moving" the "cursor" on the line as we update it.
253  */
254 static int
find_end_of_change(SCREEN * sp,int row,int col)255 find_end_of_change(SCREEN *sp, int row, int col)
256 {
257     int result = col;
258     struct ldat *curdat = CurScreen(sp)->_line + row;
259     struct ldat *newdat = NewScreen(sp)->_line + row;
260 
261     while (col <= newdat->lastchar) {
262 #if USE_WIDEC_SUPPORT
263 	if (isWidecExt(curdat->text[col]) ||
264 	    isWidecExt(newdat->text[col])) {
265 	    result = col;
266 	} else if (memcmp(&curdat->text[col],
267 			  &newdat->text[col],
268 			  sizeof(curdat->text[0]))) {
269 	    result = col;
270 	} else {
271 	    break;
272 	}
273 #else
274 	if (curdat->text[col] != newdat->text[col]) {
275 	    result = col;
276 	} else {
277 	    break;
278 	}
279 #endif
280 	++col;
281     }
282     return result;
283 }
284 
285 /*
286  * Given a row,col position at the end of a change-chunk, look for the
287  * beginning of the next change-chunk.
288  */
289 static int
find_next_change(SCREEN * sp,int row,int col)290 find_next_change(SCREEN *sp, int row, int col)
291 {
292     struct ldat *curdat = CurScreen(sp)->_line + row;
293     struct ldat *newdat = NewScreen(sp)->_line + row;
294     int result = newdat->lastchar + 1;
295 
296     while (++col <= newdat->lastchar) {
297 #if USE_WIDEC_SUPPORT
298 	if (isWidecExt(curdat->text[col]) !=
299 	    isWidecExt(newdat->text[col])) {
300 	    result = col;
301 	    break;
302 	} else if (memcmp(&curdat->text[col],
303 			  &newdat->text[col],
304 			  sizeof(curdat->text[0]))) {
305 	    result = col;
306 	    break;
307 	}
308 #else
309 	if (curdat->text[col] != newdat->text[col]) {
310 	    result = col;
311 	    break;
312 	}
313 #endif
314     }
315     return result;
316 }
317 
318 #define EndChange(first) \
319 	find_end_of_change(sp, y, first)
320 #define NextChange(last)                        \
321 	find_next_change(sp, y, last)
322 
323 #endif /* EXP_OPTIMIZE */
324 
325 #define MARK_NOCHANGE(win,row)                 \
326     win->_line[row].firstchar = _NOCHANGE;     \
327     win->_line[row].lastchar  = _NOCHANGE
328 
329 static bool
restore_original_screen(void)330 restore_original_screen(void)
331 {
332     COORD bufferCoord;
333     bool result = FALSE;
334     SMALL_RECT save_region = WINCONSOLE.save_region;
335 
336     T(("... restoring %s", WINCONSOLE.window_only ?
337        "window" : "entire buffer"));
338 
339     bufferCoord.X = (SHORT) (WINCONSOLE.window_only ?
340 			     WINCONSOLE.SBI.srWindow.Left : 0);
341     bufferCoord.Y = (SHORT) (WINCONSOLE.window_only ?
342 			     WINCONSOLE.SBI.srWindow.Top : 0);
343 
344     if (write_screen(WINCONSOLE.hdl,
345 		     WINCONSOLE.save_screen,
346 		     WINCONSOLE.save_size,
347 		     bufferCoord,
348 		     &save_region)) {
349 	result = TRUE;
350 	mvcur(-1, -1, LINES - 2, 0);
351 	T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)",
352 	   WINCONSOLE.save_size.Y,
353 	   WINCONSOLE.save_size.X,
354 	   save_region.Top,
355 	   save_region.Left,
356 	   save_region.Bottom,
357 	   save_region.Right));
358     } else {
359 	T(("... restore original screen contents err"));
360     }
361     return result;
362 }
363 
364 static const char *
wcon_name(TERMINAL_CONTROL_BLOCK * TCB)365 wcon_name(TERMINAL_CONTROL_BLOCK * TCB)
366 {
367     (void) TCB;
368     return "win32console";
369 }
370 
371 static int
wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)372 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB)
373 {
374     int result = ERR;
375     int y, nonempty, n, x0, x1, Width, Height;
376     SCREEN *sp;
377 
378     T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB));
379     if (validateConsoleHandle()) {
380 	SetSP();
381 
382 	Width = screen_columns(sp);
383 	Height = screen_lines(sp);
384 	nonempty = Min(Height, NewScreen(sp)->_maxy + 1);
385 
386 	T(("... %dx%d clear cur:%d new:%d",
387 	   Height, Width,
388 	   CurScreen(sp)->_clear,
389 	   NewScreen(sp)->_clear));
390 
391 	if (SP_PARM->_endwin == ewSuspend) {
392 
393 	    T(("coming back from shell mode"));
394 	    NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG);
395 
396 	    NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG);
397 	    NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG);
398 	    SP_PARM->_mouse_resume(SP_PARM);
399 
400 	    SP_PARM->_endwin = ewRunning;
401 	}
402 
403 	if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) {
404 	    int x;
405 #if USE_WIDEC_SUPPORT
406 	    MakeArray(empty, cchar_t, Width);
407 	    wchar_t blank[2] =
408 	    {
409 		L' ', L'\0'
410 	    };
411 
412 	    for (x = 0; x < Width; x++)
413 		setcchar(&empty[x], blank, 0, 0, NULL);
414 #else
415 	    MakeArray(empty, chtype, Width);
416 
417 	    for (x = 0; x < Width; x++)
418 		empty[x] = ' ';
419 #endif
420 
421 	    for (y = 0; y < nonempty; y++) {
422 		con_write(TCB, y, 0, empty, Width);
423 		memcpy(empty,
424 		       CurScreen(sp)->_line[y].text,
425 		       (size_t) Width * sizeof(empty[0]));
426 	    }
427 	    CurScreen(sp)->_clear = FALSE;
428 	    NewScreen(sp)->_clear = FALSE;
429 	    touchwin(NewScreen(sp));
430 	    T(("... cleared %dx%d lines @%d of screen", nonempty, Width,
431 	       AdjustY()));
432 	}
433 
434 	for (y = 0; y < nonempty; y++) {
435 	    x0 = NewScreen(sp)->_line[y].firstchar;
436 	    if (x0 != _NOCHANGE) {
437 #if EXP_OPTIMIZE
438 		int x2;
439 		int limit = NewScreen(sp)->_line[y].lastchar;
440 		while ((x1 = EndChange(x0)) <= limit) {
441 		    while ((x2 = NextChange(x1)) <=
442 			   limit && x2 <= (x1 + 2)) {
443 			x1 = x2;
444 		    }
445 		    n = x1 - x0 + 1;
446 		    memcpy(&CurScreen(sp)->_line[y].text[x0],
447 			   &NewScreen(sp)->_line[y].text[x0],
448 			   n * sizeof(CurScreen(sp)->_line[y].text[x0]));
449 		    con_write(TCB,
450 			      y,
451 			      x0,
452 			      &CurScreen(sp)->_line[y].text[x0], n);
453 		    x0 = NextChange(x1);
454 		}
455 
456 		/* mark line changed successfully */
457 		if (y <= NewScreen(sp)->_maxy) {
458 		    MARK_NOCHANGE(NewScreen(sp), y);
459 		}
460 		if (y <= CurScreen(sp)->_maxy) {
461 		    MARK_NOCHANGE(CurScreen(sp), y);
462 		}
463 #else
464 		x1 = NewScreen(sp)->_line[y].lastchar;
465 		n = x1 - x0 + 1;
466 		if (n > 0) {
467 		    memcpy(&CurScreen(sp)->_line[y].text[x0],
468 			   &NewScreen(sp)->_line[y].text[x0],
469 			   (size_t) n *
470 			   sizeof(CurScreen(sp)->_line[y].text[x0]));
471 		    con_write(TCB,
472 			      y,
473 			      x0,
474 			      &CurScreen(sp)->_line[y].text[x0], n);
475 
476 		    /* mark line changed successfully */
477 		    if (y <= NewScreen(sp)->_maxy) {
478 			MARK_NOCHANGE(NewScreen(sp), y);
479 		    }
480 		    if (y <= CurScreen(sp)->_maxy) {
481 			MARK_NOCHANGE(CurScreen(sp), y);
482 		    }
483 		}
484 #endif
485 	    }
486 	}
487 
488 	/* put everything back in sync */
489 	for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) {
490 	    MARK_NOCHANGE(NewScreen(sp), y);
491 	}
492 	for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) {
493 	    MARK_NOCHANGE(CurScreen(sp), y);
494 	}
495 
496 	if (!NewScreen(sp)->_leaveok) {
497 	    CurScreen(sp)->_curx = NewScreen(sp)->_curx;
498 	    CurScreen(sp)->_cury = NewScreen(sp)->_cury;
499 
500 	    TCB->drv->td_hwcur(TCB,
501 			       0,
502 			       0,
503 			       CurScreen(sp)->_cury,
504 			       CurScreen(sp)->_curx);
505 	}
506 	_nc_console_selectActiveHandle();
507 	result = OK;
508     }
509     returnCode(result);
510 }
511 
512 static bool
wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,const char * tname,int * errret GCC_UNUSED)513 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB,
514 	       const char *tname,
515 	       int *errret GCC_UNUSED)
516 {
517     bool code = FALSE;
518 
519     T((T_CALLED("win32con::wcon_CanHandle(%p,%s,%p)"),
520        (void *) TCB, NonNull(tname), (void *) errret));
521 
522     assert(TCB != NULL);
523 
524     TCB->magic = WINMAGIC;
525 
526     if (tname == NULL || *tname == 0) {
527 	if (!_nc_console_vt_supported())
528 	    code = TRUE;
529     } else if (tname != NULL && *tname == '#') {
530 	/*
531 	 * Use "#" (a character which cannot begin a terminal's name) to
532 	 * select specific driver from the table.
533 	 *
534 	 * In principle, we could have more than one non-terminfo driver,
535 	 * e.g., "win32gui".
536 	 */
537 	size_t n = strlen(tname + 1);
538 	if (n != 0
539 	    && ((strncmp(tname + 1, "win32console", n) == 0)
540 		|| (strncmp(tname + 1, "win32con", n) == 0))) {
541 	    code = TRUE;
542 	}
543     } else if (tname != NULL && stricmp(tname, "unknown") == 0) {
544 	code = TRUE;
545     }
546 #if !USE_NAMED_PIPES
547     else if (_isatty(TCB->term.Filedes)) {
548 	code = TRUE;
549     }
550 #endif
551 
552     /*
553      * This is intentional, to avoid unnecessary breakage of applications
554      * using <term.h> symbols.
555      */
556     if (code && (TerminalType(&TCB->term).Booleans == 0)) {
557 	_nc_init_termtype(&TerminalType(&TCB->term));
558 #if NCURSES_EXT_NUMBERS
559 	_nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term));
560 #endif
561     }
562 
563     if (!code) {
564 	if (_nc_console_test(0)) {
565 	    T(("isTermInfoConsole=TRUE"));
566 	    WINCONSOLE.isTermInfoConsole = TRUE;
567 	}
568     }
569     returnBool(code);
570 }
571 
572 static int
wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,int beepFlag)573 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB,
574 		 int beepFlag)
575 {
576     SCREEN *sp;
577     int res = ERR;
578 
579     int high = (WINCONSOLE.SBI.srWindow.Bottom -
580 		WINCONSOLE.SBI.srWindow.Top + 1);
581     int wide = (WINCONSOLE.SBI.srWindow.Right -
582 		WINCONSOLE.SBI.srWindow.Left + 1);
583     int max_cells = (high * wide);
584     int i;
585 
586     MakeArray(this_screen, CHAR_INFO, max_cells);
587     MakeArray(that_screen, CHAR_INFO, max_cells);
588     COORD this_size;
589     SMALL_RECT this_region;
590     COORD bufferCoord;
591 
592     if (validateConsoleHandle()) {
593 	SetSP();
594 	this_region.Top = WINCONSOLE.SBI.srWindow.Top;
595 	this_region.Left = WINCONSOLE.SBI.srWindow.Left;
596 	this_region.Bottom = WINCONSOLE.SBI.srWindow.Bottom;
597 	this_region.Right = WINCONSOLE.SBI.srWindow.Right;
598 
599 	this_size.X = (SHORT) wide;
600 	this_size.Y = (SHORT) high;
601 
602 	bufferCoord.X = this_region.Left;
603 	bufferCoord.Y = this_region.Top;
604 
605 	if (!beepFlag &&
606 	    read_screen(WINCONSOLE.hdl,
607 			this_screen,
608 			this_size,
609 			bufferCoord,
610 			&this_region)) {
611 
612 	    memcpy(that_screen,
613 		   this_screen,
614 		   sizeof(CHAR_INFO) * (size_t) max_cells);
615 
616 	    for (i = 0; i < max_cells; i++) {
617 		that_screen[i].Attributes =
618 		    RevAttr(that_screen[i].Attributes);
619 	    }
620 
621 	    write_screen(WINCONSOLE.hdl, that_screen, this_size,
622 			 bufferCoord, &this_region);
623 	    Sleep(200);
624 	    write_screen(WINCONSOLE.hdl, this_screen, this_size,
625 			 bufferCoord, &this_region);
626 
627 	} else {
628 	    MessageBeep(MB_ICONWARNING);	/* MB_OK might be better */
629 	}
630 	res = OK;
631     }
632     return res;
633 }
634 
635 static int
wcon_print(TERMINAL_CONTROL_BLOCK * TCB,char * data GCC_UNUSED,int len GCC_UNUSED)636 wcon_print(TERMINAL_CONTROL_BLOCK * TCB,
637 	   char *data GCC_UNUSED,
638 	   int len GCC_UNUSED)
639 {
640     SCREEN *sp;
641 
642     AssertTCB();
643     SetSP();
644 
645     return ERR;
646 }
647 
648 static int
wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,int fg GCC_UNUSED,int bg GCC_UNUSED)649 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB,
650 		   int fg GCC_UNUSED,
651 		   int bg GCC_UNUSED)
652 {
653     SCREEN *sp;
654     int code = ERR;
655 
656     AssertTCB();
657     SetSP();
658 
659     return (code);
660 }
661 
662 static void
wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,int fore,int color,int (* outc)(SCREEN *,int)GCC_UNUSED)663 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB,
664 	      int fore,
665 	      int color,
666 	      int (*outc) (SCREEN *, int) GCC_UNUSED)
667 {
668     (void) TCB;
669     if (validateConsoleHandle()) {
670 	WORD a = _nc_console_MapColor(fore, color);
671 	a |= (WORD) ((WINCONSOLE.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f));
672 	SetConsoleTextAttribute(WINCONSOLE.hdl, a);
673 	_nc_console_get_SBI();
674     }
675 }
676 
677 static bool
wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)678 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB)
679 {
680     bool res = FALSE;
681 
682     (void) TCB;
683     if (validateConsoleHandle()) {
684 	WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN;
685 	SetConsoleTextAttribute(WINCONSOLE.hdl, a);
686 	_nc_console_get_SBI();
687 	res = TRUE;
688     }
689     return res;
690 }
691 
692 static bool
wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)693 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB)
694 {
695     int result = FALSE;
696     SCREEN *sp;
697 
698     AssertTCB();
699     SetSP();
700 
701     return result;
702 }
703 
704 static int
wcon_size(TERMINAL_CONTROL_BLOCK * TCB,int * Lines,int * Cols)705 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols)
706 {
707     int result = ERR;
708 
709     T((T_CALLED("win32con::wcon_size(%p)"), TCB));
710 
711     if (validateConsoleHandle() &&
712 	(Lines != NULL) && (Cols != NULL)) {
713 	_nc_console_size(Lines, Cols);
714 	result = OK;
715     }
716     returnCode(result);
717 }
718 
719 static int
wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,int l GCC_UNUSED,int c GCC_UNUSED)720 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,
721 	     int l GCC_UNUSED,
722 	     int c GCC_UNUSED)
723 {
724     AssertTCB();
725     return ERR;
726 }
727 
728 static int
wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB,int setFlag,TTY * buf)729 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf)
730 {
731     int result = ERR;
732 
733     T((T_CALLED("win32con::wcon_sgmode(TCB=(%p),setFlag=%d,TTY=(%p)"),
734        TCB, setFlag, buf));
735     if (buf != NULL && validateConsoleHandle()) {
736 
737 	if (setFlag) {
738 	    _nc_console_setmode(WINCONSOLE.hdl, buf);
739 	    TCB->term.Nttyb = *buf;
740 	} else {
741 	    _nc_console_getmode(WINCONSOLE.hdl, &(TCB->term.Nttyb));
742 	    *buf = TCB->term.Nttyb;
743 	}
744 	result = OK;
745     }
746     returnCode(result);
747 }
748 
749 static int
wcon_mode(TERMINAL_CONTROL_BLOCK * TCB,int progFlag,int defFlag)750 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag)
751 {
752     SCREEN *sp;
753     TERMINAL *_term = (TERMINAL *) TCB;
754     int code = ERR;
755 
756     T((T_CALLED("win32con::wcon_mode(%p, progFlag=%d, defFlag=%d)"),
757        TCB, progFlag, defFlag));
758 
759     if (validateConsoleHandle()) {
760 	sp = TCB->csp;
761 
762 	WINCONSOLE.progMode = progFlag;
763 	WINCONSOLE.lastOut = progFlag ? WINCONSOLE.hdl : WINCONSOLE.out;
764 	SetConsoleActiveScreenBuffer(WINCONSOLE.lastOut);
765 
766 	if (progFlag) /* prog mode */  {
767 	    if (defFlag) {
768 		if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) {
769 		    code = OK;
770 		}
771 	    } else {
772 		/* reset_prog_mode */
773 		if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) {
774 		    if (sp) {
775 			if (sp->_keypad_on)
776 			    _nc_keypad(sp, TRUE);
777 		    }
778 		    if (!WINCONSOLE.buffered) {
779 			_nc_console_set_scrollback(FALSE, &WINCONSOLE.SBI);
780 		    }
781 		    code = OK;
782 		}
783 	    }
784 	    T(("... buffered:%d, clear:%d",
785 	       WINCONSOLE.buffered, CurScreen(sp)->_clear));
786 	} else {		/* shell mode */
787 	    if (defFlag) {
788 		/* def_shell_mode */
789 		if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) {
790 		    code = OK;
791 		}
792 	    } else {
793 		/* reset_shell_mode */
794 		if (sp) {
795 		    _nc_keypad(sp, FALSE);
796 		    NCURSES_SP_NAME(_nc_flush) (sp);
797 		}
798 		code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb));
799 		if (!WINCONSOLE.buffered) {
800 		    _nc_console_set_scrollback(TRUE, &WINCONSOLE.save_SBI);
801 		    if (!restore_original_screen())
802 			code = ERR;
803 		}
804 		SetConsoleCursorInfo(WINCONSOLE.hdl, &WINCONSOLE.save_CI);
805 	    }
806 	}
807 
808     }
809     returnCode(code);
810 }
811 
812 static void
wcon_screen_init(SCREEN * sp GCC_UNUSED)813 wcon_screen_init(SCREEN *sp GCC_UNUSED)
814 {
815 }
816 
817 static void
wcon_wrap(SCREEN * sp GCC_UNUSED)818 wcon_wrap(SCREEN *sp GCC_UNUSED)
819 {
820 }
821 
822 static void
wcon_release(TERMINAL_CONTROL_BLOCK * TCB)823 wcon_release(TERMINAL_CONTROL_BLOCK * TCB)
824 {
825     T((T_CALLED("win32con::wcon_release(%p)"), TCB));
826 
827     AssertTCB();
828     if (TCB->prop)
829 	free(TCB->prop);
830 
831     returnVoid;
832 }
833 
834 static void
wcon_init(TERMINAL_CONTROL_BLOCK * TCB)835 wcon_init(TERMINAL_CONTROL_BLOCK * TCB)
836 {
837     T((T_CALLED("win32con::wcon_init(%p)"), TCB));
838 
839     AssertTCB();
840 
841     if (!(console_initialized = _nc_console_checkinit(USE_NAMED_PIPES))) {
842 	returnVoid;
843     }
844 
845     if (TCB) {
846 	TCB->info.initcolor = TRUE;
847 	TCB->info.canchange = FALSE;
848 	TCB->info.hascolor = TRUE;
849 	TCB->info.caninit = TRUE;
850 
851 	TCB->info.maxpairs = CON_NUMPAIRS;
852 	TCB->info.maxcolors = 8;
853 	TCB->info.numlabels = 0;
854 	TCB->info.labelwidth = 0;
855 	TCB->info.labelheight = 0;
856 	TCB->info.nocolorvideo = 1;
857 	TCB->info.tabsize = 8;
858 
859 	TCB->info.numbuttons = WINCONSOLE.numButtons;
860 	TCB->info.defaultPalette = _nc_cga_palette;
861 
862     }
863     returnVoid;
864 }
865 
866 static void
wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,int pair,int f,int b)867 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB,
868 	      int pair,
869 	      int f,
870 	      int b)
871 {
872     SCREEN *sp;
873 
874     if (validateConsoleHandle()) {
875 	SetSP();
876 
877 	if ((pair > 0) && (pair < CON_NUMPAIRS) && (f >= 0) && (f < 8)
878 	    && (b >= 0) && (b < 8)) {
879 	    WINCONSOLE.pairs[pair] =
880 		_nc_console_MapColor(true, f) |
881 		_nc_console_MapColor(false, b);
882 	}
883     }
884 }
885 
886 static void
wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,int color GCC_UNUSED,int r GCC_UNUSED,int g GCC_UNUSED,int b GCC_UNUSED)887 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB,
888 	       int color GCC_UNUSED,
889 	       int r GCC_UNUSED,
890 	       int g GCC_UNUSED,
891 	       int b GCC_UNUSED)
892 {
893     SCREEN *sp;
894 
895     AssertTCB();
896     SetSP();
897 }
898 
899 static void
wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,int old_pair GCC_UNUSED,int pair GCC_UNUSED,int reverse GCC_UNUSED,int (* outc)(SCREEN *,int)GCC_UNUSED)900 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB,
901 	      int old_pair GCC_UNUSED,
902 	      int pair GCC_UNUSED,
903 	      int reverse GCC_UNUSED,
904 	      int (*outc) (SCREEN *, int) GCC_UNUSED
905 )
906 {
907     SCREEN *sp;
908 
909     AssertTCB();
910     SetSP();
911 }
912 
913 static void
wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)914 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB)
915 {
916     SCREEN *sp;
917 
918     T((T_CALLED("win32con::wcon_initmouse(%p)"), TCB));
919 
920     if (validateConsoleHandle()) {
921 	SetSP();
922 
923 	sp->_mouse_type = M_TERM_DRIVER;
924     }
925     returnVoid;
926 }
927 
928 static int
wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,int delay EVENTLIST_2nd (_nc_eventlist * evl))929 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB,
930 	       int delay
931 	       EVENTLIST_2nd(_nc_eventlist * evl))
932 {
933     int rc = 0;
934     SCREEN *sp;
935 
936     T((T_CALLED("win32con::wcon_testmouse(%p)"), TCB));
937     if (validateConsoleHandle()) {
938 	SetSP();
939 
940 	if (sp->_drv_mouse_head < sp->_drv_mouse_tail) {
941 	    rc = TW_MOUSE;
942 	} else {
943 	    rc = TCBOf(sp)->drv->td_twait(TCBOf(sp),
944 					  TWAIT_MASK,
945 					  delay,
946 					  (int *) 0
947 					  EVENTLIST_2nd(evl));
948 	}
949     }
950 
951     returnCode(rc);
952 }
953 
954 static int
wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,int yold GCC_UNUSED,int xold GCC_UNUSED,int y,int x)955 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB,
956 	   int yold GCC_UNUSED, int xold GCC_UNUSED,
957 	   int y, int x)
958 {
959     int ret = ERR;
960 
961     (void) TCB;
962     if (validateConsoleHandle()) {
963 	COORD loc;
964 	loc.X = (short) x;
965 	loc.Y = (short) (y + AdjustY());
966 	SetConsoleCursorPosition(WINCONSOLE.hdl, loc);
967 	ret = OK;
968     }
969     return ret;
970 }
971 
972 static void
wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,int labnum GCC_UNUSED,char * text GCC_UNUSED)973 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB,
974 	     int labnum GCC_UNUSED,
975 	     char *text GCC_UNUSED)
976 {
977     SCREEN *sp;
978 
979     AssertTCB();
980     SetSP();
981 }
982 
983 static void
wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,int OnFlag GCC_UNUSED)984 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB,
985 		  int OnFlag GCC_UNUSED)
986 {
987     SCREEN *sp;
988 
989     AssertTCB();
990     SetSP();
991 }
992 
993 static chtype
wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)994 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED)
995 {
996     chtype res = A_NORMAL;
997     res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR);
998     return res;
999 }
1000 
1001 static void
wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)1002 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB)
1003 {
1004     SCREEN *sp;
1005 
1006     AssertTCB();
1007     SetSP();
1008 }
1009 
1010 static void
wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,chtype * real_map GCC_UNUSED,chtype * fake_map GCC_UNUSED)1011 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB,
1012 	     chtype *real_map GCC_UNUSED,
1013 	     chtype *fake_map GCC_UNUSED)
1014 {
1015 #define DATA(a,b) { a, b }
1016     static struct {
1017 	int acs_code;
1018 	int use_code;
1019     } table[] = {
1020 	DATA('a', 0xb1),	/* ACS_CKBOARD  */
1021 	    DATA('f', 0xf8),	/* ACS_DEGREE   */
1022 	    DATA('g', 0xf1),	/* ACS_PLMINUS  */
1023 	    DATA('j', 0xd9),	/* ACS_LRCORNER */
1024 	    DATA('l', 0xda),	/* ACS_ULCORNER */
1025 	    DATA('k', 0xbf),	/* ACS_URCORNER */
1026 	    DATA('m', 0xc0),	/* ACS_LLCORNER */
1027 	    DATA('n', 0xc5),	/* ACS_PLUS     */
1028 	    DATA('q', 0xc4),	/* ACS_HLINE    */
1029 	    DATA('t', 0xc3),	/* ACS_LTEE     */
1030 	    DATA('u', 0xb4),	/* ACS_RTEE     */
1031 	    DATA('v', 0xc1),	/* ACS_BTEE     */
1032 	    DATA('w', 0xc2),	/* ACS_TTEE     */
1033 	    DATA('x', 0xb3),	/* ACS_VLINE    */
1034 	    DATA('y', 0xf3),	/* ACS_LEQUAL   */
1035 	    DATA('z', 0xf2),	/* ACS_GEQUAL   */
1036 	    DATA('0', 0xdb),	/* ACS_BLOCK    */
1037 	    DATA('{', 0xe3),	/* ACS_PI       */
1038 	    DATA('}', 0x9c),	/* ACS_STERLING */
1039 	    DATA(',', 0xae),	/* ACS_LARROW   */
1040 	    DATA('+', 0xaf),	/* ACS_RARROW   */
1041 	    DATA('~', 0xf9),	/* ACS_BULLET   */
1042     };
1043 #undef DATA
1044     unsigned n;
1045 
1046     SCREEN *sp;
1047     if (validateConsoleHandle()) {
1048 	SetSP();
1049 
1050 	for (n = 0; n < SIZEOF(table); ++n) {
1051 	    real_map[table[n].acs_code] =
1052 		(chtype) table[n].use_code | A_ALTCHARSET;
1053 	    if (sp != NULL)
1054 		sp->_screen_acs_map[table[n].acs_code] = TRUE;
1055 	}
1056     }
1057 }
1058 
1059 static int
wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,int mode,int milliseconds,int * timeleft EVENTLIST_2nd (_nc_eventlist * evl))1060 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB,
1061 	   int mode,
1062 	   int milliseconds,
1063 	   int *timeleft
1064 	   EVENTLIST_2nd(_nc_eventlist * evl))
1065 {
1066     SCREEN *sp;
1067     int code = 0;
1068 
1069     if (validateConsoleHandle()) {
1070 	SetSP();
1071 
1072 	code = _nc_console_twait(sp,
1073 				 WINCONSOLE.inp,
1074 				 mode,
1075 				 milliseconds,
1076 				 timeleft EVENTLIST_2nd(evl));
1077     }
1078     return code;
1079 }
1080 
1081 static int
wcon_read(TERMINAL_CONTROL_BLOCK * TCB,int * buf)1082 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf)
1083 {
1084     SCREEN *sp;
1085     int n = -1;
1086 
1087     T((T_CALLED("win32con::wcon_read(%p)"), TCB));
1088 
1089     assert(buf);
1090     if (validateConsoleHandle()) {
1091 	SetSP();
1092 
1093 	n = _nc_console_read(sp, WINCONSOLE.inp, buf);
1094     }
1095     returnCode(n);
1096 }
1097 
1098 static int
wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,int ms)1099 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms)
1100 {
1101     T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms));
1102     Sleep((DWORD) ms);
1103     returnCode(OK);
1104 }
1105 
1106 static int
wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,int mode)1107 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode)
1108 {
1109     int res = -1;
1110 
1111     T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode));
1112     if (validateConsoleHandle()) {
1113 	CONSOLE_CURSOR_INFO this_CI = WINCONSOLE.save_CI;
1114 	switch (mode) {
1115 	case 0:
1116 	    this_CI.bVisible = FALSE;
1117 	    break;
1118 	case 1:
1119 	    break;
1120 	case 2:
1121 	    this_CI.dwSize = 100;
1122 	    break;
1123 	}
1124 	SetConsoleCursorInfo(WINCONSOLE.hdl, &this_CI);
1125     }
1126     returnCode(res);
1127 }
1128 
1129 static bool
wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED,int keycode)1130 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode)
1131 {
1132     bool found = FALSE;
1133 
1134     T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode));
1135     found = _nc_console_keyExist(keycode);
1136     returnBool(found);
1137 }
1138 
1139 static int
wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB,int flag GCC_UNUSED)1140 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED)
1141 {
1142     SCREEN *sp;
1143     int code = ERR;
1144 
1145     T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag));
1146 
1147     if (validateConsoleHandle()) {
1148 	SetSP();
1149 
1150 	if (sp) {
1151 	    code = OK;
1152 	}
1153     }
1154     returnCode(code);
1155 }
1156 
1157 static int
wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,int keycode,int flag)1158 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB,
1159 	   int keycode,
1160 	   int flag)
1161 {
1162     int code = ERR;
1163     SCREEN *sp;
1164 
1165     T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag));
1166 
1167     if (validateConsoleHandle()) {
1168 	SetSP();
1169 	if (sp) {
1170 	    code = _nc_console_keyok(keycode, flag);
1171 	}
1172     }
1173     returnCode(code);
1174 }
1175 
1176 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = {
1177     FALSE,
1178 	wcon_name,		/* Name          */
1179 	wcon_CanHandle,		/* CanHandle     */
1180 	wcon_init,		/* init          */
1181 	wcon_release,		/* release       */
1182 	wcon_size,		/* size          */
1183 	wcon_sgmode,		/* sgmode        */
1184 	wcon_conattr,		/* conattr       */
1185 	wcon_mvcur,		/* hwcur         */
1186 	wcon_mode,		/* mode          */
1187 	wcon_rescol,		/* rescol        */
1188 	wcon_rescolors,		/* rescolors     */
1189 	wcon_setcolor,		/* color         */
1190 	wcon_dobeepflash,	/* DoBeepFlash   */
1191 	wcon_initpair,		/* initpair      */
1192 	wcon_initcolor,		/* initcolor     */
1193 	wcon_do_color,		/* docolor       */
1194 	wcon_initmouse,		/* initmouse     */
1195 	wcon_testmouse,		/* testmouse     */
1196 	wcon_setfilter,		/* setfilter     */
1197 	wcon_hwlabel,		/* hwlabel       */
1198 	wcon_hwlabelOnOff,	/* hwlabelOnOff  */
1199 	wcon_doupdate,		/* update        */
1200 	wcon_defaultcolors,	/* defaultcolors */
1201 	wcon_print,		/* print         */
1202 	wcon_size,		/* getsize       */
1203 	wcon_setsize,		/* setsize       */
1204 	wcon_initacs,		/* initacs       */
1205 	wcon_screen_init,	/* scinit        */
1206 	wcon_wrap,		/* scexit        */
1207 	wcon_twait,		/* twait         */
1208 	wcon_read,		/* read          */
1209 	wcon_nap,		/* nap           */
1210 	wcon_kpad,		/* kpad          */
1211 	wcon_keyok,		/* kyOk          */
1212 	wcon_kyExist,		/* kyExist       */
1213 	wcon_cursorSet		/* cursorSet     */
1214 };
1215