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 51MODULE_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 56static 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 77static WORD 78MapAttr(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 */ 109static void 110dump_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 */ 169static BOOL 170con_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 220static BOOL 221con_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 */ 266static int 267find_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 */ 301static int 302find_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 341static bool 342restore_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 376static const char * 377wcon_name(TERMINAL_CONTROL_BLOCK * TCB) 378{ 379 (void) TCB; 380 return "win32console"; 381} 382 383static int 384wcon_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 524static bool 525wcon_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 578static int 579wcon_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 641static int 642wcon_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 654static int 655wcon_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 668static void 669wcon_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 683static bool 684wcon_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 698static bool 699wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB) 700{ 701 int result = FALSE; 702 SCREEN *sp; 703 704 AssertTCB(); 705 SetSP(); 706 707 return result; 708} 709 710static int 711wcon_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 725static int 726wcon_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 734static int 735wcon_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 758static int 759wcon_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 821static void 822wcon_screen_init(SCREEN *sp GCC_UNUSED) 823{ 824} 825 826static void 827wcon_wrap(SCREEN *sp GCC_UNUSED) 828{ 829} 830 831static void 832wcon_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 843static void 844wcon_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 875static void 876wcon_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 895static void 896wcon_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 908static void 909wcon_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 922static void 923wcon_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 934static int 935wcon_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 959static int 960wcon_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 977static void 978wcon_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 988static void 989wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB, 990 int OnFlag GCC_UNUSED) 991{ 992 SCREEN *sp; 993 994 AssertTCB(); 995 SetSP(); 996} 997 998static chtype 999wcon_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 1006static void 1007wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB) 1008{ 1009 SCREEN *sp; 1010 1011 AssertTCB(); 1012 SetSP(); 1013} 1014 1015static void 1016wcon_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 1064static int 1065wcon_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 1086static int 1087wcon_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 1103static int 1104wcon_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 1111static int 1112wcon_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 1134static bool 1135wcon_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 1144static int 1145wcon_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 1162static int 1163wcon_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 1181NCURSES_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