10e3d5408SPeter Wemm /****************************************************************************
2d8977eafSRong-En Fan  * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
30e3d5408SPeter Wemm  *                                                                          *
40e3d5408SPeter Wemm  * Permission is hereby granted, free of charge, to any person obtaining a  *
50e3d5408SPeter Wemm  * copy of this software and associated documentation files (the            *
60e3d5408SPeter Wemm  * "Software"), to deal in the Software without restriction, including      *
70e3d5408SPeter Wemm  * without limitation the rights to use, copy, modify, merge, publish,      *
80e3d5408SPeter Wemm  * distribute, distribute with modifications, sublicense, and/or sell       *
90e3d5408SPeter Wemm  * copies of the Software, and to permit persons to whom the Software is    *
100e3d5408SPeter Wemm  * furnished to do so, subject to the following conditions:                 *
110e3d5408SPeter Wemm  *                                                                          *
120e3d5408SPeter Wemm  * The above copyright notice and this permission notice shall be included  *
130e3d5408SPeter Wemm  * in all copies or substantial portions of the Software.                   *
140e3d5408SPeter Wemm  *                                                                          *
150e3d5408SPeter Wemm  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
160e3d5408SPeter Wemm  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
170e3d5408SPeter Wemm  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
180e3d5408SPeter Wemm  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
190e3d5408SPeter Wemm  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
200e3d5408SPeter Wemm  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
210e3d5408SPeter Wemm  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
220e3d5408SPeter Wemm  *                                                                          *
230e3d5408SPeter Wemm  * Except as contained in this notice, the name(s) of the above copyright   *
240e3d5408SPeter Wemm  * holders shall not be used in advertising or otherwise to promote the     *
250e3d5408SPeter Wemm  * sale, use or other dealings in this Software without prior written       *
260e3d5408SPeter Wemm  * authorization.                                                           *
270e3d5408SPeter Wemm  ****************************************************************************/
280e3d5408SPeter Wemm 
290e3d5408SPeter Wemm /****************************************************************************
300e3d5408SPeter Wemm  *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
310e3d5408SPeter Wemm  *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
324a1a9510SRong-En Fan  *     and: Thomas E. Dickey                        1996-on                 *
330e3d5408SPeter Wemm  ****************************************************************************/
340e3d5408SPeter Wemm 
350e3d5408SPeter Wemm /*
360e3d5408SPeter Wemm **	lib_getch.c
370e3d5408SPeter Wemm **
380e3d5408SPeter Wemm **	The routine getch().
390e3d5408SPeter Wemm **
400e3d5408SPeter Wemm */
410e3d5408SPeter Wemm 
420e3d5408SPeter Wemm #include <curses.priv.h>
430e3d5408SPeter Wemm 
44d8977eafSRong-En Fan MODULE_ID("$Id: lib_getch.c,v 1.82 2008/01/19 21:07:30 tom Exp $")
450e3d5408SPeter Wemm 
460e3d5408SPeter Wemm #include <fifo_defs.h>
470e3d5408SPeter Wemm 
485ca44d1cSRong-En Fan #if USE_REENTRANT
495ca44d1cSRong-En Fan NCURSES_EXPORT(int)
505ca44d1cSRong-En Fan NCURSES_PUBLIC_VAR(ESCDELAY) (void)
515ca44d1cSRong-En Fan {
525ca44d1cSRong-En Fan     return SP ? SP->_ESCDELAY : 1000;
535ca44d1cSRong-En Fan }
545ca44d1cSRong-En Fan #else
557a69bbfbSPeter Wemm NCURSES_EXPORT_VAR(int)
567a69bbfbSPeter Wemm ESCDELAY = 1000;		/* max interval betw. chars in funkeys, in millisecs */
575ca44d1cSRong-En Fan #endif
580e3d5408SPeter Wemm 
59d8977eafSRong-En Fan #if NCURSES_EXT_FUNCS
60d8977eafSRong-En Fan NCURSES_EXPORT(int)
61d8977eafSRong-En Fan set_escdelay(int value)
62d8977eafSRong-En Fan {
63d8977eafSRong-En Fan     int code = OK;
64d8977eafSRong-En Fan #if USE_REENTRANT
65d8977eafSRong-En Fan     if (SP) {
66d8977eafSRong-En Fan 	SP->_ESCDELAY = value;
67d8977eafSRong-En Fan     } else {
68d8977eafSRong-En Fan 	code = ERR;
69d8977eafSRong-En Fan     }
70d8977eafSRong-En Fan #else
71d8977eafSRong-En Fan     ESCDELAY = value;
72d8977eafSRong-En Fan #endif
73d8977eafSRong-En Fan     return code;
74d8977eafSRong-En Fan }
75d8977eafSRong-En Fan #endif
76d8977eafSRong-En Fan 
774a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
784a1a9510SRong-En Fan #define TWAIT_MASK 7
794a1a9510SRong-En Fan #else
804a1a9510SRong-En Fan #define TWAIT_MASK 3
814a1a9510SRong-En Fan #endif
824a1a9510SRong-En Fan 
834a1a9510SRong-En Fan /*
844a1a9510SRong-En Fan  * Check for mouse activity, returning nonzero if we find any.
854a1a9510SRong-En Fan  */
864a1a9510SRong-En Fan static int
874a1a9510SRong-En Fan check_mouse_activity(int delay EVENTLIST_2nd(_nc_eventlist * evl))
884a1a9510SRong-En Fan {
894a1a9510SRong-En Fan     int rc;
904a1a9510SRong-En Fan 
914a1a9510SRong-En Fan #if USE_SYSMOUSE
924a1a9510SRong-En Fan     if ((SP->_mouse_type == M_SYSMOUSE)
934a1a9510SRong-En Fan 	&& (SP->_sysmouse_head < SP->_sysmouse_tail)) {
944a1a9510SRong-En Fan 	return 2;
954a1a9510SRong-En Fan     }
964a1a9510SRong-En Fan #endif
974a1a9510SRong-En Fan     rc = _nc_timed_wait(TWAIT_MASK, delay, (int *) 0 EVENTLIST_2nd(evl));
984a1a9510SRong-En Fan #if USE_SYSMOUSE
994a1a9510SRong-En Fan     if ((SP->_mouse_type == M_SYSMOUSE)
1004a1a9510SRong-En Fan 	&& (SP->_sysmouse_head < SP->_sysmouse_tail)
1014a1a9510SRong-En Fan 	&& (rc == 0)
1024a1a9510SRong-En Fan 	&& (errno == EINTR)) {
1034a1a9510SRong-En Fan 	rc |= 2;
1044a1a9510SRong-En Fan     }
1054a1a9510SRong-En Fan #endif
1064a1a9510SRong-En Fan     return rc;
1074a1a9510SRong-En Fan }
1084a1a9510SRong-En Fan 
1094a1a9510SRong-En Fan static NCURSES_INLINE int
11015589c42SPeter Wemm fifo_peek(void)
1110e3d5408SPeter Wemm {
1120e3d5408SPeter Wemm     int ch = SP->_fifo[peek];
11318259542SPeter Wemm     TR(TRACE_IEVENT, ("peeking at %d", peek));
1140e3d5408SPeter Wemm 
1150e3d5408SPeter Wemm     p_inc();
1160e3d5408SPeter Wemm     return ch;
1170e3d5408SPeter Wemm }
1180e3d5408SPeter Wemm 
1194a1a9510SRong-En Fan static NCURSES_INLINE int
12015589c42SPeter Wemm fifo_pull(void)
1210e3d5408SPeter Wemm {
1220e3d5408SPeter Wemm     int ch;
1230e3d5408SPeter Wemm     ch = SP->_fifo[head];
12439f2269fSPeter Wemm     TR(TRACE_IEVENT, ("pulling %s from %d", _tracechar(ch), head));
1250e3d5408SPeter Wemm 
12615589c42SPeter Wemm     if (peek == head) {
1270e3d5408SPeter Wemm 	h_inc();
1280e3d5408SPeter Wemm 	peek = head;
12915589c42SPeter Wemm     } else
1300e3d5408SPeter Wemm 	h_inc();
1310e3d5408SPeter Wemm 
1320e3d5408SPeter Wemm #ifdef TRACE
1335ca44d1cSRong-En Fan     if (USE_TRACEF(TRACE_IEVENT)) {
13415589c42SPeter Wemm 	_nc_fifo_dump();
1355ca44d1cSRong-En Fan 	_nc_unlock_global(tracef);
1365ca44d1cSRong-En Fan     }
1370e3d5408SPeter Wemm #endif
1380e3d5408SPeter Wemm     return ch;
1390e3d5408SPeter Wemm }
1400e3d5408SPeter Wemm 
1414a1a9510SRong-En Fan static NCURSES_INLINE int
1424a1a9510SRong-En Fan fifo_push(EVENTLIST_0th(_nc_eventlist * evl))
1430e3d5408SPeter Wemm {
1440e3d5408SPeter Wemm     int n;
1454a1a9510SRong-En Fan     int ch = 0;
1464a1a9510SRong-En Fan     int mask = 0;
1470e3d5408SPeter Wemm 
1484a1a9510SRong-En Fan     (void) mask;
14915589c42SPeter Wemm     if (tail == -1)
15015589c42SPeter Wemm 	return ERR;
1510e3d5408SPeter Wemm 
1520e3d5408SPeter Wemm #ifdef HIDE_EINTR
1530e3d5408SPeter Wemm   again:
1540e3d5408SPeter Wemm     errno = 0;
1550e3d5408SPeter Wemm #endif
1560e3d5408SPeter Wemm 
1574a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
1584a1a9510SRong-En Fan     if (evl
1594a1a9510SRong-En Fan #if USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE
1604a1a9510SRong-En Fan 	|| (SP->_mouse_fd >= 0)
1614a1a9510SRong-En Fan #endif
1624a1a9510SRong-En Fan 	) {
1634a1a9510SRong-En Fan 	mask = check_mouse_activity(-1 EVENTLIST_2nd(evl));
1644a1a9510SRong-En Fan     } else
1654a1a9510SRong-En Fan 	mask = 0;
1664a1a9510SRong-En Fan 
1674a1a9510SRong-En Fan     if (mask & 4) {
1684a1a9510SRong-En Fan 	T(("fifo_push: ungetch KEY_EVENT"));
1694a1a9510SRong-En Fan 	ungetch(KEY_EVENT);
1704a1a9510SRong-En Fan 	return KEY_EVENT;
1714a1a9510SRong-En Fan     }
1724a1a9510SRong-En Fan #elif USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE
1734a1a9510SRong-En Fan     if (SP->_mouse_fd >= 0) {
1744a1a9510SRong-En Fan 	mask = check_mouse_activity(-1 EVENTLIST_2nd(evl));
1754a1a9510SRong-En Fan     }
1764a1a9510SRong-En Fan #endif
1774a1a9510SRong-En Fan 
1784a1a9510SRong-En Fan #if USE_GPM_SUPPORT || USE_EMX_MOUSE
1794a1a9510SRong-En Fan     if ((SP->_mouse_fd >= 0) && (mask & 2)) {
1800e3d5408SPeter Wemm 	SP->_mouse_event(SP);
1810e3d5408SPeter Wemm 	ch = KEY_MOUSE;
1820e3d5408SPeter Wemm 	n = 1;
1830e3d5408SPeter Wemm     } else
1840e3d5408SPeter Wemm #endif
1854a1a9510SRong-En Fan #if USE_SYSMOUSE
1864a1a9510SRong-En Fan 	if ((SP->_mouse_type == M_SYSMOUSE)
1874a1a9510SRong-En Fan 	    && (SP->_sysmouse_head < SP->_sysmouse_tail)) {
1884a1a9510SRong-En Fan 	SP->_mouse_event(SP);
1894a1a9510SRong-En Fan 	ch = KEY_MOUSE;
1904a1a9510SRong-En Fan 	n = 1;
1914a1a9510SRong-En Fan     } else if ((SP->_mouse_type == M_SYSMOUSE)
1924a1a9510SRong-En Fan 	       && (mask <= 0) && errno == EINTR) {
1934a1a9510SRong-En Fan 	SP->_mouse_event(SP);
1944a1a9510SRong-En Fan 	ch = KEY_MOUSE;
1954a1a9510SRong-En Fan 	n = 1;
1964a1a9510SRong-En Fan     } else
1974a1a9510SRong-En Fan #endif
1984a1a9510SRong-En Fan     {				/* Can block... */
1990e3d5408SPeter Wemm 	unsigned char c2 = 0;
2000e3d5408SPeter Wemm 	n = read(SP->_ifd, &c2, 1);
20139f2269fSPeter Wemm 	ch = c2;
2020e3d5408SPeter Wemm     }
2030e3d5408SPeter Wemm 
2040e3d5408SPeter Wemm #ifdef HIDE_EINTR
2050e3d5408SPeter Wemm     /*
2060e3d5408SPeter Wemm      * Under System V curses with non-restarting signals, getch() returns
2070e3d5408SPeter Wemm      * with value ERR when a handled signal keeps it from completing.
2080e3d5408SPeter Wemm      * If signals restart system calls, OTOH, the signal is invisible
2090e3d5408SPeter Wemm      * except to its handler.
2100e3d5408SPeter Wemm      *
2110e3d5408SPeter Wemm      * We don't want this difference to show.  This piece of code
2120e3d5408SPeter Wemm      * tries to make it look like we always have restarting signals.
2130e3d5408SPeter Wemm      */
2140e3d5408SPeter Wemm     if (n <= 0 && errno == EINTR)
2150e3d5408SPeter Wemm 	goto again;
2160e3d5408SPeter Wemm #endif
2170e3d5408SPeter Wemm 
21815589c42SPeter Wemm     if ((n == -1) || (n == 0)) {
21918259542SPeter Wemm 	TR(TRACE_IEVENT, ("read(%d,&ch,1)=%d, errno=%d", SP->_ifd, n, errno));
22018259542SPeter Wemm 	ch = ERR;
2210e3d5408SPeter Wemm     }
22218259542SPeter Wemm     TR(TRACE_IEVENT, ("read %d characters", n));
2230e3d5408SPeter Wemm 
2240e3d5408SPeter Wemm     SP->_fifo[tail] = ch;
2250e3d5408SPeter Wemm     SP->_fifohold = 0;
2260e3d5408SPeter Wemm     if (head == -1)
2270e3d5408SPeter Wemm 	head = peek = tail;
2280e3d5408SPeter Wemm     t_inc();
22939f2269fSPeter Wemm     TR(TRACE_IEVENT, ("pushed %s at %d", _tracechar(ch), tail));
2300e3d5408SPeter Wemm #ifdef TRACE
2315ca44d1cSRong-En Fan     if (USE_TRACEF(TRACE_IEVENT)) {
23215589c42SPeter Wemm 	_nc_fifo_dump();
2335ca44d1cSRong-En Fan 	_nc_unlock_global(tracef);
2345ca44d1cSRong-En Fan     }
2350e3d5408SPeter Wemm #endif
2360e3d5408SPeter Wemm     return ch;
2370e3d5408SPeter Wemm }
2380e3d5408SPeter Wemm 
2394a1a9510SRong-En Fan static NCURSES_INLINE void
24015589c42SPeter Wemm fifo_clear(void)
2410e3d5408SPeter Wemm {
24239f2269fSPeter Wemm     memset(SP->_fifo, 0, sizeof(SP->_fifo));
24315589c42SPeter Wemm     head = -1;
24415589c42SPeter Wemm     tail = peek = 0;
2450e3d5408SPeter Wemm }
2460e3d5408SPeter Wemm 
2474a1a9510SRong-En Fan static int kgetch(EVENTLIST_0th(_nc_eventlist * evl));
2480e3d5408SPeter Wemm 
2490e3d5408SPeter Wemm #define wgetch_should_refresh(win) (\
2500e3d5408SPeter Wemm 	(is_wintouched(win) || (win->_flags & _HASMOVED)) \
2510e3d5408SPeter Wemm 	&& !(win->_flags & _ISPAD))
2520e3d5408SPeter Wemm 
2537a69bbfbSPeter Wemm NCURSES_EXPORT(int)
2544a1a9510SRong-En Fan _nc_wgetch(WINDOW *win,
2554a1a9510SRong-En Fan 	   unsigned long *result,
2564a1a9510SRong-En Fan 	   int use_meta
2574a1a9510SRong-En Fan 	   EVENTLIST_2nd(_nc_eventlist * evl))
2580e3d5408SPeter Wemm {
2590e3d5408SPeter Wemm     int ch;
2604a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
2614a1a9510SRong-En Fan     long event_delay = -1;
2624a1a9510SRong-En Fan #endif
2630e3d5408SPeter Wemm 
2644a1a9510SRong-En Fan     T((T_CALLED("_nc_wgetch(%p)"), win));
2650e3d5408SPeter Wemm 
26639f2269fSPeter Wemm     *result = 0;
2675ca44d1cSRong-En Fan     if (win == 0 || SP == 0) {
2680e3d5408SPeter Wemm 	returnCode(ERR);
2695ca44d1cSRong-En Fan     }
2700e3d5408SPeter Wemm 
27115589c42SPeter Wemm     if (cooked_key_in_fifo()) {
2720e3d5408SPeter Wemm 	if (wgetch_should_refresh(win))
2730e3d5408SPeter Wemm 	    wrefresh(win);
2740e3d5408SPeter Wemm 
27539f2269fSPeter Wemm 	*result = fifo_pull();
2765ca44d1cSRong-En Fan 	returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
2770e3d5408SPeter Wemm     }
2784a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
2794a1a9510SRong-En Fan     if (evl && (evl->count == 0))
2804a1a9510SRong-En Fan 	evl = NULL;
2814a1a9510SRong-En Fan     event_delay = _nc_eventlist_timeout(evl);
2824a1a9510SRong-En Fan #endif
2830e3d5408SPeter Wemm 
2840e3d5408SPeter Wemm     /*
2850e3d5408SPeter Wemm      * Handle cooked mode.  Grab a string from the screen,
2860e3d5408SPeter Wemm      * stuff its contents in the FIFO queue, and pop off
2870e3d5408SPeter Wemm      * the first character to return it.
2880e3d5408SPeter Wemm      */
2894a1a9510SRong-En Fan     if (head == -1 &&
2904a1a9510SRong-En Fan 	!SP->_notty &&
2914a1a9510SRong-En Fan 	!SP->_raw &&
2924a1a9510SRong-En Fan 	!SP->_cbreak &&
2934a1a9510SRong-En Fan 	!SP->_called_wgetch) {
2940e3d5408SPeter Wemm 	char buf[MAXCOLUMNS], *sp;
2954a1a9510SRong-En Fan 	int rc;
2960e3d5408SPeter Wemm 
29718259542SPeter Wemm 	TR(TRACE_IEVENT, ("filling queue in cooked mode"));
2980e3d5408SPeter Wemm 
2994a1a9510SRong-En Fan 	SP->_called_wgetch = TRUE;
3004a1a9510SRong-En Fan 	rc = wgetnstr(win, buf, MAXCOLUMNS);
3014a1a9510SRong-En Fan 	SP->_called_wgetch = FALSE;
3020e3d5408SPeter Wemm 
3030e3d5408SPeter Wemm 	/* ungetch in reverse order */
3044a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
3054a1a9510SRong-En Fan 	if (rc != KEY_EVENT)
3064a1a9510SRong-En Fan #endif
3070e3d5408SPeter Wemm 	    ungetch('\n');
3080e3d5408SPeter Wemm 	for (sp = buf + strlen(buf); sp > buf; sp--)
3090e3d5408SPeter Wemm 	    ungetch(sp[-1]);
3100e3d5408SPeter Wemm 
3114a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
3124a1a9510SRong-En Fan 	/* Return it first */
3134a1a9510SRong-En Fan 	if (rc == KEY_EVENT) {
3144a1a9510SRong-En Fan 	    *result = rc;
3155ca44d1cSRong-En Fan 	} else
3164a1a9510SRong-En Fan #endif
31739f2269fSPeter Wemm 	    *result = fifo_pull();
3185ca44d1cSRong-En Fan 	returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
3190e3d5408SPeter Wemm     }
3200e3d5408SPeter Wemm 
32139f2269fSPeter Wemm     if (win->_use_keypad != SP->_keypad_on)
32239f2269fSPeter Wemm 	_nc_keypad(win->_use_keypad);
32339f2269fSPeter Wemm 
3240e3d5408SPeter Wemm     if (wgetch_should_refresh(win))
3250e3d5408SPeter Wemm 	wrefresh(win);
3260e3d5408SPeter Wemm 
32715589c42SPeter Wemm     if (!win->_notimeout && (win->_delay >= 0 || SP->_cbreak > 1)) {
3284a1a9510SRong-En Fan 	if (head == -1) {	/* fifo is empty */
3290e3d5408SPeter Wemm 	    int delay;
3304a1a9510SRong-En Fan 	    int rc;
3310e3d5408SPeter Wemm 
33218259542SPeter Wemm 	    TR(TRACE_IEVENT, ("timed delay in wgetch()"));
3330e3d5408SPeter Wemm 	    if (SP->_cbreak > 1)
3340e3d5408SPeter Wemm 		delay = (SP->_cbreak - 1) * 100;
3350e3d5408SPeter Wemm 	    else
3360e3d5408SPeter Wemm 		delay = win->_delay;
3370e3d5408SPeter Wemm 
3384a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
3394a1a9510SRong-En Fan 	    if (event_delay >= 0 && delay > event_delay)
3404a1a9510SRong-En Fan 		delay = event_delay;
3414a1a9510SRong-En Fan #endif
3424a1a9510SRong-En Fan 
34318259542SPeter Wemm 	    TR(TRACE_IEVENT, ("delay is %d milliseconds", delay));
3440e3d5408SPeter Wemm 
3454a1a9510SRong-En Fan 	    rc = check_mouse_activity(delay EVENTLIST_2nd(evl));
3464a1a9510SRong-En Fan 
3474a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
3484a1a9510SRong-En Fan 	    if (rc & 4) {
3494a1a9510SRong-En Fan 		*result = KEY_EVENT;
3505ca44d1cSRong-En Fan 		returnCode(KEY_CODE_YES);
3514a1a9510SRong-En Fan 	    }
3524a1a9510SRong-En Fan #endif
3534a1a9510SRong-En Fan 	    if (!rc)
3540e3d5408SPeter Wemm 		returnCode(ERR);
3554a1a9510SRong-En Fan 	}
3560e3d5408SPeter Wemm 	/* else go on to read data available */
3570e3d5408SPeter Wemm     }
3580e3d5408SPeter Wemm 
35915589c42SPeter Wemm     if (win->_use_keypad) {
3600e3d5408SPeter Wemm 	/*
3610e3d5408SPeter Wemm 	 * This is tricky.  We only want to get special-key
3620e3d5408SPeter Wemm 	 * events one at a time.  But we want to accumulate
3630e3d5408SPeter Wemm 	 * mouse events until either (a) the mouse logic tells
3640e3d5408SPeter Wemm 	 * us it's picked up a complete gesture, or (b)
3650e3d5408SPeter Wemm 	 * there's a detectable time lapse after one.
3660e3d5408SPeter Wemm 	 *
3670e3d5408SPeter Wemm 	 * Note: if the mouse code starts failing to compose
3680e3d5408SPeter Wemm 	 * press/release events into clicks, you should probably
3690e3d5408SPeter Wemm 	 * increase the wait with mouseinterval().
3700e3d5408SPeter Wemm 	 */
3710e3d5408SPeter Wemm 	int runcount = 0;
3724a1a9510SRong-En Fan 	int rc;
3730e3d5408SPeter Wemm 
3740e3d5408SPeter Wemm 	do {
3754a1a9510SRong-En Fan 	    ch = kgetch(EVENTLIST_1st(evl));
37615589c42SPeter Wemm 	    if (ch == KEY_MOUSE) {
3770e3d5408SPeter Wemm 		++runcount;
3780e3d5408SPeter Wemm 		if (SP->_mouse_inline(SP))
3790e3d5408SPeter Wemm 		    break;
3800e3d5408SPeter Wemm 	    }
38139f2269fSPeter Wemm 	    if (SP->_maxclick < 0)
38239f2269fSPeter Wemm 		break;
3830e3d5408SPeter Wemm 	} while
3840e3d5408SPeter Wemm 	    (ch == KEY_MOUSE
3854a1a9510SRong-En Fan 	     && (((rc = check_mouse_activity(SP->_maxclick
3864a1a9510SRong-En Fan 					     EVENTLIST_2nd(evl))) != 0
3874a1a9510SRong-En Fan 		  && !(rc & 4))
3880e3d5408SPeter Wemm 		 || !SP->_mouse_parse(runcount)));
3894a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
3904a1a9510SRong-En Fan 	if ((rc & 4) && !ch == KEY_EVENT) {
3914a1a9510SRong-En Fan 	    ungetch(ch);
3924a1a9510SRong-En Fan 	    ch = KEY_EVENT;
3934a1a9510SRong-En Fan 	}
3944a1a9510SRong-En Fan #endif
39515589c42SPeter Wemm 	if (runcount > 0 && ch != KEY_MOUSE) {
3964a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
3974a1a9510SRong-En Fan 	    /* mouse event sequence ended by an event, report event */
3984a1a9510SRong-En Fan 	    if (ch == KEY_EVENT) {
3994a1a9510SRong-En Fan 		ungetch(KEY_MOUSE);	/* FIXME This interrupts a gesture... */
4004a1a9510SRong-En Fan 	    } else
4014a1a9510SRong-En Fan #endif
4024a1a9510SRong-En Fan 	    {
4034a1a9510SRong-En Fan 		/* mouse event sequence ended by keystroke, store keystroke */
4040e3d5408SPeter Wemm 		ungetch(ch);
4050e3d5408SPeter Wemm 		ch = KEY_MOUSE;
4060e3d5408SPeter Wemm 	    }
4074a1a9510SRong-En Fan 	}
4080e3d5408SPeter Wemm     } else {
4090e3d5408SPeter Wemm 	if (head == -1)
4104a1a9510SRong-En Fan 	    fifo_push(EVENTLIST_1st(evl));
4110e3d5408SPeter Wemm 	ch = fifo_pull();
4120e3d5408SPeter Wemm     }
4130e3d5408SPeter Wemm 
41415589c42SPeter Wemm     if (ch == ERR) {
4150e3d5408SPeter Wemm #if USE_SIZECHANGE
4165ca44d1cSRong-En Fan 	if (_nc_handle_sigwinch(FALSE)) {
4170e3d5408SPeter Wemm 	    _nc_update_screensize();
4180e3d5408SPeter Wemm 	    /* resizeterm can push KEY_RESIZE */
41915589c42SPeter Wemm 	    if (cooked_key_in_fifo()) {
42039f2269fSPeter Wemm 		*result = fifo_pull();
421b82face1SPeter Wemm 		returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
4220e3d5408SPeter Wemm 	    }
4230e3d5408SPeter Wemm 	}
4240e3d5408SPeter Wemm #endif
4250e3d5408SPeter Wemm 	returnCode(ERR);
4260e3d5408SPeter Wemm     }
4270e3d5408SPeter Wemm 
4280e3d5408SPeter Wemm     /*
42915589c42SPeter Wemm      * If echo() is in effect, display the printable version of the
43015589c42SPeter Wemm      * key on the screen.  Carriage return and backspace are treated
43115589c42SPeter Wemm      * specially by Solaris curses:
43215589c42SPeter Wemm      *
43315589c42SPeter Wemm      * If carriage return is defined as a function key in the
43415589c42SPeter Wemm      * terminfo, e.g., kent, then Solaris may return either ^J (or ^M
43515589c42SPeter Wemm      * if nonl() is set) or KEY_ENTER depending on the echo() mode.
43615589c42SPeter Wemm      * We echo before translating carriage return based on nonl(),
43715589c42SPeter Wemm      * since the visual result simply moves the cursor to column 0.
43815589c42SPeter Wemm      *
43915589c42SPeter Wemm      * Backspace is a different matter.  Solaris curses does not
44015589c42SPeter Wemm      * translate it to KEY_BACKSPACE if kbs=^H.  This does not depend
44115589c42SPeter Wemm      * on the stty modes, but appears to be a hardcoded special case.
44215589c42SPeter Wemm      * This is a difference from ncurses, which uses the terminfo entry.
44315589c42SPeter Wemm      * However, we provide the same visual result as Solaris, moving the
44415589c42SPeter Wemm      * cursor to the left.
44515589c42SPeter Wemm      */
44615589c42SPeter Wemm     if (SP->_echo && !(win->_flags & _ISPAD)) {
44715589c42SPeter Wemm 	chtype backup = (ch == KEY_BACKSPACE) ? '\b' : ch;
44815589c42SPeter Wemm 	if (backup < KEY_MIN)
44915589c42SPeter Wemm 	    wechochar(win, backup);
45015589c42SPeter Wemm     }
45115589c42SPeter Wemm 
45215589c42SPeter Wemm     /*
4530e3d5408SPeter Wemm      * Simulate ICRNL mode
4540e3d5408SPeter Wemm      */
4550e3d5408SPeter Wemm     if ((ch == '\r') && SP->_nl)
4560e3d5408SPeter Wemm 	ch = '\n';
4570e3d5408SPeter Wemm 
4580e3d5408SPeter Wemm     /* Strip 8th-bit if so desired.  We do this only for characters that
4590e3d5408SPeter Wemm      * are in the range 128-255, to provide compatibility with terminals
4600e3d5408SPeter Wemm      * that display only 7-bit characters.  Note that 'ch' may be a
4610e3d5408SPeter Wemm      * function key at this point, so we mustn't strip _those_.
4620e3d5408SPeter Wemm      */
46339f2269fSPeter Wemm     if (!use_meta)
4640e3d5408SPeter Wemm 	if ((ch < KEY_MIN) && (ch & 0x80))
4650e3d5408SPeter Wemm 	    ch &= 0x7f;
4660e3d5408SPeter Wemm 
46739f2269fSPeter Wemm     T(("wgetch returning : %s", _tracechar(ch)));
4680e3d5408SPeter Wemm 
46939f2269fSPeter Wemm     *result = ch;
47039f2269fSPeter Wemm     returnCode(ch >= KEY_MIN ? KEY_CODE_YES : OK);
47139f2269fSPeter Wemm }
47239f2269fSPeter Wemm 
4734a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
4744a1a9510SRong-En Fan NCURSES_EXPORT(int)
4754a1a9510SRong-En Fan wgetch_events(WINDOW *win, _nc_eventlist * evl)
4764a1a9510SRong-En Fan {
4774a1a9510SRong-En Fan     int code;
4784a1a9510SRong-En Fan     unsigned long value;
4794a1a9510SRong-En Fan 
4804a1a9510SRong-En Fan     T((T_CALLED("wgetch_events(%p,%p)"), win, evl));
4814a1a9510SRong-En Fan     code = _nc_wgetch(win,
4824a1a9510SRong-En Fan 		      &value,
4834a1a9510SRong-En Fan 		      SP->_use_meta
4844a1a9510SRong-En Fan 		      EVENTLIST_2nd(evl));
4854a1a9510SRong-En Fan     if (code != ERR)
4864a1a9510SRong-En Fan 	code = value;
4874a1a9510SRong-En Fan     returnCode(code);
4884a1a9510SRong-En Fan }
4894a1a9510SRong-En Fan #endif
4904a1a9510SRong-En Fan 
49139f2269fSPeter Wemm NCURSES_EXPORT(int)
49239f2269fSPeter Wemm wgetch(WINDOW *win)
49339f2269fSPeter Wemm {
49439f2269fSPeter Wemm     int code;
49539f2269fSPeter Wemm     unsigned long value;
49639f2269fSPeter Wemm 
49739f2269fSPeter Wemm     T((T_CALLED("wgetch(%p)"), win));
4984a1a9510SRong-En Fan     code = _nc_wgetch(win,
4994a1a9510SRong-En Fan 		      &value,
5004a1a9510SRong-En Fan 		      (SP ? SP->_use_meta : 0)
5014a1a9510SRong-En Fan 		      EVENTLIST_2nd((_nc_eventlist *) 0));
50239f2269fSPeter Wemm     if (code != ERR)
50339f2269fSPeter Wemm 	code = value;
50439f2269fSPeter Wemm     returnCode(code);
5050e3d5408SPeter Wemm }
5060e3d5408SPeter Wemm 
5070e3d5408SPeter Wemm /*
5080e3d5408SPeter Wemm **      int
5090e3d5408SPeter Wemm **      kgetch()
5100e3d5408SPeter Wemm **
5110e3d5408SPeter Wemm **      Get an input character, but take care of keypad sequences, returning
5120e3d5408SPeter Wemm **      an appropriate code when one matches the input.  After each character
5130e3d5408SPeter Wemm **      is received, set an alarm call based on ESCDELAY.  If no more of the
5140e3d5408SPeter Wemm **      sequence is received by the time the alarm goes off, pass through
5150e3d5408SPeter Wemm **      the sequence gotten so far.
5160e3d5408SPeter Wemm **
51739f2269fSPeter Wemm **	This function must be called when there are no cooked keys in queue.
5180e3d5408SPeter Wemm **	(that is head==-1 || peek==head)
5190e3d5408SPeter Wemm **
5200e3d5408SPeter Wemm */
5210e3d5408SPeter Wemm 
5220e3d5408SPeter Wemm static int
5234a1a9510SRong-En Fan kgetch(EVENTLIST_0th(_nc_eventlist * evl))
5240e3d5408SPeter Wemm {
5255ca44d1cSRong-En Fan     TRIES *ptr;
5260e3d5408SPeter Wemm     int ch = 0;
5270e3d5408SPeter Wemm     int timeleft = ESCDELAY;
5280e3d5408SPeter Wemm 
52939f2269fSPeter Wemm     TR(TRACE_IEVENT, ("kgetch() called"));
5300e3d5408SPeter Wemm 
5310e3d5408SPeter Wemm     ptr = SP->_keytry;
5320e3d5408SPeter Wemm 
53315589c42SPeter Wemm     for (;;) {
5344a1a9510SRong-En Fan 	if (cooked_key_in_fifo() && SP->_fifo[head] >= KEY_MIN) {
5354a1a9510SRong-En Fan 	    break;
5364a1a9510SRong-En Fan 	} else if (!raw_key_in_fifo()) {
5374a1a9510SRong-En Fan 	    ch = fifo_push(EVENTLIST_1st(evl));
5384a1a9510SRong-En Fan 	    if (ch == ERR) {
5390e3d5408SPeter Wemm 		peek = head;	/* the keys stay uninterpreted */
5400e3d5408SPeter Wemm 		return ERR;
5410e3d5408SPeter Wemm 	    }
5424a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
5434a1a9510SRong-En Fan 	    else if (ch == KEY_EVENT) {
5444a1a9510SRong-En Fan 		peek = head;	/* the keys stay uninterpreted */
5454a1a9510SRong-En Fan 		return fifo_pull();	/* Remove KEY_EVENT from the queue */
5460e3d5408SPeter Wemm 	    }
5474a1a9510SRong-En Fan #endif
5484a1a9510SRong-En Fan 	}
5494a1a9510SRong-En Fan 
5500e3d5408SPeter Wemm 	ch = fifo_peek();
55115589c42SPeter Wemm 	if (ch >= KEY_MIN) {
5524a1a9510SRong-En Fan 	    /* If not first in queue, somebody put this key there on purpose in
5534a1a9510SRong-En Fan 	     * emergency.  Consider it higher priority than the unfinished
5544a1a9510SRong-En Fan 	     * keysequence we are parsing.
5554a1a9510SRong-En Fan 	     */
5560e3d5408SPeter Wemm 	    peek = head;
5570e3d5408SPeter Wemm 	    /* assume the key is the last in fifo */
5580e3d5408SPeter Wemm 	    t_dec();		/* remove the key */
5590e3d5408SPeter Wemm 	    return ch;
5600e3d5408SPeter Wemm 	}
5610e3d5408SPeter Wemm 
56239f2269fSPeter Wemm 	TR(TRACE_IEVENT, ("ch: %s", _tracechar((unsigned char) ch)));
5630e3d5408SPeter Wemm 	while ((ptr != NULL) && (ptr->ch != (unsigned char) ch))
5640e3d5408SPeter Wemm 	    ptr = ptr->sibling;
56539f2269fSPeter Wemm 
56615589c42SPeter Wemm 	if (ptr == NULL) {
56715589c42SPeter Wemm 	    TR(TRACE_IEVENT, ("ptr is null"));
56839f2269fSPeter Wemm 	    break;
56939f2269fSPeter Wemm 	}
5700e3d5408SPeter Wemm 	TR(TRACE_IEVENT, ("ptr=%p, ch=%d, value=%d",
5710e3d5408SPeter Wemm 			  ptr, ptr->ch, ptr->value));
5720e3d5408SPeter Wemm 
5730e3d5408SPeter Wemm 	if (ptr->value != 0) {	/* sequence terminated */
5740e3d5408SPeter Wemm 	    TR(TRACE_IEVENT, ("end of sequence"));
5750e3d5408SPeter Wemm 	    if (peek == tail)
5760e3d5408SPeter Wemm 		fifo_clear();
5770e3d5408SPeter Wemm 	    else
5780e3d5408SPeter Wemm 		head = peek;
5790e3d5408SPeter Wemm 	    return (ptr->value);
5800e3d5408SPeter Wemm 	}
5810e3d5408SPeter Wemm 
5820e3d5408SPeter Wemm 	ptr = ptr->child;
5830e3d5408SPeter Wemm 
58415589c42SPeter Wemm 	if (!raw_key_in_fifo()) {
5854a1a9510SRong-En Fan 	    int rc;
5864a1a9510SRong-En Fan 
5870e3d5408SPeter Wemm 	    TR(TRACE_IEVENT, ("waiting for rest of sequence"));
5884a1a9510SRong-En Fan 	    rc = check_mouse_activity(timeleft EVENTLIST_2nd(evl));
5894a1a9510SRong-En Fan #ifdef NCURSES_WGETCH_EVENTS
5904a1a9510SRong-En Fan 	    if (rc & 4) {
5914a1a9510SRong-En Fan 		TR(TRACE_IEVENT, ("interrupted by a user event"));
5924a1a9510SRong-En Fan 		/* FIXME Should have preserved remainder timeleft for reuse... */
5934a1a9510SRong-En Fan 		peek = head;	/* Restart interpreting later */
5944a1a9510SRong-En Fan 		return KEY_EVENT;
5954a1a9510SRong-En Fan 	    }
5964a1a9510SRong-En Fan #endif
5974a1a9510SRong-En Fan 	    if (!rc) {
5980e3d5408SPeter Wemm 		TR(TRACE_IEVENT, ("ran out of time"));
5990e3d5408SPeter Wemm 		break;
6000e3d5408SPeter Wemm 	    }
6010e3d5408SPeter Wemm 	}
6020e3d5408SPeter Wemm     }
6030e3d5408SPeter Wemm     ch = fifo_pull();
6040e3d5408SPeter Wemm     peek = head;
6050e3d5408SPeter Wemm     return ch;
6060e3d5408SPeter Wemm }
607