10e3d5408SPeter Wemm /****************************************************************************
2d8977eafSRong-En Fan  * Copyright 2018-2019,2020 Thomas E. Dickey                                *
30e3d5408SPeter Wemm  * Copyright 1998-2015,2016 Free Software Foundation, Inc.                  *
40e3d5408SPeter Wemm  *                                                                          *
50e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
60e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
70e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
80e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
90e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
100e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
110e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
120e3d5408SPeter Wemm  *                                                                          *
130e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
140e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
150e3d5408SPeter Wemm  *                                                                          *
160e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
170e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
180e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
190e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
200e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
210e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
220e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
230e3d5408SPeter Wemm  *                                                                          *
240e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
250e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
260e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
270e3d5408SPeter Wemm  * authorization.                                                           *
280e3d5408SPeter Wemm  ****************************************************************************/
290e3d5408SPeter Wemm 
300e3d5408SPeter Wemm /****************************************************************************
310e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
324a1a9510SRong-En Fan  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
330e3d5408SPeter Wemm  *     and: Thomas E. Dickey                        1996-on                 *
340e3d5408SPeter Wemm  *     and: Juergen Pfeifer                         2009                    *
350e3d5408SPeter Wemm  ****************************************************************************/
360e3d5408SPeter Wemm 
370e3d5408SPeter Wemm /*
380e3d5408SPeter Wemm **	lib_getch.c
390e3d5408SPeter Wemm **
400e3d5408SPeter Wemm **	The routine getch().
410e3d5408SPeter Wemm **
420e3d5408SPeter Wemm */
430e3d5408SPeter Wemm 
445d08fb1fSRong-En Fan #define NEED_KEY_EVENT
450e3d5408SPeter Wemm #include <curses.priv.h>
460e3d5408SPeter Wemm 
470e3d5408SPeter Wemm MODULE_ID("$Id: lib_getch.c,v 1.141 2020/09/05 22:50:47 tom Exp $")
485ca44d1cSRong-En Fan 
49aa59d4d4SRong-En Fan #include <fifo_defs.h>
505ca44d1cSRong-En Fan 
515ca44d1cSRong-En Fan #if USE_REENTRANT
525ca44d1cSRong-En Fan #define GetEscdelay(sp) *_nc_ptr_Escdelay(sp)
NCURSES_EXPORT(int)53aa59d4d4SRong-En Fan NCURSES_EXPORT(int)
545ca44d1cSRong-En Fan NCURSES_PUBLIC_VAR(ESCDELAY) (void)
555ca44d1cSRong-En Fan {
56aa59d4d4SRong-En Fan     return *(_nc_ptr_Escdelay(CURRENT_SCREEN));
577a69bbfbSPeter Wemm }
587a69bbfbSPeter Wemm 
595ca44d1cSRong-En Fan NCURSES_EXPORT(int *)
_nc_ptr_Escdelay(SCREEN * sp)600e3d5408SPeter Wemm _nc_ptr_Escdelay(SCREEN *sp)
61d8977eafSRong-En Fan {
62d8977eafSRong-En Fan     return ptrEscdelay(sp);
63d8977eafSRong-En Fan }
64d8977eafSRong-En Fan #else
65d8977eafSRong-En Fan #define GetEscdelay(sp) ESCDELAY
66d8977eafSRong-En Fan NCURSES_EXPORT_VAR(int) ESCDELAY = 1000;
67d8977eafSRong-En Fan #endif
68d8977eafSRong-En Fan 
69d8977eafSRong-En Fan #if NCURSES_EXT_FUNCS
70d8977eafSRong-En Fan NCURSES_EXPORT(int)
NCURSES_SP_NAME(set_escdelay)71d8977eafSRong-En Fan NCURSES_SP_NAME(set_escdelay) (NCURSES_SP_DCLx int value)
72d8977eafSRong-En Fan {
73d8977eafSRong-En Fan     int code = OK;
74d8977eafSRong-En Fan     if (value < 0) {
75d8977eafSRong-En Fan 	code = ERR;
76d8977eafSRong-En Fan     } else {
77d8977eafSRong-En Fan #if USE_REENTRANT
78d8977eafSRong-En Fan 	if (SP_PARM) {
795d08fb1fSRong-En Fan 	    SET_ESCDELAY(value);
805d08fb1fSRong-En Fan 	} else {
815d08fb1fSRong-En Fan 	    code = ERR;
825d08fb1fSRong-En Fan 	}
835d08fb1fSRong-En Fan #else
845d08fb1fSRong-En Fan 	(void) SP_PARM;
855d08fb1fSRong-En Fan 	ESCDELAY = value;
864a1a9510SRong-En Fan #endif
874a1a9510SRong-En Fan     }
884a1a9510SRong-En Fan     return code;
894a1a9510SRong-En Fan }
904a1a9510SRong-En Fan 
914a1a9510SRong-En Fan #if NCURSES_SP_FUNCS
924a1a9510SRong-En Fan NCURSES_EXPORT(int)
set_escdelay(int value)934a1a9510SRong-En Fan set_escdelay(int value)
944a1a9510SRong-En Fan {
954a1a9510SRong-En Fan     int code;
96aa59d4d4SRong-En Fan     if (value < 0) {
974a1a9510SRong-En Fan 	code = ERR;
984a1a9510SRong-En Fan     } else {
994a1a9510SRong-En Fan #if USE_REENTRANT
1004a1a9510SRong-En Fan 	code = NCURSES_SP_NAME(set_escdelay) (CURRENT_SCREEN, value);
101aa59d4d4SRong-En Fan #else
102aa59d4d4SRong-En Fan 	ESCDELAY = value;
1034a1a9510SRong-En Fan 	code = OK;
1044a1a9510SRong-En Fan #endif
1054a1a9510SRong-En Fan     }
106aa59d4d4SRong-En Fan     return code;
1074a1a9510SRong-En Fan }
108aa59d4d4SRong-En Fan #endif
109aa59d4d4SRong-En Fan #endif /* NCURSES_EXT_FUNCS */
1104a1a9510SRong-En Fan 
1114a1a9510SRong-En Fan #if NCURSES_EXT_FUNCS
1124a1a9510SRong-En Fan NCURSES_EXPORT(int)
NCURSES_SP_NAME(get_escdelay)1134a1a9510SRong-En Fan NCURSES_SP_NAME(get_escdelay) (NCURSES_SP_DCL0)
1144a1a9510SRong-En Fan {
1154a1a9510SRong-En Fan #if !USE_REENTRANT
1164a1a9510SRong-En Fan     (void) SP_PARM;
1174a1a9510SRong-En Fan #endif
1184a1a9510SRong-En Fan     return GetEscdelay(SP_PARM);
119aa59d4d4SRong-En Fan }
1200e3d5408SPeter Wemm 
121aa59d4d4SRong-En Fan #if NCURSES_SP_FUNCS
12218259542SPeter Wemm NCURSES_EXPORT(int)
get_escdelay(void)1230e3d5408SPeter Wemm get_escdelay(void)
1240e3d5408SPeter Wemm {
1250e3d5408SPeter Wemm     return NCURSES_SP_NAME(get_escdelay) (CURRENT_SCREEN);
1260e3d5408SPeter Wemm }
1270e3d5408SPeter Wemm #endif
1284a1a9510SRong-En Fan #endif /* NCURSES_EXT_FUNCS */
129aa59d4d4SRong-En Fan 
1300e3d5408SPeter Wemm static int
_nc_use_meta(WINDOW * win)1310e3d5408SPeter Wemm _nc_use_meta(WINDOW *win)
132aa59d4d4SRong-En Fan {
1335d08fb1fSRong-En Fan     SCREEN *sp = _nc_screen_of(win);
1340e3d5408SPeter Wemm     return (sp ? sp->_use_meta : 0);
13515589c42SPeter Wemm }
1360e3d5408SPeter Wemm 
1370e3d5408SPeter Wemm #ifdef USE_TERM_DRIVER
13815589c42SPeter Wemm # if defined(_NC_WINDOWS) && !defined(EXP_WIN32_DRIVER)
1390e3d5408SPeter Wemm static HANDLE
_nc_get_handle(int fd)1400e3d5408SPeter Wemm _nc_get_handle(int fd)
1410e3d5408SPeter Wemm {
1425ca44d1cSRong-En Fan     intptr_t value = _get_osfhandle(fd);
143aa59d4d4SRong-En Fan     return (HANDLE) value;
1445ca44d1cSRong-En Fan }
1455ca44d1cSRong-En Fan # endif
1460e3d5408SPeter Wemm #endif
1470e3d5408SPeter Wemm 
1480e3d5408SPeter Wemm /*
1490e3d5408SPeter Wemm  * Check for mouse activity, returning nonzero if we find any.
1504a1a9510SRong-En Fan  */
151aa59d4d4SRong-En Fan static int
check_mouse_activity(SCREEN * sp,int delay EVENTLIST_2nd (_nc_eventlist * evl))1520e3d5408SPeter Wemm check_mouse_activity(SCREEN *sp, int delay EVENTLIST_2nd(_nc_eventlist * evl))
1530e3d5408SPeter Wemm {
1544a1a9510SRong-En Fan     int rc;
1554a1a9510SRong-En Fan 
1560e3d5408SPeter Wemm #ifdef USE_TERM_DRIVER
1574a1a9510SRong-En Fan     TERMINAL_CONTROL_BLOCK *TCB = TCBOf(sp);
15815589c42SPeter Wemm     rc = TCBOf(sp)->drv->td_testmouse(TCBOf(sp), delay EVENTLIST_2nd(evl));
15915589c42SPeter Wemm # if defined(EXP_WIN32_DRIVER)
1600e3d5408SPeter Wemm     /* if we emulate terminfo on console, we have to use the console routine */
1610e3d5408SPeter Wemm     if (IsTermInfoOnConsole(sp)) {
1620e3d5408SPeter Wemm 	rc = _nc_console_testmouse(sp,
1630e3d5408SPeter Wemm 				   _nc_console_handle(sp->_ifd),
1640e3d5408SPeter Wemm 				   delay EVENTLIST_2nd(evl));
1650e3d5408SPeter Wemm     } else
1664a1a9510SRong-En Fan # elif defined(_NC_WINDOWS)
1674a1a9510SRong-En Fan     /* if we emulate terminfo on console, we have to use the console routine */
1684a1a9510SRong-En Fan     if (IsTermInfoOnConsole(sp)) {
169aa59d4d4SRong-En Fan 	HANDLE fd = _nc_get_handle(sp->_ifd);
1704a1a9510SRong-En Fan 	rc = _nc_mingw_testmouse(sp, fd, delay EVENTLIST_2nd(evl));
1714a1a9510SRong-En Fan     } else
172aa59d4d4SRong-En Fan # endif
1734a1a9510SRong-En Fan 	rc = TCB->drv->td_testmouse(TCB, delay EVENTLIST_2nd(evl));
1744a1a9510SRong-En Fan #else /* !USE_TERM_DRIVER */
1754a1a9510SRong-En Fan # if USE_SYSMOUSE
1764a1a9510SRong-En Fan     if ((sp->_mouse_type == M_SYSMOUSE)
1774a1a9510SRong-En Fan 	&& (sp->_sysmouse_head < sp->_sysmouse_tail)) {
178aa59d4d4SRong-En Fan 	rc = TW_MOUSE;
1794a1a9510SRong-En Fan     } else
1804a1a9510SRong-En Fan # endif
1814a1a9510SRong-En Fan     {
182aa59d4d4SRong-En Fan # if defined(EXP_WIN32_DRIVER)
183aa59d4d4SRong-En Fan 	rc = _nc_console_testmouse(sp,
1844a1a9510SRong-En Fan 				   _nc_console_handle(sp->_ifd),
1854a1a9510SRong-En Fan 				   delay
1864a1a9510SRong-En Fan 				   EVENTLIST_2nd(evl));
1874a1a9510SRong-En Fan # else
188aa59d4d4SRong-En Fan 	rc = _nc_timed_wait(sp,
189aa59d4d4SRong-En Fan 			    TWAIT_MASK,
1900e3d5408SPeter Wemm 			    delay,
1910e3d5408SPeter Wemm 			    (int *) 0
1920e3d5408SPeter Wemm 			    EVENTLIST_2nd(evl));
1930e3d5408SPeter Wemm # endif
1944a1a9510SRong-En Fan # if USE_SYSMOUSE
195aa59d4d4SRong-En Fan 	if ((sp->_mouse_type == M_SYSMOUSE)
196aa59d4d4SRong-En Fan 	    && (sp->_sysmouse_head < sp->_sysmouse_tail)
197aa59d4d4SRong-En Fan 	    && (rc == 0)
1984a1a9510SRong-En Fan 	    && (errno == EINTR)) {
1994a1a9510SRong-En Fan 	    rc |= TW_MOUSE;
200aa59d4d4SRong-En Fan 	}
2014a1a9510SRong-En Fan # endif
202aa59d4d4SRong-En Fan     }
2034a1a9510SRong-En Fan #endif /* USE_TERM_DRIVER */
2044a1a9510SRong-En Fan     return rc;
2054a1a9510SRong-En Fan }
2064a1a9510SRong-En Fan 
2074a1a9510SRong-En Fan static NCURSES_INLINE int
fifo_peek(SCREEN * sp)2080e3d5408SPeter Wemm fifo_peek(SCREEN *sp)
209aa59d4d4SRong-En Fan {
21039f2269fSPeter Wemm     int ch = (peek >= 0) ? sp->_fifo[peek] : ERR;
2110e3d5408SPeter Wemm     TR(TRACE_IEVENT, ("peeking at %d", peek));
2120e3d5408SPeter Wemm 
2130e3d5408SPeter Wemm     p_inc();
2140e3d5408SPeter Wemm     return ch;
2150e3d5408SPeter Wemm }
2160e3d5408SPeter Wemm 
2170e3d5408SPeter Wemm static NCURSES_INLINE int
fifo_pull(SCREEN * sp)2180e3d5408SPeter Wemm fifo_pull(SCREEN *sp)
2190e3d5408SPeter Wemm {
2200e3d5408SPeter Wemm     int ch = (head >= 0) ? sp->_fifo[head] : ERR;
2210e3d5408SPeter Wemm 
2220e3d5408SPeter Wemm     TR(TRACE_IEVENT, ("pulling %s from %d", _nc_tracechar(sp, ch), head));
2230e3d5408SPeter Wemm 
2240e3d5408SPeter Wemm     if (peek == head) {
2250e3d5408SPeter Wemm 	h_inc();
2260e3d5408SPeter Wemm 	peek = head;
22715589c42SPeter Wemm     } else {
228aa59d4d4SRong-En Fan 	h_inc();
22918259542SPeter Wemm     }
2300e3d5408SPeter Wemm 
23118259542SPeter Wemm #ifdef TRACE
2320e3d5408SPeter Wemm     if (USE_TRACEF(TRACE_IEVENT)) {
233aa59d4d4SRong-En Fan 	_nc_fifo_dump(sp);
234aa59d4d4SRong-En Fan 	_nc_unlock_global(tracef);
2350e3d5408SPeter Wemm     }
2360e3d5408SPeter Wemm #endif
2370e3d5408SPeter Wemm     return ch;
2385d08fb1fSRong-En Fan }
2390e3d5408SPeter Wemm 
2405ca44d1cSRong-En Fan static NCURSES_INLINE int
fifo_push(SCREEN * sp EVENTLIST_2nd (_nc_eventlist * evl))241aa59d4d4SRong-En Fan fifo_push(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl))
2425ca44d1cSRong-En Fan {
2435ca44d1cSRong-En Fan     int n;
2440e3d5408SPeter Wemm     int ch = 0;
2450e3d5408SPeter Wemm     int mask = 0;
2460e3d5408SPeter Wemm 
2470e3d5408SPeter Wemm     (void) mask;
2484a1a9510SRong-En Fan     if (tail < 0)
249aa59d4d4SRong-En Fan 	return ERR;
2500e3d5408SPeter Wemm 
251aa59d4d4SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
25215589c42SPeter Wemm     if (evl
25315589c42SPeter Wemm #if USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE
2540e3d5408SPeter Wemm 	|| (sp->_mouse_fd >= 0)
2550e3d5408SPeter Wemm #endif
256aa59d4d4SRong-En Fan 	) {
2570e3d5408SPeter Wemm 	mask = check_mouse_activity(sp, -1 EVENTLIST_2nd(evl));
2585d08fb1fSRong-En Fan     } else
2595d08fb1fSRong-En Fan 	mask = 0;
2605d08fb1fSRong-En Fan 
2615d08fb1fSRong-En Fan     if (mask & TW_EVENT) {
2625d08fb1fSRong-En Fan 	T(("fifo_push: ungetch KEY_EVENT"));
2635d08fb1fSRong-En Fan 	safe_ungetch(sp, KEY_EVENT);
2645d08fb1fSRong-En Fan 	return KEY_EVENT;
2655d08fb1fSRong-En Fan     }
2665d08fb1fSRong-En Fan #elif USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE
2675d08fb1fSRong-En Fan     if (sp->_mouse_fd >= 0) {
2685d08fb1fSRong-En Fan 	mask = check_mouse_activity(sp, -1 EVENTLIST_2nd(evl));
2695d08fb1fSRong-En Fan     }
2705d08fb1fSRong-En Fan #endif
2715d08fb1fSRong-En Fan 
2725d08fb1fSRong-En Fan #if USE_GPM_SUPPORT || USE_EMX_MOUSE
2735d08fb1fSRong-En Fan     if ((sp->_mouse_fd >= 0) && (mask & TW_MOUSE)) {
2745d08fb1fSRong-En Fan 	sp->_mouse_event(sp);
2755d08fb1fSRong-En Fan 	ch = KEY_MOUSE;
2765d08fb1fSRong-En Fan 	n = 1;
2775d08fb1fSRong-En Fan     } else
2785d08fb1fSRong-En Fan #endif
2795d08fb1fSRong-En Fan #if USE_SYSMOUSE
2805d08fb1fSRong-En Fan 	if ((sp->_mouse_type == M_SYSMOUSE)
2815d08fb1fSRong-En Fan 	    && (sp->_sysmouse_head < sp->_sysmouse_tail)) {
2825d08fb1fSRong-En Fan 	sp->_mouse_event(sp);
2835d08fb1fSRong-En Fan 	ch = KEY_MOUSE;
2845d08fb1fSRong-En Fan 	n = 1;
2855d08fb1fSRong-En Fan     } else if ((sp->_mouse_type == M_SYSMOUSE)
2865d08fb1fSRong-En Fan 	       && (mask <= 0) && errno == EINTR) {
2875d08fb1fSRong-En Fan 	sp->_mouse_event(sp);
2885d08fb1fSRong-En Fan 	ch = KEY_MOUSE;
2895d08fb1fSRong-En Fan 	n = 1;
2905d08fb1fSRong-En Fan     } else
2915d08fb1fSRong-En Fan #endif
2925d08fb1fSRong-En Fan #ifdef USE_TERM_DRIVER
2935d08fb1fSRong-En Fan 	if ((sp->_mouse_type == M_TERM_DRIVER)
2945d08fb1fSRong-En Fan 	    && (sp->_drv_mouse_head < sp->_drv_mouse_tail)) {
2955d08fb1fSRong-En Fan 	sp->_mouse_event(sp);
2965d08fb1fSRong-En Fan 	ch = KEY_MOUSE;
2975d08fb1fSRong-En Fan 	n = 1;
2985d08fb1fSRong-En Fan     } else
2995d08fb1fSRong-En Fan #endif
3005d08fb1fSRong-En Fan #if USE_KLIBC_KBD
3015d08fb1fSRong-En Fan     if (NC_ISATTY(sp->_ifd) && sp->_cbreak) {
3025d08fb1fSRong-En Fan 	ch = _read_kbd(0, 1, !sp->_raw);
3035d08fb1fSRong-En Fan 	n = (ch == -1) ? -1 : 1;
3045d08fb1fSRong-En Fan 	sp->_extended_key = (ch == 0);
3055d08fb1fSRong-En Fan     } else
3065d08fb1fSRong-En Fan #endif
3075d08fb1fSRong-En Fan     {				/* Can block... */
3085d08fb1fSRong-En Fan #if defined(USE_TERM_DRIVER)
3095d08fb1fSRong-En Fan 	int buf;
3105d08fb1fSRong-En Fan # if defined(EXP_WIN32_DRIVER)
3110e3d5408SPeter Wemm 	if (NC_ISATTY(sp->_ifd) && IsTermInfoOnConsole(sp) && sp->_cbreak) {
3127a69bbfbSPeter Wemm #  if USE_PTHREADS_EINTR
3134a1a9510SRong-En Fan 	    if ((pthread_self) && (pthread_kill) && (pthread_equal))
3144a1a9510SRong-En Fan 		_nc_globals.read_thread = pthread_self();
3154a1a9510SRong-En Fan #  endif
3164a1a9510SRong-En Fan 	    n = _nc_console_read(sp,
3170e3d5408SPeter Wemm 				 _nc_console_handle(sp->_ifd),
3185d08fb1fSRong-En Fan 				 &buf);
3190e3d5408SPeter Wemm #  if USE_PTHREADS_EINTR
3204a1a9510SRong-En Fan 	    _nc_globals.read_thread = 0;
3214a1a9510SRong-En Fan #  endif
3224a1a9510SRong-En Fan 	} else
3230e3d5408SPeter Wemm # elif defined(_NC_WINDOWS)
3244a1a9510SRong-En Fan 	if (NC_ISATTY(sp->_ifd) && IsTermInfoOnConsole(sp) && sp->_cbreak)
3250e3d5408SPeter Wemm 	    n = _nc_mingw_console_read(sp,
32639f2269fSPeter Wemm 				       _nc_get_handle(sp->_ifd),
3275d08fb1fSRong-En Fan 				       &buf);
3285d08fb1fSRong-En Fan 	else
329aa59d4d4SRong-En Fan # endif	/* EXP_WIN32_DRIVER */
3300e3d5408SPeter Wemm 	    n = CallDriver_1(sp, td_read, &buf);
3315ca44d1cSRong-En Fan 	ch = buf;
3320e3d5408SPeter Wemm #else /* !USE_TERM_DRIVER */
33315589c42SPeter Wemm #if defined(EXP_WIN32_DRIVER)
3345d08fb1fSRong-En Fan 	int buf;
335aa59d4d4SRong-En Fan #endif
3365ca44d1cSRong-En Fan 	unsigned char c2 = 0;
3370e3d5408SPeter Wemm #if USE_PTHREADS_EINTR
3384a1a9510SRong-En Fan #if USE_WEAK_SYMBOLS
3394a1a9510SRong-En Fan 	if ((pthread_self) && (pthread_kill) && (pthread_equal))
3404a1a9510SRong-En Fan #endif
3414a1a9510SRong-En Fan 	    _nc_globals.read_thread = pthread_self();
3424a1a9510SRong-En Fan #endif
3430e3d5408SPeter Wemm #if defined(EXP_WIN32_DRIVER)
3440e3d5408SPeter Wemm 	n = _nc_console_read(sp,
3450e3d5408SPeter Wemm 			     _nc_console_handle(sp->_ifd),
3460e3d5408SPeter Wemm 			     &buf);
3470e3d5408SPeter Wemm 	c2 = buf;
3480e3d5408SPeter Wemm #else
3494a1a9510SRong-En Fan 	n = (int) read(sp->_ifd, &c2, (size_t) 1);
350aa59d4d4SRong-En Fan #endif
351aa59d4d4SRong-En Fan #if USE_PTHREADS_EINTR
352aa59d4d4SRong-En Fan 	_nc_globals.read_thread = 0;
353aa59d4d4SRong-En Fan #endif
354aa59d4d4SRong-En Fan 	ch = c2;
3554a1a9510SRong-En Fan #endif /* USE_TERM_DRIVER */
3560e3d5408SPeter Wemm     }
35718259542SPeter Wemm 
3580e3d5408SPeter Wemm     if ((n == -1) || (n == 0)) {
3595d08fb1fSRong-En Fan 	TR(TRACE_IEVENT, ("read(%d,&ch,1)=%d, errno=%d", sp->_ifd, n, errno));
3600e3d5408SPeter Wemm 	ch = ERR;
3610e3d5408SPeter Wemm     }
3624a1a9510SRong-En Fan     TR(TRACE_IEVENT, ("read %d characters", n));
3634a1a9510SRong-En Fan 
3644a1a9510SRong-En Fan     sp->_fifo[tail] = ch;
365aa59d4d4SRong-En Fan     sp->_fifohold = 0;
366aa59d4d4SRong-En Fan     if (head == -1)
367aa59d4d4SRong-En Fan 	head = peek = tail;
3680e3d5408SPeter Wemm     t_inc();
3694a1a9510SRong-En Fan     TR(TRACE_IEVENT, ("pushed %s at %d", _nc_tracechar(sp, ch), tail));
3704a1a9510SRong-En Fan #ifdef TRACE
3714a1a9510SRong-En Fan     if (USE_TRACEF(TRACE_IEVENT)) {
3724a1a9510SRong-En Fan 	_nc_fifo_dump(sp);
3735ca44d1cSRong-En Fan 	_nc_unlock_global(tracef);
3744a1a9510SRong-En Fan     }
375aa59d4d4SRong-En Fan #endif
3765ca44d1cSRong-En Fan     return ch;
3770e3d5408SPeter Wemm }
3780e3d5408SPeter Wemm 
379aa59d4d4SRong-En Fan static NCURSES_INLINE void
fifo_clear(SCREEN * sp)380aa59d4d4SRong-En Fan fifo_clear(SCREEN *sp)
38139f2269fSPeter Wemm {
3825d08fb1fSRong-En Fan     memset(sp->_fifo, 0, sizeof(sp->_fifo));
3830e3d5408SPeter Wemm     head = -1;
3845d08fb1fSRong-En Fan     tail = peek = 0;
3854a1a9510SRong-En Fan }
3860e3d5408SPeter Wemm 
3874a1a9510SRong-En Fan static int kgetch(SCREEN *, bool EVENTLIST_2nd(_nc_eventlist *));
3880e3d5408SPeter Wemm 
38918259542SPeter Wemm static void
recur_wrefresh(WINDOW * win)390aa59d4d4SRong-En Fan recur_wrefresh(WINDOW *win)
391aa59d4d4SRong-En Fan {
3920e3d5408SPeter Wemm #ifdef USE_PTHREADS
3930e3d5408SPeter Wemm     SCREEN *sp = _nc_screen_of(win);
3940e3d5408SPeter Wemm     if (_nc_use_pthreads && sp != CURRENT_SCREEN) {
3954a1a9510SRong-En Fan 	SCREEN *save_SP;
3964a1a9510SRong-En Fan 
3974a1a9510SRong-En Fan 	/* temporarily switch to the window's screen to check/refresh */
3984a1a9510SRong-En Fan 	_nc_lock_global(curses);
3994a1a9510SRong-En Fan 	save_SP = CURRENT_SCREEN;
40018259542SPeter Wemm 	_nc_set_screen(sp);
4010e3d5408SPeter Wemm 	recur_wrefresh(win);
402aa59d4d4SRong-En Fan 	_nc_set_screen(save_SP);
4034a1a9510SRong-En Fan 	_nc_unlock_global(curses);
4044a1a9510SRong-En Fan     } else
4054a1a9510SRong-En Fan #endif
4064a1a9510SRong-En Fan 	if ((is_wintouched(win) || (win->_flags & _HASMOVED))
4075ca44d1cSRong-En Fan 	    && !(win->_flags & _ISPAD)) {
4084a1a9510SRong-En Fan 	wrefresh(win);
4094a1a9510SRong-En Fan     }
4105d08fb1fSRong-En Fan }
4110e3d5408SPeter Wemm 
4124a1a9510SRong-En Fan static int
recur_wgetnstr(WINDOW * win,char * buf)4135d08fb1fSRong-En Fan recur_wgetnstr(WINDOW *win, char *buf)
4140e3d5408SPeter Wemm {
4150e3d5408SPeter Wemm     SCREEN *sp = _nc_screen_of(win);
4160e3d5408SPeter Wemm     int rc;
41715589c42SPeter Wemm 
4180e3d5408SPeter Wemm     if (sp != 0) {
4190e3d5408SPeter Wemm #ifdef USE_PTHREADS
4200e3d5408SPeter Wemm 	if (_nc_use_pthreads && sp != CURRENT_SCREEN) {
4210e3d5408SPeter Wemm 	    SCREEN *save_SP;
4220e3d5408SPeter Wemm 
4230e3d5408SPeter Wemm 	    /* temporarily switch to the window's screen to get cooked input */
4240e3d5408SPeter Wemm 	    _nc_lock_global(curses);
4250e3d5408SPeter Wemm 	    save_SP = CURRENT_SCREEN;
4260e3d5408SPeter Wemm 	    _nc_set_screen(sp);
4270e3d5408SPeter Wemm 	    rc = recur_wgetnstr(win, buf);
4280e3d5408SPeter Wemm 	    _nc_set_screen(save_SP);
4290e3d5408SPeter Wemm 	    _nc_unlock_global(curses);
4304a1a9510SRong-En Fan 	} else
4310e3d5408SPeter Wemm #endif
4320e3d5408SPeter Wemm 	{
433aa59d4d4SRong-En Fan 	    sp->_called_wgetch = TRUE;
43415589c42SPeter Wemm 	    rc = wgetnstr(win, buf, MAXCOLUMNS);
4350e3d5408SPeter Wemm 	    sp->_called_wgetch = FALSE;
436aa59d4d4SRong-En Fan 	}
4370e3d5408SPeter Wemm     } else {
4380e3d5408SPeter Wemm 	rc = ERR;
439aa59d4d4SRong-En Fan     }
44039f2269fSPeter Wemm     return rc;
4410e3d5408SPeter Wemm }
4420e3d5408SPeter Wemm 
443aa59d4d4SRong-En Fan NCURSES_EXPORT(int)
_nc_wgetch(WINDOW * win,int * result,int use_meta EVENTLIST_2nd (_nc_eventlist * evl))4444a1a9510SRong-En Fan _nc_wgetch(WINDOW *win,
4454a1a9510SRong-En Fan 	   int *result,
4465d08fb1fSRong-En Fan 	   int use_meta
4474a1a9510SRong-En Fan 	   EVENTLIST_2nd(_nc_eventlist * evl))
4484a1a9510SRong-En Fan {
449aa59d4d4SRong-En Fan     SCREEN *sp;
4504a1a9510SRong-En Fan     int ch;
4514a1a9510SRong-En Fan     int rc = 0;
4524a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
45315589c42SPeter Wemm     int event_delay = -1;
4544a1a9510SRong-En Fan #endif
4554a1a9510SRong-En Fan 
4564a1a9510SRong-En Fan     T((T_CALLED("_nc_wgetch(%p)"), (void *) win));
457aa59d4d4SRong-En Fan 
4584a1a9510SRong-En Fan     *result = 0;
4594a1a9510SRong-En Fan 
4604a1a9510SRong-En Fan     sp = _nc_screen_of(win);
4614a1a9510SRong-En Fan     if (win == 0 || sp == 0) {
462aa59d4d4SRong-En Fan 	returnCode(ERR);
4630e3d5408SPeter Wemm     }
4640e3d5408SPeter Wemm 
4654a1a9510SRong-En Fan     if (cooked_key_in_fifo()) {
4660e3d5408SPeter Wemm 	recur_wrefresh(win);
4670e3d5408SPeter Wemm 	*result = fifo_pull(sp);
468aa59d4d4SRong-En Fan 	returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
469aa59d4d4SRong-En Fan     }
4700e3d5408SPeter Wemm #ifdef NCURSES_WGETCH_EVENTS
4710e3d5408SPeter Wemm     if (evl && (evl->count == 0))
47215589c42SPeter Wemm 	evl = NULL;
4730e3d5408SPeter Wemm     event_delay = _nc_eventlist_timeout(evl);
474aa59d4d4SRong-En Fan #endif
475aa59d4d4SRong-En Fan 
4760e3d5408SPeter Wemm     /*
47715589c42SPeter Wemm      * Handle cooked mode.  Grab a string from the screen,
478aa59d4d4SRong-En Fan      * stuff its contents in the FIFO queue, and pop off
4794ee07662SRong-En Fan      * the first character to return it.
4804ee07662SRong-En Fan      */
4814ee07662SRong-En Fan     if (head == -1 &&
4824ee07662SRong-En Fan 	!sp->_notty &&
4834ee07662SRong-En Fan 	!sp->_raw &&
4844ee07662SRong-En Fan 	!sp->_cbreak &&
485b82face1SPeter Wemm 	!sp->_called_wgetch) {
4860e3d5408SPeter Wemm 	char buf[MAXCOLUMNS], *bufp;
4870e3d5408SPeter Wemm 
4880e3d5408SPeter Wemm 	TR(TRACE_IEVENT, ("filling queue in cooked mode"));
4890e3d5408SPeter Wemm 
4900e3d5408SPeter Wemm 	/* ungetch in reverse order */
4910e3d5408SPeter Wemm #ifdef NCURSES_WGETCH_EVENTS
4920e3d5408SPeter Wemm 	rc = recur_wgetnstr(win, buf);
49315589c42SPeter Wemm 	if (rc != KEY_EVENT && rc != ERR)
49415589c42SPeter Wemm 	    safe_ungetch(sp, '\n');
49515589c42SPeter Wemm #else
49615589c42SPeter Wemm 	if (recur_wgetnstr(win, buf) != ERR)
49715589c42SPeter Wemm 	    safe_ungetch(sp, '\n');
49815589c42SPeter Wemm #endif
49915589c42SPeter Wemm 	for (bufp = buf + strlen(buf); bufp > buf; bufp--)
50015589c42SPeter Wemm 	    safe_ungetch(sp, bufp[-1]);
50115589c42SPeter Wemm 
50215589c42SPeter Wemm #ifdef NCURSES_WGETCH_EVENTS
50315589c42SPeter Wemm 	/* Return it first */
50415589c42SPeter Wemm 	if (rc == KEY_EVENT) {
50515589c42SPeter Wemm 	    *result = rc;
50615589c42SPeter Wemm 	} else
50715589c42SPeter Wemm #endif
50815589c42SPeter Wemm 	    *result = fifo_pull(sp);
50915589c42SPeter Wemm 	returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
510aa59d4d4SRong-En Fan     }
51115589c42SPeter Wemm 
51215589c42SPeter Wemm     if (win->_use_keypad != sp->_keypad_on)
51315589c42SPeter Wemm 	_nc_keypad(sp, win->_use_keypad);
51415589c42SPeter Wemm 
51515589c42SPeter Wemm     recur_wrefresh(win);
51615589c42SPeter Wemm 
5170e3d5408SPeter Wemm     if (win->_notimeout || (win->_delay >= 0) || (sp->_cbreak > 1)) {
5180e3d5408SPeter Wemm 	if (head == -1) {	/* fifo is empty */
519aa59d4d4SRong-En Fan 	    int delay;
5200e3d5408SPeter Wemm 
5210e3d5408SPeter Wemm 	    TR(TRACE_IEVENT, ("timed delay in wgetch()"));
5220e3d5408SPeter Wemm 	    if (sp->_cbreak > 1)
5230e3d5408SPeter Wemm 		delay = (sp->_cbreak - 1) * 100;
5240e3d5408SPeter Wemm 	    else
5250e3d5408SPeter Wemm 		delay = win->_delay;
5260e3d5408SPeter Wemm 
52739f2269fSPeter Wemm #ifdef NCURSES_WGETCH_EVENTS
5280e3d5408SPeter Wemm 	    if (event_delay >= 0 && delay > event_delay)
5290e3d5408SPeter Wemm 		delay = event_delay;
5300e3d5408SPeter Wemm #endif
5315d08fb1fSRong-En Fan 
5320e3d5408SPeter Wemm 	    TR(TRACE_IEVENT, ("delay is %d milliseconds", delay));
53339f2269fSPeter Wemm 
53439f2269fSPeter Wemm 	    rc = check_mouse_activity(sp, delay EVENTLIST_2nd(evl));
53539f2269fSPeter Wemm 
53639f2269fSPeter Wemm #ifdef NCURSES_WGETCH_EVENTS
5374a1a9510SRong-En Fan 	    if (rc & TW_EVENT) {
5384a1a9510SRong-En Fan 		*result = KEY_EVENT;
5394a1a9510SRong-En Fan 		returnCode(KEY_CODE_YES);
5404a1a9510SRong-En Fan 	    }
5414a1a9510SRong-En Fan #endif
5424a1a9510SRong-En Fan 	    if (!rc) {
5434a1a9510SRong-En Fan 		goto check_sigwinch;
5444a1a9510SRong-En Fan 	    }
5454a1a9510SRong-En Fan 	}
5464a1a9510SRong-En Fan 	/* else go on to read data available */
5475d08fb1fSRong-En Fan     }
5484a1a9510SRong-En Fan 
5494a1a9510SRong-En Fan     if (win->_use_keypad) {
5504a1a9510SRong-En Fan 	/*
5514a1a9510SRong-En Fan 	 * This is tricky.  We only want to get special-key
5524a1a9510SRong-En Fan 	 * events one at a time.  But we want to accumulate
5534a1a9510SRong-En Fan 	 * mouse events until either (a) the mouse logic tells
5544a1a9510SRong-En Fan 	 * us it's picked up a complete gesture, or (b)
55539f2269fSPeter Wemm 	 * there's a detectable time lapse after one.
55639f2269fSPeter Wemm 	 *
55739f2269fSPeter Wemm 	 * Note: if the mouse code starts failing to compose
55839f2269fSPeter Wemm 	 * press/release events into clicks, you should probably
55939f2269fSPeter Wemm 	 * increase the wait with mouseinterval().
56039f2269fSPeter Wemm 	 */
56139f2269fSPeter Wemm 	int runcount = 0;
5624a1a9510SRong-En Fan 
5634a1a9510SRong-En Fan 	do {
5645d08fb1fSRong-En Fan 	    ch = kgetch(sp, win->_notimeout EVENTLIST_2nd(evl));
5654a1a9510SRong-En Fan 	    if (ch == KEY_MOUSE) {
56639f2269fSPeter Wemm 		++runcount;
56739f2269fSPeter Wemm 		if (sp->_mouse_inline(sp))
56839f2269fSPeter Wemm 		    break;
5690e3d5408SPeter Wemm 	    }
5700e3d5408SPeter Wemm 	    if (sp->_maxclick < 0)
5710e3d5408SPeter Wemm 		break;
5720e3d5408SPeter Wemm 	} while
5730e3d5408SPeter Wemm 	    (ch == KEY_MOUSE
5740e3d5408SPeter Wemm 	     && (((rc = check_mouse_activity(sp, sp->_maxclick
5750e3d5408SPeter Wemm 					     EVENTLIST_2nd(evl))) != 0
5760e3d5408SPeter Wemm 		  && !(rc & TW_EVENT))
5770e3d5408SPeter Wemm 		 || !sp->_mouse_parse(sp, runcount)));
5780e3d5408SPeter Wemm #ifdef NCURSES_WGETCH_EVENTS
5790e3d5408SPeter Wemm 	if ((rc & TW_EVENT) && !(ch == KEY_EVENT)) {
5800e3d5408SPeter Wemm 	    safe_ungetch(sp, ch);
58139f2269fSPeter Wemm 	    ch = KEY_EVENT;
5820e3d5408SPeter Wemm 	}
5830e3d5408SPeter Wemm #endif
5840e3d5408SPeter Wemm 	if (runcount > 0 && ch != KEY_MOUSE) {
5850e3d5408SPeter Wemm #ifdef NCURSES_WGETCH_EVENTS
5860e3d5408SPeter Wemm 	    /* mouse event sequence ended by an event, report event */
587aa59d4d4SRong-En Fan 	    if (ch == KEY_EVENT) {
5880e3d5408SPeter Wemm 		safe_ungetch(sp, KEY_MOUSE);	/* FIXME This interrupts a gesture... */
5895ca44d1cSRong-En Fan 	    } else
5900e3d5408SPeter Wemm #endif
591aa59d4d4SRong-En Fan 	    {
5920e3d5408SPeter Wemm 		/* mouse event sequence ended by keystroke, store keystroke */
59339f2269fSPeter Wemm 		safe_ungetch(sp, ch);
5940e3d5408SPeter Wemm 		ch = KEY_MOUSE;
595aa59d4d4SRong-En Fan 	    }
5960e3d5408SPeter Wemm 	}
59715589c42SPeter Wemm     } else {
598aa59d4d4SRong-En Fan 	if (head == -1)
5994a1a9510SRong-En Fan 	    fifo_push(sp EVENTLIST_2nd(evl));
6004a1a9510SRong-En Fan 	ch = fifo_pull(sp);
601aa59d4d4SRong-En Fan     }
6024a1a9510SRong-En Fan 
6030e3d5408SPeter Wemm     if (ch == ERR) {
6040e3d5408SPeter Wemm       check_sigwinch:
6050e3d5408SPeter Wemm #if USE_SIZECHANGE
6064a1a9510SRong-En Fan 	if (_nc_handle_sigwinch(sp)) {
6074a1a9510SRong-En Fan 	    _nc_update_screensize(sp);
6084a1a9510SRong-En Fan 	    /* resizeterm can push KEY_RESIZE */
609aa59d4d4SRong-En Fan 	    if (cooked_key_in_fifo()) {
6100e3d5408SPeter Wemm 		*result = fifo_pull(sp);
6114a1a9510SRong-En Fan 		/*
6124a1a9510SRong-En Fan 		 * Get the ERR from queue -- it is from WINCH,
6134a1a9510SRong-En Fan 		 * so we should take it out, the "error" is handled.
614aa59d4d4SRong-En Fan 		 */
61515589c42SPeter Wemm 		if (fifo_peek(sp) == -1)
6164a1a9510SRong-En Fan 		    fifo_pull(sp);
6174a1a9510SRong-En Fan 		returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
6184a1a9510SRong-En Fan 	    }
6194a1a9510SRong-En Fan 	}
6200e3d5408SPeter Wemm #endif
6210e3d5408SPeter Wemm 	returnCode(ERR);
6220e3d5408SPeter Wemm     }
6230e3d5408SPeter Wemm 
6240e3d5408SPeter Wemm     /*
6250e3d5408SPeter Wemm      * If echo() is in effect, display the printable version of the
6265d08fb1fSRong-En Fan      * key on the screen.  Carriage return and backspace are treated
6270e3d5408SPeter Wemm      * specially by Solaris curses:
6280e3d5408SPeter Wemm      *
62939f2269fSPeter Wemm      * If carriage return is defined as a function key in the
63015589c42SPeter Wemm      * terminfo, e.g., kent, then Solaris may return either ^J (or ^M
63115589c42SPeter Wemm      * if nonl() is set) or KEY_ENTER depending on the echo() mode.
63239f2269fSPeter Wemm      * We echo before translating carriage return based on nonl(),
63339f2269fSPeter Wemm      * since the visual result simply moves the cursor to column 0.
6340e3d5408SPeter Wemm      *
6350e3d5408SPeter Wemm      * Backspace is a different matter.  Solaris curses does not
6360e3d5408SPeter Wemm      * translate it to KEY_BACKSPACE if kbs=^H.  This does not depend
6370e3d5408SPeter Wemm      * on the stty modes, but appears to be a hardcoded special case.
6380e3d5408SPeter Wemm      * This is a difference from ncurses, which uses the terminfo entry.
6390e3d5408SPeter Wemm      * However, we provide the same visual result as Solaris, moving the
640aa59d4d4SRong-En Fan      * cursor to the left.
6410e3d5408SPeter Wemm      */
6420e3d5408SPeter Wemm     if (sp->_echo && !(win->_flags & _ISPAD)) {
6430e3d5408SPeter Wemm 	chtype backup = (chtype) ((ch == KEY_BACKSPACE) ? '\b' : ch);
6440e3d5408SPeter Wemm 	if (backup < KEY_MIN)
6450e3d5408SPeter Wemm 	    wechochar(win, backup);
6460e3d5408SPeter Wemm     }
6470e3d5408SPeter Wemm 
64815589c42SPeter Wemm     /*
6494a1a9510SRong-En Fan      * Simulate ICRNL mode
6504a1a9510SRong-En Fan      */
6510e3d5408SPeter Wemm     if ((ch == '\r') && sp->_nl)
652aa59d4d4SRong-En Fan 	ch = '\n';
6534a1a9510SRong-En Fan 
6544a1a9510SRong-En Fan     /* Strip 8th-bit if so desired.  We do this only for characters that
6554a1a9510SRong-En Fan      * are in the range 128-255, to provide compatibility with terminals
6564a1a9510SRong-En Fan      * that display only 7-bit characters.  Note that 'ch' may be a
6574a1a9510SRong-En Fan      * function key at this point, so we mustn't strip _those_.
6584a1a9510SRong-En Fan      */
6594a1a9510SRong-En Fan     if (!use_meta)
6604a1a9510SRong-En Fan 	if ((ch < KEY_MIN) && (ch & 0x80))
6614a1a9510SRong-En Fan 	    ch &= 0x7f;
6620e3d5408SPeter Wemm 
6630e3d5408SPeter Wemm     T(("wgetch returning : %s", _nc_tracechar(sp, ch)));
6640e3d5408SPeter Wemm 
6650e3d5408SPeter Wemm     *result = ch;
6660e3d5408SPeter Wemm     returnCode(ch >= KEY_MIN ? KEY_CODE_YES : OK);
667aa59d4d4SRong-En Fan }
6680e3d5408SPeter Wemm 
6690e3d5408SPeter Wemm #ifdef NCURSES_WGETCH_EVENTS
6700e3d5408SPeter Wemm NCURSES_EXPORT(int)
wgetch_events(WINDOW * win,_nc_eventlist * evl)671 wgetch_events(WINDOW *win, _nc_eventlist * evl)
672 {
673     int code;
674     int value;
675 
676     T((T_CALLED("wgetch_events(%p,%p)"), (void *) win, (void *) evl));
677     code = _nc_wgetch(win,
678 		      &value,
679 		      _nc_use_meta(win)
680 		      EVENTLIST_2nd(evl));
681     if (code != ERR)
682 	code = value;
683     returnCode(code);
684 }
685 #endif
686 
687 NCURSES_EXPORT(int)
wgetch(WINDOW * win)688 wgetch(WINDOW *win)
689 {
690     int code;
691     int value;
692 
693     T((T_CALLED("wgetch(%p)"), (void *) win));
694     code = _nc_wgetch(win,
695 		      &value,
696 		      _nc_use_meta(win)
697 		      EVENTLIST_2nd((_nc_eventlist *) 0));
698     if (code != ERR)
699 	code = value;
700     returnCode(code);
701 }
702 
703 /*
704 **      int
705 **      kgetch()
706 **
707 **      Get an input character, but take care of keypad sequences, returning
708 **      an appropriate code when one matches the input.  After each character
709 **      is received, set an alarm call based on ESCDELAY.  If no more of the
710 **      sequence is received by the time the alarm goes off, pass through
711 **      the sequence gotten so far.
712 **
713 **	This function must be called when there are no cooked keys in queue.
714 **	(that is head==-1 || peek==head)
715 **
716 */
717 
718 static int
kgetch(SCREEN * sp,bool forever EVENTLIST_2nd (_nc_eventlist * evl))719 kgetch(SCREEN *sp, bool forever EVENTLIST_2nd(_nc_eventlist * evl))
720 {
721     TRIES *ptr;
722     int ch = 0;
723     int timeleft = forever ? 9999999 : GetEscdelay(sp);
724 
725     TR(TRACE_IEVENT, ("kgetch() called"));
726 
727     ptr = sp->_keytry;
728 
729     for (;;) {
730 	if (cooked_key_in_fifo() && sp->_fifo[head] >= KEY_MIN) {
731 	    break;
732 	} else if (!raw_key_in_fifo()) {
733 	    ch = fifo_push(sp EVENTLIST_2nd(evl));
734 	    if (ch == ERR) {
735 		peek = head;	/* the keys stay uninterpreted */
736 		return ERR;
737 	    }
738 #ifdef NCURSES_WGETCH_EVENTS
739 	    else if (ch == KEY_EVENT) {
740 		peek = head;	/* the keys stay uninterpreted */
741 		return fifo_pull(sp);	/* Remove KEY_EVENT from the queue */
742 	    }
743 #endif
744 	}
745 
746 	ch = fifo_peek(sp);
747 	if (ch >= KEY_MIN) {
748 	    /* If not first in queue, somebody put this key there on purpose in
749 	     * emergency.  Consider it higher priority than the unfinished
750 	     * keysequence we are parsing.
751 	     */
752 	    peek = head;
753 	    /* assume the key is the last in fifo */
754 	    t_dec();		/* remove the key */
755 	    return ch;
756 	}
757 
758 	TR(TRACE_IEVENT, ("ch: %s", _nc_tracechar(sp, (unsigned char) ch)));
759 	while ((ptr != NULL) && (ptr->ch != (unsigned char) ch))
760 	    ptr = ptr->sibling;
761 
762 	if (ptr == NULL) {
763 	    TR(TRACE_IEVENT, ("ptr is null"));
764 	    break;
765 	}
766 	TR(TRACE_IEVENT, ("ptr=%p, ch=%d, value=%d",
767 			  (void *) ptr, ptr->ch, ptr->value));
768 
769 	if (ptr->value != 0) {	/* sequence terminated */
770 	    TR(TRACE_IEVENT, ("end of sequence"));
771 	    if (peek == tail) {
772 		fifo_clear(sp);
773 	    } else {
774 		head = peek;
775 	    }
776 	    return (ptr->value);
777 	}
778 
779 	ptr = ptr->child;
780 
781 	if (!raw_key_in_fifo()) {
782 	    int rc;
783 
784 	    TR(TRACE_IEVENT, ("waiting for rest of sequence"));
785 	    rc = check_mouse_activity(sp, timeleft EVENTLIST_2nd(evl));
786 #ifdef NCURSES_WGETCH_EVENTS
787 	    if (rc & TW_EVENT) {
788 		TR(TRACE_IEVENT, ("interrupted by a user event"));
789 		/* FIXME Should have preserved remainder timeleft for reuse... */
790 		peek = head;	/* Restart interpreting later */
791 		return KEY_EVENT;
792 	    }
793 #endif
794 	    if (!rc) {
795 		TR(TRACE_IEVENT, ("ran out of time"));
796 		break;
797 	    }
798 	}
799     }
800     ch = fifo_pull(sp);
801     peek = head;
802     return ch;
803 }
804