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 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 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 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 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 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 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 * 377 wcon_name(TERMINAL_CONTROL_BLOCK * TCB) 378 { 379 (void) TCB; 380 return "win32console"; 381 } 382 383 static int 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 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 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 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 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 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 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 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 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 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 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 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 822 wcon_screen_init(SCREEN *sp GCC_UNUSED) 823 { 824 } 825 826 static void 827 wcon_wrap(SCREEN *sp GCC_UNUSED) 828 { 829 } 830 831 static void 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 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 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 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 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 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 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 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 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 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 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 1007 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB) 1008 { 1009 SCREEN *sp; 1010 1011 AssertTCB(); 1012 SetSP(); 1013 } 1014 1015 static void 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 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 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 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 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 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 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 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