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