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