1/**************************************************************************** 2 * Copyright 2018-2021,2023 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#define CONTROL_PRESSED (LEFT_CTRL_PRESSED | RIGHT_CTRL_PRESSED) 59 60MODULE_ID("$Id: win_driver.c,v 1.74 2023/09/16 16:27:44 tom Exp $") 61 62#define TypeAlloca(type,count) (type*) _alloca(sizeof(type) * (size_t) (count)) 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 70static bool InitConsole(void); 71static 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/* *INDENT-OFF* */ 88static 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}; 101static 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/* *INDENT-ON* */ 115#define N_INI ((int)array_length(keylist)) 116#define FKEYS 24 117#define MAPSIZE (FKEYS + N_INI) 118#define NUMPAIRS 64 119 120/* A process can only have a single console, so it is safe 121 to maintain all the information about it in a single 122 static structure. 123 */ 124static struct { 125 BOOL initialized; 126 BOOL buffered; 127 BOOL window_only; 128 BOOL progMode; 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 148static BOOL console_initialized = FALSE; 149 150static WORD 151MapColor(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 170static WORD 171MapAttr(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 */ 202static void 203dump_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 */ 261static BOOL 262con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit) 263{ 264 int actual = 0; 265 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, 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 311static BOOL 312con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n) 313{ 314 CHAR_INFO *ci = TypeAlloca(CHAR_INFO, 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 */ 357static int 358find_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 */ 391static int 392find_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 430static void 431selectActiveHandle(void) 432{ 433 if (CON.lastOut != CON.hdl) { 434 CON.lastOut = CON.hdl; 435 SetConsoleActiveScreenBuffer(CON.lastOut); 436 } 437} 438 439static bool 440restore_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 471static const char * 472wcon_name(TERMINAL_CONTROL_BLOCK * TCB) 473{ 474 (void) TCB; 475 return "win32console"; 476} 477 478static int 479wcon_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 = TypeAlloca(cchar_t, 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 = TypeAlloca(chtype, 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#ifdef __MING32__ 616#define SysISATTY(fd) _isatty(fd) 617#else 618#define SysISATTY(fd) isatty(fd) 619#endif 620 621static bool 622wcon_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, 623 const char *tname, 624 int *errret GCC_UNUSED) 625{ 626 bool code = FALSE; 627 628 T((T_CALLED("win32con::wcon_CanHandle(%p)"), TCB)); 629 630 assert((TCB != 0) && (tname != 0)); 631 632 TCB->magic = WINMAGIC; 633 634 if (tname == 0 || *tname == 0) 635 code = TRUE; 636 else if (tname != 0 && *tname == '#') { 637 /* 638 * Use "#" (a character which cannot begin a terminal's name) to 639 * select specific driver from the table. 640 * 641 * In principle, we could have more than one non-terminfo driver, 642 * e.g., "win32gui". 643 */ 644 size_t n = strlen(tname + 1); 645 if (n != 0 646 && ((strncmp(tname + 1, "win32console", n) == 0) 647 || (strncmp(tname + 1, "win32con", n) == 0))) { 648 code = TRUE; 649 } 650 } else if (tname != 0 && stricmp(tname, "unknown") == 0) { 651 code = TRUE; 652 } else if (SysISATTY(TCB->term.Filedes)) { 653 code = TRUE; 654 } 655 656 /* 657 * This is intentional, to avoid unnecessary breakage of applications 658 * using <term.h> symbols. 659 */ 660 if (code && (TerminalType(&TCB->term).Booleans == 0)) { 661 _nc_init_termtype(&TerminalType(&TCB->term)); 662#if NCURSES_EXT_NUMBERS 663 _nc_export_termtype2(&TCB->term.type, &TerminalType(&TCB->term)); 664#endif 665 } 666 667 if (!code) { 668 if (_nc_mingw_isconsole(0)) 669 CON.isTermInfoConsole = TRUE; 670 } 671 returnBool(code); 672} 673 674static int 675wcon_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB, 676 int beepFlag) 677{ 678 SCREEN *sp; 679 int res = ERR; 680 681 int high = (CON.SBI.srWindow.Bottom - CON.SBI.srWindow.Top + 1); 682 int wide = (CON.SBI.srWindow.Right - CON.SBI.srWindow.Left + 1); 683 int max_cells = (high * wide); 684 int i; 685 686 CHAR_INFO *this_screen = TypeAlloca(CHAR_INFO, max_cells); 687 CHAR_INFO *that_screen = TypeAlloca(CHAR_INFO, max_cells); 688 COORD this_size; 689 SMALL_RECT this_region; 690 COORD bufferCoord; 691 692 if (okConsoleHandle(TCB)) { 693 SetSP(); 694 this_region.Top = CON.SBI.srWindow.Top; 695 this_region.Left = CON.SBI.srWindow.Left; 696 this_region.Bottom = CON.SBI.srWindow.Bottom; 697 this_region.Right = CON.SBI.srWindow.Right; 698 699 this_size.X = (SHORT) wide; 700 this_size.Y = (SHORT) high; 701 702 bufferCoord.X = this_region.Left; 703 bufferCoord.Y = this_region.Top; 704 705 if (!beepFlag && 706 read_screen(CON.hdl, 707 this_screen, 708 this_size, 709 bufferCoord, 710 &this_region)) { 711 712 memcpy(that_screen, 713 this_screen, 714 sizeof(CHAR_INFO) * (size_t) max_cells); 715 716 for (i = 0; i < max_cells; i++) { 717 that_screen[i].Attributes = RevAttr(that_screen[i].Attributes); 718 } 719 720 write_screen(CON.hdl, that_screen, this_size, bufferCoord, &this_region); 721 Sleep(200); 722 write_screen(CON.hdl, this_screen, this_size, bufferCoord, &this_region); 723 724 } else { 725 MessageBeep(MB_ICONWARNING); /* MB_OK might be better */ 726 } 727 res = OK; 728 } 729 return res; 730} 731 732static int 733wcon_print(TERMINAL_CONTROL_BLOCK * TCB, 734 char *data GCC_UNUSED, 735 int len GCC_UNUSED) 736{ 737 SCREEN *sp; 738 739 AssertTCB(); 740 SetSP(); 741 742 return ERR; 743} 744 745static int 746wcon_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB, 747 int fg GCC_UNUSED, 748 int bg GCC_UNUSED) 749{ 750 SCREEN *sp; 751 int code = ERR; 752 753 AssertTCB(); 754 SetSP(); 755 756 return (code); 757} 758 759static bool 760get_SBI(void) 761{ 762 bool rc = FALSE; 763 if (GetConsoleScreenBufferInfo(CON.hdl, &(CON.SBI))) { 764 T(("GetConsoleScreenBufferInfo")); 765 T(("... buffer(X:%d Y:%d)", 766 CON.SBI.dwSize.X, 767 CON.SBI.dwSize.Y)); 768 T(("... window(X:%d Y:%d)", 769 CON.SBI.dwMaximumWindowSize.X, 770 CON.SBI.dwMaximumWindowSize.Y)); 771 T(("... cursor(X:%d Y:%d)", 772 CON.SBI.dwCursorPosition.X, 773 CON.SBI.dwCursorPosition.Y)); 774 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)", 775 CON.SBI.srWindow.Top, 776 CON.SBI.srWindow.Bottom, 777 CON.SBI.srWindow.Left, 778 CON.SBI.srWindow.Right)); 779 if (CON.buffered) { 780 CON.origin.X = 0; 781 CON.origin.Y = 0; 782 } else { 783 CON.origin.X = CON.SBI.srWindow.Left; 784 CON.origin.Y = CON.SBI.srWindow.Top; 785 } 786 rc = TRUE; 787 } else { 788 T(("GetConsoleScreenBufferInfo ERR")); 789 } 790 return rc; 791} 792 793static void 794wcon_setcolor(TERMINAL_CONTROL_BLOCK * TCB, 795 int fore, 796 int color, 797 int (*outc) (SCREEN *, int) GCC_UNUSED) 798{ 799 if (okConsoleHandle(TCB)) { 800 WORD a = MapColor(fore, color); 801 a |= (WORD) ((CON.SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)); 802 SetConsoleTextAttribute(CON.hdl, a); 803 get_SBI(); 804 } 805} 806 807static bool 808wcon_rescol(TERMINAL_CONTROL_BLOCK * TCB) 809{ 810 bool res = FALSE; 811 812 if (okConsoleHandle(TCB)) { 813 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; 814 SetConsoleTextAttribute(CON.hdl, a); 815 get_SBI(); 816 res = TRUE; 817 } 818 return res; 819} 820 821static bool 822wcon_rescolors(TERMINAL_CONTROL_BLOCK * TCB) 823{ 824 int result = FALSE; 825 SCREEN *sp; 826 827 AssertTCB(); 828 SetSP(); 829 830 return result; 831} 832 833static int 834wcon_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols) 835{ 836 int result = ERR; 837 838 T((T_CALLED("win32con::wcon_size(%p)"), TCB)); 839 840 if (okConsoleHandle(TCB) && 841 Lines != NULL && 842 Cols != NULL) { 843 if (CON.buffered) { 844 *Lines = (int) (CON.SBI.dwSize.Y); 845 *Cols = (int) (CON.SBI.dwSize.X); 846 } else { 847 *Lines = (int) (CON.SBI.srWindow.Bottom + 1 - 848 CON.SBI.srWindow.Top); 849 *Cols = (int) (CON.SBI.srWindow.Right + 1 - 850 CON.SBI.srWindow.Left); 851 } 852 result = OK; 853 } 854 returnCode(result); 855} 856 857static int 858wcon_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, 859 int l GCC_UNUSED, 860 int c GCC_UNUSED) 861{ 862 AssertTCB(); 863 return ERR; 864} 865 866static int 867wcon_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf) 868{ 869 DWORD dwFlag = 0; 870 tcflag_t iflag; 871 tcflag_t lflag; 872 int result = ERR; 873 874 if (buf != NULL && okConsoleHandle(TCB)) { 875 876 if (setFlag) { 877 iflag = buf->c_iflag; 878 lflag = buf->c_lflag; 879 880 GetConsoleMode(CON.inp, &dwFlag); 881 882 if (lflag & ICANON) 883 dwFlag |= ENABLE_LINE_INPUT; 884 else 885 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT); 886 887 if (lflag & ECHO) 888 dwFlag |= ENABLE_ECHO_INPUT; 889 else 890 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT); 891 892 if (iflag & BRKINT) 893 dwFlag |= ENABLE_PROCESSED_INPUT; 894 else 895 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT); 896 897 dwFlag |= ENABLE_MOUSE_INPUT; 898 899 buf->c_iflag = iflag; 900 buf->c_lflag = lflag; 901 SetConsoleMode(CON.inp, dwFlag); 902 TCB->term.Nttyb = *buf; 903 } else { 904 iflag = TCB->term.Nttyb.c_iflag; 905 lflag = TCB->term.Nttyb.c_lflag; 906 GetConsoleMode(CON.inp, &dwFlag); 907 908 if (dwFlag & ENABLE_LINE_INPUT) 909 lflag |= ICANON; 910 else 911 lflag &= (tcflag_t) (~ICANON); 912 913 if (dwFlag & ENABLE_ECHO_INPUT) 914 lflag |= ECHO; 915 else 916 lflag &= (tcflag_t) (~ECHO); 917 918 if (dwFlag & ENABLE_PROCESSED_INPUT) 919 iflag |= BRKINT; 920 else 921 iflag &= (tcflag_t) (~BRKINT); 922 923 TCB->term.Nttyb.c_iflag = iflag; 924 TCB->term.Nttyb.c_lflag = lflag; 925 926 *buf = TCB->term.Nttyb; 927 } 928 result = OK; 929 } 930 return result; 931} 932 933#define MIN_WIDE 80 934#define MIN_HIGH 24 935 936/* 937 * In "normal" mode, reset the buffer- and window-sizes back to their original values. 938 */ 939static void 940set_scrollback(bool normal, CONSOLE_SCREEN_BUFFER_INFO * info) 941{ 942 SMALL_RECT rect; 943 COORD coord; 944 bool changed = FALSE; 945 946 T((T_CALLED("win32con::set_scrollback(%s)"), 947 (normal 948 ? "normal" 949 : "application"))); 950 951 T(("... SBI.srWindow %d,%d .. %d,%d", 952 info->srWindow.Top, 953 info->srWindow.Left, 954 info->srWindow.Bottom, 955 info->srWindow.Right)); 956 T(("... SBI.dwSize %dx%d", 957 info->dwSize.Y, 958 info->dwSize.X)); 959 960 if (normal) { 961 rect = info->srWindow; 962 coord = info->dwSize; 963 if (memcmp(info, &CON.SBI, sizeof(*info)) != 0) { 964 changed = TRUE; 965 CON.SBI = *info; 966 } 967 } else { 968 int high = info->srWindow.Bottom - info->srWindow.Top + 1; 969 int wide = info->srWindow.Right - info->srWindow.Left + 1; 970 971 if (high < MIN_HIGH) { 972 T(("... height %d < %d", high, MIN_HIGH)); 973 high = MIN_HIGH; 974 changed = TRUE; 975 } 976 if (wide < MIN_WIDE) { 977 T(("... width %d < %d", wide, MIN_WIDE)); 978 wide = MIN_WIDE; 979 changed = TRUE; 980 } 981 982 rect.Left = 983 rect.Top = 0; 984 rect.Right = (SHORT) (wide - 1); 985 rect.Bottom = (SHORT) (high - 1); 986 987 coord.X = (SHORT) wide; 988 coord.Y = (SHORT) high; 989 990 if (info->dwSize.Y != high || 991 info->dwSize.X != wide || 992 info->srWindow.Top != 0 || 993 info->srWindow.Left != 0) { 994 changed = TRUE; 995 } 996 997 } 998 999 if (changed) { 1000 T(("... coord %d,%d", coord.Y, coord.X)); 1001 T(("... rect %d,%d - %d,%d", 1002 rect.Top, rect.Left, 1003 rect.Bottom, rect.Right)); 1004 SetConsoleScreenBufferSize(CON.hdl, coord); /* dwSize */ 1005 SetConsoleWindowInfo(CON.hdl, TRUE, &rect); /* srWindow */ 1006 get_SBI(); 1007 } 1008 returnVoid; 1009} 1010 1011static int 1012wcon_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag) 1013{ 1014 SCREEN *sp; 1015 TERMINAL *_term = (TERMINAL *) TCB; 1016 int code = ERR; 1017 1018 if (okConsoleHandle(TCB)) { 1019 sp = TCB->csp; 1020 1021 T((T_CALLED("win32con::wcon_mode(%p, prog=%d, def=%d)"), 1022 TCB, progFlag, defFlag)); 1023 1024 CON.progMode = progFlag; 1025 CON.lastOut = progFlag ? CON.hdl : CON.out; 1026 SetConsoleActiveScreenBuffer(CON.lastOut); 1027 1028 if (progFlag) /* prog mode */ { 1029 if (defFlag) { 1030 if ((wcon_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) { 1031 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS); 1032 code = OK; 1033 } 1034 } else { 1035 /* reset_prog_mode */ 1036 if (wcon_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) { 1037 if (sp) { 1038 if (sp->_keypad_on) 1039 _nc_keypad(sp, TRUE); 1040 } 1041 if (!CON.buffered) { 1042 set_scrollback(FALSE, &CON.SBI); 1043 } 1044 code = OK; 1045 } 1046 } 1047 T(("... buffered:%d, clear:%d", CON.buffered, CurScreen(sp)->_clear)); 1048 } else { /* shell mode */ 1049 if (defFlag) { 1050 /* def_shell_mode */ 1051 if (wcon_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) { 1052 code = OK; 1053 } 1054 } else { 1055 /* reset_shell_mode */ 1056 if (sp) { 1057 _nc_keypad(sp, FALSE); 1058 NCURSES_SP_NAME(_nc_flush) (sp); 1059 } 1060 code = wcon_sgmode(TCB, TRUE, &(_term->Ottyb)); 1061 if (!CON.buffered) { 1062 set_scrollback(TRUE, &CON.save_SBI); 1063 if (!restore_original_screen()) 1064 code = ERR; 1065 } 1066 SetConsoleCursorInfo(CON.hdl, &CON.save_CI); 1067 } 1068 } 1069 1070 } 1071 returnCode(code); 1072} 1073 1074static void 1075wcon_screen_init(SCREEN *sp GCC_UNUSED) 1076{ 1077} 1078 1079static void 1080wcon_wrap(SCREEN *sp GCC_UNUSED) 1081{ 1082} 1083 1084static int 1085rkeycompare(const void *el1, const void *el2) 1086{ 1087 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff; 1088 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff; 1089 1090 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1)); 1091} 1092 1093static int 1094keycompare(const void *el1, const void *el2) 1095{ 1096 WORD key1 = HIWORD((*((const LONG *) el1))); 1097 WORD key2 = HIWORD((*((const LONG *) el2))); 1098 1099 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1)); 1100} 1101 1102static int 1103MapKey(WORD vKey) 1104{ 1105 WORD nKey = 0; 1106 void *res; 1107 LONG key = GenMap(vKey, 0); 1108 int code = -1; 1109 1110 res = bsearch(&key, 1111 CON.map, 1112 (size_t) (N_INI + FKEYS), 1113 sizeof(keylist[0]), 1114 keycompare); 1115 if (res) { 1116 key = *((LONG *) res); 1117 nKey = LOWORD(key); 1118 code = (int) (nKey & 0x7fff); 1119 if (nKey & 0x8000) 1120 code = -code; 1121 } 1122 return code; 1123} 1124 1125static int 1126AnsiKey(WORD vKey) 1127{ 1128 WORD nKey = 0; 1129 void *res; 1130 LONG key = GenMap(vKey, 0); 1131 int code = -1; 1132 1133 res = bsearch(&key, 1134 CON.ansi_map, 1135 (size_t) (N_INI + FKEYS), 1136 sizeof(keylist[0]), 1137 keycompare); 1138 if (res) { 1139 key = *((LONG *) res); 1140 nKey = LOWORD(key); 1141 code = (int) (nKey & 0x7fff); 1142 if (nKey & 0x8000) 1143 code = -code; 1144 } 1145 return code; 1146} 1147 1148static void 1149wcon_release(TERMINAL_CONTROL_BLOCK * TCB) 1150{ 1151 T((T_CALLED("win32con::wcon_release(%p)"), TCB)); 1152 1153 AssertTCB(); 1154 if (TCB->prop) 1155 free(TCB->prop); 1156 1157 returnVoid; 1158} 1159 1160static bool 1161read_screen_data(void) 1162{ 1163 bool result = FALSE; 1164 COORD bufferCoord; 1165 size_t want; 1166 1167 CON.save_size.X = (SHORT) (CON.save_region.Right 1168 - CON.save_region.Left + 1); 1169 CON.save_size.Y = (SHORT) (CON.save_region.Bottom 1170 - CON.save_region.Top + 1); 1171 1172 want = (size_t) (CON.save_size.X * CON.save_size.Y); 1173 1174 if ((CON.save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) { 1175 bufferCoord.X = (SHORT) (CON.window_only ? CON.SBI.srWindow.Left : 0); 1176 bufferCoord.Y = (SHORT) (CON.window_only ? CON.SBI.srWindow.Top : 0); 1177 1178 T(("... reading console %s %dx%d into %d,%d - %d,%d at %d,%d", 1179 CON.window_only ? "window" : "buffer", 1180 CON.save_size.Y, CON.save_size.X, 1181 CON.save_region.Top, 1182 CON.save_region.Left, 1183 CON.save_region.Bottom, 1184 CON.save_region.Right, 1185 bufferCoord.Y, 1186 bufferCoord.X)); 1187 1188 if (read_screen(CON.hdl, 1189 CON.save_screen, 1190 CON.save_size, 1191 bufferCoord, 1192 &CON.save_region)) { 1193 result = TRUE; 1194 } else { 1195 T((" error %#lx", (unsigned long) GetLastError())); 1196 FreeAndNull(CON.save_screen); 1197 } 1198 } 1199 1200 return result; 1201} 1202 1203/* 1204 * Attempt to save the screen contents. PDCurses does this if 1205 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on 1206 * restoration as if the library had allocated a console buffer. MSDN 1207 * says that the data which can be read is limited to 64Kb (and may be 1208 * less). 1209 */ 1210static bool 1211save_original_screen(void) 1212{ 1213 bool result = FALSE; 1214 1215 CON.save_region.Top = 0; 1216 CON.save_region.Left = 0; 1217 CON.save_region.Bottom = (SHORT) (CON.SBI.dwSize.Y - 1); 1218 CON.save_region.Right = (SHORT) (CON.SBI.dwSize.X - 1); 1219 1220 if (read_screen_data()) { 1221 result = TRUE; 1222 } else { 1223 1224 CON.save_region.Top = CON.SBI.srWindow.Top; 1225 CON.save_region.Left = CON.SBI.srWindow.Left; 1226 CON.save_region.Bottom = CON.SBI.srWindow.Bottom; 1227 CON.save_region.Right = CON.SBI.srWindow.Right; 1228 1229 CON.window_only = TRUE; 1230 1231 if (read_screen_data()) { 1232 result = TRUE; 1233 } 1234 } 1235 1236 T(("... save original screen contents %s", result ? "ok" : "err")); 1237 return result; 1238} 1239 1240static void 1241wcon_init(TERMINAL_CONTROL_BLOCK * TCB) 1242{ 1243 T((T_CALLED("win32con::wcon_init(%p)"), TCB)); 1244 1245 AssertTCB(); 1246 1247 if (TCB) { 1248 if (!InitConsole()) { 1249 returnVoid; 1250 } 1251 1252 TCB->info.initcolor = TRUE; 1253 TCB->info.canchange = FALSE; 1254 TCB->info.hascolor = TRUE; 1255 TCB->info.caninit = TRUE; 1256 1257 TCB->info.maxpairs = NUMPAIRS; 1258 TCB->info.maxcolors = 8; 1259 TCB->info.numlabels = 0; 1260 TCB->info.labelwidth = 0; 1261 TCB->info.labelheight = 0; 1262 TCB->info.nocolorvideo = 1; 1263 TCB->info.tabsize = 8; 1264 1265 TCB->info.numbuttons = CON.numButtons; 1266 TCB->info.defaultPalette = _nc_cga_palette; 1267 1268 } 1269 returnVoid; 1270} 1271 1272static void 1273wcon_initpair(TERMINAL_CONTROL_BLOCK * TCB, 1274 int pair, 1275 int f, 1276 int b) 1277{ 1278 SCREEN *sp; 1279 1280 if (okConsoleHandle(TCB)) { 1281 SetSP(); 1282 1283 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8) 1284 && (b >= 0) && (b < 8)) { 1285 CON.pairs[pair] = MapColor(true, f) | MapColor(false, b); 1286 } 1287 } 1288} 1289 1290static void 1291wcon_initcolor(TERMINAL_CONTROL_BLOCK * TCB, 1292 int color GCC_UNUSED, 1293 int r GCC_UNUSED, 1294 int g GCC_UNUSED, 1295 int b GCC_UNUSED) 1296{ 1297 SCREEN *sp; 1298 1299 AssertTCB(); 1300 SetSP(); 1301} 1302 1303static void 1304wcon_do_color(TERMINAL_CONTROL_BLOCK * TCB, 1305 int old_pair GCC_UNUSED, 1306 int pair GCC_UNUSED, 1307 int reverse GCC_UNUSED, 1308 int (*outc) (SCREEN *, int) GCC_UNUSED 1309) 1310{ 1311 SCREEN *sp; 1312 1313 AssertTCB(); 1314 SetSP(); 1315} 1316 1317static void 1318wcon_initmouse(TERMINAL_CONTROL_BLOCK * TCB) 1319{ 1320 SCREEN *sp; 1321 1322 if (okConsoleHandle(TCB)) { 1323 SetSP(); 1324 1325 sp->_mouse_type = M_TERM_DRIVER; 1326 } 1327} 1328 1329static int 1330wcon_testmouse(TERMINAL_CONTROL_BLOCK * TCB, 1331 int delay 1332 EVENTLIST_2nd(_nc_eventlist * evl)) 1333{ 1334 int rc = 0; 1335 SCREEN *sp; 1336 1337 if (okConsoleHandle(TCB)) { 1338 SetSP(); 1339 1340 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) { 1341 rc = TW_MOUSE; 1342 } else { 1343 rc = TCBOf(sp)->drv->td_twait(TCBOf(sp), 1344 TWAIT_MASK, 1345 delay, 1346 (int *) 0 1347 EVENTLIST_2nd(evl)); 1348 } 1349 } 1350 1351 return rc; 1352} 1353 1354static int 1355wcon_mvcur(TERMINAL_CONTROL_BLOCK * TCB, 1356 int yold GCC_UNUSED, int xold GCC_UNUSED, 1357 int y, int x) 1358{ 1359 int ret = ERR; 1360 if (okConsoleHandle(TCB)) { 1361 COORD loc; 1362 loc.X = (short) x; 1363 loc.Y = (short) (y + AdjustY()); 1364 SetConsoleCursorPosition(CON.hdl, loc); 1365 ret = OK; 1366 } 1367 return ret; 1368} 1369 1370static void 1371wcon_hwlabel(TERMINAL_CONTROL_BLOCK * TCB, 1372 int labnum GCC_UNUSED, 1373 char *text GCC_UNUSED) 1374{ 1375 SCREEN *sp; 1376 1377 AssertTCB(); 1378 SetSP(); 1379} 1380 1381static void 1382wcon_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB, 1383 int OnFlag GCC_UNUSED) 1384{ 1385 SCREEN *sp; 1386 1387 AssertTCB(); 1388 SetSP(); 1389} 1390 1391static chtype 1392wcon_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED) 1393{ 1394 chtype res = A_NORMAL; 1395 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR); 1396 return res; 1397} 1398 1399static void 1400wcon_setfilter(TERMINAL_CONTROL_BLOCK * TCB) 1401{ 1402 SCREEN *sp; 1403 1404 AssertTCB(); 1405 SetSP(); 1406} 1407 1408static void 1409wcon_initacs(TERMINAL_CONTROL_BLOCK * TCB, 1410 chtype *real_map GCC_UNUSED, 1411 chtype *fake_map GCC_UNUSED) 1412{ 1413#define DATA(a,b) { a, b } 1414 static struct { 1415 int acs_code; 1416 int use_code; 1417 } table[] = { 1418 DATA('a', 0xb1), /* ACS_CKBOARD */ 1419 DATA('f', 0xf8), /* ACS_DEGREE */ 1420 DATA('g', 0xf1), /* ACS_PLMINUS */ 1421 DATA('j', 0xd9), /* ACS_LRCORNER */ 1422 DATA('l', 0xda), /* ACS_ULCORNER */ 1423 DATA('k', 0xbf), /* ACS_URCORNER */ 1424 DATA('m', 0xc0), /* ACS_LLCORNER */ 1425 DATA('n', 0xc5), /* ACS_PLUS */ 1426 DATA('q', 0xc4), /* ACS_HLINE */ 1427 DATA('t', 0xc3), /* ACS_LTEE */ 1428 DATA('u', 0xb4), /* ACS_RTEE */ 1429 DATA('v', 0xc1), /* ACS_BTEE */ 1430 DATA('w', 0xc2), /* ACS_TTEE */ 1431 DATA('x', 0xb3), /* ACS_VLINE */ 1432 DATA('y', 0xf3), /* ACS_LEQUAL */ 1433 DATA('z', 0xf2), /* ACS_GEQUAL */ 1434 DATA('0', 0xdb), /* ACS_BLOCK */ 1435 DATA('{', 0xe3), /* ACS_PI */ 1436 DATA('}', 0x9c), /* ACS_STERLING */ 1437 DATA(',', 0xae), /* ACS_LARROW */ 1438 DATA('+', 0xaf), /* ACS_RARROW */ 1439 DATA('~', 0xf9), /* ACS_BULLET */ 1440 }; 1441#undef DATA 1442 unsigned n; 1443 1444 SCREEN *sp; 1445 if (okConsoleHandle(TCB)) { 1446 SetSP(); 1447 1448 for (n = 0; n < SIZEOF(table); ++n) { 1449 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET; 1450 if (sp != 0) 1451 sp->_screen_acs_map[table[n].acs_code] = TRUE; 1452 } 1453 } 1454} 1455 1456static ULONGLONG 1457tdiff(FILETIME fstart, FILETIME fend) 1458{ 1459 ULARGE_INTEGER ustart; 1460 ULARGE_INTEGER uend; 1461 ULONGLONG diff; 1462 1463 ustart.LowPart = fstart.dwLowDateTime; 1464 ustart.HighPart = fstart.dwHighDateTime; 1465 uend.LowPart = fend.dwLowDateTime; 1466 uend.HighPart = fend.dwHighDateTime; 1467 1468 diff = (uend.QuadPart - ustart.QuadPart) / 10000; 1469 return diff; 1470} 1471 1472static int 1473Adjust(int milliseconds, int diff) 1474{ 1475 if (milliseconds != INFINITY) { 1476 milliseconds -= diff; 1477 if (milliseconds < 0) 1478 milliseconds = 0; 1479 } 1480 return milliseconds; 1481} 1482 1483#define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \ 1484 FROM_LEFT_2ND_BUTTON_PRESSED | \ 1485 FROM_LEFT_3RD_BUTTON_PRESSED | \ 1486 FROM_LEFT_4TH_BUTTON_PRESSED | \ 1487 RIGHTMOST_BUTTON_PRESSED) 1488 1489static mmask_t 1490decode_mouse(SCREEN *sp, int mask) 1491{ 1492 mmask_t result = 0; 1493 1494 (void) sp; 1495 assert(sp && console_initialized); 1496 1497 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED) 1498 result |= BUTTON1_PRESSED; 1499 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED) 1500 result |= BUTTON2_PRESSED; 1501 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED) 1502 result |= BUTTON3_PRESSED; 1503 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED) 1504 result |= BUTTON4_PRESSED; 1505 1506 if (mask & RIGHTMOST_BUTTON_PRESSED) { 1507 switch (CON.numButtons) { 1508 case 1: 1509 result |= BUTTON1_PRESSED; 1510 break; 1511 case 2: 1512 result |= BUTTON2_PRESSED; 1513 break; 1514 case 3: 1515 result |= BUTTON3_PRESSED; 1516 break; 1517 case 4: 1518 result |= BUTTON4_PRESSED; 1519 break; 1520 } 1521 } 1522 1523 return result; 1524} 1525 1526static int 1527console_twait( 1528 SCREEN *sp, 1529 HANDLE fd, 1530 int mode, 1531 int milliseconds, 1532 int *timeleft 1533 EVENTLIST_2nd(_nc_eventlist * evl)) 1534{ 1535 INPUT_RECORD inp_rec; 1536 BOOL b; 1537 DWORD nRead = 0, rc = (DWORD) (-1); 1538 int code = 0; 1539 FILETIME fstart; 1540 FILETIME fend; 1541 int diff; 1542 bool isImmed = (milliseconds == 0); 1543 1544#ifdef NCURSES_WGETCH_EVENTS 1545 (void) evl; /* TODO: implement wgetch-events */ 1546#endif 1547 1548#define CONSUME() ReadConsoleInput(fd,&inp_rec,1,&nRead) 1549 1550 assert(sp); 1551 1552 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d", 1553 milliseconds, mode)); 1554 1555 if (milliseconds < 0) 1556 milliseconds = INFINITY; 1557 1558 memset(&inp_rec, 0, sizeof(inp_rec)); 1559 1560 while (true) { 1561 GetSystemTimeAsFileTime(&fstart); 1562 rc = WaitForSingleObject(fd, (DWORD) milliseconds); 1563 GetSystemTimeAsFileTime(&fend); 1564 diff = (int) tdiff(fstart, fend); 1565 milliseconds = Adjust(milliseconds, diff); 1566 1567 if (!isImmed && milliseconds <= 0) 1568 break; 1569 1570 if (rc == WAIT_OBJECT_0) { 1571 if (mode) { 1572 b = GetNumberOfConsoleInputEvents(fd, &nRead); 1573 if (b && nRead > 0) { 1574 b = PeekConsoleInput(fd, &inp_rec, 1, &nRead); 1575 if (b && nRead > 0) { 1576 switch (inp_rec.EventType) { 1577 case KEY_EVENT: 1578 if (mode & TW_INPUT) { 1579 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode; 1580 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar; 1581 1582 if (inp_rec.Event.KeyEvent.bKeyDown) { 1583 if (0 == ch) { 1584 int nKey = MapKey(vk); 1585 if (nKey < 0) { 1586 CONSUME(); 1587 continue; 1588 } 1589 } 1590 code = TW_INPUT; 1591 goto end; 1592 } else { 1593 CONSUME(); 1594 } 1595 } 1596 continue; 1597 case MOUSE_EVENT: 1598 if (decode_mouse(sp, 1599 (inp_rec.Event.MouseEvent.dwButtonState 1600 & BUTTON_MASK)) == 0) { 1601 CONSUME(); 1602 } else if (mode & TW_MOUSE) { 1603 code = TW_MOUSE; 1604 goto end; 1605 } 1606 continue; 1607 /* e.g., FOCUS_EVENT */ 1608 default: 1609 CONSUME(); 1610 selectActiveHandle(); 1611 continue; 1612 } 1613 } 1614 } 1615 } 1616 continue; 1617 } else { 1618 if (rc != WAIT_TIMEOUT) { 1619 code = -1; 1620 break; 1621 } else { 1622 code = 0; 1623 break; 1624 } 1625 } 1626 } 1627 end: 1628 1629 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec", 1630 code, errno, milliseconds)); 1631 1632 if (timeleft) 1633 *timeleft = milliseconds; 1634 1635 return code; 1636} 1637 1638static int 1639wcon_twait(TERMINAL_CONTROL_BLOCK * TCB, 1640 int mode, 1641 int milliseconds, 1642 int *timeleft 1643 EVENTLIST_2nd(_nc_eventlist * evl)) 1644{ 1645 SCREEN *sp; 1646 int code = 0; 1647 1648 if (okConsoleHandle(TCB)) { 1649 SetSP(); 1650 1651 code = console_twait(sp, 1652 CON.inp, 1653 mode, 1654 milliseconds, 1655 timeleft EVENTLIST_2nd(evl)); 1656 } 1657 return code; 1658} 1659 1660static bool 1661handle_mouse(SCREEN *sp, MOUSE_EVENT_RECORD mer) 1662{ 1663 MEVENT work; 1664 bool result = FALSE; 1665 1666 assert(sp); 1667 1668 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons; 1669 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK; 1670 1671 /* 1672 * We're only interested if the button is pressed or released. 1673 * FIXME: implement continuous event-tracking. 1674 */ 1675 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) { 1676 1677 memset(&work, 0, sizeof(work)); 1678 1679 if (sp->_drv_mouse_new_buttons) { 1680 1681 work.bstate |= decode_mouse(sp, sp->_drv_mouse_new_buttons); 1682 1683 } else { 1684 1685 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */ 1686 work.bstate |= (decode_mouse(sp, 1687 sp->_drv_mouse_old_buttons) 1688 >> 1); 1689 1690 result = TRUE; 1691 } 1692 1693 work.x = mer.dwMousePosition.X; 1694 work.y = mer.dwMousePosition.Y - AdjustY(); 1695 1696 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work; 1697 sp->_drv_mouse_tail += 1; 1698 } 1699 1700 return result; 1701} 1702 1703static int 1704wcon_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf) 1705{ 1706 SCREEN *sp; 1707 int n = -1; 1708 1709 T((T_CALLED("win32con::wcon_read(%p)"), TCB)); 1710 1711 assert(buf); 1712 if (okConsoleHandle(TCB)) { 1713 SetSP(); 1714 1715 n = _nc_mingw_console_read(sp, CON.inp, buf); 1716 } 1717 returnCode(n); 1718} 1719 1720static int 1721wcon_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms) 1722{ 1723 T((T_CALLED("win32con::wcon_nap(%p, %d)"), TCB, ms)); 1724 Sleep((DWORD) ms); 1725 returnCode(OK); 1726} 1727 1728static int 1729wcon_cursorSet(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int mode) 1730{ 1731 int res = -1; 1732 1733 T((T_CALLED("win32con:wcon_cursorSet(%d)"), mode)); 1734 if (okConsoleHandle(TCB)) { 1735 CONSOLE_CURSOR_INFO this_CI = CON.save_CI; 1736 switch (mode) { 1737 case 0: 1738 this_CI.bVisible = FALSE; 1739 break; 1740 case 1: 1741 break; 1742 case 2: 1743 this_CI.dwSize = 100; 1744 break; 1745 } 1746 SetConsoleCursorInfo(CON.hdl, &this_CI); 1747 } 1748 returnCode(res); 1749} 1750 1751static bool 1752wcon_kyExist(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int keycode) 1753{ 1754 WORD nKey; 1755 void *res; 1756 bool found = FALSE; 1757 LONG key = GenMap(0, (WORD) keycode); 1758 1759 T((T_CALLED("win32con::wcon_kyExist(%d)"), keycode)); 1760 res = bsearch(&key, 1761 CON.rmap, 1762 (size_t) (N_INI + FKEYS), 1763 sizeof(keylist[0]), 1764 rkeycompare); 1765 if (res) { 1766 key = *((LONG *) res); 1767 nKey = LOWORD(key); 1768 if (!(nKey & 0x8000)) 1769 found = TRUE; 1770 } 1771 returnCode(found); 1772} 1773 1774static int 1775wcon_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED) 1776{ 1777 SCREEN *sp; 1778 int code = ERR; 1779 1780 T((T_CALLED("win32con::wcon_kpad(%p, %d)"), TCB, flag)); 1781 1782 if (okConsoleHandle(TCB)) { 1783 SetSP(); 1784 1785 if (sp) { 1786 code = OK; 1787 } 1788 } 1789 returnCode(code); 1790} 1791 1792static int 1793wcon_keyok(TERMINAL_CONTROL_BLOCK * TCB, 1794 int keycode, 1795 int flag) 1796{ 1797 int code = ERR; 1798 SCREEN *sp; 1799 WORD nKey; 1800 WORD vKey; 1801 void *res; 1802 LONG key = GenMap(0, (WORD) keycode); 1803 1804 T((T_CALLED("win32con::wcon_keyok(%p, %d, %d)"), TCB, keycode, flag)); 1805 1806 if (okConsoleHandle(TCB)) { 1807 SetSP(); 1808 1809 if (sp) { 1810 res = bsearch(&key, 1811 CON.rmap, 1812 (size_t) (N_INI + FKEYS), 1813 sizeof(keylist[0]), 1814 rkeycompare); 1815 if (res) { 1816 key = *((LONG *) res); 1817 vKey = HIWORD(key); 1818 nKey = (LOWORD(key)) & 0x7fff; 1819 if (!flag) 1820 nKey |= 0x8000; 1821 *(LONG *) res = GenMap(vKey, nKey); 1822 } 1823 } 1824 } 1825 returnCode(code); 1826} 1827 1828NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = { 1829 FALSE, 1830 wcon_name, /* Name */ 1831 wcon_CanHandle, /* CanHandle */ 1832 wcon_init, /* init */ 1833 wcon_release, /* release */ 1834 wcon_size, /* size */ 1835 wcon_sgmode, /* sgmode */ 1836 wcon_conattr, /* conattr */ 1837 wcon_mvcur, /* hwcur */ 1838 wcon_mode, /* mode */ 1839 wcon_rescol, /* rescol */ 1840 wcon_rescolors, /* rescolors */ 1841 wcon_setcolor, /* color */ 1842 wcon_dobeepflash, /* DoBeepFlash */ 1843 wcon_initpair, /* initpair */ 1844 wcon_initcolor, /* initcolor */ 1845 wcon_do_color, /* docolor */ 1846 wcon_initmouse, /* initmouse */ 1847 wcon_testmouse, /* testmouse */ 1848 wcon_setfilter, /* setfilter */ 1849 wcon_hwlabel, /* hwlabel */ 1850 wcon_hwlabelOnOff, /* hwlabelOnOff */ 1851 wcon_doupdate, /* update */ 1852 wcon_defaultcolors, /* defaultcolors */ 1853 wcon_print, /* print */ 1854 wcon_size, /* getsize */ 1855 wcon_setsize, /* setsize */ 1856 wcon_initacs, /* initacs */ 1857 wcon_screen_init, /* scinit */ 1858 wcon_wrap, /* scexit */ 1859 wcon_twait, /* twait */ 1860 wcon_read, /* read */ 1861 wcon_nap, /* nap */ 1862 wcon_kpad, /* kpad */ 1863 wcon_keyok, /* kyOk */ 1864 wcon_kyExist, /* kyExist */ 1865 wcon_cursorSet /* cursorSet */ 1866}; 1867 1868/* --------------------------------------------------------- */ 1869 1870static HANDLE 1871get_handle(int fd) 1872{ 1873 intptr_t value = _get_osfhandle(fd); 1874 return (HANDLE) value; 1875} 1876 1877#if WINVER >= 0x0600 1878/* This function tests, whether or not the ncurses application 1879 is running as a descendant of MSYS2/cygwin mintty terminal 1880 application. mintty doesn't use Windows Console for its screen 1881 I/O, so the native Windows _isatty doesn't recognize it as 1882 character device. But we can discover we are at the end of an 1883 Pipe and can query to server side of the pipe, looking whether 1884 or not this is mintty. 1885 */ 1886static int 1887_ismintty(int fd, LPHANDLE pMinTTY) 1888{ 1889 HANDLE handle = get_handle(fd); 1890 DWORD dw; 1891 int code = 0; 1892 1893 T((T_CALLED("win32con::_ismintty(%d, %p)"), fd, pMinTTY)); 1894 1895 if (handle != INVALID_HANDLE_VALUE) { 1896 dw = GetFileType(handle); 1897 if (dw == FILE_TYPE_PIPE) { 1898 if (GetNamedPipeInfo(handle, 0, 0, 0, 0)) { 1899 ULONG pPid; 1900 /* Requires NT6 */ 1901 if (GetNamedPipeServerProcessId(handle, &pPid)) { 1902 TCHAR buf[MAX_PATH]; 1903 DWORD len = 0; 1904 /* These security attributes may allow us to 1905 create a remote thread in mintty to manipulate 1906 the terminal state remotely */ 1907 HANDLE pHandle = OpenProcess( 1908 PROCESS_CREATE_THREAD 1909 | PROCESS_QUERY_INFORMATION 1910 | PROCESS_VM_OPERATION 1911 | PROCESS_VM_WRITE 1912 | PROCESS_VM_READ, 1913 FALSE, 1914 pPid); 1915 if (pMinTTY) 1916 *pMinTTY = INVALID_HANDLE_VALUE; 1917 if (pHandle != INVALID_HANDLE_VALUE) { 1918 if ((len = GetProcessImageFileName( 1919 pHandle, 1920 buf, 1921 (DWORD) 1922 array_length(buf)))) { 1923 TCHAR *pos = _tcsrchr(buf, _T('\\')); 1924 if (pos) { 1925 pos++; 1926 if (_tcsnicmp(pos, _TEXT("mintty.exe"), 10) 1927 == 0) { 1928 if (pMinTTY) 1929 *pMinTTY = pHandle; 1930 code = 1; 1931 } 1932 } 1933 } 1934 } 1935 } 1936 } 1937 } 1938 } 1939 returnCode(code); 1940} 1941#endif 1942 1943/* Borrowed from ansicon project. 1944 Check whether or not an I/O handle is associated with 1945 a Windows console. 1946*/ 1947static BOOL 1948IsConsoleHandle(HANDLE hdl) 1949{ 1950 DWORD dwFlag = 0; 1951 BOOL result; 1952 1953 if (!GetConsoleMode(hdl, &dwFlag)) { 1954 result = (int) WriteConsoleA(hdl, NULL, 0, &dwFlag, NULL); 1955 } else { 1956 result = (int) (dwFlag & ENABLE_PROCESSED_OUTPUT); 1957 } 1958 return result; 1959} 1960 1961/* Our replacement for the systems _isatty to include also 1962 a test for mintty. This is called from the NC_ISATTY macro 1963 defined in curses.priv.h 1964 */ 1965int 1966_nc_mingw_isatty(int fd) 1967{ 1968 int result = 0; 1969 1970 if (SysISATTY(fd)) { 1971 result = 1; 1972 } else { 1973#if WINVER >= 0x0600 1974 result = _ismintty(fd, NULL); 1975#endif 1976 } 1977 return result; 1978} 1979 1980/* This is used when running in terminfo mode to discover, 1981 whether or not the "terminal" is actually a Windows 1982 Console. It is the responsibility of the console to deal 1983 with the terminal escape sequences that are sent by 1984 terminfo. 1985 */ 1986int 1987_nc_mingw_isconsole(int fd) 1988{ 1989 HANDLE hdl = get_handle(fd); 1990 int code = 0; 1991 1992 T((T_CALLED("win32con::_nc_mingw_isconsole(%d)"), fd)); 1993 1994 code = (int) IsConsoleHandle(hdl); 1995 1996 returnCode(code); 1997} 1998 1999#define TC_PROLOGUE(fd) \ 2000 SCREEN *sp; \ 2001 TERMINAL *term = 0; \ 2002 int code = ERR; \ 2003 if (_nc_screen_chain == 0) \ 2004 return 0; \ 2005 for (each_screen(sp)) { \ 2006 if (sp->_term && (sp->_term->Filedes == fd)) { \ 2007 term = sp->_term; \ 2008 break; \ 2009 } \ 2010 } \ 2011 assert(term != 0) 2012 2013int 2014_nc_mingw_tcsetattr( 2015 int fd, 2016 int optional_action GCC_UNUSED, 2017 const struct termios *arg) 2018{ 2019 TC_PROLOGUE(fd); 2020 2021 if (_nc_mingw_isconsole(fd)) { 2022 DWORD dwFlag = 0; 2023 HANDLE ofd = get_handle(fd); 2024 if (ofd != INVALID_HANDLE_VALUE) { 2025 if (arg) { 2026 if (arg->c_lflag & ICANON) 2027 dwFlag |= ENABLE_LINE_INPUT; 2028 else 2029 dwFlag = dwFlag & (DWORD) (~ENABLE_LINE_INPUT); 2030 2031 if (arg->c_lflag & ECHO) 2032 dwFlag = dwFlag | ENABLE_ECHO_INPUT; 2033 else 2034 dwFlag = dwFlag & (DWORD) (~ENABLE_ECHO_INPUT); 2035 2036 if (arg->c_iflag & BRKINT) 2037 dwFlag |= ENABLE_PROCESSED_INPUT; 2038 else 2039 dwFlag = dwFlag & (DWORD) (~ENABLE_PROCESSED_INPUT); 2040 } 2041 dwFlag |= ENABLE_MOUSE_INPUT; 2042 SetConsoleMode(ofd, dwFlag); 2043 code = OK; 2044 } 2045 } 2046 if (arg) 2047 term->Nttyb = *arg; 2048 2049 return code; 2050} 2051 2052int 2053_nc_mingw_tcgetattr(int fd, struct termios *arg) 2054{ 2055 TC_PROLOGUE(fd); 2056 2057 if (_nc_mingw_isconsole(fd)) { 2058 if (arg) 2059 *arg = term->Nttyb; 2060 } 2061 return code; 2062} 2063 2064int 2065_nc_mingw_tcflush(int fd, int queue) 2066{ 2067 TC_PROLOGUE(fd); 2068 (void) term; 2069 2070 if (_nc_mingw_isconsole(fd)) { 2071 if (queue == TCIFLUSH) { 2072 BOOL b = FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE)); 2073 if (!b) 2074 return (int) GetLastError(); 2075 } 2076 } 2077 return code; 2078} 2079 2080int 2081_nc_mingw_testmouse( 2082 SCREEN *sp, 2083 HANDLE fd, 2084 int delay 2085 EVENTLIST_2nd(_nc_eventlist * evl)) 2086{ 2087 int rc = 0; 2088 2089 assert(sp); 2090 2091 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) { 2092 rc = TW_MOUSE; 2093 } else { 2094 rc = console_twait(sp, 2095 fd, 2096 TWAIT_MASK, 2097 delay, 2098 (int *) 0 2099 EVENTLIST_2nd(evl)); 2100 } 2101 return rc; 2102} 2103 2104int 2105_nc_mingw_console_read( 2106 SCREEN *sp, 2107 HANDLE fd, 2108 int *buf) 2109{ 2110 int rc = -1; 2111 INPUT_RECORD inp_rec; 2112 BOOL b; 2113 DWORD nRead; 2114 WORD vk; 2115 2116 assert(sp); 2117 assert(buf); 2118 2119 memset(&inp_rec, 0, sizeof(inp_rec)); 2120 2121 T((T_CALLED("_nc_mingw_console_read(%p)"), sp)); 2122 2123 while ((b = ReadConsoleInput(fd, &inp_rec, 1, &nRead))) { 2124 if (b && nRead > 0) { 2125 if (rc < 0) 2126 rc = 0; 2127 rc = rc + (int) nRead; 2128 if (inp_rec.EventType == KEY_EVENT) { 2129 if (!inp_rec.Event.KeyEvent.bKeyDown) 2130 continue; 2131 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar; 2132 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode; 2133 /* 2134 * There are 24 virtual function-keys (defined in winuser.h), 2135 * and typically 12 function-keys on a keyboard. Use the 2136 * shift-modifier to provide the remaining keys. 2137 */ 2138 if (vk >= VK_F1 && vk <= VK_F12) { 2139 if (inp_rec.Event.KeyEvent.dwControlKeyState & SHIFT_PRESSED) { 2140 vk = (WORD) (vk + 12); 2141 } 2142 } 2143 if (*buf == 0) { 2144 int key = MapKey(vk); 2145 if (key < 0) 2146 continue; 2147 if (sp->_keypad_on) { 2148 *buf = key; 2149 } else { 2150 ungetch('\0'); 2151 *buf = AnsiKey(vk); 2152 } 2153 } else if (vk == VK_BACK) { 2154 if (!(inp_rec.Event.KeyEvent.dwControlKeyState 2155 & (SHIFT_PRESSED | CONTROL_PRESSED))) { 2156 *buf = KEY_BACKSPACE; 2157 } 2158 } 2159 break; 2160 } else if (inp_rec.EventType == MOUSE_EVENT) { 2161 if (handle_mouse(sp, 2162 inp_rec.Event.MouseEvent)) { 2163 *buf = KEY_MOUSE; 2164 break; 2165 } 2166 } 2167 continue; 2168 } 2169 } 2170 returnCode(rc); 2171} 2172 2173static bool 2174InitConsole(void) 2175{ 2176 /* initialize once, or not at all */ 2177 if (!console_initialized) { 2178 int i; 2179 DWORD num_buttons; 2180 WORD a; 2181 BOOL buffered = TRUE; 2182 BOOL b; 2183 2184 START_TRACE(); 2185 2186 for (i = 0; i < (N_INI + FKEYS); i++) { 2187 if (i < N_INI) { 2188 CON.rmap[i] = CON.map[i] = 2189 (DWORD) keylist[i]; 2190 CON.ansi_map[i] = (DWORD) ansi_keys[i]; 2191 } else { 2192 CON.rmap[i] = CON.map[i] = 2193 (DWORD) GenMap((VK_F1 + (i - N_INI)), 2194 (KEY_F(1) + (i - N_INI))); 2195 CON.ansi_map[i] = 2196 (DWORD) GenMap((VK_F1 + (i - N_INI)), 2197 (';' + (i - N_INI))); 2198 } 2199 } 2200 qsort(CON.ansi_map, 2201 (size_t) (MAPSIZE), 2202 sizeof(keylist[0]), 2203 keycompare); 2204 qsort(CON.map, 2205 (size_t) (MAPSIZE), 2206 sizeof(keylist[0]), 2207 keycompare); 2208 qsort(CON.rmap, 2209 (size_t) (MAPSIZE), 2210 sizeof(keylist[0]), 2211 rkeycompare); 2212 2213 if (GetNumberOfConsoleMouseButtons(&num_buttons)) { 2214 CON.numButtons = (int) num_buttons; 2215 } else { 2216 CON.numButtons = 1; 2217 } 2218 2219 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK); 2220 for (i = 0; i < NUMPAIRS; i++) 2221 CON.pairs[i] = a; 2222 2223 b = AllocConsole(); 2224 2225 if (!b) 2226 b = AttachConsole(ATTACH_PARENT_PROCESS); 2227 2228 CON.inp = GetDirectHandle("CONIN$", FILE_SHARE_READ); 2229 CON.out = GetDirectHandle("CONOUT$", FILE_SHARE_WRITE); 2230 2231 if (getenv("NCGDB") || getenv("NCURSES_CONSOLE2")) { 2232 T(("... will not buffer console")); 2233 buffered = FALSE; 2234 CON.hdl = CON.out; 2235 } else { 2236 T(("... creating console buffer")); 2237 CON.hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 2238 FILE_SHARE_READ | FILE_SHARE_WRITE, 2239 NULL, 2240 CONSOLE_TEXTMODE_BUFFER, 2241 NULL); 2242 } 2243 2244 if (CON.hdl != INVALID_HANDLE_VALUE) { 2245 CON.buffered = buffered; 2246 get_SBI(); 2247 CON.save_SBI = CON.SBI; 2248 if (!buffered) { 2249 save_original_screen(); 2250 set_scrollback(FALSE, &CON.SBI); 2251 } 2252 GetConsoleCursorInfo(CON.hdl, &CON.save_CI); 2253 T(("... initial cursor is %svisible, %d%%", 2254 (CON.save_CI.bVisible ? "" : "not-"), 2255 (int) CON.save_CI.dwSize)); 2256 } 2257 2258 console_initialized = TRUE; 2259 } 2260 return (CON.hdl != INVALID_HANDLE_VALUE); 2261} 2262 2263static bool 2264okConsoleHandle(TERMINAL_CONTROL_BLOCK * TCB) 2265{ 2266 return ((TCB != 0) && 2267 (TCB->magic == WINMAGIC) && 2268 InitConsole()); 2269} 2270 2271/* 2272 * While a constructor would ensure that this module is initialized, that will 2273 * interfere with applications that may combine this with GUI interfaces. 2274 */ 2275#if 0 2276static 2277__attribute__((constructor)) 2278 void _enter_console(void) 2279{ 2280 (void) InitConsole(); 2281} 2282#endif 2283