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 - GetMousePos(POINT * result) from ntconio.c 37 * TODO - implement nodelay 38 * TODO - improve screen-repainting performance, using implied wraparound to reduce write's 39 * TODO - make it optional whether screen is restored or not when non-buffered 40 */ 41 42 #include <curses.priv.h> 43 44 #ifdef _WIN32 45 #include <tchar.h> 46 #else 47 #include <windows.h> 48 #include <wchar.h> 49 #endif 50 51 #include <io.h> 52 53 #define PSAPI_VERSION 2 54 #include <psapi.h> 55 56 #define CUR TerminalType(my_term). 57 58 MODULE_ID("$Id: win_driver.c,v 1.63 2020/02/02 23:34:34 tom Exp $") 59 60 #ifndef __GNUC__ 61 # error We need GCC to compile for MinGW 62 #endif 63 64 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE) 65 66 #define EXP_OPTIMIZE 0 67 68 #define array_length(a) (sizeof(a)/sizeof(a[0])) 69 70 static bool InitConsole(void); 71 static bool okConsoleHandle(TERMINAL_CONTROL_BLOCK *); 72 73 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC)) 74 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp 75 76 #define GenMap(vKey,key) MAKELONG(key, vKey) 77 78 #define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top) 79 80 #if USE_WIDEC_SUPPORT 81 #define write_screen WriteConsoleOutputW 82 #define read_screen ReadConsoleOutputW 83 #else 84 #define write_screen WriteConsoleOutput 85 #define read_screen ReadConsoleOutput 86 #endif 87 88 static const LONG keylist[] = 89 { 90 GenMap(VK_PRIOR, KEY_PPAGE), 91 GenMap(VK_NEXT, KEY_NPAGE), 92 GenMap(VK_END, KEY_END), 93 GenMap(VK_HOME, KEY_HOME), 94 GenMap(VK_LEFT, KEY_LEFT), 95 GenMap(VK_UP, KEY_UP), 96 GenMap(VK_RIGHT, KEY_RIGHT), 97 GenMap(VK_DOWN, KEY_DOWN), 98 GenMap(VK_DELETE, KEY_DC), 99 GenMap(VK_INSERT, KEY_IC) 100 }; 101 static const LONG ansi_keys[] = 102 { 103 GenMap(VK_PRIOR, 'I'), 104 GenMap(VK_NEXT, 'Q'), 105 GenMap(VK_END, 'O'), 106 GenMap(VK_HOME, 'H'), 107 GenMap(VK_LEFT, 'K'), 108 GenMap(VK_UP, 'H'), 109 GenMap(VK_RIGHT, 'M'), 110 GenMap(VK_DOWN, 'P'), 111 GenMap(VK_DELETE, 'S'), 112 GenMap(VK_INSERT, 'R') 113 }; 114 #define N_INI ((int)array_length(keylist)) 115 #define FKEYS 24 116 #define MAPSIZE (FKEYS + N_INI) 117 #define NUMPAIRS 64 118 119 /* A process can only have a single console, so it's safe 120 to maintain all the information about it in a single 121 static structure. 122 */ 123 static struct { 124 BOOL initialized; 125 BOOL buffered; 126 BOOL window_only; 127 BOOL progMode; 128 BOOL isMinTTY; 129 BOOL isTermInfoConsole; 130 HANDLE out; 131 HANDLE inp; 132 HANDLE hdl; 133 HANDLE lastOut; 134 int numButtons; 135 DWORD ansi_map[MAPSIZE]; 136 DWORD map[MAPSIZE]; 137 DWORD rmap[MAPSIZE]; 138 WORD pairs[NUMPAIRS]; 139 COORD origin; 140 CHAR_INFO *save_screen; 141 COORD save_size; 142 SMALL_RECT save_region; 143 CONSOLE_SCREEN_BUFFER_INFO SBI; 144 CONSOLE_SCREEN_BUFFER_INFO save_SBI; 145 CONSOLE_CURSOR_INFO save_CI; 146 } CON; 147 148 static BOOL console_initialized = FALSE; 149 150 static WORD 151 MapColor(bool fore, int color) 152 { 153 static const int _cmap[] = 154 {0, 4, 2, 6, 1, 5, 3, 7}; 155 int a; 156 if (color < 0 || color > 7) 157 a = fore ? 7 : 0; 158 else 159 a = _cmap[color]; 160 if (!fore) 161 a = a << 4; 162 return (WORD) a; 163 } 164 165 #define RevAttr(attr) \ 166 (WORD) (((attr) & 0xff00) | \ 167 ((((attr) & 0x07) << 4) | \ 168 (((attr) & 0x70) >> 4))) 169 170 static WORD 171 MapAttr(WORD res, attr_t ch) 172 { 173 if (ch & A_COLOR) { 174 int p; 175 176 p = PairNumber(ch); 177 if (p > 0 && p < NUMPAIRS) { 178 WORD a; 179 a = CON.pairs[p]; 180 res = (WORD) ((res & 0xff00) | a); 181 } 182 } 183 184 if (ch & A_REVERSE) { 185 res = RevAttr(res); 186 } 187 188 if (ch & A_STANDOUT) { 189 res = RevAttr(res) | BACKGROUND_INTENSITY; 190 } 191 192 if (ch & A_BOLD) 193 res |= FOREGROUND_INTENSITY; 194 195 if (ch & A_DIM) 196 res |= BACKGROUND_INTENSITY; 197 198 return res; 199 } 200 201 #if 0 /* def TRACE */ 202 static void 203 dump_screen(const char *fn, int ln) 204 { 205 int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1; 206 char output[max_cells]; 207 CHAR_INFO save_screen[max_cells]; 208 COORD save_size; 209 SMALL_RECT save_region; 210 COORD bufferCoord; 211 212 T(("dump_screen %s@%d", fn, ln)); 213 214 save_region.Top = CON.SBI.srWindow.Top; 215 save_region.Left = CON.SBI.srWindow.Left; 216 save_region.Bottom = CON.SBI.srWindow.Bottom; 217 save_region.Right = CON.SBI.srWindow.Right; 218 219 save_size.X = (SHORT) (save_region.Right - save_region.Left + 1); 220 save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1); 221 222 bufferCoord.X = bufferCoord.Y = 0; 223 224 if (read_screen(CON.hdl, 225 save_screen, 226 save_size, 227 bufferCoord, 228 &save_region)) { 229 int i, j; 230 int ij = 0; 231 int k = 0; 232 233 for (i = save_region.Top; i <= save_region.Bottom; ++i) { 234 for (j = save_region.Left; j <= save_region.Right; ++j) { 235 output[k++] = save_screen[ij++].Char.AsciiChar; 236 } 237 output[k++] = '\n'; 238 } 239 output[k] = 0; 240 241 T(("DUMP: %d,%d - %d,%d", 242 save_region.Top, 243 save_region.Left, 244 save_region.Bottom, 245 save_region.Right)); 246 T(("%s", output)); 247 } 248 } 249 250 #else 251 #define dump_screen(fn,ln) /* nothing */ 252 #endif 253 254 #if USE_WIDEC_SUPPORT 255 /* 256 * TODO: support surrogate pairs 257 * TODO: support combining characters 258 * TODO: support acsc 259 * TODO: _nc_wacs should be part of sp. 260 */ 261 static BOOL 262 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit) 263 { 264 int actual = 0; 265 CHAR_INFO ci[limit]; 266 COORD loc, siz; 267 SMALL_RECT rec; 268 int i; 269 cchar_t ch; 270 SCREEN *sp; 271 272 AssertTCB(); 273 SetSP(); 274 275 for (i = actual = 0; i < limit; i++) { 276 ch = str[i]; 277 if (isWidecExt(ch)) 278 continue; 279 ci[actual].Char.UnicodeChar = CharOf(ch); 280 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes, 281 AttrOf(ch)); 282 if (AttrOf(ch) & A_ALTCHARSET) { 283 if (_nc_wacs) { 284 int which = CharOf(ch); 285 if (which > 0 286 && which < ACS_LEN 287 && CharOf(_nc_wacs[which]) != 0) { 288 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]); 289 } else { 290 ci[actual].Char.UnicodeChar = ' '; 291 } 292 } 293 } 294 ++actual; 295 } 296 297 loc.X = (SHORT) 0; 298 loc.Y = (SHORT) 0; 299 siz.X = (SHORT) actual; 300 siz.Y = 1; 301 302 rec.Left = (SHORT) x; 303 rec.Top = (SHORT) (y + AdjustY()); 304 rec.Right = (SHORT) (x + limit - 1); 305 rec.Bottom = rec.Top; 306 307 return write_screen(CON.hdl, ci, siz, loc, &rec); 308 } 309 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n) 310 #else 311 static BOOL 312 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n) 313 { 314 CHAR_INFO ci[n]; 315 COORD loc, siz; 316 SMALL_RECT rec; 317 int i; 318 chtype ch; 319 SCREEN *sp; 320 321 AssertTCB(); 322 SetSP(); 323 324 for (i = 0; i < n; i++) { 325 ch = str[i]; 326 ci[i].Char.AsciiChar = ChCharOf(ch); 327 ci[i].Attributes = MapAttr(CON.SBI.wAttributes, 328 ChAttrOf(ch)); 329 if (ChAttrOf(ch) & A_ALTCHARSET) { 330 if (sp->_acs_map) 331 ci[i].Char.AsciiChar = 332 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch))); 333 } 334 } 335 336 loc.X = (short) 0; 337 loc.Y = (short) 0; 338 siz.X = (short) n; 339 siz.Y = 1; 340 341 rec.Left = (short) x; 342 rec.Top = (short) y; 343 rec.Right = (short) (x + n - 1); 344 rec.Bottom = rec.Top; 345 346 return write_screen(CON.hdl, ci, siz, loc, &rec); 347 } 348 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n) 349 #endif 350 351 #if EXP_OPTIMIZE 352 /* 353 * Comparing new/current screens, determine the last column-index for a change 354 * beginning on the given row,col position. Unlike a serial terminal, there is 355 * no cost for "moving" the "cursor" on the line as we update it. 356 */ 357 static int 358 find_end_of_change(SCREEN *sp, int row, int col) 359 { 360 int result = col; 361 struct ldat *curdat = CurScreen(sp)->_line + row; 362 struct ldat *newdat = NewScreen(sp)->_line + row; 363 364 while (col <= newdat->lastchar) { 365 #if USE_WIDEC_SUPPORT 366 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) { 367 result = col; 368 } else if (memcmp(&curdat->text[col], 369 &newdat->text[col], 370 sizeof(curdat->text[0]))) { 371 result = col; 372 } else { 373 break; 374 } 375 #else 376 if (curdat->text[col] != newdat->text[col]) { 377 result = col; 378 } else { 379 break; 380 } 381 #endif 382 ++col; 383 } 384 return result; 385 } 386 387 /* 388 * Given a row,col position at the end of a change-chunk, look for the 389 * beginning of the next change-chunk. 390 */ 391 static int 392 find_next_change(SCREEN *sp, int row, int col) 393 { 394 struct ldat *curdat = CurScreen(sp)->_line + row; 395 struct ldat *newdat = NewScreen(sp)->_line + row; 396 int result = newdat->lastchar + 1; 397 398 while (++col <= newdat->lastchar) { 399 #if USE_WIDEC_SUPPORT 400 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) { 401 result = col; 402 break; 403 } else if (memcmp(&curdat->text[col], 404 &newdat->text[col], 405 sizeof(curdat->text[0]))) { 406 result = col; 407 break; 408 } 409 #else 410 if (curdat->text[col] != newdat->text[col]) { 411 result = col; 412 break; 413 } 414 #endif 415 } 416 return result; 417 } 418 419 #define EndChange(first) \ 420 find_end_of_change(sp, y, first) 421 #define NextChange(last) \ 422 find_next_change(sp, y, last) 423 424 #endif /* EXP_OPTIMIZE */ 425 426 #define MARK_NOCHANGE(win,row) \ 427 win->_line[row].firstchar = _NOCHANGE; \ 428 win->_line[row].lastchar = _NOCHANGE 429 430 static void 431 selectActiveHandle(void) 432 { 433 if (CON.lastOut != CON.hdl) { 434 CON.lastOut = CON.hdl; 435 SetConsoleActiveScreenBuffer(CON.lastOut); 436 } 437 } 438 439 static bool 440 restore_original_screen(void) 441 { 442 COORD bufferCoord; 443 bool result = FALSE; 444 SMALL_RECT save_region = CON.save_region; 445 446 T(("... restoring %s", CON.window_only ? "window" : "entire buffer")); 447 448 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0); 449 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0); 450 451 if (write_screen(CON.hdl, 452 CON.save_screen, 453 CON.save_size, 454 bufferCoord, 455 &save_region)) { 456 result = TRUE; 457 mvcur(-1, -1, LINES - 2, 0); 458 T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)", 459 CON.save_size.Y, 460 CON.save_size.X, 461 save_region.Top, 462 save_region.Left, 463 save_region.Bottom, 464 save_region.Right)); 465 } else { 466 T(("... restore original screen contents err")); 467 } 468 return result; 469 } 470 471 static const char * 472 wcon_name(TERMINAL_CONTROL_BLOCK * TCB) 473 { 474 (void) TCB; 475 return "win32console"; 476 } 477 478 static int 479 wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB) 480 { 481 int result = ERR; 482 int y, nonempty, n, x0, x1, Width, Height; 483 SCREEN *sp; 484 485 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB)); 486 if (okConsoleHandle(TCB)) { 487 SetSP(); 488 489 Width = screen_columns(sp); 490 Height = screen_lines(sp); 491 nonempty = min(Height, NewScreen(sp)->_maxy + 1); 492 493 T(("... %dx%d clear cur:%d new:%d", 494 Height, Width, 495 CurScreen(sp)->_clear, 496 NewScreen(sp)->_clear)); 497 498 if (SP_PARM->_endwin == ewSuspend) { 499 500 T(("coming back from shell mode")); 501 NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG); 502 503 NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG); 504 NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG); 505 SP_PARM->_mouse_resume(SP_PARM); 506 507 SP_PARM->_endwin = ewRunning; 508 } 509 510 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) { 511 int x; 512 #if USE_WIDEC_SUPPORT 513 cchar_t empty[Width]; 514 wchar_t blank[2] = 515 { 516 L' ', L'\0' 517 }; 518 519 for (x = 0; x < Width; x++) 520 setcchar(&empty[x], blank, 0, 0, 0); 521 #else 522 chtype empty[Width]; 523 524 for (x = 0; x < Width; x++) 525 empty[x] = ' '; 526 #endif 527 528 for (y = 0; y < nonempty; y++) { 529 con_write(TCB, y, 0, empty, Width); 530 memcpy(empty, 531 CurScreen(sp)->_line[y].text, 532 (size_t) Width * sizeof(empty[0])); 533 } 534 CurScreen(sp)->_clear = FALSE; 535 NewScreen(sp)->_clear = FALSE; 536 touchwin(NewScreen(sp)); 537 T(("... cleared %dx%d lines @%d of screen", nonempty, Width, 538 AdjustY())); 539 } 540 541 for (y = 0; y < nonempty; y++) { 542 x0 = NewScreen(sp)->_line[y].firstchar; 543 if (x0 != _NOCHANGE) { 544 #if EXP_OPTIMIZE 545 int x2; 546 int limit = NewScreen(sp)->_line[y].lastchar; 547 while ((x1 = EndChange(x0)) <= limit) { 548 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) { 549 x1 = x2; 550 } 551 n = x1 - x0 + 1; 552 memcpy(&CurScreen(sp)->_line[y].text[x0], 553 &NewScreen(sp)->_line[y].text[x0], 554 n * sizeof(CurScreen(sp)->_line[y].text[x0])); 555 con_write(TCB, 556 y, 557 x0, 558 &CurScreen(sp)->_line[y].text[x0], n); 559 x0 = NextChange(x1); 560 } 561 562 /* mark line changed successfully */ 563 if (y <= NewScreen(sp)->_maxy) { 564 MARK_NOCHANGE(NewScreen(sp), y); 565 } 566 if (y <= CurScreen(sp)->_maxy) { 567 MARK_NOCHANGE(CurScreen(sp), y); 568 } 569 #else 570 x1 = NewScreen(sp)->_line[y].lastchar; 571 n = x1 - x0 + 1; 572 if (n > 0) { 573 memcpy(&CurScreen(sp)->_line[y].text[x0], 574 &NewScreen(sp)->_line[y].text[x0], 575 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0])); 576 con_write(TCB, 577 y, 578 x0, 579 &CurScreen(sp)->_line[y].text[x0], n); 580 581 /* mark line changed successfully */ 582 if (y <= NewScreen(sp)->_maxy) { 583 MARK_NOCHANGE(NewScreen(sp), y); 584 } 585 if (y <= CurScreen(sp)->_maxy) { 586 MARK_NOCHANGE(CurScreen(sp), y); 587 } 588 } 589 #endif 590 } 591 } 592 593 /* put everything back in sync */ 594 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) { 595 MARK_NOCHANGE(NewScreen(sp), y); 596 } 597 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) { 598 MARK_NOCHANGE(CurScreen(sp), y); 599 } 600 601 if (!NewScreen(sp)->_leaveok) { 602 CurScreen(sp)->_curx = NewScreen(sp)->_curx; 603 CurScreen(sp)->_cury = NewScreen(sp)->_cury; 604 605 TCB->drv->td_hwcur(TCB, 606 0, 0, 607 CurScreen(sp)->_cury, CurScreen(sp)->_curx); 608 } 609 selectActiveHandle(); 610 result = OK; 611 } 612 returnCode(result); 613 } 614 615 static bool 616 wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, 617 const char *tname, 618 int *errret GCC_UNUSED) 619 { 620 bool code = FALSE; 621 622 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB)); 623 624 assert((TCB != 0) && (tname != 0)); 625 626 TCB->magic = WINMAGIC; 627 628 if (tname == 0 || *tname == 0) 629 code = TRUE; 630 else if (tname != 0 && *tname == '#') { 631 /* 632 * Use "#" (a character which cannot begin a terminal's name) to 633 * select specific driver from the table. 634 * 635 * In principle, we could have more than one non-terminfo driver, 636 * e.g., "win32gui". 637 */ 638 size_t n = strlen(tname + 1); 639 if (n != 0 640 && ((strncmp(tname + 1, "win32console", n) == 0) 641 || (strncmp(tname + 1, "win32con", n) == 0))) { 642 code = TRUE; 643 } 644 } else if (tname != 0 && stricmp(tname, "unknown") == 0) { 645 code = TRUE; 646 } 647 648 /* 649 * This is intentional, to avoid unnecessary breakage of applications 650 * using <term.h> symbols. 651 */ 652 if (code && (TerminalType(&TCB->term).Booleans == 0)) { 653 _nc_init_termtype(&TerminalType(&TCB->term)); 654 #if NCURSES_EXT_NUMBERS 655 _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term)); 656 #endif 657 } 658 659 if (!code) { 660 if (_nc_mingw_isconsole(0)) 661 CON.isTermInfoConsole = TRUE; 662 } 663 returnBool(code); 664 } 665 666 static int 667 wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB, 668 int beepFlag) 669 { 670 SCREEN *sp; 671 int res = ERR; 672 673 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1); 674 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1); 675 int max_cells = (high * wide); 676 int i; 677 678 CHAR_INFO this_screen[max_cells]; 679 CHAR_INFO that_screen[max_cells]; 680 COORD this_size; 681 SMALL_RECT this_region; 682 COORD bufferCoord; 683 684 if (okConsoleHandle(TCB)) { 685 SetSP(); 686 this_region.Top = CON.SBI.srWindow.Top; 687 this_region.Left = CON.SBI.srWindow.Left; 688 this_region.Bottom = CON.SBI.srWindow.Bottom; 689 this_region.Right = CON.SBI.srWindow.Right; 690 691 this_size.X = (SHORT) wide; 692 this_size.Y = (SHORT) high; 693 694 bufferCoord.X = this_region.Left; 695 bufferCoord.Y = this_region.Top; 696 697 if (!beepFlag && 698 read_screen(CON.hdl, 699 this_screen, 700 this_size, 701 bufferCoord, 702 &this_region)) { 703 704 memcpy(that_screen, this_screen, sizeof(that_screen)); 705 706 for (i = 0; i < max_cells; i++) { 707 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes); 708 } 709 710 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region); 711 Sleep(200); 712 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region); 713 714 } else { 715 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */ 716 } 717 res = OK; 718 } 719 return res; 720 } 721 722 static int 723 wcon_print(TERMINAL_CONTROL_BLOCK * TCB, 724 char *data GCC_UNUSED, 725 int len GCC_UNUSED) 726 { 727 SCREEN *sp; 728 729 AssertTCB(); 730 SetSP(); 731 732 return ERR; 733 } 734 735 static int 736 wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB, 737 int fg GCC_UNUSED, 738 int bg GCC_UNUSED) 739 { 740 SCREEN *sp; 741 int code = ERR; 742 743 AssertTCB(); 744 SetSP(); 745 746 return (code); 747 } 748 749 static bool 750 get_SBI(void) 751 { 752 bool rc = FALSE; 753 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) { 754 T(("GetConsoleScreenBufferInfo")); 755 T(("... buffer(X:%d Y:%d)", 756 CON.SBI.dwSize.X, 757 CON.SBI.dwSize.Y)); 758 T(("... window(X:%d Y:%d)", 759 CON.SBI.dwMaximumWindowSize.X, 760 CON.SBI.dwMaximumWindowSize.Y)); 761 T(("... cursor(X:%d Y:%d)", 762 CON.SBI.dwCursorPosition.X, 763 CON.SBI.dwCursorPosition.Y)); 764 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)", 765 CON.SBI.srWindow.Top, 766 CON.SBI.srWindow.Bottom, 767 CON.SBI.srWindow.Left, 768 CON.SBI.srWindow.Right)); 769 if (CON.buffered) { 770 CON.origin.X = 0; 771 CON.origin.Y = 0; 772 } else { 773 CON.origin.X = CON.SBI.srWindow.Left; 774 CON.origin.Y = CON.SBI.srWindow.Top; 775 } 776 rc = TRUE; 777 } else { 778 T(("GetConsoleScreenBufferInfo ERR")); 779 } 780 return rc; 781 } 782 783 static void 784 wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB, 785 int fore, 786 int color, 787 int (*outc) (SCREEN *, int) GCC_UNUSED) 788 { 789 if (okConsoleHandle(TCB)) { 790 WORD a = MapColor(fore, color); 791 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)); 792 SetConsoleTextAttribute(CON.hdl, a); 793 get_SBI(); 794 } 795 } 796 797 static bool 798 wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB) 799 { 800 bool res = FALSE; 801 802 if (okConsoleHandle(TCB)) { 803 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; 804 SetConsoleTextAttribute(CON.hdl, a); 805 get_SBI(); 806 res = TRUE; 807 } 808 return res; 809 } 810 811 static bool 812 wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB) 813 { 814 int result = FALSE; 815 SCREEN *sp; 816 817 AssertTCB(); 818 SetSP(); 819 820 return result; 821 } 822 823 static int 824 wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols) 825 { 826 int result = ERR; 827 828 T((T_CALLED("win32con::wcon_size(%p)"), TCB)); 829 830 if (okConsoleHandle(TCB) && 831 Lines != NULL && 832 Cols != NULL) { 833 if (CON.buffered) { 834 *Lines = (int) (CON.SBI.dwSize.Y); 835 *Cols = (int) (CON.SBI.dwSize.X); 836 } else { 837 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 - 838 CON.SBI.srWindow.Top); 839 *Cols = (int) (CON.SBI.srWindow.Right + 1 - 840 CON.SBI.srWindow.Left); 841 } 842 result = OK; 843 } 844 returnCode(result); 845 } 846 847 static int 848 wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, 849 int l GCC_UNUSED, 850 int c GCC_UNUSED) 851 { 852 AssertTCB(); 853 return ERR; 854 } 855 856 static int 857 wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf) 858 { 859 DWORD dwFlag = 0; 860 tcflag_t iflag; 861 tcflag_t lflag; 862 int result = ERR; 863 864 if (buf != NULL && okConsoleHandle(TCB)) { 865 866 if (setFlag) { 867 iflag = buf->c_iflag; 868 lflag = buf->c_lflag; 869 870 GetConsoleMode(CON.inp, &dwFlag); 871 872 if (lflag & ICANON) 873 dwFlag |= ENABLE_LINE_INPUT; 874 else 875 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT); 876 877 if (lflag & ECHO) 878 dwFlag |= ENABLE_ECHO_INPUT; 879 else 880 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT); 881 882 if (iflag & BRKINT) 883 dwFlag |= ENABLE_PROCESSED_INPUT; 884 else 885 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT); 886 887 dwFlag |= ENABLE_MOUSE_INPUT; 888 889 buf->c_iflag = iflag; 890 buf->c_lflag = lflag; 891 SetConsoleMode(CON.inp, dwFlag); 892 TCB->term.Nttyb = *buf; 893 } else { 894 iflag = TCB->term.Nttyb.c_iflag; 895 lflag = TCB->term.Nttyb.c_lflag; 896 GetConsoleMode(CON.inp, &dwFlag); 897 898 if (dwFlag & ENABLE_LINE_INPUT) 899 lflag |= ICANON; 900 else 901 lflag &= (tcflag_t) (~ICANON); 902 903 if (dwFlag & ENABLE_ECHO_INPUT) 904 lflag |= ECHO; 905 else 906 lflag &= (tcflag_t) (~ECHO); 907 908 if (dwFlag & ENABLE_PROCESSED_INPUT) 909 iflag |= BRKINT; 910 else 911 iflag &= (tcflag_t) (~BRKINT); 912 913 TCB->term.Nttyb.c_iflag = iflag; 914 TCB->term.Nttyb.c_lflag = lflag; 915 916 *buf = TCB->term.Nttyb; 917 } 918 result = OK; 919 } 920 return result; 921 } 922 923 #define MIN_WIDE 80 924 #define MIN_HIGH 24 925 926 /* 927 * In "normal" mode, reset the buffer- and window-sizes back to their original values. 928 */ 929 static void 930 set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info) 931 { 932 SMALL_RECT rect; 933 COORD coord; 934 bool changed = FALSE; 935 936 T((T_CALLED("win32con::set_scrollback(%s)"), 937 (normal 938 ? "normal" 939 : "application"))); 940 941 T(("... SBI.srWindow %d,%d .. %d,%d", 942 info->srWindow.Top, 943 info->srWindow.Left, 944 info->srWindow.Bottom, 945 info->srWindow.Right)); 946 T(("... SBI.dwSize %dx%d", 947 info->dwSize.Y, 948 info->dwSize.X)); 949 950 if (normal) { 951 rect = info->srWindow; 952 coord = info->dwSize; 953 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) { 954 changed = TRUE; 955 CON.SBI = *info; 956 } 957 } else { 958 int high = info->srWindow.Bottom - info->srWindow.Top + 1; 959 int wide = info->srWindow.Right - info->srWindow.Left + 1; 960 961 if (high < MIN_HIGH) { 962 T(("... height %d < %d", high, MIN_HIGH)); 963 high = MIN_HIGH; 964 changed = TRUE; 965 } 966 if (wide < MIN_WIDE) { 967 T(("... width %d < %d", wide, MIN_WIDE)); 968 wide = MIN_WIDE; 969 changed = TRUE; 970 } 971 972 rect.Left = 973 rect.Top = 0; 974 rect.Right = (SHORT) (wide - 1); 975 rect.Bottom = (SHORT) (high - 1); 976 977 coord.X = (SHORT) wide; 978 coord.Y = (SHORT) high; 979 980 if (info->dwSize.Y != high || 981 info->dwSize.X != wide || 982 info->srWindow.Top != 0 || 983 info->srWindow.Left != 0) { 984 changed = TRUE; 985 } 986 987 } 988 989 if (changed) { 990 T(("... coord %d,%d", coord.Y, coord.X)); 991 T(("... rect %d,%d - %d,%d", 992 rect.Top, rect.Left, 993 rect.Bottom, rect.Right)); 994 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */ 995 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */ 996 get_SBI(); 997 } 998 returnVoid; 999 } 1000 1001 static int 1002 wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag) 1003 { 1004 SCREEN *sp; 1005 TERMINAL *_term = (TERMINAL *) TCB; 1006 int code = ERR; 1007 1008 if (okConsoleHandle(TCB)) { 1009 sp = TCB->csp; 1010 1011 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"), 1012 TCB, progFlag, defFlag)); 1013 1014 CON.progMode = progFlag; 1015 CON.lastOut = progFlag ? CON.hdl : CON.out; 1016 SetConsoleActiveScreenBuffer(CON.lastOut); 1017 1018 if (progFlag) /* prog mode */ { 1019 if (defFlag) { 1020 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) { 1021 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS); 1022 code = OK; 1023 } 1024 } else { 1025 /* reset_prog_mode */ 1026 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) { 1027 if (sp) { 1028 if (sp->_keypad_on) 1029 _nc_keypad(sp, TRUE); 1030 } 1031 if (!CON.buffered) { 1032 set_scrollback(FALSE, &CON.SBI); 1033 } 1034 code = OK; 1035 } 1036 } 1037 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear)); 1038 } else { /* shell mode */ 1039 if (defFlag) { 1040 /* def_shell_mode */ 1041 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) { 1042 code = OK; 1043 } 1044 } else { 1045 /* reset_shell_mode */ 1046 if (sp) { 1047 _nc_keypad(sp, FALSE); 1048 NCURSES_SP_NAME(_nc_flush) (sp); 1049 } 1050 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb)); 1051 if (!CON.buffered) { 1052 set_scrollback(TRUE, &CON.save_SBI); 1053 if (!restore_original_screen()) 1054 code = ERR; 1055 } 1056 SetConsoleCursorInfo(CON.hdl, &CON.save_CI); 1057 } 1058 } 1059 1060 } 1061 returnCode(code); 1062 } 1063 1064 static void 1065 wcon_screen_init(SCREEN *sp GCC_UNUSED) 1066 { 1067 } 1068 1069 static void 1070 wcon_wrap(SCREEN *sp GCC_UNUSED) 1071 { 1072 } 1073 1074 static int 1075 rkeycompare(const void *el1, const void *el2) 1076 { 1077 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff; 1078 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff; 1079 1080 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1)); 1081 } 1082 1083 static int 1084 keycompare(const void *el1, const void *el2) 1085 { 1086 WORD key1 = HIWORD((*((const LONG *) el1))); 1087 WORD key2 = HIWORD((*((const LONG *) el2))); 1088 1089 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1)); 1090 } 1091 1092 static int 1093 MapKey(WORD vKey) 1094 { 1095 WORD nKey = 0; 1096 void *res; 1097 LONG key = GenMap(vKey, 0); 1098 int code = -1; 1099 1100 res = bsearch(&key, 1101 CON.map, 1102 (size_t) (N_INI + FKEYS), 1103 sizeof(keylist[0]), 1104 keycompare); 1105 if (res) { 1106 key = *((LONG *) res); 1107 nKey = LOWORD(key); 1108 code = (int) (nKey & 0x7fff); 1109 if (nKey & 0x8000) 1110 code = -code; 1111 } 1112 return code; 1113 } 1114 1115 static int 1116 AnsiKey(WORD vKey) 1117 { 1118 WORD nKey = 0; 1119 void *res; 1120 LONG key = GenMap(vKey, 0); 1121 int code = -1; 1122 1123 res = bsearch(&key, 1124 CON.ansi_map, 1125 (size_t) (N_INI + FKEYS), 1126 sizeof(keylist[0]), 1127 keycompare); 1128 if (res) { 1129 key = *((LONG *) res); 1130 nKey = LOWORD(key); 1131 code = (int) (nKey & 0x7fff); 1132 if (nKey & 0x8000) 1133 code = -code; 1134 } 1135 return code; 1136 } 1137 1138 static void 1139 wcon_release(TERMINAL_CONTROL_BLOCK * TCB) 1140 { 1141 T((T_CALLED("win32con::wcon_release(%p)"), TCB)); 1142 1143 AssertTCB(); 1144 if (TCB->prop) 1145 free(TCB->prop); 1146 1147 returnVoid; 1148 } 1149 1150 static bool 1151 read_screen_data(void) 1152 { 1153 bool result = FALSE; 1154 COORD bufferCoord; 1155 size_t want; 1156 1157 CON.save_size.X = (SHORT) (CON.save_region.Right 1158 - CON.save_region.Left + 1); 1159 CON.save_size.Y = (SHORT) (CON.save_region.Bottom 1160 - CON.save_region.Top + 1); 1161 1162 want = (size_t) (CON.save_size.X * CON.save_size.Y); 1163 1164 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) { 1165 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0); 1166 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0); 1167 1168 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d", 1169 CON.window_only ? "window" : "buffer", 1170 CON.save_size.Y, CON.save_size.X, 1171 CON.save_region.Top, 1172 CON.save_region.Left, 1173 CON.save_region.Bottom, 1174 CON.save_region.Right, 1175 bufferCoord.Y, 1176 bufferCoord.X)); 1177 1178 if (read_screen(CON.hdl, 1179 CON.save_screen, 1180 CON.save_size, 1181 bufferCoord, 1182 &CON.save_region)) { 1183 result = TRUE; 1184 } else { 1185 T((" error %#lx", (unsigned long) GetLastError())); 1186 FreeAndNull(CON.save_screen); 1187 } 1188 } 1189 1190 return result; 1191 } 1192 1193 /* 1194 * Attempt to save the screen contents. PDCurses does this if 1195 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on 1196 * restoration as if the library had allocated a console buffer. MSDN 1197 * says that the data which can be read is limited to 64Kb (and may be 1198 * less). 1199 */ 1200 static bool 1201 save_original_screen(void) 1202 { 1203 bool result = FALSE; 1204 1205 CON.save_region.Top = 0; 1206 CON.save_region.Left = 0; 1207 CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1); 1208 CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1); 1209 1210 if (read_screen_data()) { 1211 result = TRUE; 1212 } else { 1213 1214 CON.save_region.Top = CON.SBI.srWindow.Top; 1215 CON.save_region.Left = CON.SBI.srWindow.Left; 1216 CON.save_region.Bottom = CON.SBI.srWindow.Bottom; 1217 CON.save_region.Right = CON.SBI.srWindow.Right; 1218 1219 CON.window_only = TRUE; 1220 1221 if (read_screen_data()) { 1222 result = TRUE; 1223 } 1224 } 1225 1226 T(("... save original screen contents %s", result ? "ok" : "err")); 1227 return result; 1228 } 1229 1230 static void 1231 wcon_init(TERMINAL_CONTROL_BLOCK * TCB) 1232 { 1233 T((T_CALLED("win32con::wcon_init(%p)"), TCB)); 1234 1235 AssertTCB(); 1236 1237 if (TCB) { 1238 if (!InitConsole()) { 1239 returnVoid; 1240 } 1241 1242 TCB->info.initcolor = TRUE; 1243 TCB->info.canchange = FALSE; 1244 TCB->info.hascolor = TRUE; 1245 TCB->info.caninit = TRUE; 1246 1247 TCB->info.maxpairs = NUMPAIRS; 1248 TCB->info.maxcolors = 8; 1249 TCB->info.numlabels = 0; 1250 TCB->info.labelwidth = 0; 1251 TCB->info.labelheight = 0; 1252 TCB->info.nocolorvideo = 1; 1253 TCB->info.tabsize = 8; 1254 1255 TCB->info.numbuttons = CON.numButtons; 1256 TCB->info.defaultPalette = _nc_cga_palette; 1257 1258 } 1259 returnVoid; 1260 } 1261 1262 static void 1263 wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB, 1264 int pair, 1265 int f, 1266 int b) 1267 { 1268 SCREEN *sp; 1269 1270 if (okConsoleHandle(TCB)) { 1271 SetSP(); 1272 1273 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8) 1274 && (b >= 0) && (b < 8)) { 1275 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b); 1276 } 1277 } 1278 } 1279 1280 static void 1281 wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB, 1282 int color GCC_UNUSED, 1283 int r GCC_UNUSED, 1284 int g GCC_UNUSED, 1285 int b GCC_UNUSED) 1286 { 1287 SCREEN *sp; 1288 1289 AssertTCB(); 1290 SetSP(); 1291 } 1292 1293 static void 1294 wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB, 1295 int old_pair GCC_UNUSED, 1296 int pair GCC_UNUSED, 1297 int reverse GCC_UNUSED, 1298 int (*outc) (SCREEN *, int) GCC_UNUSED 1299 ) 1300 { 1301 SCREEN *sp; 1302 1303 AssertTCB(); 1304 SetSP(); 1305 } 1306 1307 static void 1308 wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB) 1309 { 1310 SCREEN *sp; 1311 1312 if (okConsoleHandle(TCB)) { 1313 SetSP(); 1314 1315 sp->_mouse_type = M_TERM_DRIVER; 1316 } 1317 } 1318 1319 static int 1320 wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, 1321 int delay 1322 EVENTLIST_2nd(_nc_eventlist * evl)) 1323 { 1324 int rc = 0; 1325 SCREEN *sp; 1326 1327 if (okConsoleHandle(TCB)) { 1328 SetSP(); 1329 1330 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) { 1331 rc = TW_MOUSE; 1332 } else { 1333 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp), 1334 TWAIT_MASK, 1335 delay, 1336 (int *) 0 1337 EVENTLIST_2nd(evl)); 1338 } 1339 } 1340 1341 return rc; 1342 } 1343 1344 static int 1345 wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB, 1346 int yold GCC_UNUSED, int xold GCC_UNUSED, 1347 int y, int x) 1348 { 1349 int ret = ERR; 1350 if (okConsoleHandle(TCB)) { 1351 COORD loc; 1352 loc.X = (short) x; 1353 loc.Y = (short) (y + AdjustY()); 1354 SetConsoleCursorPosition(CON.hdl, loc); 1355 ret = OK; 1356 } 1357 return ret; 1358 } 1359 1360 static void 1361 wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB, 1362 int labnum GCC_UNUSED, 1363 char *text GCC_UNUSED) 1364 { 1365 SCREEN *sp; 1366 1367 AssertTCB(); 1368 SetSP(); 1369 } 1370 1371 static void 1372 wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB, 1373 int OnFlag GCC_UNUSED) 1374 { 1375 SCREEN *sp; 1376 1377 AssertTCB(); 1378 SetSP(); 1379 } 1380 1381 static chtype 1382 wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED) 1383 { 1384 chtype res = A_NORMAL; 1385 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR); 1386 return res; 1387 } 1388 1389 static void 1390 wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB) 1391 { 1392 SCREEN *sp; 1393 1394 AssertTCB(); 1395 SetSP(); 1396 } 1397 1398 static void 1399 wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB, 1400 chtype *real_map GCC_UNUSED, 1401 chtype *fake_map GCC_UNUSED) 1402 { 1403 #define DATA(a,b) { a, b } 1404 static struct { 1405 int acs_code; 1406 int use_code; 1407 } table[] = { 1408 DATA('a', 0xb1), /* ACS_CKBOARD */ 1409 DATA('f', 0xf8), /* ACS_DEGREE */ 1410 DATA('g', 0xf1), /* ACS_PLMINUS */ 1411 DATA('j', 0xd9), /* ACS_LRCORNER */ 1412 DATA('l', 0xda), /* ACS_ULCORNER */ 1413 DATA('k', 0xbf), /* ACS_URCORNER */ 1414 DATA('m', 0xc0), /* ACS_LLCORNER */ 1415 DATA('n', 0xc5), /* ACS_PLUS */ 1416 DATA('q', 0xc4), /* ACS_HLINE */ 1417 DATA('t', 0xc3), /* ACS_LTEE */ 1418 DATA('u', 0xb4), /* ACS_RTEE */ 1419 DATA('v', 0xc1), /* ACS_BTEE */ 1420 DATA('w', 0xc2), /* ACS_TTEE */ 1421 DATA('x', 0xb3), /* ACS_VLINE */ 1422 DATA('y', 0xf3), /* ACS_LEQUAL */ 1423 DATA('z', 0xf2), /* ACS_GEQUAL */ 1424 DATA('0', 0xdb), /* ACS_BLOCK */ 1425 DATA('{', 0xe3), /* ACS_PI */ 1426 DATA('}', 0x9c), /* ACS_STERLING */ 1427 DATA(',', 0xae), /* ACS_LARROW */ 1428 DATA('+', 0xaf), /* ACS_RARROW */ 1429 DATA('~', 0xf9), /* ACS_BULLET */ 1430 }; 1431 #undef DATA 1432 unsigned n; 1433 1434 SCREEN *sp; 1435 if (okConsoleHandle(TCB)) { 1436 SetSP(); 1437 1438 for (n = 0; n < SIZEOF(table); ++n) { 1439 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET; 1440 if (sp != 0) 1441 sp->_screen_acs_map[table[n].acs_code] = TRUE; 1442 } 1443 } 1444 } 1445 1446 static ULONGLONG 1447 tdiff(FILETIME fstart, FILETIME fend) 1448 { 1449 ULARGE_INTEGER ustart; 1450 ULARGE_INTEGER uend; 1451 ULONGLONG diff; 1452 1453 ustart.LowPart = fstart.dwLowDateTime; 1454 ustart.HighPart = fstart.dwHighDateTime; 1455 uend.LowPart = fend.dwLowDateTime; 1456 uend.HighPart = fend.dwHighDateTime; 1457 1458 diff = (uend.QuadPart - ustart.QuadPart) / 10000; 1459 return diff; 1460 } 1461 1462 static int 1463 Adjust(int milliseconds, int diff) 1464 { 1465 if (milliseconds != INFINITY) { 1466 milliseconds -= diff; 1467 if (milliseconds < 0) 1468 milliseconds = 0; 1469 } 1470 return milliseconds; 1471 } 1472 1473 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \ 1474 FROM_LEFT_2ND_BUTTON_PRESSED | \ 1475 FROM_LEFT_3RD_BUTTON_PRESSED | \ 1476 FROM_LEFT_4TH_BUTTON_PRESSED | \ 1477 RIGHTMOST_BUTTON_PRESSED) 1478 1479 static int 1480 decode_mouse(SCREEN *sp, int mask) 1481 { 1482 int result = 0; 1483 1484 (void) sp; 1485 assert(sp && console_initialized); 1486 1487 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED) 1488 result |= BUTTON1_PRESSED; 1489 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED) 1490 result |= BUTTON2_PRESSED; 1491 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED) 1492 result |= BUTTON3_PRESSED; 1493 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED) 1494 result |= BUTTON4_PRESSED; 1495 1496 if (mask & RIGHTMOST_BUTTON_PRESSED) { 1497 switch (CON.numButtons) { 1498 case 1: 1499 result |= BUTTON1_PRESSED; 1500 break; 1501 case 2: 1502 result |= BUTTON2_PRESSED; 1503 break; 1504 case 3: 1505 result |= BUTTON3_PRESSED; 1506 break; 1507 case 4: 1508 result |= BUTTON4_PRESSED; 1509 break; 1510 } 1511 } 1512 1513 return result; 1514 } 1515 1516 static int 1517 console_twait( 1518 SCREEN *sp, 1519 HANDLE fd, 1520 int mode, 1521 int milliseconds, 1522 int *timeleft 1523 EVENTLIST_2nd(_nc_eventlist * evl)) 1524 { 1525 INPUT_RECORD inp_rec; 1526 BOOL b; 1527 DWORD nRead = 0, rc = (DWORD) (-1); 1528 int code = 0; 1529 FILETIME fstart; 1530 FILETIME fend; 1531 int diff; 1532 bool isImmed = (milliseconds == 0); 1533 1534 #ifdef NCURSES_WGETCH_EVENTS 1535 (void) evl; /* TODO: implement wgetch-events */ 1536 #endif 1537 1538 #define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead) 1539 1540 assert(sp); 1541 1542 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d", 1543 milliseconds, mode)); 1544 1545 if (milliseconds < 0) 1546 milliseconds = INFINITY; 1547 1548 memset(&inp_rec, 0, sizeof(inp_rec)); 1549 1550 while (true) { 1551 GetSystemTimeAsFileTime(&fstart); 1552 rc = WaitForSingleObject(fd, (DWORD) milliseconds); 1553 GetSystemTimeAsFileTime(&fend); 1554 diff = (int) tdiff(fstart, fend); 1555 milliseconds = Adjust(milliseconds, diff); 1556 1557 if (!isImmed && milliseconds <= 0) 1558 break; 1559 1560 if (rc == WAIT_OBJECT_0) { 1561 if (mode) { 1562 b = GetNumberOfConsoleInputEvents(fd, &nRead); 1563 if (b && nRead > 0) { 1564 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead); 1565 if (b && nRead > 0) { 1566 switch (inp_rec.EventType) { 1567 case KEY_EVENT: 1568 if (mode & TW_INPUT) { 1569 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode; 1570 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar; 1571 1572 if (inp_rec.Event.KeyEvent.bKeyDown) { 1573 if (0 == ch) { 1574 int nKey = MapKey(vk); 1575 if (nKey < 0) { 1576 CONSUME(); 1577 continue; 1578 } 1579 } 1580 code = TW_INPUT; 1581 goto end; 1582 } else { 1583 CONSUME(); 1584 } 1585 } 1586 continue; 1587 case MOUSE_EVENT: 1588 if (decode_mouse(sp, 1589 (inp_rec.Event.MouseEvent.dwButtonState 1590 & BUTTON_MASK)) == 0) { 1591 CONSUME(); 1592 } else if (mode & TW_MOUSE) { 1593 code = TW_MOUSE; 1594 goto end; 1595 } 1596 continue; 1597 /* e.g., FOCUS_EVENT */ 1598 default: 1599 CONSUME(); 1600 selectActiveHandle(); 1601 continue; 1602 } 1603 } 1604 } 1605 } 1606 continue; 1607 } else { 1608 if (rc != WAIT_TIMEOUT) { 1609 code = -1; 1610 break; 1611 } else { 1612 code = 0; 1613 break; 1614 } 1615 } 1616 } 1617 end: 1618 1619 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec", 1620 code, errno, milliseconds)); 1621 1622 if (timeleft) 1623 *timeleft = milliseconds; 1624 1625 return code; 1626 } 1627 1628 static int 1629 wcon_twait(TERMINAL_CONTROL_BLOCK * TCB, 1630 int mode, 1631 int milliseconds, 1632 int *timeleft 1633 EVENTLIST_2nd(_nc_eventlist * evl)) 1634 { 1635 SCREEN *sp; 1636 int code = 0; 1637 1638 if (okConsoleHandle(TCB)) { 1639 SetSP(); 1640 1641 code = console_twait(sp, 1642 CON.inp, 1643 mode, 1644 milliseconds, 1645 timeleft EVENTLIST_2nd(evl)); 1646 } 1647 return code; 1648 } 1649 1650 static bool 1651 handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer) 1652 { 1653 MEVENT work; 1654 bool result = FALSE; 1655 1656 assert(sp); 1657 1658 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons; 1659 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK; 1660 1661 /* 1662 * We're only interested if the button is pressed or released. 1663 * FIXME: implement continuous event-tracking. 1664 */ 1665 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) { 1666 1667 memset(&work, 0, sizeof(work)); 1668 1669 if (sp->_drv_mouse_new_buttons) { 1670 1671 work.bstate |= (mmask_t) decode_mouse(sp, sp->_drv_mouse_new_buttons); 1672 1673 } else { 1674 1675 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */ 1676 work.bstate |= (mmask_t) (decode_mouse(sp, 1677 sp->_drv_mouse_old_buttons) 1678 >> 1); 1679 1680 result = TRUE; 1681 } 1682 1683 work.x = mer.dwMousePosition.X; 1684 work.y = mer.dwMousePosition.Y - AdjustY(); 1685 1686 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work; 1687 sp->_drv_mouse_tail += 1; 1688 } 1689 1690 return result; 1691 } 1692 1693 static int 1694 wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf) 1695 { 1696 SCREEN *sp; 1697 int n = -1; 1698 1699 T((T_CALLED("win32con::wcon_read(%p)"), TCB)); 1700 1701 assert(buf); 1702 if (okConsoleHandle(TCB)) { 1703 SetSP(); 1704 1705 n = _nc_mingw_console_read(sp, CON.inp, buf); 1706 } 1707 returnCode(n); 1708 } 1709 1710 static int 1711 wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms) 1712 { 1713 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms)); 1714 Sleep((DWORD) ms); 1715 returnCode(OK); 1716 } 1717 1718 static int 1719 wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode) 1720 { 1721 int res = -1; 1722 1723 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode)); 1724 if (okConsoleHandle(TCB)) { 1725 CONSOLE_CURSOR_INFO this_CI = CON.save_CI; 1726 switch (mode) { 1727 case 0: 1728 this_CI.bVisible = FALSE; 1729 break; 1730 case 1: 1731 break; 1732 case 2: 1733 this_CI.dwSize = 100; 1734 break; 1735 } 1736 SetConsoleCursorInfo(CON.hdl, &this_CI); 1737 } 1738 returnCode(res); 1739 } 1740 1741 static bool 1742 wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode) 1743 { 1744 WORD nKey; 1745 void *res; 1746 bool found = FALSE; 1747 LONG key = GenMap(0, (WORD) keycode); 1748 1749 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode)); 1750 res = bsearch(&key, 1751 CON.rmap, 1752 (size_t) (N_INI + FKEYS), 1753 sizeof(keylist[0]), 1754 rkeycompare); 1755 if (res) { 1756 key = *((LONG *) res); 1757 nKey = LOWORD(key); 1758 if (!(nKey & 0x8000)) 1759 found = TRUE; 1760 } 1761 returnCode(found); 1762 } 1763 1764 static int 1765 wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED) 1766 { 1767 SCREEN *sp; 1768 int code = ERR; 1769 1770 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag)); 1771 1772 if (okConsoleHandle(TCB)) { 1773 SetSP(); 1774 1775 if (sp) { 1776 code = OK; 1777 } 1778 } 1779 returnCode(code); 1780 } 1781 1782 static int 1783 wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB, 1784 int keycode, 1785 int flag) 1786 { 1787 int code = ERR; 1788 SCREEN *sp; 1789 WORD nKey; 1790 WORD vKey; 1791 void *res; 1792 LONG key = GenMap(0, (WORD) keycode); 1793 1794 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag)); 1795 1796 if (okConsoleHandle(TCB)) { 1797 SetSP(); 1798 1799 if (sp) { 1800 res = bsearch(&key, 1801 CON.rmap, 1802 (size_t) (N_INI + FKEYS), 1803 sizeof(keylist[0]), 1804 rkeycompare); 1805 if (res) { 1806 key = *((LONG *) res); 1807 vKey = HIWORD(key); 1808 nKey = (LOWORD(key)) & 0x7fff; 1809 if (!flag) 1810 nKey |= 0x8000; 1811 *(LONG *) res = GenMap(vKey, nKey); 1812 } 1813 } 1814 } 1815 returnCode(code); 1816 } 1817 1818 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = { 1819 FALSE, 1820 wcon_name, /* Name */ 1821 wcon_CanHandle, /* CanHandle */ 1822 wcon_init, /* init */ 1823 wcon_release, /* release */ 1824 wcon_size, /* size */ 1825 wcon_sgmode, /* sgmode */ 1826 wcon_conattr, /* conattr */ 1827 wcon_mvcur, /* hwcur */ 1828 wcon_mode, /* mode */ 1829 wcon_rescol, /* rescol */ 1830 wcon_rescolors, /* rescolors */ 1831 wcon_setcolor, /* color */ 1832 wcon_dobeepflash, /* DoBeepFlash */ 1833 wcon_initpair, /* initpair */ 1834 wcon_initcolor, /* initcolor */ 1835 wcon_do_color, /* docolor */ 1836 wcon_initmouse, /* initmouse */ 1837 wcon_testmouse, /* testmouse */ 1838 wcon_setfilter, /* setfilter */ 1839 wcon_hwlabel, /* hwlabel */ 1840 wcon_hwlabelOnOff, /* hwlabelOnOff */ 1841 wcon_doupdate, /* update */ 1842 wcon_defaultcolors, /* defaultcolors */ 1843 wcon_print, /* print */ 1844 wcon_size, /* getsize */ 1845 wcon_setsize, /* setsize */ 1846 wcon_initacs, /* initacs */ 1847 wcon_screen_init, /* scinit */ 1848 wcon_wrap, /* scexit */ 1849 wcon_twait, /* twait */ 1850 wcon_read, /* read */ 1851 wcon_nap, /* nap */ 1852 wcon_kpad, /* kpad */ 1853 wcon_keyok, /* kyOk */ 1854 wcon_kyExist, /* kyExist */ 1855 wcon_cursorSet /* cursorSet */ 1856 }; 1857 1858 /* --------------------------------------------------------- */ 1859 1860 static HANDLE 1861 get_handle(int fd) 1862 { 1863 intptr_t value = _get_osfhandle(fd); 1864 return (HANDLE) value; 1865 } 1866 1867 #if WINVER >= 0x0600 1868 /* This function tests, whether or not the ncurses application 1869 is running as a descendant of MSYS2/cygwin mintty terminal 1870 application. mintty doesn't use Windows Console for it's screen 1871 I/O, so the native Windows _isatty doesn't recognize it as 1872 character device. But we can discover we are at the end of an 1873 Pipe and can query to server side of the pipe, looking whether 1874 or not this is mintty. 1875 */ 1876 static int 1877 _ismintty(int fd, LPHANDLE pMinTTY) 1878 { 1879 HANDLE handle = get_handle(fd); 1880 DWORD dw; 1881 int code = 0; 1882 1883 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY)); 1884 1885 if (handle != INVALID_HANDLE_VALUE) { 1886 dw = GetFileType(handle); 1887 if (dw == FILE_TYPE_PIPE) { 1888 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) { 1889 ULONG pPid; 1890 /* Requires NT6 */ 1891 if (GetNamedPipeServerProcessId(handle, &pPid)) { 1892 TCHAR buf[MAX_PATH]; 1893 DWORD len = 0; 1894 /* These security attributes may allow us to 1895 create a remote thread in mintty to manipulate 1896 the terminal state remotely */ 1897 HANDLE pHandle = OpenProcess( 1898 PROCESS_CREATE_THREAD 1899 | PROCESS_QUERY_INFORMATION 1900 | PROCESS_VM_OPERATION 1901 | PROCESS_VM_WRITE 1902 | PROCESS_VM_READ, 1903 FALSE, 1904 pPid); 1905 if (pMinTTY) 1906 *pMinTTY = INVALID_HANDLE_VALUE; 1907 if (pHandle != INVALID_HANDLE_VALUE) { 1908 if ((len = GetProcessImageFileName( 1909 pHandle, 1910 buf, 1911 (DWORD) 1912 array_length(buf)))) { 1913 TCHAR *pos = _tcsrchr(buf, _T('\\')); 1914 if (pos) { 1915 pos++; 1916 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10) 1917 == 0) { 1918 if (pMinTTY) 1919 *pMinTTY = pHandle; 1920 code = 1; 1921 } 1922 } 1923 } 1924 } 1925 } 1926 } 1927 } 1928 } 1929 returnCode(code); 1930 } 1931 #endif 1932 1933 /* Borrowed from ansicon project. 1934 Check whether or not an I/O handle is associated with 1935 a Windows console. 1936 */ 1937 static BOOL 1938 IsConsoleHandle(HANDLE hdl) 1939 { 1940 DWORD dwFlag = 0; 1941 BOOL result; 1942 1943 if (!GetConsoleMode(hdl, &dwFlag)) { 1944 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL); 1945 } else { 1946 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT); 1947 } 1948 return result; 1949 } 1950 1951 /* Our replacement for the systems _isatty to include also 1952 a test for mintty. This is called from the NC_ISATTY macro 1953 defined in curses.priv.h 1954 */ 1955 int 1956 _nc_mingw_isatty(int fd) 1957 { 1958 int result = 0; 1959 1960 #ifdef __MING32__ 1961 #define SysISATTY(fd) _isatty(fd) 1962 #else 1963 #define SysISATTY(fd) isatty(fd) 1964 #endif 1965 if (SysISATTY(fd)) { 1966 result = 1; 1967 } else { 1968 #if WINVER >= 0x0600 1969 result = _ismintty(fd, NULL); 1970 #endif 1971 } 1972 return result; 1973 } 1974 1975 /* This is used when running in terminfo mode to discover, 1976 whether or not the "terminal" is actually a Windows 1977 Console. It's the responsibility of the console to deal 1978 with the terminal escape sequences that are sent by 1979 terminfo. 1980 */ 1981 int 1982 _nc_mingw_isconsole(int fd) 1983 { 1984 HANDLE hdl = get_handle(fd); 1985 int code = 0; 1986 1987 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd)); 1988 1989 code = (int) IsConsoleHandle(hdl); 1990 1991 returnCode(code); 1992 } 1993 1994 #define TC_PROLOGUE(fd) \ 1995 SCREEN *sp; \ 1996 TERMINAL *term = 0; \ 1997 int code = ERR; \ 1998 if (_nc_screen_chain == 0) \ 1999 return 0; \ 2000 for (each_screen(sp)) { \ 2001 if (sp->_term && (sp->_term->Filedes == fd)) { \ 2002 term = sp->_term; \ 2003 break; \ 2004 } \ 2005 } \ 2006 assert(term != 0) 2007 2008 int 2009 _nc_mingw_tcsetattr( 2010 int fd, 2011 int optional_action GCC_UNUSED, 2012 const struct termios *arg) 2013 { 2014 TC_PROLOGUE(fd); 2015 2016 if (_nc_mingw_isconsole(fd)) { 2017 DWORD dwFlag = 0; 2018 HANDLE ofd = get_handle(fd); 2019 if (ofd != INVALID_HANDLE_VALUE) { 2020 if (arg) { 2021 if (arg->c_lflag & ICANON) 2022 dwFlag |= ENABLE_LINE_INPUT; 2023 else 2024 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT); 2025 2026 if (arg->c_lflag & ECHO) 2027 dwFlag = dwFlag | ENABLE_ECHO_INPUT; 2028 else 2029 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT); 2030 2031 if (arg->c_iflag & BRKINT) 2032 dwFlag |= ENABLE_PROCESSED_INPUT; 2033 else 2034 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT); 2035 } 2036 dwFlag |= ENABLE_MOUSE_INPUT; 2037 SetConsoleMode(ofd, dwFlag); 2038 code = OK; 2039 } 2040 } 2041 if (arg) 2042 term->Nttyb = *arg; 2043 2044 return code; 2045 } 2046 2047 int 2048 _nc_mingw_tcgetattr(int fd, struct termios *arg) 2049 { 2050 TC_PROLOGUE(fd); 2051 2052 if (_nc_mingw_isconsole(fd)) { 2053 if (arg) 2054 *arg = term->Nttyb; 2055 } 2056 return code; 2057 } 2058 2059 int 2060 _nc_mingw_tcflush(int fd, int queue) 2061 { 2062 TC_PROLOGUE(fd); 2063 (void) term; 2064 2065 if (_nc_mingw_isconsole(fd)) { 2066 if (queue == TCIFLUSH) { 2067 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); 2068 if (!b) 2069 return (int) GetLastError(); 2070 } 2071 } 2072 return code; 2073 } 2074 2075 int 2076 _nc_mingw_testmouse( 2077 SCREEN *sp, 2078 HANDLE fd, 2079 int delay 2080 EVENTLIST_2nd(_nc_eventlist * evl)) 2081 { 2082 int rc = 0; 2083 2084 assert(sp); 2085 2086 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) { 2087 rc = TW_MOUSE; 2088 } else { 2089 rc = console_twait(sp, 2090 fd, 2091 TWAIT_MASK, 2092 delay, 2093 (int *) 0 2094 EVENTLIST_2nd(evl)); 2095 } 2096 return rc; 2097 } 2098 2099 int 2100 _nc_mingw_console_read( 2101 SCREEN *sp, 2102 HANDLE fd, 2103 int *buf) 2104 { 2105 int rc = -1; 2106 INPUT_RECORD inp_rec; 2107 BOOL b; 2108 DWORD nRead; 2109 WORD vk; 2110 2111 assert(sp); 2112 assert(buf); 2113 2114 memset(&inp_rec, 0, sizeof(inp_rec)); 2115 2116 T((T_CALLED("_nc_mingw_console_read(%p)"), sp)); 2117 2118 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) { 2119 if (b && nRead > 0) { 2120 if (rc < 0) 2121 rc = 0; 2122 rc = rc + (int) nRead; 2123 if (inp_rec.EventType == KEY_EVENT) { 2124 if (!inp_rec.Event.KeyEvent.bKeyDown) 2125 continue; 2126 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar; 2127 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode; 2128 /* 2129 * There are 24 virtual function-keys, and typically 2130 * 12 function-keys on a keyboard. Use the shift-modifier 2131 * to provide the remaining 12 keys. 2132 */ 2133 if (vk >= VK_F1 && vk <= VK_F12) { 2134 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) { 2135 vk = (WORD) (vk + 12); 2136 } 2137 } 2138 if (*buf == 0) { 2139 int key = MapKey(vk); 2140 if (key < 0) 2141 continue; 2142 if (sp->_keypad_on) { 2143 *buf = key; 2144 } else { 2145 ungetch('\0'); 2146 *buf = AnsiKey(vk); 2147 } 2148 } 2149 break; 2150 } else if (inp_rec.EventType == MOUSE_EVENT) { 2151 if (handle_mouse(sp, 2152 inp_rec.Event.MouseEvent)) { 2153 *buf = KEY_MOUSE; 2154 break; 2155 } 2156 } 2157 continue; 2158 } 2159 } 2160 returnCode(rc); 2161 } 2162 2163 static bool 2164 InitConsole(void) 2165 { 2166 /* initialize once, or not at all */ 2167 if (!console_initialized) { 2168 int i; 2169 DWORD num_buttons; 2170 WORD a; 2171 BOOL buffered = TRUE; 2172 BOOL b; 2173 2174 START_TRACE(); 2175 if (_nc_mingw_isatty(0)) { 2176 CON.isMinTTY = TRUE; 2177 } 2178 2179 for (i = 0; i < (N_INI + FKEYS); i++) { 2180 if (i < N_INI) { 2181 CON.rmap[i] = CON.map[i] = 2182 (DWORD) keylist[i]; 2183 CON.ansi_map[i] = (DWORD) ansi_keys[i]; 2184 } else { 2185 CON.rmap[i] = CON.map[i] = 2186 (DWORD) GenMap((VK_F1 + (i - N_INI)), 2187 (KEY_F(1) + (i - N_INI))); 2188 CON.ansi_map[i] = 2189 (DWORD) GenMap((VK_F1 + (i - N_INI)), 2190 (';' + (i - N_INI))); 2191 } 2192 } 2193 qsort(CON.ansi_map, 2194 (size_t) (MAPSIZE), 2195 sizeof(keylist[0]), 2196 keycompare); 2197 qsort(CON.map, 2198 (size_t) (MAPSIZE), 2199 sizeof(keylist[0]), 2200 keycompare); 2201 qsort(CON.rmap, 2202 (size_t) (MAPSIZE), 2203 sizeof(keylist[0]), 2204 rkeycompare); 2205 2206 if (GetNumberOfConsoleMouseButtons(&num_buttons)) { 2207 CON.numButtons = (int) num_buttons; 2208 } else { 2209 CON.numButtons = 1; 2210 } 2211 2212 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK); 2213 for (i = 0; i < NUMPAIRS; i++) 2214 CON.pairs[i] = a; 2215 2216 CON.inp = GetStdHandle(STD_INPUT_HANDLE); 2217 CON.out = GetStdHandle(STD_OUTPUT_HANDLE); 2218 2219 b = AllocConsole(); 2220 2221 if (!b) 2222 b = AttachConsole(ATTACH_PARENT_PROCESS); 2223 2224 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) { 2225 T(("... will not buffer console")); 2226 buffered = FALSE; 2227 CON.hdl = CON.out; 2228 } else { 2229 T(("... creating console buffer")); 2230 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 2231 0, 2232 NULL, 2233 CONSOLE_TEXTMODE_BUFFER, 2234 NULL); 2235 } 2236 2237 if (CON.hdl != INVALID_HANDLE_VALUE) { 2238 CON.buffered = buffered; 2239 get_SBI(); 2240 CON.save_SBI = CON.SBI; 2241 if (!buffered) { 2242 save_original_screen(); 2243 set_scrollback(FALSE, &CON.SBI); 2244 } 2245 GetConsoleCursorInfo(CON.hdl, &CON.save_CI); 2246 T(("... initial cursor is %svisible, %d%%", 2247 (CON.save_CI.bVisible ? "" : "not-"), 2248 (int) CON.save_CI.dwSize)); 2249 } 2250 2251 console_initialized = TRUE; 2252 } 2253 return (CON.hdl != INVALID_HANDLE_VALUE); 2254 } 2255 2256 static bool 2257 okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB) 2258 { 2259 return ((TCB != 0) && 2260 (TCB->magic == WINMAGIC) && 2261 InitConsole()); 2262 } 2263 2264 /* 2265 * While a constructor would ensure that this module is initialized, that will 2266 * interfere with applications that may combine this with GUI interfaces. 2267 */ 2268 #if 0 2269 static 2270 __attribute__((constructor)) 2271 void _enter_console(void) 2272 { 2273 (void) InitConsole(); 2274 } 2275 #endif 2276