1 /**************************************************************************** 2 * Copyright (c) 1998-2015,2016 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: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * 31 * and: Eric S. Raymond <esr@snark.thyrsus.com> * 32 * and: Thomas E. Dickey 1996-on * 33 * and: Juergen Pfeifer 2009 * 34 ****************************************************************************/ 35 36 /* 37 ** lib_getch.c 38 ** 39 ** The routine getch(). 40 ** 41 */ 42 43 #include <curses.priv.h> 44 45 MODULE_ID("$Id: lib_getch.c,v 1.134 2016/01/23 21:32:00 tom Exp $") 46 47 #include <fifo_defs.h> 48 49 #if USE_REENTRANT 50 #define GetEscdelay(sp) *_nc_ptr_Escdelay(sp) 51 NCURSES_EXPORT(int) 52 NCURSES_PUBLIC_VAR(ESCDELAY) (void) 53 { 54 return *(_nc_ptr_Escdelay(CURRENT_SCREEN)); 55 } 56 57 NCURSES_EXPORT(int *) 58 _nc_ptr_Escdelay(SCREEN *sp) 59 { 60 return ptrEscdelay(sp); 61 } 62 #else 63 #define GetEscdelay(sp) ESCDELAY 64 NCURSES_EXPORT_VAR(int) ESCDELAY = 1000; 65 #endif 66 67 #if NCURSES_EXT_FUNCS 68 NCURSES_EXPORT(int) 69 NCURSES_SP_NAME(set_escdelay) (NCURSES_SP_DCLx int value) 70 { 71 int code = OK; 72 #if USE_REENTRANT 73 if (SP_PARM) { 74 SET_ESCDELAY(value); 75 } else { 76 code = ERR; 77 } 78 #else 79 (void) SP_PARM; 80 ESCDELAY = value; 81 #endif 82 return code; 83 } 84 85 #if NCURSES_SP_FUNCS 86 NCURSES_EXPORT(int) 87 set_escdelay(int value) 88 { 89 int code; 90 #if USE_REENTRANT 91 code = NCURSES_SP_NAME(set_escdelay) (CURRENT_SCREEN, value); 92 #else 93 ESCDELAY = value; 94 code = OK; 95 #endif 96 return code; 97 } 98 #endif 99 #endif /* NCURSES_EXT_FUNCS */ 100 101 #if NCURSES_EXT_FUNCS 102 NCURSES_EXPORT(int) 103 NCURSES_SP_NAME(get_escdelay) (NCURSES_SP_DCL0) 104 { 105 #if !USE_REENTRANT 106 (void) SP_PARM; 107 #endif 108 return GetEscdelay(SP_PARM); 109 } 110 111 #if NCURSES_SP_FUNCS 112 NCURSES_EXPORT(int) 113 get_escdelay(void) 114 { 115 return NCURSES_SP_NAME(get_escdelay) (CURRENT_SCREEN); 116 } 117 #endif 118 #endif /* NCURSES_EXT_FUNCS */ 119 120 static int 121 _nc_use_meta(WINDOW *win) 122 { 123 SCREEN *sp = _nc_screen_of(win); 124 return (sp ? sp->_use_meta : 0); 125 } 126 127 #ifdef USE_TERM_DRIVER 128 # ifdef __MINGW32__ 129 static HANDLE 130 _nc_get_handle(int fd) 131 { 132 intptr_t value = _get_osfhandle(fd); 133 return (HANDLE) value; 134 } 135 # endif 136 #endif 137 138 /* 139 * Check for mouse activity, returning nonzero if we find any. 140 */ 141 static int 142 check_mouse_activity(SCREEN *sp, int delay EVENTLIST_2nd(_nc_eventlist * evl)) 143 { 144 int rc; 145 146 #ifdef USE_TERM_DRIVER 147 TERMINAL_CONTROL_BLOCK *TCB = TCBOf(sp); 148 rc = TCBOf(sp)->drv->td_testmouse(TCBOf(sp), delay EVENTLIST_2nd(evl)); 149 # ifdef __MINGW32__ 150 /* if we emulate terminfo on console, we have to use the console routine */ 151 if (IsTermInfoOnConsole(sp)) { 152 HANDLE fd = _nc_get_handle(sp->_ifd); 153 rc = _nc_mingw_testmouse(sp, fd, delay EVENTLIST_2nd(evl)); 154 } else 155 # endif 156 rc = TCB->drv->td_testmouse(TCB, delay EVENTLIST_2nd(evl)); 157 #else 158 #if USE_SYSMOUSE 159 if ((sp->_mouse_type == M_SYSMOUSE) 160 && (sp->_sysmouse_head < sp->_sysmouse_tail)) { 161 rc = TW_MOUSE; 162 } else 163 #endif 164 { 165 rc = _nc_timed_wait(sp, 166 TWAIT_MASK, 167 delay, 168 (int *) 0 169 EVENTLIST_2nd(evl)); 170 #if USE_SYSMOUSE 171 if ((sp->_mouse_type == M_SYSMOUSE) 172 && (sp->_sysmouse_head < sp->_sysmouse_tail) 173 && (rc == 0) 174 && (errno == EINTR)) { 175 rc |= TW_MOUSE; 176 } 177 #endif 178 } 179 #endif 180 return rc; 181 } 182 183 static NCURSES_INLINE int 184 fifo_peek(SCREEN *sp) 185 { 186 int ch = (peek >= 0) ? sp->_fifo[peek] : ERR; 187 TR(TRACE_IEVENT, ("peeking at %d", peek)); 188 189 p_inc(); 190 return ch; 191 } 192 193 static NCURSES_INLINE int 194 fifo_pull(SCREEN *sp) 195 { 196 int ch = (head >= 0) ? sp->_fifo[head] : ERR; 197 198 TR(TRACE_IEVENT, ("pulling %s from %d", _nc_tracechar(sp, ch), head)); 199 200 if (peek == head) { 201 h_inc(); 202 peek = head; 203 } else { 204 h_inc(); 205 } 206 207 #ifdef TRACE 208 if (USE_TRACEF(TRACE_IEVENT)) { 209 _nc_fifo_dump(sp); 210 _nc_unlock_global(tracef); 211 } 212 #endif 213 return ch; 214 } 215 216 static NCURSES_INLINE int 217 fifo_push(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl)) 218 { 219 int n; 220 int ch = 0; 221 int mask = 0; 222 223 (void) mask; 224 if (tail < 0) 225 return ERR; 226 227 #ifdef HIDE_EINTR 228 again: 229 errno = 0; 230 #endif 231 232 #ifdef NCURSES_WGETCH_EVENTS 233 if (evl 234 #if USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE 235 || (sp->_mouse_fd >= 0) 236 #endif 237 ) { 238 mask = check_mouse_activity(sp, -1 EVENTLIST_2nd(evl)); 239 } else 240 mask = 0; 241 242 if (mask & TW_EVENT) { 243 T(("fifo_push: ungetch KEY_EVENT")); 244 safe_ungetch(sp, KEY_EVENT); 245 return KEY_EVENT; 246 } 247 #elif USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE 248 if (sp->_mouse_fd >= 0) { 249 mask = check_mouse_activity(sp, -1 EVENTLIST_2nd(evl)); 250 } 251 #endif 252 253 #if USE_GPM_SUPPORT || USE_EMX_MOUSE 254 if ((sp->_mouse_fd >= 0) && (mask & TW_MOUSE)) { 255 sp->_mouse_event(sp); 256 ch = KEY_MOUSE; 257 n = 1; 258 } else 259 #endif 260 #if USE_SYSMOUSE 261 if ((sp->_mouse_type == M_SYSMOUSE) 262 && (sp->_sysmouse_head < sp->_sysmouse_tail)) { 263 sp->_mouse_event(sp); 264 ch = KEY_MOUSE; 265 n = 1; 266 } else if ((sp->_mouse_type == M_SYSMOUSE) 267 && (mask <= 0) && errno == EINTR) { 268 sp->_mouse_event(sp); 269 ch = KEY_MOUSE; 270 n = 1; 271 } else 272 #endif 273 #ifdef USE_TERM_DRIVER 274 if ((sp->_mouse_type == M_TERM_DRIVER) 275 && (sp->_drv_mouse_head < sp->_drv_mouse_tail)) { 276 sp->_mouse_event(sp); 277 ch = KEY_MOUSE; 278 n = 1; 279 } else 280 #endif 281 #if USE_KLIBC_KBD 282 if (NC_ISATTY(sp->_ifd) && sp->_cbreak) { 283 ch = _read_kbd(0, 1, !sp->_raw); 284 n = (ch == -1) ? -1 : 1; 285 sp->_extended_key = (ch == 0); 286 } else 287 #endif 288 { /* Can block... */ 289 #ifdef USE_TERM_DRIVER 290 int buf; 291 #ifdef __MINGW32__ 292 if (NC_ISATTY(sp->_ifd) && IsTermInfoOnConsole(sp) && sp->_cbreak) 293 n = _nc_mingw_console_read(sp, 294 _nc_get_handle(sp->_ifd), 295 &buf); 296 else 297 #endif 298 n = CallDriver_1(sp, td_read, &buf); 299 ch = buf; 300 #else 301 unsigned char c2 = 0; 302 # if USE_PTHREADS_EINTR 303 # if USE_WEAK_SYMBOLS 304 if ((pthread_self) && (pthread_kill) && (pthread_equal)) 305 # endif 306 _nc_globals.read_thread = pthread_self(); 307 # endif 308 n = (int) read(sp->_ifd, &c2, (size_t) 1); 309 #if USE_PTHREADS_EINTR 310 _nc_globals.read_thread = 0; 311 #endif 312 ch = c2; 313 #endif 314 } 315 316 #ifdef HIDE_EINTR 317 /* 318 * Under System V curses with non-restarting signals, getch() returns 319 * with value ERR when a handled signal keeps it from completing. 320 * If signals restart system calls, OTOH, the signal is invisible 321 * except to its handler. 322 * 323 * We don't want this difference to show. This piece of code 324 * tries to make it look like we always have restarting signals. 325 */ 326 if (n <= 0 && errno == EINTR 327 # if USE_PTHREADS_EINTR 328 && (_nc_globals.have_sigwinch == 0) 329 # endif 330 ) 331 goto again; 332 #endif 333 334 if ((n == -1) || (n == 0)) { 335 TR(TRACE_IEVENT, ("read(%d,&ch,1)=%d, errno=%d", sp->_ifd, n, errno)); 336 ch = ERR; 337 } 338 TR(TRACE_IEVENT, ("read %d characters", n)); 339 340 sp->_fifo[tail] = ch; 341 sp->_fifohold = 0; 342 if (head == -1) 343 head = peek = tail; 344 t_inc(); 345 TR(TRACE_IEVENT, ("pushed %s at %d", _nc_tracechar(sp, ch), tail)); 346 #ifdef TRACE 347 if (USE_TRACEF(TRACE_IEVENT)) { 348 _nc_fifo_dump(sp); 349 _nc_unlock_global(tracef); 350 } 351 #endif 352 return ch; 353 } 354 355 static NCURSES_INLINE void 356 fifo_clear(SCREEN *sp) 357 { 358 memset(sp->_fifo, 0, sizeof(sp->_fifo)); 359 head = -1; 360 tail = peek = 0; 361 } 362 363 static int kgetch(SCREEN *EVENTLIST_2nd(_nc_eventlist * evl)); 364 365 static void 366 recur_wrefresh(WINDOW *win) 367 { 368 #ifdef USE_PTHREADS 369 SCREEN *sp = _nc_screen_of(win); 370 if (_nc_use_pthreads && sp != CURRENT_SCREEN) { 371 SCREEN *save_SP; 372 373 /* temporarily switch to the window's screen to check/refresh */ 374 _nc_lock_global(curses); 375 save_SP = CURRENT_SCREEN; 376 _nc_set_screen(sp); 377 recur_wrefresh(win); 378 _nc_set_screen(save_SP); 379 _nc_unlock_global(curses); 380 } else 381 #endif 382 if ((is_wintouched(win) || (win->_flags & _HASMOVED)) 383 && !(win->_flags & _ISPAD)) { 384 wrefresh(win); 385 } 386 } 387 388 static int 389 recur_wgetnstr(WINDOW *win, char *buf) 390 { 391 SCREEN *sp = _nc_screen_of(win); 392 int rc; 393 394 if (sp != 0) { 395 #ifdef USE_PTHREADS 396 if (_nc_use_pthreads && sp != CURRENT_SCREEN) { 397 SCREEN *save_SP; 398 399 /* temporarily switch to the window's screen to get cooked input */ 400 _nc_lock_global(curses); 401 save_SP = CURRENT_SCREEN; 402 _nc_set_screen(sp); 403 rc = recur_wgetnstr(win, buf); 404 _nc_set_screen(save_SP); 405 _nc_unlock_global(curses); 406 } else 407 #endif 408 { 409 sp->_called_wgetch = TRUE; 410 rc = wgetnstr(win, buf, MAXCOLUMNS); 411 sp->_called_wgetch = FALSE; 412 } 413 } else { 414 rc = ERR; 415 } 416 return rc; 417 } 418 419 NCURSES_EXPORT(int) 420 _nc_wgetch(WINDOW *win, 421 int *result, 422 int use_meta 423 EVENTLIST_2nd(_nc_eventlist * evl)) 424 { 425 SCREEN *sp; 426 int ch; 427 int rc = 0; 428 #ifdef NCURSES_WGETCH_EVENTS 429 int event_delay = -1; 430 #endif 431 432 T((T_CALLED("_nc_wgetch(%p)"), (void *) win)); 433 434 *result = 0; 435 436 sp = _nc_screen_of(win); 437 if (win == 0 || sp == 0) { 438 returnCode(ERR); 439 } 440 441 if (cooked_key_in_fifo()) { 442 recur_wrefresh(win); 443 *result = fifo_pull(sp); 444 returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK); 445 } 446 #ifdef NCURSES_WGETCH_EVENTS 447 if (evl && (evl->count == 0)) 448 evl = NULL; 449 event_delay = _nc_eventlist_timeout(evl); 450 #endif 451 452 /* 453 * Handle cooked mode. Grab a string from the screen, 454 * stuff its contents in the FIFO queue, and pop off 455 * the first character to return it. 456 */ 457 if (head == -1 && 458 !sp->_notty && 459 !sp->_raw && 460 !sp->_cbreak && 461 !sp->_called_wgetch) { 462 char buf[MAXCOLUMNS], *bufp; 463 464 TR(TRACE_IEVENT, ("filling queue in cooked mode")); 465 466 /* ungetch in reverse order */ 467 #ifdef NCURSES_WGETCH_EVENTS 468 rc = recur_wgetnstr(win, buf); 469 if (rc != KEY_EVENT && rc != ERR) 470 safe_ungetch(sp, '\n'); 471 #else 472 if (recur_wgetnstr(win, buf) != ERR) 473 safe_ungetch(sp, '\n'); 474 #endif 475 for (bufp = buf + strlen(buf); bufp > buf; bufp--) 476 safe_ungetch(sp, bufp[-1]); 477 478 #ifdef NCURSES_WGETCH_EVENTS 479 /* Return it first */ 480 if (rc == KEY_EVENT) { 481 *result = rc; 482 } else 483 #endif 484 *result = fifo_pull(sp); 485 returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK); 486 } 487 488 if (win->_use_keypad != sp->_keypad_on) 489 _nc_keypad(sp, win->_use_keypad); 490 491 recur_wrefresh(win); 492 493 if (win->_notimeout || (win->_delay >= 0) || (sp->_cbreak > 1)) { 494 if (head == -1) { /* fifo is empty */ 495 int delay; 496 497 TR(TRACE_IEVENT, ("timed delay in wgetch()")); 498 if (sp->_cbreak > 1) 499 delay = (sp->_cbreak - 1) * 100; 500 else if (win->_notimeout) 501 delay = 0; 502 else 503 delay = win->_delay; 504 505 #ifdef NCURSES_WGETCH_EVENTS 506 if (event_delay >= 0 && delay > event_delay) 507 delay = event_delay; 508 #endif 509 510 TR(TRACE_IEVENT, ("delay is %d milliseconds", delay)); 511 512 rc = check_mouse_activity(sp, delay EVENTLIST_2nd(evl)); 513 514 #ifdef NCURSES_WGETCH_EVENTS 515 if (rc & TW_EVENT) { 516 *result = KEY_EVENT; 517 returnCode(KEY_CODE_YES); 518 } 519 #endif 520 if (!rc) { 521 goto check_sigwinch; 522 } 523 } 524 /* else go on to read data available */ 525 } 526 527 if (win->_use_keypad) { 528 /* 529 * This is tricky. We only want to get special-key 530 * events one at a time. But we want to accumulate 531 * mouse events until either (a) the mouse logic tells 532 * us it's picked up a complete gesture, or (b) 533 * there's a detectable time lapse after one. 534 * 535 * Note: if the mouse code starts failing to compose 536 * press/release events into clicks, you should probably 537 * increase the wait with mouseinterval(). 538 */ 539 int runcount = 0; 540 541 do { 542 ch = kgetch(sp EVENTLIST_2nd(evl)); 543 if (ch == KEY_MOUSE) { 544 ++runcount; 545 if (sp->_mouse_inline(sp)) 546 break; 547 } 548 if (sp->_maxclick < 0) 549 break; 550 } while 551 (ch == KEY_MOUSE 552 && (((rc = check_mouse_activity(sp, sp->_maxclick 553 EVENTLIST_2nd(evl))) != 0 554 && !(rc & TW_EVENT)) 555 || !sp->_mouse_parse(sp, runcount))); 556 #ifdef NCURSES_WGETCH_EVENTS 557 if ((rc & TW_EVENT) && !(ch == KEY_EVENT)) { 558 safe_ungetch(sp, ch); 559 ch = KEY_EVENT; 560 } 561 #endif 562 if (runcount > 0 && ch != KEY_MOUSE) { 563 #ifdef NCURSES_WGETCH_EVENTS 564 /* mouse event sequence ended by an event, report event */ 565 if (ch == KEY_EVENT) { 566 safe_ungetch(sp, KEY_MOUSE); /* FIXME This interrupts a gesture... */ 567 } else 568 #endif 569 { 570 /* mouse event sequence ended by keystroke, store keystroke */ 571 safe_ungetch(sp, ch); 572 ch = KEY_MOUSE; 573 } 574 } 575 } else { 576 if (head == -1) 577 fifo_push(sp EVENTLIST_2nd(evl)); 578 ch = fifo_pull(sp); 579 } 580 581 if (ch == ERR) { 582 check_sigwinch: 583 #if USE_SIZECHANGE 584 if (_nc_handle_sigwinch(sp)) { 585 _nc_update_screensize(sp); 586 /* resizeterm can push KEY_RESIZE */ 587 if (cooked_key_in_fifo()) { 588 *result = fifo_pull(sp); 589 /* 590 * Get the ERR from queue -- it is from WINCH, 591 * so we should take it out, the "error" is handled. 592 */ 593 if (fifo_peek(sp) == -1) 594 fifo_pull(sp); 595 returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK); 596 } 597 } 598 #endif 599 returnCode(ERR); 600 } 601 602 /* 603 * If echo() is in effect, display the printable version of the 604 * key on the screen. Carriage return and backspace are treated 605 * specially by Solaris curses: 606 * 607 * If carriage return is defined as a function key in the 608 * terminfo, e.g., kent, then Solaris may return either ^J (or ^M 609 * if nonl() is set) or KEY_ENTER depending on the echo() mode. 610 * We echo before translating carriage return based on nonl(), 611 * since the visual result simply moves the cursor to column 0. 612 * 613 * Backspace is a different matter. Solaris curses does not 614 * translate it to KEY_BACKSPACE if kbs=^H. This does not depend 615 * on the stty modes, but appears to be a hardcoded special case. 616 * This is a difference from ncurses, which uses the terminfo entry. 617 * However, we provide the same visual result as Solaris, moving the 618 * cursor to the left. 619 */ 620 if (sp->_echo && !(win->_flags & _ISPAD)) { 621 chtype backup = (chtype) ((ch == KEY_BACKSPACE) ? '\b' : ch); 622 if (backup < KEY_MIN) 623 wechochar(win, backup); 624 } 625 626 /* 627 * Simulate ICRNL mode 628 */ 629 if ((ch == '\r') && sp->_nl) 630 ch = '\n'; 631 632 /* Strip 8th-bit if so desired. We do this only for characters that 633 * are in the range 128-255, to provide compatibility with terminals 634 * that display only 7-bit characters. Note that 'ch' may be a 635 * function key at this point, so we mustn't strip _those_. 636 */ 637 if (!use_meta) 638 if ((ch < KEY_MIN) && (ch & 0x80)) 639 ch &= 0x7f; 640 641 T(("wgetch returning : %s", _nc_tracechar(sp, ch))); 642 643 *result = ch; 644 returnCode(ch >= KEY_MIN ? KEY_CODE_YES : OK); 645 } 646 647 #ifdef NCURSES_WGETCH_EVENTS 648 NCURSES_EXPORT(int) 649 wgetch_events(WINDOW *win, _nc_eventlist * evl) 650 { 651 int code; 652 int value; 653 654 T((T_CALLED("wgetch_events(%p,%p)"), (void *) win, (void *)evl)); 655 code = _nc_wgetch(win, 656 &value, 657 _nc_use_meta(win) 658 EVENTLIST_2nd(evl)); 659 if (code != ERR) 660 code = value; 661 returnCode(code); 662 } 663 #endif 664 665 NCURSES_EXPORT(int) 666 wgetch(WINDOW *win) 667 { 668 int code; 669 int value; 670 671 T((T_CALLED("wgetch(%p)"), (void *) win)); 672 code = _nc_wgetch(win, 673 &value, 674 _nc_use_meta(win) 675 EVENTLIST_2nd((_nc_eventlist *) 0)); 676 if (code != ERR) 677 code = value; 678 returnCode(code); 679 } 680 681 /* 682 ** int 683 ** kgetch() 684 ** 685 ** Get an input character, but take care of keypad sequences, returning 686 ** an appropriate code when one matches the input. After each character 687 ** is received, set an alarm call based on ESCDELAY. If no more of the 688 ** sequence is received by the time the alarm goes off, pass through 689 ** the sequence gotten so far. 690 ** 691 ** This function must be called when there are no cooked keys in queue. 692 ** (that is head==-1 || peek==head) 693 ** 694 */ 695 696 static int 697 kgetch(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl)) 698 { 699 TRIES *ptr; 700 int ch = 0; 701 int timeleft = GetEscdelay(sp); 702 703 TR(TRACE_IEVENT, ("kgetch() called")); 704 705 ptr = sp->_keytry; 706 707 for (;;) { 708 if (cooked_key_in_fifo() && sp->_fifo[head] >= KEY_MIN) { 709 break; 710 } else if (!raw_key_in_fifo()) { 711 ch = fifo_push(sp EVENTLIST_2nd(evl)); 712 if (ch == ERR) { 713 peek = head; /* the keys stay uninterpreted */ 714 return ERR; 715 } 716 #ifdef NCURSES_WGETCH_EVENTS 717 else if (ch == KEY_EVENT) { 718 peek = head; /* the keys stay uninterpreted */ 719 return fifo_pull(sp); /* Remove KEY_EVENT from the queue */ 720 } 721 #endif 722 } 723 724 ch = fifo_peek(sp); 725 if (ch >= KEY_MIN) { 726 /* If not first in queue, somebody put this key there on purpose in 727 * emergency. Consider it higher priority than the unfinished 728 * keysequence we are parsing. 729 */ 730 peek = head; 731 /* assume the key is the last in fifo */ 732 t_dec(); /* remove the key */ 733 return ch; 734 } 735 736 TR(TRACE_IEVENT, ("ch: %s", _nc_tracechar(sp, (unsigned char) ch))); 737 while ((ptr != NULL) && (ptr->ch != (unsigned char) ch)) 738 ptr = ptr->sibling; 739 740 if (ptr == NULL) { 741 TR(TRACE_IEVENT, ("ptr is null")); 742 break; 743 } 744 TR(TRACE_IEVENT, ("ptr=%p, ch=%d, value=%d", 745 (void *) ptr, ptr->ch, ptr->value)); 746 747 if (ptr->value != 0) { /* sequence terminated */ 748 TR(TRACE_IEVENT, ("end of sequence")); 749 if (peek == tail) { 750 fifo_clear(sp); 751 } else { 752 head = peek; 753 } 754 return (ptr->value); 755 } 756 757 ptr = ptr->child; 758 759 if (!raw_key_in_fifo()) { 760 int rc; 761 762 TR(TRACE_IEVENT, ("waiting for rest of sequence")); 763 rc = check_mouse_activity(sp, timeleft EVENTLIST_2nd(evl)); 764 #ifdef NCURSES_WGETCH_EVENTS 765 if (rc & TW_EVENT) { 766 TR(TRACE_IEVENT, ("interrupted by a user event")); 767 /* FIXME Should have preserved remainder timeleft for reuse... */ 768 peek = head; /* Restart interpreting later */ 769 return KEY_EVENT; 770 } 771 #endif 772 if (!rc) { 773 TR(TRACE_IEVENT, ("ran out of time")); 774 break; 775 } 776 } 777 } 778 ch = fifo_pull(sp); 779 peek = head; 780 return ch; 781 } 782