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