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