1 /**************************************************************************** 2 * Copyright (c) 1998-2013,2014 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29 /**************************************************************************** 30 * Author: Juergen Pfeifer * 31 ****************************************************************************/ 32 33 /* 34 * TODO - GetMousePos(POINT * result) from ntconio.c 35 * TODO - implement nodelay 36 * TODO - when $NCGDB is set, implement non-buffered output, like PDCurses 37 */ 38 39 #include <curses.priv.h> 40 #define CUR my_term.type. 41 42 MODULE_ID("$Id: win_driver.c,v 1.24 2014/02/23 01:23:29 tom Exp $") 43 44 #define WINMAGIC NCDRV_MAGIC(NCDRV_WINCONSOLE) 45 46 #define EXP_OPTIMIZE 0 47 48 #define okConsoleHandle(TCB) (TCB != 0 && !InvalidConsoleHandle(TCB->hdl)) 49 50 #define AssertTCB() assert(TCB != 0 && (TCB->magic == WINMAGIC)) 51 #define SetSP() assert(TCB->csp != 0); sp = TCB->csp; (void) sp 52 53 #define GenMap(vKey,key) MAKELONG(key, vKey) 54 55 #define AdjustY(p) ((p)->buffered ? 0 : (int) (p)->SBI.srWindow.Top) 56 57 static const LONG keylist[] = 58 { 59 GenMap(VK_PRIOR, KEY_PPAGE), 60 GenMap(VK_NEXT, KEY_NPAGE), 61 GenMap(VK_END, KEY_END), 62 GenMap(VK_HOME, KEY_HOME), 63 GenMap(VK_LEFT, KEY_LEFT), 64 GenMap(VK_UP, KEY_UP), 65 GenMap(VK_RIGHT, KEY_RIGHT), 66 GenMap(VK_DOWN, KEY_DOWN), 67 GenMap(VK_DELETE, KEY_DC), 68 GenMap(VK_INSERT, KEY_IC) 69 }; 70 #define N_INI ((int)(sizeof(keylist)/sizeof(keylist[0]))) 71 #define FKEYS 24 72 #define MAPSIZE (FKEYS + N_INI) 73 #define NUMPAIRS 64 74 75 typedef struct props { 76 CONSOLE_SCREEN_BUFFER_INFO SBI; 77 bool progMode; 78 TERM_HANDLE lastOut; 79 DWORD map[MAPSIZE]; 80 DWORD rmap[MAPSIZE]; 81 WORD pairs[NUMPAIRS]; 82 bool buffered; 83 COORD origin; 84 CHAR_INFO *save_screen; 85 } Properties; 86 87 #define PropOf(TCB) ((Properties*)TCB->prop) 88 89 int 90 _nc_mingw_ioctl(int fd GCC_UNUSED, 91 long int request GCC_UNUSED, 92 struct termios *arg GCC_UNUSED) 93 { 94 return 0; 95 endwin(); 96 fprintf(stderr, "TERMINFO currently not supported on Windows.\n"); 97 exit(1); 98 } 99 100 static WORD 101 MapColor(bool fore, int color) 102 { 103 static const int _cmap[] = 104 {0, 4, 2, 6, 1, 5, 3, 7}; 105 int a; 106 if (color < 0 || color > 7) 107 a = fore ? 7 : 0; 108 else 109 a = _cmap[color]; 110 if (!fore) 111 a = a << 4; 112 return (WORD) a; 113 } 114 115 static WORD 116 MapAttr(TERMINAL_CONTROL_BLOCK * TCB, WORD res, attr_t ch) 117 { 118 if (ch & A_COLOR) { 119 int p; 120 SCREEN *sp; 121 122 AssertTCB(); 123 SetSP(); 124 p = PairNumber(ch); 125 if (p > 0 && p < NUMPAIRS && TCB != 0 && sp != 0) { 126 WORD a; 127 a = PropOf(TCB)->pairs[p]; 128 res = (res & 0xff00) | a; 129 } 130 } 131 132 if (ch & A_REVERSE) 133 res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4))); 134 135 if (ch & A_STANDOUT) 136 res = ((res & 0xff00) | (((res & 0x07) << 4) | ((res & 0x70) >> 4)) 137 | BACKGROUND_INTENSITY); 138 139 if (ch & A_BOLD) 140 res |= FOREGROUND_INTENSITY; 141 142 if (ch & A_DIM) 143 res |= BACKGROUND_INTENSITY; 144 145 return res; 146 } 147 148 #if USE_WIDEC_SUPPORT 149 /* 150 * TODO: support surrogate pairs 151 * TODO: support combining characters 152 * TODO: support acsc 153 * TODO: check wcwidth of base character, fill if needed for double-width 154 * TODO: _nc_wacs should be part of sp. 155 */ 156 static BOOL 157 con_write16(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, cchar_t *str, int limit) 158 { 159 int actual = 0; 160 CHAR_INFO ci[limit]; 161 COORD loc, siz; 162 SMALL_RECT rec; 163 int i; 164 cchar_t ch; 165 SCREEN *sp; 166 Properties *p = PropOf(TCB); 167 168 AssertTCB(); 169 170 SetSP(); 171 172 for (i = actual = 0; i < limit; i++) { 173 ch = str[i]; 174 if (isWidecExt(ch)) 175 continue; 176 ci[actual].Char.UnicodeChar = CharOf(ch); 177 ci[actual].Attributes = MapAttr(TCB, 178 PropOf(TCB)->SBI.wAttributes, 179 AttrOf(ch)); 180 if (AttrOf(ch) & A_ALTCHARSET) { 181 if (_nc_wacs) { 182 int which = CharOf(ch); 183 if (which > 0 184 && which < ACS_LEN 185 && CharOf(_nc_wacs[which]) != 0) { 186 ci[actual].Char.UnicodeChar = CharOf(_nc_wacs[which]); 187 } else { 188 ci[actual].Char.UnicodeChar = ' '; 189 } 190 } 191 } 192 ++actual; 193 } 194 195 loc.X = (short) 0; 196 loc.Y = (short) 0; 197 siz.X = (short) actual; 198 siz.Y = 1; 199 200 rec.Left = (short) x; 201 rec.Top = (SHORT) (y + AdjustY(p)); 202 rec.Right = (short) (x + limit - 1); 203 rec.Bottom = rec.Top; 204 205 return WriteConsoleOutputW(TCB->hdl, ci, siz, loc, &rec); 206 } 207 #define con_write(tcb, y, x, str, n) con_write16(tcb, y, x, str, n) 208 #else 209 static BOOL 210 con_write8(TERMINAL_CONTROL_BLOCK * TCB, int y, int x, chtype *str, int n) 211 { 212 CHAR_INFO ci[n]; 213 COORD loc, siz; 214 SMALL_RECT rec; 215 int i; 216 chtype ch; 217 SCREEN *sp; 218 219 AssertTCB(); 220 221 SetSP(); 222 223 for (i = 0; i < n; i++) { 224 ch = str[i]; 225 ci[i].Char.AsciiChar = ChCharOf(ch); 226 ci[i].Attributes = MapAttr(TCB, 227 PropOf(TCB)->SBI.wAttributes, 228 ChAttrOf(ch)); 229 if (ChAttrOf(ch) & A_ALTCHARSET) { 230 if (sp->_acs_map) 231 ci[i].Char.AsciiChar = 232 ChCharOf(NCURSES_SP_NAME(_nc_acs_char) (sp, ChCharOf(ch))); 233 } 234 } 235 236 loc.X = (short) 0; 237 loc.Y = (short) 0; 238 siz.X = (short) n; 239 siz.Y = 1; 240 241 rec.Left = (short) x; 242 rec.Top = (short) y; 243 rec.Right = (short) (x + n - 1); 244 rec.Bottom = rec.Top; 245 246 return WriteConsoleOutput(TCB->hdl, ci, siz, loc, &rec); 247 } 248 #define con_write(tcb, y, x, str, n) con_write8(tcb, y, x, str, n) 249 #endif 250 251 #if EXP_OPTIMIZE 252 /* 253 * Comparing new/current screens, determine the last column-index for a change 254 * beginning on the given row,col position. Unlike a serial terminal, there is 255 * no cost for "moving" the "cursor" on the line as we update it. 256 */ 257 static int 258 find_end_of_change(SCREEN *sp, int row, int col) 259 { 260 int result = col; 261 struct ldat *curdat = CurScreen(sp)->_line + row; 262 struct ldat *newdat = NewScreen(sp)->_line + row; 263 264 while (col <= newdat->lastchar) { 265 #if USE_WIDEC_SUPPORT 266 if (isWidecExt(curdat->text[col]) || isWidecExt(newdat->text[col])) { 267 result = col; 268 } else if (memcmp(&curdat->text[col], 269 &newdat->text[col], 270 sizeof(curdat->text[0]))) { 271 result = col; 272 } else { 273 break; 274 } 275 #else 276 if (curdat->text[col] != newdat->text[col]) { 277 result = col; 278 } else { 279 break; 280 } 281 #endif 282 ++col; 283 } 284 return result; 285 } 286 287 /* 288 * Given a row,col position at the end of a change-chunk, look for the 289 * beginning of the next change-chunk. 290 */ 291 static int 292 find_next_change(SCREEN *sp, int row, int col) 293 { 294 struct ldat *curdat = CurScreen(sp)->_line + row; 295 struct ldat *newdat = NewScreen(sp)->_line + row; 296 int result = newdat->lastchar + 1; 297 298 while (++col <= newdat->lastchar) { 299 #if USE_WIDEC_SUPPORT 300 if (isWidecExt(curdat->text[col]) != isWidecExt(newdat->text[col])) { 301 result = col; 302 break; 303 } else if (memcmp(&curdat->text[col], 304 &newdat->text[col], 305 sizeof(curdat->text[0]))) { 306 result = col; 307 break; 308 } 309 #else 310 if (curdat->text[col] != newdat->text[col]) { 311 result = col; 312 break; 313 } 314 #endif 315 } 316 return result; 317 } 318 319 #define EndChange(first) \ 320 find_end_of_change(sp, y, first) 321 #define NextChange(last) \ 322 find_next_change(sp, y, last) 323 324 #endif /* EXP_OPTIMIZE */ 325 326 #define MARK_NOCHANGE(win,row) \ 327 win->_line[row].firstchar = _NOCHANGE; \ 328 win->_line[row].lastchar = _NOCHANGE 329 330 static void 331 selectActiveHandle(TERMINAL_CONTROL_BLOCK * TCB) 332 { 333 if (PropOf(TCB)->lastOut != TCB->hdl) { 334 PropOf(TCB)->lastOut = TCB->hdl; 335 SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut); 336 } 337 } 338 339 static int 340 drv_doupdate(TERMINAL_CONTROL_BLOCK * TCB) 341 { 342 int result = ERR; 343 int y, nonempty, n, x0, x1, Width, Height; 344 SCREEN *sp; 345 346 AssertTCB(); 347 SetSP(); 348 349 T((T_CALLED("win32con::drv_doupdate(%p)"), TCB)); 350 if (okConsoleHandle(TCB)) { 351 352 Width = screen_columns(sp); 353 Height = screen_lines(sp); 354 nonempty = min(Height, NewScreen(sp)->_maxy + 1); 355 356 if ((CurScreen(sp)->_clear || NewScreen(sp)->_clear)) { 357 int x; 358 #if USE_WIDEC_SUPPORT 359 cchar_t empty[Width]; 360 wchar_t blank[2] = 361 { 362 L' ', L'\0' 363 }; 364 365 for (x = 0; x < Width; x++) 366 setcchar(&empty[x], blank, 0, 0, 0); 367 #else 368 chtype empty[Width]; 369 370 for (x = 0; x < Width; x++) 371 empty[x] = ' '; 372 #endif 373 374 for (y = 0; y < nonempty; y++) { 375 con_write(TCB, y, 0, empty, Width); 376 memcpy(empty, 377 CurScreen(sp)->_line[y].text, 378 (size_t) Width * sizeof(empty[0])); 379 } 380 CurScreen(sp)->_clear = FALSE; 381 NewScreen(sp)->_clear = FALSE; 382 touchwin(NewScreen(sp)); 383 } 384 385 for (y = 0; y < nonempty; y++) { 386 x0 = NewScreen(sp)->_line[y].firstchar; 387 if (x0 != _NOCHANGE) { 388 #if EXP_OPTIMIZE 389 int x2; 390 int limit = NewScreen(sp)->_line[y].lastchar; 391 while ((x1 = EndChange(x0)) <= limit) { 392 while ((x2 = NextChange(x1)) <= limit && x2 <= (x1 + 2)) { 393 x1 = x2; 394 } 395 n = x1 - x0 + 1; 396 memcpy(&CurScreen(sp)->_line[y].text[x0], 397 &NewScreen(sp)->_line[y].text[x0], 398 n * sizeof(CurScreen(sp)->_line[y].text[x0])); 399 con_write(TCB, 400 y, 401 x0, 402 &CurScreen(sp)->_line[y].text[x0], n); 403 x0 = NextChange(x1); 404 } 405 406 /* mark line changed successfully */ 407 if (y <= NewScreen(sp)->_maxy) { 408 MARK_NOCHANGE(NewScreen(sp), y); 409 } 410 if (y <= CurScreen(sp)->_maxy) { 411 MARK_NOCHANGE(CurScreen(sp), y); 412 } 413 #else 414 x1 = NewScreen(sp)->_line[y].lastchar; 415 n = x1 - x0 + 1; 416 if (n > 0) { 417 memcpy(&CurScreen(sp)->_line[y].text[x0], 418 &NewScreen(sp)->_line[y].text[x0], 419 (size_t) n * sizeof(CurScreen(sp)->_line[y].text[x0])); 420 con_write(TCB, 421 y, 422 x0, 423 &CurScreen(sp)->_line[y].text[x0], n); 424 425 /* mark line changed successfully */ 426 if (y <= NewScreen(sp)->_maxy) { 427 MARK_NOCHANGE(NewScreen(sp), y); 428 } 429 if (y <= CurScreen(sp)->_maxy) { 430 MARK_NOCHANGE(CurScreen(sp), y); 431 } 432 } 433 #endif 434 } 435 } 436 437 /* put everything back in sync */ 438 for (y = nonempty; y <= NewScreen(sp)->_maxy; y++) { 439 MARK_NOCHANGE(NewScreen(sp), y); 440 } 441 for (y = nonempty; y <= CurScreen(sp)->_maxy; y++) { 442 MARK_NOCHANGE(CurScreen(sp), y); 443 } 444 445 if (!NewScreen(sp)->_leaveok) { 446 CurScreen(sp)->_curx = NewScreen(sp)->_curx; 447 CurScreen(sp)->_cury = NewScreen(sp)->_cury; 448 449 TCB->drv->hwcur(TCB, 450 0, 0, 451 CurScreen(sp)->_cury, CurScreen(sp)->_curx); 452 } 453 selectActiveHandle(TCB); 454 result = OK; 455 } 456 returnCode(result); 457 } 458 459 static bool 460 drv_CanHandle(TERMINAL_CONTROL_BLOCK * TCB, 461 const char *tname, 462 int *errret GCC_UNUSED) 463 { 464 bool code = FALSE; 465 466 T((T_CALLED("win32con::drv_CanHandle(%p)"), TCB)); 467 468 assert(TCB != 0); 469 assert(tname != 0); 470 471 TCB->magic = WINMAGIC; 472 if (*tname == 0 || *tname == 0 || *tname == '#') { 473 code = TRUE; 474 } else { 475 TERMINAL my_term; 476 int status; 477 478 code = FALSE; 479 #if (NCURSES_USE_DATABASE || NCURSES_USE_TERMCAP) 480 status = _nc_setup_tinfo(tname, &my_term.type); 481 #else 482 status = TGETENT_NO; 483 #endif 484 if (status != TGETENT_YES) { 485 const TERMTYPE *fallback = _nc_fallback(tname); 486 487 if (fallback) { 488 my_term.type = *fallback; 489 status = TGETENT_YES; 490 } else if (!strcmp(tname, "unknown")) { 491 code = TRUE; 492 } 493 } 494 if (status == TGETENT_YES) { 495 if (generic_type || hard_copy) 496 code = TRUE; 497 } 498 } 499 500 if (code) { 501 if ((TCB->term.type.Booleans) == 0) { 502 _nc_init_termtype(&(TCB->term.type)); 503 } 504 } 505 506 returnBool(code); 507 } 508 509 static int 510 drv_dobeepflash(TERMINAL_CONTROL_BLOCK * TCB, 511 int beepFlag GCC_UNUSED) 512 { 513 SCREEN *sp; 514 int res = ERR; 515 516 AssertTCB(); 517 SetSP(); 518 519 return res; 520 } 521 522 static int 523 drv_print(TERMINAL_CONTROL_BLOCK * TCB, 524 char *data GCC_UNUSED, 525 int len GCC_UNUSED) 526 { 527 SCREEN *sp; 528 529 AssertTCB(); 530 SetSP(); 531 532 return ERR; 533 } 534 535 static int 536 drv_defaultcolors(TERMINAL_CONTROL_BLOCK * TCB, 537 int fg GCC_UNUSED, 538 int bg GCC_UNUSED) 539 { 540 SCREEN *sp; 541 int code = ERR; 542 543 AssertTCB(); 544 SetSP(); 545 546 return (code); 547 } 548 549 static bool 550 get_SBI(TERMINAL_CONTROL_BLOCK * TCB) 551 { 552 bool rc = FALSE; 553 Properties *p = PropOf(TCB); 554 if (GetConsoleScreenBufferInfo(TCB->hdl, &(p->SBI))) { 555 T(("GetConsoleScreenBufferInfo")); 556 T(("... buffer(X:%d Y:%d)", 557 p->SBI.dwSize.X, 558 p->SBI.dwSize.Y)); 559 T(("... window(X:%d Y:%d)", 560 p->SBI.dwMaximumWindowSize.X, 561 p->SBI.dwMaximumWindowSize.Y)); 562 T(("... cursor(X:%d Y:%d)", 563 p->SBI.dwCursorPosition.X, 564 p->SBI.dwCursorPosition.Y)); 565 T(("... display(Top:%d Bottom:%d Left:%d Right:%d)", 566 p->SBI.srWindow.Top, 567 p->SBI.srWindow.Bottom, 568 p->SBI.srWindow.Left, 569 p->SBI.srWindow.Right)); 570 if (p->buffered) { 571 p->origin.X = 0; 572 p->origin.Y = 0; 573 } else { 574 p->origin.X = p->SBI.srWindow.Left; 575 p->origin.Y = p->SBI.srWindow.Top; 576 } 577 rc = TRUE; 578 } else { 579 T(("GetConsoleScreenBufferInfo ERR")); 580 } 581 return rc; 582 } 583 584 static void 585 drv_setcolor(TERMINAL_CONTROL_BLOCK * TCB, 586 int fore, 587 int color, 588 int (*outc) (SCREEN *, int) GCC_UNUSED) 589 { 590 AssertTCB(); 591 592 if (okConsoleHandle(TCB) && 593 PropOf(TCB) != 0) { 594 WORD a = MapColor(fore, color); 595 a |= (WORD) ((PropOf(TCB)->SBI.wAttributes) & (fore ? 0xfff8 : 0xff8f)); 596 SetConsoleTextAttribute(TCB->hdl, a); 597 get_SBI(TCB); 598 } 599 } 600 601 static bool 602 drv_rescol(TERMINAL_CONTROL_BLOCK * TCB) 603 { 604 bool res = FALSE; 605 606 AssertTCB(); 607 if (okConsoleHandle(TCB)) { 608 WORD a = FOREGROUND_BLUE | FOREGROUND_RED | FOREGROUND_GREEN; 609 SetConsoleTextAttribute(TCB->hdl, a); 610 get_SBI(TCB); 611 res = TRUE; 612 } 613 return res; 614 } 615 616 static bool 617 drv_rescolors(TERMINAL_CONTROL_BLOCK * TCB) 618 { 619 int result = FALSE; 620 SCREEN *sp; 621 622 AssertTCB(); 623 SetSP(); 624 625 return result; 626 } 627 628 static int 629 drv_size(TERMINAL_CONTROL_BLOCK * TCB, int *Lines, int *Cols) 630 { 631 int result = ERR; 632 633 AssertTCB(); 634 635 T((T_CALLED("win32con::drv_size(%p)"), TCB)); 636 637 if (okConsoleHandle(TCB) && 638 PropOf(TCB) != 0 && 639 Lines != NULL && 640 Cols != NULL) { 641 if (PropOf(TCB)->buffered) { 642 *Lines = (int) (PropOf(TCB)->SBI.dwSize.Y); 643 *Cols = (int) (PropOf(TCB)->SBI.dwSize.X); 644 } else { 645 *Lines = (int) (PropOf(TCB)->SBI.srWindow.Bottom + 1 - 646 PropOf(TCB)->SBI.srWindow.Top); 647 *Cols = (int) (PropOf(TCB)->SBI.srWindow.Right + 1 - 648 PropOf(TCB)->SBI.srWindow.Left); 649 } 650 result = OK; 651 } 652 returnCode(result); 653 } 654 655 static int 656 drv_setsize(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, 657 int l GCC_UNUSED, 658 int c GCC_UNUSED) 659 { 660 AssertTCB(); 661 return ERR; 662 } 663 664 static int 665 drv_sgmode(TERMINAL_CONTROL_BLOCK * TCB, int setFlag, TTY * buf) 666 { 667 DWORD dwFlag = 0; 668 tcflag_t iflag; 669 tcflag_t lflag; 670 671 AssertTCB(); 672 673 if (TCB == 0 || buf == NULL) 674 return ERR; 675 676 if (setFlag) { 677 iflag = buf->c_iflag; 678 lflag = buf->c_lflag; 679 680 GetConsoleMode(TCB->inp, &dwFlag); 681 682 if (lflag & ICANON) 683 dwFlag |= ENABLE_LINE_INPUT; 684 else 685 dwFlag &= (DWORD) (~ENABLE_LINE_INPUT); 686 687 if (lflag & ECHO) 688 dwFlag |= ENABLE_ECHO_INPUT; 689 else 690 dwFlag &= (DWORD) (~ENABLE_ECHO_INPUT); 691 692 if (iflag & BRKINT) 693 dwFlag |= ENABLE_PROCESSED_INPUT; 694 else 695 dwFlag &= (DWORD) (~ENABLE_PROCESSED_INPUT); 696 697 dwFlag |= ENABLE_MOUSE_INPUT; 698 699 buf->c_iflag = iflag; 700 buf->c_lflag = lflag; 701 SetConsoleMode(TCB->inp, dwFlag); 702 TCB->term.Nttyb = *buf; 703 } else { 704 iflag = TCB->term.Nttyb.c_iflag; 705 lflag = TCB->term.Nttyb.c_lflag; 706 GetConsoleMode(TCB->inp, &dwFlag); 707 708 if (dwFlag & ENABLE_LINE_INPUT) 709 lflag |= ICANON; 710 else 711 lflag &= (tcflag_t) (~ICANON); 712 713 if (dwFlag & ENABLE_ECHO_INPUT) 714 lflag |= ECHO; 715 else 716 lflag &= (tcflag_t) (~ECHO); 717 718 if (dwFlag & ENABLE_PROCESSED_INPUT) 719 iflag |= BRKINT; 720 else 721 iflag &= (tcflag_t) (~BRKINT); 722 723 TCB->term.Nttyb.c_iflag = iflag; 724 TCB->term.Nttyb.c_lflag = lflag; 725 726 *buf = TCB->term.Nttyb; 727 } 728 return OK; 729 } 730 731 static int 732 drv_mode(TERMINAL_CONTROL_BLOCK * TCB, int progFlag, int defFlag) 733 { 734 SCREEN *sp; 735 TERMINAL *_term = (TERMINAL *) TCB; 736 int code = ERR; 737 738 AssertTCB(); 739 sp = TCB->csp; 740 741 PropOf(TCB)->progMode = progFlag; 742 PropOf(TCB)->lastOut = progFlag ? TCB->hdl : TCB->out; 743 SetConsoleActiveScreenBuffer(PropOf(TCB)->lastOut); 744 745 if (progFlag) /* prog mode */ { 746 if (defFlag) { 747 if ((drv_sgmode(TCB, FALSE, &(_term->Nttyb)) == OK)) { 748 _term->Nttyb.c_oflag &= (tcflag_t) (~OFLAGS_TABS); 749 code = OK; 750 } 751 } else { 752 /* reset_prog_mode */ 753 if (drv_sgmode(TCB, TRUE, &(_term->Nttyb)) == OK) { 754 if (sp) { 755 if (sp->_keypad_on) 756 _nc_keypad(sp, TRUE); 757 NC_BUFFERED(sp, TRUE); 758 } 759 code = OK; 760 } 761 } 762 } else { /* shell mode */ 763 if (defFlag) { 764 /* def_shell_mode */ 765 if (drv_sgmode(TCB, FALSE, &(_term->Ottyb)) == OK) { 766 code = OK; 767 } 768 } else { 769 /* reset_shell_mode */ 770 if (sp) { 771 _nc_keypad(sp, FALSE); 772 NCURSES_SP_NAME(_nc_flush) (sp); 773 NC_BUFFERED(sp, FALSE); 774 } 775 code = drv_sgmode(TCB, TRUE, &(_term->Ottyb)); 776 } 777 } 778 779 return (code); 780 } 781 782 static void 783 drv_screen_init(SCREEN *sp GCC_UNUSED) 784 { 785 } 786 787 static void 788 drv_wrap(SCREEN *sp GCC_UNUSED) 789 { 790 } 791 792 static int 793 rkeycompare(const void *el1, const void *el2) 794 { 795 WORD key1 = (LOWORD((*((const LONG *) el1)))) & 0x7fff; 796 WORD key2 = (LOWORD((*((const LONG *) el2)))) & 0x7fff; 797 798 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1)); 799 } 800 801 static int 802 keycompare(const void *el1, const void *el2) 803 { 804 WORD key1 = HIWORD((*((const LONG *) el1))); 805 WORD key2 = HIWORD((*((const LONG *) el2))); 806 807 return ((key1 < key2) ? -1 : ((key1 == key2) ? 0 : 1)); 808 } 809 810 static int 811 MapKey(TERMINAL_CONTROL_BLOCK * TCB, WORD vKey) 812 { 813 WORD nKey = 0; 814 void *res; 815 LONG key = GenMap(vKey, 0); 816 int code = -1; 817 818 AssertTCB(); 819 820 res = bsearch(&key, 821 PropOf(TCB)->map, 822 (size_t) (N_INI + FKEYS), 823 sizeof(keylist[0]), 824 keycompare); 825 if (res) { 826 key = *((LONG *) res); 827 nKey = LOWORD(key); 828 code = (int) (nKey & 0x7fff); 829 if (nKey & 0x8000) 830 code = -code; 831 } 832 return code; 833 } 834 835 static void 836 drv_release(TERMINAL_CONTROL_BLOCK * TCB) 837 { 838 T((T_CALLED("win32con::drv_release(%p)"), TCB)); 839 840 AssertTCB(); 841 if (TCB->prop) 842 free(TCB->prop); 843 844 returnVoid; 845 } 846 847 /* 848 * Attempt to save the screen contents. PDCurses does this if 849 * PDC_RESTORE_SCREEN is set, giving the same visual appearance on restoration 850 * as if the library had allocated a console buffer. 851 */ 852 static bool 853 save_original_screen(TERMINAL_CONTROL_BLOCK * TCB) 854 { 855 bool result = FALSE; 856 Properties *p = PropOf(TCB); 857 COORD bufferSize; 858 COORD bufferCoord; 859 SMALL_RECT readRegion; 860 size_t want; 861 862 bufferSize.X = p->SBI.dwSize.X; 863 bufferSize.Y = p->SBI.dwSize.Y; 864 want = (size_t) (bufferSize.X * bufferSize.Y); 865 866 if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) { 867 bufferCoord.X = bufferCoord.Y = 0; 868 869 readRegion.Top = 0; 870 readRegion.Left = 0; 871 readRegion.Bottom = (SHORT) (bufferSize.Y - 1); 872 readRegion.Right = (SHORT) (bufferSize.X - 1); 873 874 T(("... reading console buffer %dx%d into %d,%d - %d,%d at %d,%d", 875 bufferSize.Y, bufferSize.X, 876 readRegion.Top, 877 readRegion.Left, 878 readRegion.Bottom, 879 readRegion.Right, 880 bufferCoord.Y, 881 bufferCoord.X)); 882 883 if (ReadConsoleOutput(TCB->hdl, 884 p->save_screen, 885 bufferSize, 886 bufferCoord, 887 &readRegion)) { 888 result = TRUE; 889 } else { 890 T((" error %#lx", (unsigned long) GetLastError())); 891 FreeAndNull(p->save_screen); 892 893 bufferSize.X = (SHORT) (p->SBI.srWindow.Right 894 - p->SBI.srWindow.Left + 1); 895 bufferSize.Y = (SHORT) (p->SBI.srWindow.Bottom 896 - p->SBI.srWindow.Top + 1); 897 want = (size_t) (bufferSize.X * bufferSize.Y); 898 899 if ((p->save_screen = malloc(want * sizeof(CHAR_INFO))) != 0) { 900 bufferCoord.X = bufferCoord.Y = 0; 901 902 readRegion.Top = p->SBI.srWindow.Top; 903 readRegion.Left = p->SBI.srWindow.Left; 904 readRegion.Bottom = p->SBI.srWindow.Bottom; 905 readRegion.Right = p->SBI.srWindow.Right; 906 907 T(("... reading console window %dx%d into %d,%d - %d,%d at %d,%d", 908 bufferSize.Y, bufferSize.X, 909 readRegion.Top, 910 readRegion.Left, 911 readRegion.Bottom, 912 readRegion.Right, 913 bufferCoord.Y, 914 bufferCoord.X)); 915 916 if (ReadConsoleOutput(TCB->hdl, 917 p->save_screen, 918 bufferSize, 919 bufferCoord, 920 &readRegion)) { 921 result = TRUE; 922 } else { 923 T((" error %#lx", (unsigned long) GetLastError())); 924 } 925 } 926 } 927 } 928 929 T(("... save original screen contents %s", result ? "ok" : "err")); 930 return result; 931 } 932 933 static void 934 drv_init(TERMINAL_CONTROL_BLOCK * TCB) 935 { 936 DWORD num_buttons; 937 938 T((T_CALLED("win32con::drv_init(%p)"), TCB)); 939 940 AssertTCB(); 941 942 if (TCB) { 943 BOOL b = AllocConsole(); 944 WORD a; 945 int i; 946 bool buffered = TRUE; 947 948 if (!b) 949 b = AttachConsole(ATTACH_PARENT_PROCESS); 950 951 TCB->inp = GetStdHandle(STD_INPUT_HANDLE); 952 TCB->out = GetStdHandle(STD_OUTPUT_HANDLE); 953 954 if (getenv("NCGDB")) { 955 TCB->hdl = TCB->out; 956 buffered = FALSE; 957 } else { 958 TCB->hdl = CreateConsoleScreenBuffer(GENERIC_READ | GENERIC_WRITE, 959 0, 960 NULL, 961 CONSOLE_TEXTMODE_BUFFER, 962 NULL); 963 } 964 965 if (InvalidConsoleHandle(TCB->hdl)) { 966 returnVoid; 967 } else if ((TCB->prop = typeCalloc(Properties, 1)) != 0) { 968 PropOf(TCB)->buffered = buffered; 969 if (!get_SBI(TCB)) { 970 FreeAndNull(TCB->prop); /* force error in drv_size */ 971 returnVoid; 972 } 973 if (!buffered) { 974 if (!save_original_screen(TCB)) { 975 FreeAndNull(TCB->prop); /* force error in drv_size */ 976 returnVoid; 977 } 978 } 979 } 980 981 TCB->info.initcolor = TRUE; 982 TCB->info.canchange = FALSE; 983 TCB->info.hascolor = TRUE; 984 TCB->info.caninit = TRUE; 985 986 TCB->info.maxpairs = NUMPAIRS; 987 TCB->info.maxcolors = 8; 988 TCB->info.numlabels = 0; 989 TCB->info.labelwidth = 0; 990 TCB->info.labelheight = 0; 991 TCB->info.nocolorvideo = 1; 992 TCB->info.tabsize = 8; 993 994 if (GetNumberOfConsoleMouseButtons(&num_buttons)) { 995 T(("mouse has %ld buttons", num_buttons)); 996 TCB->info.numbuttons = (int) num_buttons; 997 } else { 998 TCB->info.numbuttons = 1; 999 } 1000 1001 TCB->info.defaultPalette = _nc_cga_palette; 1002 1003 for (i = 0; i < (N_INI + FKEYS); i++) { 1004 if (i < N_INI) 1005 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = (DWORD) keylist[i]; 1006 else 1007 PropOf(TCB)->rmap[i] = PropOf(TCB)->map[i] = 1008 GenMap((VK_F1 + (i - N_INI)), (KEY_F(1) + (i - N_INI))); 1009 } 1010 qsort(PropOf(TCB)->map, 1011 (size_t) (MAPSIZE), 1012 sizeof(keylist[0]), 1013 keycompare); 1014 qsort(PropOf(TCB)->rmap, 1015 (size_t) (MAPSIZE), 1016 sizeof(keylist[0]), 1017 rkeycompare); 1018 1019 a = MapColor(true, COLOR_WHITE) | MapColor(false, COLOR_BLACK); 1020 for (i = 0; i < NUMPAIRS; i++) 1021 PropOf(TCB)->pairs[i] = a; 1022 } 1023 returnVoid; 1024 } 1025 1026 static void 1027 drv_initpair(TERMINAL_CONTROL_BLOCK * TCB, 1028 int pair, 1029 int f, 1030 int b) 1031 { 1032 SCREEN *sp; 1033 1034 AssertTCB(); 1035 SetSP(); 1036 1037 if ((pair > 0) && (pair < NUMPAIRS) && (f >= 0) && (f < 8) 1038 && (b >= 0) && (b < 8)) { 1039 PropOf(TCB)->pairs[pair] = MapColor(true, f) | MapColor(false, b); 1040 } 1041 } 1042 1043 static void 1044 drv_initcolor(TERMINAL_CONTROL_BLOCK * TCB, 1045 int color GCC_UNUSED, 1046 int r GCC_UNUSED, 1047 int g GCC_UNUSED, 1048 int b GCC_UNUSED) 1049 { 1050 SCREEN *sp; 1051 1052 AssertTCB(); 1053 SetSP(); 1054 } 1055 1056 static void 1057 drv_do_color(TERMINAL_CONTROL_BLOCK * TCB, 1058 int old_pair GCC_UNUSED, 1059 int pair GCC_UNUSED, 1060 int reverse GCC_UNUSED, 1061 int (*outc) (SCREEN *, int) GCC_UNUSED 1062 ) 1063 { 1064 SCREEN *sp; 1065 1066 AssertTCB(); 1067 SetSP(); 1068 } 1069 1070 static void 1071 drv_initmouse(TERMINAL_CONTROL_BLOCK * TCB) 1072 { 1073 SCREEN *sp; 1074 1075 AssertTCB(); 1076 SetSP(); 1077 1078 sp->_mouse_type = M_TERM_DRIVER; 1079 } 1080 1081 static int 1082 drv_testmouse(TERMINAL_CONTROL_BLOCK * TCB, int delay) 1083 { 1084 int rc = 0; 1085 SCREEN *sp; 1086 1087 AssertTCB(); 1088 SetSP(); 1089 1090 if (sp->_drv_mouse_head < sp->_drv_mouse_tail) { 1091 rc = TW_MOUSE; 1092 } else { 1093 rc = TCBOf(sp)->drv->twait(TCBOf(sp), 1094 TWAIT_MASK, 1095 delay, 1096 (int *) 0 1097 EVENTLIST_2nd(evl)); 1098 } 1099 1100 return rc; 1101 } 1102 1103 static int 1104 drv_mvcur(TERMINAL_CONTROL_BLOCK * TCB, 1105 int yold GCC_UNUSED, int xold GCC_UNUSED, 1106 int y, int x) 1107 { 1108 int ret = ERR; 1109 if (okConsoleHandle(TCB)) { 1110 Properties *p = PropOf(TCB); 1111 COORD loc; 1112 loc.X = (short) x; 1113 loc.Y = (short) (y + AdjustY(p)); 1114 SetConsoleCursorPosition(TCB->hdl, loc); 1115 ret = OK; 1116 } 1117 return ret; 1118 } 1119 1120 static void 1121 drv_hwlabel(TERMINAL_CONTROL_BLOCK * TCB, 1122 int labnum GCC_UNUSED, 1123 char *text GCC_UNUSED) 1124 { 1125 SCREEN *sp; 1126 1127 AssertTCB(); 1128 SetSP(); 1129 } 1130 1131 static void 1132 drv_hwlabelOnOff(TERMINAL_CONTROL_BLOCK * TCB, 1133 int OnFlag GCC_UNUSED) 1134 { 1135 SCREEN *sp; 1136 1137 AssertTCB(); 1138 SetSP(); 1139 } 1140 1141 static chtype 1142 drv_conattr(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED) 1143 { 1144 chtype res = A_NORMAL; 1145 res |= (A_BOLD | A_DIM | A_REVERSE | A_STANDOUT | A_COLOR); 1146 return res; 1147 } 1148 1149 static void 1150 drv_setfilter(TERMINAL_CONTROL_BLOCK * TCB) 1151 { 1152 SCREEN *sp; 1153 1154 AssertTCB(); 1155 SetSP(); 1156 } 1157 1158 static void 1159 drv_initacs(TERMINAL_CONTROL_BLOCK * TCB, 1160 chtype *real_map GCC_UNUSED, 1161 chtype *fake_map GCC_UNUSED) 1162 { 1163 #define DATA(a,b) { a, b } 1164 static struct { 1165 int acs_code; 1166 int use_code; 1167 } table[] = { 1168 DATA('a', 0xb1), /* ACS_CKBOARD */ 1169 DATA('f', 0xf8), /* ACS_DEGREE */ 1170 DATA('g', 0xf1), /* ACS_PLMINUS */ 1171 DATA('j', 0xd9), /* ACS_LRCORNER */ 1172 DATA('l', 0xda), /* ACS_ULCORNER */ 1173 DATA('k', 0xbf), /* ACS_URCORNER */ 1174 DATA('m', 0xc0), /* ACS_LLCORNER */ 1175 DATA('n', 0xc5), /* ACS_PLUS */ 1176 DATA('q', 0xc4), /* ACS_HLINE */ 1177 DATA('t', 0xc3), /* ACS_LTEE */ 1178 DATA('u', 0xb4), /* ACS_RTEE */ 1179 DATA('v', 0xc1), /* ACS_BTEE */ 1180 DATA('w', 0xc2), /* ACS_TTEE */ 1181 DATA('x', 0xb3), /* ACS_VLINE */ 1182 DATA('y', 0xf3), /* ACS_LEQUAL */ 1183 DATA('z', 0xf2), /* ACS_GEQUAL */ 1184 DATA('0', 0xdb), /* ACS_BLOCK */ 1185 DATA('{', 0xe3), /* ACS_PI */ 1186 DATA('}', 0x9c), /* ACS_STERLING */ 1187 DATA(',', 0xae), /* ACS_LARROW */ 1188 DATA('+', 0xaf), /* ACS_RARROW */ 1189 DATA('~', 0xf9), /* ACS_BULLET */ 1190 }; 1191 #undef DATA 1192 unsigned n; 1193 1194 SCREEN *sp; 1195 AssertTCB(); 1196 SetSP(); 1197 1198 for (n = 0; n < SIZEOF(table); ++n) { 1199 real_map[table[n].acs_code] = (chtype) table[n].use_code | A_ALTCHARSET; 1200 if (sp != 0) 1201 sp->_screen_acs_map[table[n].acs_code] = TRUE; 1202 } 1203 } 1204 1205 static ULONGLONG 1206 tdiff(FILETIME fstart, FILETIME fend) 1207 { 1208 ULARGE_INTEGER ustart; 1209 ULARGE_INTEGER uend; 1210 ULONGLONG diff; 1211 1212 ustart.LowPart = fstart.dwLowDateTime; 1213 ustart.HighPart = fstart.dwHighDateTime; 1214 uend.LowPart = fend.dwLowDateTime; 1215 uend.HighPart = fend.dwHighDateTime; 1216 1217 diff = (uend.QuadPart - ustart.QuadPart) / 10000; 1218 return diff; 1219 } 1220 1221 static int 1222 Adjust(int milliseconds, int diff) 1223 { 1224 if (milliseconds == INFINITY) 1225 return milliseconds; 1226 milliseconds -= diff; 1227 if (milliseconds < 0) 1228 milliseconds = 0; 1229 return milliseconds; 1230 } 1231 1232 #define BUTTON_MASK (FROM_LEFT_1ST_BUTTON_PRESSED | \ 1233 FROM_LEFT_2ND_BUTTON_PRESSED | \ 1234 FROM_LEFT_3RD_BUTTON_PRESSED | \ 1235 FROM_LEFT_4TH_BUTTON_PRESSED | \ 1236 RIGHTMOST_BUTTON_PRESSED) 1237 1238 static int 1239 decode_mouse(TERMINAL_CONTROL_BLOCK * TCB, int mask) 1240 { 1241 SCREEN *sp; 1242 int result = 0; 1243 1244 AssertTCB(); 1245 SetSP(); 1246 1247 if (mask & FROM_LEFT_1ST_BUTTON_PRESSED) 1248 result |= BUTTON1_PRESSED; 1249 if (mask & FROM_LEFT_2ND_BUTTON_PRESSED) 1250 result |= BUTTON2_PRESSED; 1251 if (mask & FROM_LEFT_3RD_BUTTON_PRESSED) 1252 result |= BUTTON3_PRESSED; 1253 if (mask & FROM_LEFT_4TH_BUTTON_PRESSED) 1254 result |= BUTTON4_PRESSED; 1255 1256 if (mask & RIGHTMOST_BUTTON_PRESSED) { 1257 switch (TCB->info.numbuttons) { 1258 case 1: 1259 result |= BUTTON1_PRESSED; 1260 break; 1261 case 2: 1262 result |= BUTTON2_PRESSED; 1263 break; 1264 case 3: 1265 result |= BUTTON3_PRESSED; 1266 break; 1267 case 4: 1268 result |= BUTTON4_PRESSED; 1269 break; 1270 } 1271 } 1272 1273 return result; 1274 } 1275 1276 static int 1277 drv_twait(TERMINAL_CONTROL_BLOCK * TCB, 1278 int mode, 1279 int milliseconds, 1280 int *timeleft 1281 EVENTLIST_2nd(_nc_eventlist * evl)) 1282 { 1283 SCREEN *sp; 1284 INPUT_RECORD inp_rec; 1285 BOOL b; 1286 DWORD nRead = 0, rc = (DWORD) (-1); 1287 int code = 0; 1288 FILETIME fstart; 1289 FILETIME fend; 1290 int diff; 1291 bool isImmed = (milliseconds == 0); 1292 1293 #define CONSUME() ReadConsoleInput(TCB->inp,&inp_rec,1,&nRead) 1294 1295 AssertTCB(); 1296 SetSP(); 1297 1298 TR(TRACE_IEVENT, ("start twait: %d milliseconds, mode: %d", 1299 milliseconds, mode)); 1300 1301 if (milliseconds < 0) 1302 milliseconds = INFINITY; 1303 1304 memset(&inp_rec, 0, sizeof(inp_rec)); 1305 1306 while (true) { 1307 GetSystemTimeAsFileTime(&fstart); 1308 rc = WaitForSingleObject(TCB->inp, (DWORD) milliseconds); 1309 GetSystemTimeAsFileTime(&fend); 1310 diff = (int) tdiff(fstart, fend); 1311 milliseconds = Adjust(milliseconds, diff); 1312 1313 if (!isImmed && milliseconds == 0) 1314 break; 1315 1316 if (rc == WAIT_OBJECT_0) { 1317 if (mode) { 1318 b = GetNumberOfConsoleInputEvents(TCB->inp, &nRead); 1319 if (b && nRead > 0) { 1320 b = PeekConsoleInput(TCB->inp, &inp_rec, 1, &nRead); 1321 if (b && nRead > 0) { 1322 switch (inp_rec.EventType) { 1323 case KEY_EVENT: 1324 if (mode & TW_INPUT) { 1325 WORD vk = inp_rec.Event.KeyEvent.wVirtualKeyCode; 1326 char ch = inp_rec.Event.KeyEvent.uChar.AsciiChar; 1327 1328 if (inp_rec.Event.KeyEvent.bKeyDown) { 1329 if (0 == ch) { 1330 int nKey = MapKey(TCB, vk); 1331 if ((nKey < 0) || FALSE == sp->_keypad_on) { 1332 CONSUME(); 1333 continue; 1334 } 1335 } 1336 code = TW_INPUT; 1337 goto end; 1338 } else { 1339 CONSUME(); 1340 } 1341 } 1342 continue; 1343 case MOUSE_EVENT: 1344 if (decode_mouse(TCB, 1345 (inp_rec.Event.MouseEvent.dwButtonState 1346 & BUTTON_MASK)) == 0) { 1347 CONSUME(); 1348 } else if (mode & TW_MOUSE) { 1349 code = TW_MOUSE; 1350 goto end; 1351 } 1352 continue; 1353 default: 1354 selectActiveHandle(TCB); 1355 continue; 1356 } 1357 } 1358 } 1359 } 1360 continue; 1361 } else { 1362 if (rc != WAIT_TIMEOUT) { 1363 code = -1; 1364 break; 1365 } else { 1366 code = 0; 1367 break; 1368 } 1369 } 1370 } 1371 end: 1372 1373 TR(TRACE_IEVENT, ("end twait: returned %d (%d), remaining time %d msec", 1374 code, errno, milliseconds)); 1375 1376 if (timeleft) 1377 *timeleft = milliseconds; 1378 1379 return code; 1380 } 1381 1382 static bool 1383 handle_mouse(TERMINAL_CONTROL_BLOCK * TCB, MOUSE_EVENT_RECORD mer) 1384 { 1385 SCREEN *sp; 1386 MEVENT work; 1387 bool result = FALSE; 1388 1389 AssertTCB(); 1390 SetSP(); 1391 1392 sp->_drv_mouse_old_buttons = sp->_drv_mouse_new_buttons; 1393 sp->_drv_mouse_new_buttons = mer.dwButtonState & BUTTON_MASK; 1394 1395 /* 1396 * We're only interested if the button is pressed or released. 1397 * FIXME: implement continuous event-tracking. 1398 */ 1399 if (sp->_drv_mouse_new_buttons != sp->_drv_mouse_old_buttons) { 1400 Properties *p = PropOf(TCB); 1401 1402 memset(&work, 0, sizeof(work)); 1403 1404 if (sp->_drv_mouse_new_buttons) { 1405 1406 work.bstate |= (mmask_t) decode_mouse(TCB, sp->_drv_mouse_new_buttons); 1407 1408 } else { 1409 1410 /* cf: BUTTON_PRESSED, BUTTON_RELEASED */ 1411 work.bstate |= (mmask_t) (decode_mouse(TCB, 1412 sp->_drv_mouse_old_buttons) 1413 >> 1); 1414 1415 result = TRUE; 1416 } 1417 1418 work.x = mer.dwMousePosition.X; 1419 work.y = mer.dwMousePosition.Y - AdjustY(p); 1420 1421 sp->_drv_mouse_fifo[sp->_drv_mouse_tail] = work; 1422 sp->_drv_mouse_tail += 1; 1423 } 1424 1425 return result; 1426 } 1427 1428 static int 1429 drv_read(TERMINAL_CONTROL_BLOCK * TCB, int *buf) 1430 { 1431 SCREEN *sp; 1432 int n = 1; 1433 INPUT_RECORD inp_rec; 1434 BOOL b; 1435 DWORD nRead; 1436 WORD vk; 1437 1438 AssertTCB(); 1439 assert(buf); 1440 SetSP(); 1441 1442 memset(&inp_rec, 0, sizeof(inp_rec)); 1443 1444 T((T_CALLED("win32con::drv_read(%p)"), TCB)); 1445 while ((b = ReadConsoleInput(TCB->inp, &inp_rec, 1, &nRead))) { 1446 if (b && nRead > 0) { 1447 if (inp_rec.EventType == KEY_EVENT) { 1448 if (!inp_rec.Event.KeyEvent.bKeyDown) 1449 continue; 1450 *buf = (int) inp_rec.Event.KeyEvent.uChar.AsciiChar; 1451 vk = inp_rec.Event.KeyEvent.wVirtualKeyCode; 1452 if (*buf == 0) { 1453 if (sp->_keypad_on) { 1454 *buf = MapKey(TCB, vk); 1455 if (0 > (*buf)) 1456 continue; 1457 else 1458 break; 1459 } else 1460 continue; 1461 } else { /* *buf != 0 */ 1462 break; 1463 } 1464 } else if (inp_rec.EventType == MOUSE_EVENT) { 1465 if (handle_mouse(TCB, inp_rec.Event.MouseEvent)) { 1466 *buf = KEY_MOUSE; 1467 break; 1468 } 1469 } 1470 continue; 1471 } 1472 } 1473 returnCode(n); 1474 } 1475 1476 static int 1477 drv_nap(TERMINAL_CONTROL_BLOCK * TCB GCC_UNUSED, int ms) 1478 { 1479 T((T_CALLED("win32con::drv_nap(%p, %d)"), TCB, ms)); 1480 Sleep((DWORD) ms); 1481 returnCode(OK); 1482 } 1483 1484 static bool 1485 drv_kyExist(TERMINAL_CONTROL_BLOCK * TCB, int keycode) 1486 { 1487 SCREEN *sp; 1488 WORD nKey; 1489 void *res; 1490 bool found = FALSE; 1491 LONG key = GenMap(0, (WORD) keycode); 1492 1493 AssertTCB(); 1494 SetSP(); 1495 1496 AssertTCB(); 1497 1498 T((T_CALLED("win32con::drv_kyExist(%p, %d)"), TCB, keycode)); 1499 res = bsearch(&key, 1500 PropOf(TCB)->rmap, 1501 (size_t) (N_INI + FKEYS), 1502 sizeof(keylist[0]), 1503 rkeycompare); 1504 if (res) { 1505 key = *((LONG *) res); 1506 nKey = LOWORD(key); 1507 if (!(nKey & 0x8000)) 1508 found = TRUE; 1509 } 1510 returnCode(found); 1511 } 1512 1513 static int 1514 drv_kpad(TERMINAL_CONTROL_BLOCK * TCB, int flag GCC_UNUSED) 1515 { 1516 SCREEN *sp; 1517 int code = ERR; 1518 1519 AssertTCB(); 1520 sp = TCB->csp; 1521 1522 T((T_CALLED("win32con::drv_kpad(%p, %d)"), TCB, flag)); 1523 if (sp) { 1524 code = OK; 1525 } 1526 returnCode(code); 1527 } 1528 1529 static int 1530 drv_keyok(TERMINAL_CONTROL_BLOCK * TCB, int keycode, int flag) 1531 { 1532 int code = ERR; 1533 SCREEN *sp; 1534 WORD nKey; 1535 WORD vKey; 1536 void *res; 1537 LONG key = GenMap(0, (WORD) keycode); 1538 1539 AssertTCB(); 1540 SetSP(); 1541 1542 T((T_CALLED("win32con::drv_keyok(%p, %d, %d)"), TCB, keycode, flag)); 1543 if (sp) { 1544 res = bsearch(&key, 1545 PropOf(TCB)->rmap, 1546 (size_t) (N_INI + FKEYS), 1547 sizeof(keylist[0]), 1548 rkeycompare); 1549 if (res) { 1550 key = *((LONG *) res); 1551 vKey = HIWORD(key); 1552 nKey = (LOWORD(key)) & 0x7fff; 1553 if (!flag) 1554 nKey |= 0x8000; 1555 *(LONG *) res = GenMap(vKey, nKey); 1556 } 1557 } 1558 returnCode(code); 1559 } 1560 1561 NCURSES_EXPORT_VAR (TERM_DRIVER) _nc_WIN_DRIVER = { 1562 FALSE, 1563 drv_CanHandle, /* CanHandle */ 1564 drv_init, /* init */ 1565 drv_release, /* release */ 1566 drv_size, /* size */ 1567 drv_sgmode, /* sgmode */ 1568 drv_conattr, /* conattr */ 1569 drv_mvcur, /* hwcur */ 1570 drv_mode, /* mode */ 1571 drv_rescol, /* rescol */ 1572 drv_rescolors, /* rescolors */ 1573 drv_setcolor, /* color */ 1574 drv_dobeepflash, /* DoBeepFlash */ 1575 drv_initpair, /* initpair */ 1576 drv_initcolor, /* initcolor */ 1577 drv_do_color, /* docolor */ 1578 drv_initmouse, /* initmouse */ 1579 drv_testmouse, /* testmouse */ 1580 drv_setfilter, /* setfilter */ 1581 drv_hwlabel, /* hwlabel */ 1582 drv_hwlabelOnOff, /* hwlabelOnOff */ 1583 drv_doupdate, /* update */ 1584 drv_defaultcolors, /* defaultcolors */ 1585 drv_print, /* print */ 1586 drv_size, /* getsize */ 1587 drv_setsize, /* setsize */ 1588 drv_initacs, /* initacs */ 1589 drv_screen_init, /* scinit */ 1590 drv_wrap, /* scexit */ 1591 drv_twait, /* twait */ 1592 drv_read, /* read */ 1593 drv_nap, /* nap */ 1594 drv_kpad, /* kpad */ 1595 drv_keyok, /* kyOk */ 1596 drv_kyExist /* kyExist */ 1597 }; 1598