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 58MODULE_ID("$Id: win_driver.c,v 1.66 2020/03/01 00:18:49 tom Exp $") 59 60#define TypeAlloca(type,count) (type*) _alloca(sizeof(type) * (size_t) (count)) 61 62#define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE) 63 64#define EXP_OPTIMIZE 0 65 66#define array_length(a) (sizeof(a)/sizeof(a[0])) 67 68static bool InitConsole(void); 69static bool okConsoleHandle(TERMINAL_CONTROL_BLOCK *); 70 71#define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC)) 72#define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp 73 74#define GenMap(vKey,key) MAKELONG(key, vKey) 75 76#define AdjustY() (CON.buffered ? 0 : (int) CON.SBI.srWindow.Top) 77 78#if USE_WIDEC_SUPPORT 79#define write_screen WriteConsoleOutputW 80#define read_screen ReadConsoleOutputW 81#else 82#define write_screen WriteConsoleOutput 83#define read_screen ReadConsoleOutput 84#endif 85 86static const LONG keylist[] = 87{ 88 GenMap(VK_PRIOR, KEY_PPAGE), 89 GenMap(VK_NEXT, KEY_NPAGE), 90 GenMap(VK_END, KEY_END), 91 GenMap(VK_HOME, KEY_HOME), 92 GenMap(VK_LEFT, KEY_LEFT), 93 GenMap(VK_UP, KEY_UP), 94 GenMap(VK_RIGHT, KEY_RIGHT), 95 GenMap(VK_DOWN, KEY_DOWN), 96 GenMap(VK_DELETE, KEY_DC), 97 GenMap(VK_INSERT, KEY_IC) 98}; 99static const LONG ansi_keys[] = 100{ 101 GenMap(VK_PRIOR, 'I'), 102 GenMap(VK_NEXT, 'Q'), 103 GenMap(VK_END, 'O'), 104 GenMap(VK_HOME, 'H'), 105 GenMap(VK_LEFT, 'K'), 106 GenMap(VK_UP, 'H'), 107 GenMap(VK_RIGHT, 'M'), 108 GenMap(VK_DOWN, 'P'), 109 GenMap(VK_DELETE, 'S'), 110 GenMap(VK_INSERT, 'R') 111}; 112#define N_INI ((int)array_length(keylist)) 113#define FKEYS 24 114#define MAPSIZE (FKEYS + N_INI) 115#define NUMPAIRS 64 116 117/* A process can only have a single console, so it's safe 118 to maintain all the information about it in a single 119 static structure. 120 */ 121static struct { 122 BOOL initialized; 123 BOOL buffered; 124 BOOL window_only; 125 BOOL progMode; 126 BOOL isMinTTY; 127 BOOL isTermInfoConsole; 128 HANDLE out; 129 HANDLE inp; 130 HANDLE hdl; 131 HANDLE lastOut; 132 int numButtons; 133 DWORD ansi_map[MAPSIZE]; 134 DWORD map[MAPSIZE]; 135 DWORD rmap[MAPSIZE]; 136 WORD pairs[NUMPAIRS]; 137 COORD origin; 138 CHAR_INFO *save_screen; 139 COORD save_size; 140 SMALL_RECT save_region; 141 CONSOLE_SCREEN_BUFFER_INFO SBI; 142 CONSOLE_SCREEN_BUFFER_INFO save_SBI; 143 CONSOLE_CURSOR_INFO save_CI; 144} CON; 145 146static BOOL console_initialized = FALSE; 147 148static WORD 149MapColor(bool fore, int color) 150{ 151 static const int _cmap[] = 152 {0, 4, 2, 6, 1, 5, 3, 7}; 153 int a; 154 if (color < 0 || color > 7) 155 a = fore ? 7 : 0; 156 else 157 a = _cmap[color]; 158 if (!fore) 159 a = a << 4; 160 return (WORD) a; 161} 162 163#define RevAttr(attr) \ 164 (WORD) (((attr) & 0xff00) | \ 165 ((((attr) & 0x07) << 4) | \ 166 (((attr) & 0x70) >> 4))) 167 168static WORD 169MapAttr(WORD res, attr_t ch) 170{ 171 if (ch & A_COLOR) { 172 int p; 173 174 p = PairNumber(ch); 175 if (p > 0 && p < NUMPAIRS) { 176 WORD a; 177 a = CON.pairs[p]; 178 res = (WORD) ((res & 0xff00) | a); 179 } 180 } 181 182 if (ch & A_REVERSE) { 183 res = RevAttr(res); 184 } 185 186 if (ch & A_STANDOUT) { 187 res = RevAttr(res) | BACKGROUND_INTENSITY; 188 } 189 190 if (ch & A_BOLD) 191 res |= FOREGROUND_INTENSITY; 192 193 if (ch & A_DIM) 194 res |= BACKGROUND_INTENSITY; 195 196 return res; 197} 198 199#if 0 /* def TRACE */ 200static void 201dump_screen(const char *fn, int ln) 202{ 203 int max_cells = (CON.SBI.dwSize.Y * (1 + CON.SBI.dwSize.X)) + 1; 204 char output[max_cells]; 205 CHAR_INFO save_screen[max_cells]; 206 COORD save_size; 207 SMALL_RECT save_region; 208 COORD bufferCoord; 209 210 T(("dump_screen %s@%d", fn, ln)); 211 212 save_region.Top = CON.SBI.srWindow.Top; 213 save_region.Left = CON.SBI.srWindow.Left; 214 save_region.Bottom = CON.SBI.srWindow.Bottom; 215 save_region.Right = CON.SBI.srWindow.Right; 216 217 save_size.X = (SHORT) (save_region.Right - save_region.Left + 1); 218 save_size.Y = (SHORT) (save_region.Bottom - save_region.Top + 1); 219 220 bufferCoord.X = bufferCoord.Y = 0; 221 222 if (read_screen(CON.hdl, 223 save_screen, 224 save_size, 225 bufferCoord, 226 &save_region)) { 227 int i, j; 228 int ij = 0; 229 int k = 0; 230 231 for (i = save_region.Top; i <= save_region.Bottom; ++i) { 232 for (j = save_region.Left; j <= save_region.Right; ++j) { 233 output[k++] = save_screen[ij++].Char.AsciiChar; 234 } 235 output[k++] = '\n'; 236 } 237 output[k] = 0; 238 239 T(("DUMP: %d,%d - %d,%d", 240 save_region.Top, 241 save_region.Left, 242 save_region.Bottom, 243 save_region.Right)); 244 T(("%s", output)); 245 } 246} 247 248#else 249#define dump_screen(fn,ln) /* nothing */ 250#endif 251 252#if USE_WIDEC_SUPPORT 253/* 254 * TODO: support surrogate pairs 255 * TODO: support combining characters 256 * TODO: support acsc 257 * TODO: _nc_wacs should be part of sp. 258 */ 259static BOOL 260con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit) 261{ 262 int actual = 0; 263 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, limit); 264 COORD loc, siz; 265 SMALL_RECT rec; 266 int i; 267 cchar_t ch; 268 SCREEN *sp; 269 270 AssertTCB(); 271 SetSP(); 272 273 for (i = actual = 0; i < limit; i++) { 274 ch = str[i]; 275 if (isWidecExt(ch)) 276 continue; 277 ci[actual].Char.UnicodeChar = CharOf(ch); 278 ci[actual].Attributes = MapAttr(CON.SBI.wAttributes, 279 AttrOf(ch)); 280 if (AttrOf(ch) & A_ALTCHARSET) { 281 if (_nc_wacs) { 282 int which = CharOf(ch); 283 if (which > 0 284 && which < ACS_LEN 285 && CharOf(_nc_wacs[which]) != 0) { 286 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]); 287 } else { 288 ci[actual].Char.UnicodeChar = ' '; 289 } 290 } 291 } 292 ++actual; 293 } 294 295 loc.X = (SHORT) 0; 296 loc.Y = (SHORT) 0; 297 siz.X = (SHORT) actual; 298 siz.Y = 1; 299 300 rec.Left = (SHORT) x; 301 rec.Top = (SHORT) (y + AdjustY()); 302 rec.Right = (SHORT) (x + limit - 1); 303 rec.Bottom = rec.Top; 304 305 return write_screen(CON.hdl, ci, siz, loc, &rec); 306} 307#define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n) 308#else 309static BOOL 310con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n) 311{ 312 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, n); 313 COORD loc, siz; 314 SMALL_RECT rec; 315 int i; 316 chtype ch; 317 SCREEN *sp; 318 319 AssertTCB(); 320 SetSP(); 321 322 for (i = 0; i < n; i++) { 323 ch = str[i]; 324 ci[i].Char.AsciiChar = ChCharOf(ch); 325 ci[i].Attributes = MapAttr(CON.SBI.wAttributes, 326 ChAttrOf(ch)); 327 if (ChAttrOf(ch) & A_ALTCHARSET) { 328 if (sp->_acs_map) 329 ci[i].Char.AsciiChar = 330 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch))); 331 } 332 } 333 334 loc.X = (short) 0; 335 loc.Y = (short) 0; 336 siz.X = (short) n; 337 siz.Y = 1; 338 339 rec.Left = (short) x; 340 rec.Top = (short) y; 341 rec.Right = (short) (x + n - 1); 342 rec.Bottom = rec.Top; 343 344 return write_screen(CON.hdl, ci, siz, loc, &rec); 345} 346#define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n) 347#endif 348 349#if EXP_OPTIMIZE 350/* 351 * Comparing new/current screens, determine the last column-index for a change 352 * beginning on the given row,col position. Unlike a serial terminal, there is 353 * no cost for "moving" the "cursor" on the line as we update it. 354 */ 355static int 356find_end_of_change(SCREEN *sp, int row, int col) 357{ 358 int result = col; 359 struct ldat *curdat = CurScreen(sp)->_line + row; 360 struct ldat *newdat = NewScreen(sp)->_line + row; 361 362 while (col <= newdat->lastchar) { 363#if USE_WIDEC_SUPPORT 364 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) { 365 result = col; 366 } else if (memcmp(&curdat->text[col], 367 &newdat->text[col], 368 sizeof(curdat->text[0]))) { 369 result = col; 370 } else { 371 break; 372 } 373#else 374 if (curdat->text[col] != newdat->text[col]) { 375 result = col; 376 } else { 377 break; 378 } 379#endif 380 ++col; 381 } 382 return result; 383} 384 385/* 386 * Given a row,col position at the end of a change-chunk, look for the 387 * beginning of the next change-chunk. 388 */ 389static int 390find_next_change(SCREEN *sp, int row, int col) 391{ 392 struct ldat *curdat = CurScreen(sp)->_line + row; 393 struct ldat *newdat = NewScreen(sp)->_line + row; 394 int result = newdat->lastchar + 1; 395 396 while (++col <= newdat->lastchar) { 397#if USE_WIDEC_SUPPORT 398 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) { 399 result = col; 400 break; 401 } else if (memcmp(&curdat->text[col], 402 &newdat->text[col], 403 sizeof(curdat->text[0]))) { 404 result = col; 405 break; 406 } 407#else 408 if (curdat->text[col] != newdat->text[col]) { 409 result = col; 410 break; 411 } 412#endif 413 } 414 return result; 415} 416 417#define EndChange(first) \ 418 find_end_of_change(sp, y, first) 419#define NextChange(last) \ 420 find_next_change(sp, y, last) 421 422#endif /* EXP_OPTIMIZE */ 423 424#define MARK_NOCHANGE(win,row) \ 425 win->_line[row].firstchar = _NOCHANGE; \ 426 win->_line[row].lastchar = _NOCHANGE 427 428static void 429selectActiveHandle(void) 430{ 431 if (CON.lastOut != CON.hdl) { 432 CON.lastOut = CON.hdl; 433 SetConsoleActiveScreenBuffer(CON.lastOut); 434 } 435} 436 437static bool 438restore_original_screen(void) 439{ 440 COORD bufferCoord; 441 bool result = FALSE; 442 SMALL_RECT save_region = CON.save_region; 443 444 T(("... restoring %s", CON.window_only ? "window" : "entire buffer")); 445 446 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0); 447 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0); 448 449 if (write_screen(CON.hdl, 450 CON.save_screen, 451 CON.save_size, 452 bufferCoord, 453 &save_region)) { 454 result = TRUE; 455 mvcur(-1, -1, LINES - 2, 0); 456 T(("... restore original screen contents ok %dx%d (%d,%d - %d,%d)", 457 CON.save_size.Y, 458 CON.save_size.X, 459 save_region.Top, 460 save_region.Left, 461 save_region.Bottom, 462 save_region.Right)); 463 } else { 464 T(("... restore original screen contents err")); 465 } 466 return result; 467} 468 469static const char * 470wcon_name(TERMINAL_CONTROL_BLOCK * TCB) 471{ 472 (void) TCB; 473 return "win32console"; 474} 475 476static int 477wcon_doupdate(TERMINAL_CONTROL_BLOCK * TCB) 478{ 479 int result = ERR; 480 int y, nonempty, n, x0, x1, Width, Height; 481 SCREEN *sp; 482 483 T((T_CALLED("win32con::wcon_doupdate(%p)"), TCB)); 484 if (okConsoleHandle(TCB)) { 485 SetSP(); 486 487 Width = screen_columns(sp); 488 Height = screen_lines(sp); 489 nonempty = min(Height, NewScreen(sp)->_maxy + 1); 490 491 T(("... %dx%d clear cur:%d new:%d", 492 Height, Width, 493 CurScreen(sp)->_clear, 494 NewScreen(sp)->_clear)); 495 496 if (SP_PARM->_endwin == ewSuspend) { 497 498 T(("coming back from shell mode")); 499 NCURSES_SP_NAME(reset_prog_mode) (NCURSES_SP_ARG); 500 501 NCURSES_SP_NAME(_nc_mvcur_resume) (NCURSES_SP_ARG); 502 NCURSES_SP_NAME(_nc_screen_resume) (NCURSES_SP_ARG); 503 SP_PARM->_mouse_resume(SP_PARM); 504 505 SP_PARM->_endwin = ewRunning; 506 } 507 508 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) { 509 int x; 510#if USE_WIDEC_SUPPORT 511 cchar_t *empty = TypeAlloca(cchar_t, Width); 512 wchar_t blank[2] = 513 { 514 L' ', L'\0' 515 }; 516 517 for (x = 0; x < Width; x++) 518 setcchar(&empty[x], blank, 0, 0, 0); 519#else 520 chtype *empty = TypeAlloca(chtype, Width); 521 522 for (x = 0; x < Width; x++) 523 empty[x] = ' '; 524#endif 525 526 for (y = 0; y < nonempty; y++) { 527 con_write(TCB, y, 0, empty, Width); 528 memcpy(empty, 529 CurScreen(sp)->_line[y].text, 530 (size_t) Width * sizeof(empty[0])); 531 } 532 CurScreen(sp)->_clear = FALSE; 533 NewScreen(sp)->_clear = FALSE; 534 touchwin(NewScreen(sp)); 535 T(("... cleared %dx%d lines @%d of screen", nonempty, Width, 536 AdjustY())); 537 } 538 539 for (y = 0; y < nonempty; y++) { 540 x0 = NewScreen(sp)->_line[y].firstchar; 541 if (x0 != _NOCHANGE) { 542#if EXP_OPTIMIZE 543 int x2; 544 int limit = NewScreen(sp)->_line[y].lastchar; 545 while ((x1 = EndChange(x0)) <= limit) { 546 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) { 547 x1 = x2; 548 } 549 n = x1 - x0 + 1; 550 memcpy(&CurScreen(sp)->_line[y].text[x0], 551 &NewScreen(sp)->_line[y].text[x0], 552 n * sizeof(CurScreen(sp)->_line[y].text[x0])); 553 con_write(TCB, 554 y, 555 x0, 556 &CurScreen(sp)->_line[y].text[x0], n); 557 x0 = NextChange(x1); 558 } 559 560 /* mark line changed successfully */ 561 if (y <= NewScreen(sp)->_maxy) { 562 MARK_NOCHANGE(NewScreen(sp), y); 563 } 564 if (y <= CurScreen(sp)->_maxy) { 565 MARK_NOCHANGE(CurScreen(sp), y); 566 } 567#else 568 x1 = NewScreen(sp)->_line[y].lastchar; 569 n = x1 - x0 + 1; 570 if (n > 0) { 571 memcpy(&CurScreen(sp)->_line[y].text[x0], 572 &NewScreen(sp)->_line[y].text[x0], 573 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0])); 574 con_write(TCB, 575 y, 576 x0, 577 &CurScreen(sp)->_line[y].text[x0], n); 578 579 /* mark line changed successfully */ 580 if (y <= NewScreen(sp)->_maxy) { 581 MARK_NOCHANGE(NewScreen(sp), y); 582 } 583 if (y <= CurScreen(sp)->_maxy) { 584 MARK_NOCHANGE(CurScreen(sp), y); 585 } 586 } 587#endif 588 } 589 } 590 591 /* put everything back in sync */ 592 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) { 593 MARK_NOCHANGE(NewScreen(sp), y); 594 } 595 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) { 596 MARK_NOCHANGE(CurScreen(sp), y); 597 } 598 599 if (!NewScreen(sp)->_leaveok) { 600 CurScreen(sp)->_curx = NewScreen(sp)->_curx; 601 CurScreen(sp)->_cury = NewScreen(sp)->_cury; 602 603 TCB->drv->td_hwcur(TCB, 604 0, 0, 605 CurScreen(sp)->_cury, CurScreen(sp)->_curx); 606 } 607 selectActiveHandle(); 608 result = OK; 609 } 610 returnCode(result); 611} 612 613static bool 614wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, 615 const char *tname, 616 int *errret GCC_UNUSED) 617{ 618 bool code = FALSE; 619 620 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB)); 621 622 assert((TCB != 0) && (tname != 0)); 623 624 TCB->magic = WINMAGIC; 625 626 if (tname == 0 || *tname == 0) 627 code = TRUE; 628 else if (tname != 0 && *tname == '#') { 629 /* 630 * Use "#" (a character which cannot begin a terminal's name) to 631 * select specific driver from the table. 632 * 633 * In principle, we could have more than one non-terminfo driver, 634 * e.g., "win32gui". 635 */ 636 size_t n = strlen(tname + 1); 637 if (n != 0 638 && ((strncmp(tname + 1, "win32console", n) == 0) 639 || (strncmp(tname + 1, "win32con", n) == 0))) { 640 code = TRUE; 641 } 642 } else if (tname != 0 && stricmp(tname, "unknown") == 0) { 643 code = TRUE; 644 } 645 646 /* 647 * This is intentional, to avoid unnecessary breakage of applications 648 * using <term.h> symbols. 649 */ 650 if (code && (TerminalType(&TCB->term).Booleans == 0)) { 651 _nc_init_termtype(&TerminalType(&TCB->term)); 652#if NCURSES_EXT_NUMBERS 653 _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term)); 654#endif 655 } 656 657 if (!code) { 658 if (_nc_mingw_isconsole(0)) 659 CON.isTermInfoConsole = TRUE; 660 } 661 returnBool(code); 662} 663 664static int 665wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB, 666 int beepFlag) 667{ 668 SCREEN *sp; 669 int res = ERR; 670 671 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1); 672 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1); 673 int max_cells = (high * wide); 674 int i; 675 676 CHAR_INFO *this_screen = TypeAlloca(CHAR_INFO, max_cells); 677 CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells); 678 COORD this_size; 679 SMALL_RECT this_region; 680 COORD bufferCoord; 681 682 if (okConsoleHandle(TCB)) { 683 SetSP(); 684 this_region.Top = CON.SBI.srWindow.Top; 685 this_region.Left = CON.SBI.srWindow.Left; 686 this_region.Bottom = CON.SBI.srWindow.Bottom; 687 this_region.Right = CON.SBI.srWindow.Right; 688 689 this_size.X = (SHORT) wide; 690 this_size.Y = (SHORT) high; 691 692 bufferCoord.X = this_region.Left; 693 bufferCoord.Y = this_region.Top; 694 695 if (!beepFlag && 696 read_screen(CON.hdl, 697 this_screen, 698 this_size, 699 bufferCoord, 700 &this_region)) { 701 702 memcpy(that_screen, 703 this_screen, 704 sizeof(CHAR_INFO) * (size_t) max_cells); 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 722static int 723wcon_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 735static int 736wcon_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 749static bool 750get_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 783static void 784wcon_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 797static bool 798wcon_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 811static bool 812wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB) 813{ 814 int result = FALSE; 815 SCREEN *sp; 816 817 AssertTCB(); 818 SetSP(); 819 820 return result; 821} 822 823static int 824wcon_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 847static int 848wcon_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 856static int 857wcon_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 */ 929static void 930set_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 1001static int 1002wcon_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 1064static void 1065wcon_screen_init(SCREEN *sp GCC_UNUSED) 1066{ 1067} 1068 1069static void 1070wcon_wrap(SCREEN *sp GCC_UNUSED) 1071{ 1072} 1073 1074static int 1075rkeycompare(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 1083static int 1084keycompare(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 1092static int 1093MapKey(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 1115static int 1116AnsiKey(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 1138static void 1139wcon_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 1150static bool 1151read_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 */ 1200static bool 1201save_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 1230static void 1231wcon_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 1262static void 1263wcon_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 1280static void 1281wcon_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 1293static void 1294wcon_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 1307static void 1308wcon_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 1319static int 1320wcon_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 1344static int 1345wcon_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 1360static void 1361wcon_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 1371static void 1372wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB, 1373 int OnFlag GCC_UNUSED) 1374{ 1375 SCREEN *sp; 1376 1377 AssertTCB(); 1378 SetSP(); 1379} 1380 1381static chtype 1382wcon_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 1389static void 1390wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB) 1391{ 1392 SCREEN *sp; 1393 1394 AssertTCB(); 1395 SetSP(); 1396} 1397 1398static void 1399wcon_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 1446static ULONGLONG 1447tdiff(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 1462static int 1463Adjust(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 1479static int 1480decode_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 1516static int 1517console_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 1628static int 1629wcon_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 1650static bool 1651handle_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 1693static int 1694wcon_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 1710static int 1711wcon_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 1718static int 1719wcon_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 1741static bool 1742wcon_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 1764static int 1765wcon_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 1782static int 1783wcon_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 1818NCURSES_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 1860static HANDLE 1861get_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 */ 1876static 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*/ 1937static BOOL 1938IsConsoleHandle(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 */ 1955int 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 */ 1981int 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 2008int 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 2047int 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 2059int 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 2075int 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 2099int 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 2163static bool 2164InitConsole(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 2256static bool 2257okConsoleHandle(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 2269static 2270__attribute__((constructor)) 2271 void _enter_console(void) 2272{ 2273 (void) InitConsole(); 2274} 2275#endif 2276