150276Speter/****************************************************************************
2176187Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc.              *
350276Speter *                                                                          *
450276Speter * Permission is hereby granted, free of charge, to any person obtaining a  *
550276Speter * copy of this software and associated documentation files (the            *
650276Speter * "Software"), to deal in the Software without restriction, including      *
750276Speter * without limitation the rights to use, copy, modify, merge, publish,      *
850276Speter * distribute, distribute with modifications, sublicense, and/or sell       *
950276Speter * copies of the Software, and to permit persons to whom the Software is    *
1050276Speter * furnished to do so, subject to the following conditions:                 *
1150276Speter *                                                                          *
1250276Speter * The above copyright notice and this permission notice shall be included  *
1350276Speter * in all copies or substantial portions of the Software.                   *
1450276Speter *                                                                          *
1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
2250276Speter *                                                                          *
2350276Speter * Except as contained in this notice, the name(s) of the above copyright   *
2450276Speter * holders shall not be used in advertising or otherwise to promote the     *
2550276Speter * sale, use or other dealings in this Software without prior written       *
2650276Speter * authorization.                                                           *
2750276Speter ****************************************************************************/
2850276Speter
2950276Speter/****************************************************************************
3050276Speter *  Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995               *
3150276Speter *     and: Eric S. Raymond <esr@snark.thyrsus.com>                         *
32166124Srafan *     and: Thomas E. Dickey                        1996-on                 *
3350276Speter ****************************************************************************/
3450276Speter
3550276Speter/*
3650276Speter**	lib_getch.c
3750276Speter**
3850276Speter**	The routine getch().
3950276Speter**
4050276Speter*/
4150276Speter
4250276Speter#include <curses.priv.h>
4350276Speter
44184989SrafanMODULE_ID("$Id: lib_getch.c,v 1.99 2008/09/20 19:46:13 tom Exp $")
4550276Speter
4650276Speter#include <fifo_defs.h>
4750276Speter
48174993Srafan#if USE_REENTRANT
49178866Srafan#define GetEscdelay(sp) (sp)->_ESCDELAY
50174993SrafanNCURSES_EXPORT(int)
51174993SrafanNCURSES_PUBLIC_VAR(ESCDELAY) (void)
52174993Srafan{
53178866Srafan    return SP ? GetEscdelay(SP) : 1000;
54174993Srafan}
55174993Srafan#else
56178866Srafan#define GetEscdelay(sp) ESCDELAY
5776726SpeterNCURSES_EXPORT_VAR(int)
5876726SpeterESCDELAY = 1000;		/* max interval betw. chars in funkeys, in millisecs */
59174993Srafan#endif
6050276Speter
61176187Srafan#if NCURSES_EXT_FUNCS
62176187SrafanNCURSES_EXPORT(int)
63176187Srafanset_escdelay(int value)
64176187Srafan{
65176187Srafan    int code = OK;
66176187Srafan#if USE_REENTRANT
67176187Srafan    if (SP) {
68176187Srafan	SP->_ESCDELAY = value;
69176187Srafan    } else {
70176187Srafan	code = ERR;
71176187Srafan    }
72176187Srafan#else
73176187Srafan    ESCDELAY = value;
74176187Srafan#endif
75176187Srafan    return code;
76176187Srafan}
77176187Srafan#endif
78176187Srafan
79184989Srafanstatic int
80184989Srafan_nc_use_meta(WINDOW *win)
81184989Srafan{
82184989Srafan    SCREEN *sp = _nc_screen_of(win);
83184989Srafan    return (sp ? sp->_use_meta : 0);
84184989Srafan}
85184989Srafan
86166124Srafan#ifdef NCURSES_WGETCH_EVENTS
87166124Srafan#define TWAIT_MASK 7
88166124Srafan#else
89166124Srafan#define TWAIT_MASK 3
90166124Srafan#endif
91166124Srafan
92166124Srafan/*
93166124Srafan * Check for mouse activity, returning nonzero if we find any.
94166124Srafan */
95166124Srafanstatic int
96178866Srafancheck_mouse_activity(SCREEN *sp, int delay EVENTLIST_2nd(_nc_eventlist * evl))
97166124Srafan{
98166124Srafan    int rc;
99166124Srafan
100166124Srafan#if USE_SYSMOUSE
101178866Srafan    if ((sp->_mouse_type == M_SYSMOUSE)
102178866Srafan	&& (sp->_sysmouse_head < sp->_sysmouse_tail)) {
103166124Srafan	return 2;
104166124Srafan    }
105166124Srafan#endif
106178866Srafan    rc = _nc_timed_wait(sp, TWAIT_MASK, delay, (int *) 0 EVENTLIST_2nd(evl));
107166124Srafan#if USE_SYSMOUSE
108178866Srafan    if ((sp->_mouse_type == M_SYSMOUSE)
109178866Srafan	&& (sp->_sysmouse_head < sp->_sysmouse_tail)
110166124Srafan	&& (rc == 0)
111166124Srafan	&& (errno == EINTR)) {
112166124Srafan	rc |= 2;
113166124Srafan    }
114166124Srafan#endif
115166124Srafan    return rc;
116166124Srafan}
117166124Srafan
118166124Srafanstatic NCURSES_INLINE int
119178866Srafanfifo_peek(SCREEN *sp)
12050276Speter{
121178866Srafan    int ch = sp->_fifo[peek];
12266963Speter    TR(TRACE_IEVENT, ("peeking at %d", peek));
12350276Speter
12462449Speter    p_inc();
12562449Speter    return ch;
12650276Speter}
12750276Speter
128166124Srafanstatic NCURSES_INLINE int
129178866Srafanfifo_pull(SCREEN *sp)
13050276Speter{
13162449Speter    int ch;
132178866Srafan    ch = sp->_fifo[head];
133184989Srafan    TR(TRACE_IEVENT, ("pulling %s from %d", _nc_tracechar(sp, ch), head));
13450276Speter
13562449Speter    if (peek == head) {
13662449Speter	h_inc();
13762449Speter	peek = head;
13862449Speter    } else
13962449Speter	h_inc();
14050276Speter
14150276Speter#ifdef TRACE
142174993Srafan    if (USE_TRACEF(TRACE_IEVENT)) {
143178866Srafan	_nc_fifo_dump(sp);
144174993Srafan	_nc_unlock_global(tracef);
145174993Srafan    }
14650276Speter#endif
14762449Speter    return ch;
14850276Speter}
14950276Speter
150166124Srafanstatic NCURSES_INLINE int
151178866Srafanfifo_push(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl))
15250276Speter{
15362449Speter    int n;
154166124Srafan    int ch = 0;
155166124Srafan    int mask = 0;
15650276Speter
157166124Srafan    (void) mask;
15862449Speter    if (tail == -1)
15962449Speter	return ERR;
16050276Speter
16150276Speter#ifdef HIDE_EINTR
16262449Speter  again:
16362449Speter    errno = 0;
16450276Speter#endif
16550276Speter
166166124Srafan#ifdef NCURSES_WGETCH_EVENTS
167166124Srafan    if (evl
168166124Srafan#if USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE
169178866Srafan	|| (sp->_mouse_fd >= 0)
170166124Srafan#endif
171166124Srafan	) {
172178866Srafan	mask = check_mouse_activity(sp, -1 EVENTLIST_2nd(evl));
173166124Srafan    } else
174166124Srafan	mask = 0;
175166124Srafan
176166124Srafan    if (mask & 4) {
177166124Srafan	T(("fifo_push: ungetch KEY_EVENT"));
178178866Srafan	_nc_ungetch(sp, KEY_EVENT);
179166124Srafan	return KEY_EVENT;
180166124Srafan    }
181166124Srafan#elif USE_GPM_SUPPORT || USE_EMX_MOUSE || USE_SYSMOUSE
182178866Srafan    if (sp->_mouse_fd >= 0) {
183178866Srafan	mask = check_mouse_activity(sp, -1 EVENTLIST_2nd(evl));
184166124Srafan    }
185166124Srafan#endif
186166124Srafan
187166124Srafan#if USE_GPM_SUPPORT || USE_EMX_MOUSE
188178866Srafan    if ((sp->_mouse_fd >= 0) && (mask & 2)) {
189178866Srafan	sp->_mouse_event(sp);
19062449Speter	ch = KEY_MOUSE;
19162449Speter	n = 1;
19262449Speter    } else
19350276Speter#endif
194166124Srafan#if USE_SYSMOUSE
195178866Srafan	if ((sp->_mouse_type == M_SYSMOUSE)
196178866Srafan	    && (sp->_sysmouse_head < sp->_sysmouse_tail)) {
197178866Srafan	sp->_mouse_event(sp);
198166124Srafan	ch = KEY_MOUSE;
199166124Srafan	n = 1;
200178866Srafan    } else if ((sp->_mouse_type == M_SYSMOUSE)
201166124Srafan	       && (mask <= 0) && errno == EINTR) {
202178866Srafan	sp->_mouse_event(sp);
203166124Srafan	ch = KEY_MOUSE;
204166124Srafan	n = 1;
205166124Srafan    } else
206166124Srafan#endif
207166124Srafan    {				/* Can block... */
20862449Speter	unsigned char c2 = 0;
209178866Srafan	n = read(sp->_ifd, &c2, 1);
21097049Speter	ch = c2;
21162449Speter    }
21250276Speter
21350276Speter#ifdef HIDE_EINTR
21462449Speter    /*
21562449Speter     * Under System V curses with non-restarting signals, getch() returns
21662449Speter     * with value ERR when a handled signal keeps it from completing.
21762449Speter     * If signals restart system calls, OTOH, the signal is invisible
21862449Speter     * except to its handler.
21962449Speter     *
22062449Speter     * We don't want this difference to show.  This piece of code
22162449Speter     * tries to make it look like we always have restarting signals.
22262449Speter     */
22362449Speter    if (n <= 0 && errno == EINTR)
22462449Speter	goto again;
22550276Speter#endif
22650276Speter
22762449Speter    if ((n == -1) || (n == 0)) {
228178866Srafan	TR(TRACE_IEVENT, ("read(%d,&ch,1)=%d, errno=%d", sp->_ifd, n, errno));
22966963Speter	ch = ERR;
23062449Speter    }
23166963Speter    TR(TRACE_IEVENT, ("read %d characters", n));
23250276Speter
233178866Srafan    sp->_fifo[tail] = ch;
234178866Srafan    sp->_fifohold = 0;
23562449Speter    if (head == -1)
23662449Speter	head = peek = tail;
23762449Speter    t_inc();
238184989Srafan    TR(TRACE_IEVENT, ("pushed %s at %d", _nc_tracechar(sp, ch), tail));
23950276Speter#ifdef TRACE
240174993Srafan    if (USE_TRACEF(TRACE_IEVENT)) {
241178866Srafan	_nc_fifo_dump(sp);
242174993Srafan	_nc_unlock_global(tracef);
243174993Srafan    }
24450276Speter#endif
24562449Speter    return ch;
24650276Speter}
24750276Speter
248166124Srafanstatic NCURSES_INLINE void
249178866Srafanfifo_clear(SCREEN *sp)
25050276Speter{
251178866Srafan    memset(sp->_fifo, 0, sizeof(sp->_fifo));
25262449Speter    head = -1;
25362449Speter    tail = peek = 0;
25450276Speter}
25550276Speter
256178866Srafanstatic int kgetch(SCREEN *EVENTLIST_2nd(_nc_eventlist * evl));
25750276Speter
258184989Srafanstatic void
259184989Srafanrecur_wrefresh(WINDOW *win)
260184989Srafan{
261184989Srafan#ifdef USE_PTHREADS
262184989Srafan    SCREEN *sp = _nc_screen_of(win);
263184989Srafan    if (_nc_use_pthreads && sp != SP) {
264184989Srafan	SCREEN *save_SP;
26550276Speter
266184989Srafan	/* temporarily switch to the window's screen to check/refresh */
267184989Srafan	_nc_lock_global(curses);
268184989Srafan	save_SP = SP;
269184989Srafan	_nc_set_screen(sp);
270184989Srafan	recur_wrefresh(win);
271184989Srafan	_nc_set_screen(save_SP);
272184989Srafan	_nc_unlock_global(curses);
273184989Srafan    } else
274184989Srafan#endif
275184989Srafan	if ((is_wintouched(win) || (win->_flags & _HASMOVED))
276184989Srafan	    && !(win->_flags & _ISPAD)) {
277184989Srafan	wrefresh(win);
278184989Srafan    }
279184989Srafan}
280184989Srafan
281184989Srafanstatic int
282184989Srafanrecur_wgetnstr(WINDOW *win, char *buf)
283184989Srafan{
284184989Srafan    SCREEN *sp = _nc_screen_of(win);
285184989Srafan    int rc;
286184989Srafan
287184989Srafan    if (sp != 0) {
288184989Srafan#ifdef USE_PTHREADS
289184989Srafan	if (_nc_use_pthreads && sp != SP) {
290184989Srafan	    SCREEN *save_SP;
291184989Srafan
292184989Srafan	    /* temporarily switch to the window's screen to get cooked input */
293184989Srafan	    _nc_lock_global(curses);
294184989Srafan	    save_SP = SP;
295184989Srafan	    _nc_set_screen(sp);
296184989Srafan	    rc = recur_wgetnstr(win, buf);
297184989Srafan	    _nc_set_screen(save_SP);
298184989Srafan	    _nc_unlock_global(curses);
299184989Srafan	} else
300184989Srafan#endif
301184989Srafan	{
302184989Srafan	    sp->_called_wgetch = TRUE;
303184989Srafan	    rc = wgetnstr(win, buf, MAXCOLUMNS);
304184989Srafan	    sp->_called_wgetch = FALSE;
305184989Srafan	}
306184989Srafan    } else {
307184989Srafan	rc = ERR;
308184989Srafan    }
309184989Srafan    return rc;
310184989Srafan}
311184989Srafan
31276726SpeterNCURSES_EXPORT(int)
313166124Srafan_nc_wgetch(WINDOW *win,
314166124Srafan	   unsigned long *result,
315166124Srafan	   int use_meta
316166124Srafan	   EVENTLIST_2nd(_nc_eventlist * evl))
31750276Speter{
318184989Srafan    SCREEN *sp;
31962449Speter    int ch;
320166124Srafan#ifdef NCURSES_WGETCH_EVENTS
321166124Srafan    long event_delay = -1;
322166124Srafan#endif
32350276Speter
324166124Srafan    T((T_CALLED("_nc_wgetch(%p)"), win));
32550276Speter
32697049Speter    *result = 0;
327184989Srafan
328184989Srafan    sp = _nc_screen_of(win);
329178866Srafan    if (win == 0 || sp == 0) {
33062449Speter	returnCode(ERR);
331174993Srafan    }
33250276Speter
33362449Speter    if (cooked_key_in_fifo()) {
334184989Srafan	recur_wrefresh(win);
335178866Srafan	*result = fifo_pull(sp);
336174993Srafan	returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
33762449Speter    }
338166124Srafan#ifdef NCURSES_WGETCH_EVENTS
339166124Srafan    if (evl && (evl->count == 0))
340166124Srafan	evl = NULL;
341166124Srafan    event_delay = _nc_eventlist_timeout(evl);
342166124Srafan#endif
34350276Speter
34462449Speter    /*
34562449Speter     * Handle cooked mode.  Grab a string from the screen,
34662449Speter     * stuff its contents in the FIFO queue, and pop off
34762449Speter     * the first character to return it.
34862449Speter     */
349166124Srafan    if (head == -1 &&
350178866Srafan	!sp->_notty &&
351178866Srafan	!sp->_raw &&
352178866Srafan	!sp->_cbreak &&
353178866Srafan	!sp->_called_wgetch) {
354178866Srafan	char buf[MAXCOLUMNS], *bufp;
355166124Srafan	int rc;
35650276Speter
35766963Speter	TR(TRACE_IEVENT, ("filling queue in cooked mode"));
35850276Speter
359184989Srafan	rc = recur_wgetnstr(win, buf);
36050276Speter
36162449Speter	/* ungetch in reverse order */
362166124Srafan#ifdef NCURSES_WGETCH_EVENTS
363166124Srafan	if (rc != KEY_EVENT)
364166124Srafan#endif
365178866Srafan	    _nc_ungetch(sp, '\n');
366178866Srafan	for (bufp = buf + strlen(buf); bufp > buf; bufp--)
367178866Srafan	    _nc_ungetch(sp, bufp[-1]);
36850276Speter
369166124Srafan#ifdef NCURSES_WGETCH_EVENTS
370166124Srafan	/* Return it first */
371166124Srafan	if (rc == KEY_EVENT) {
372166124Srafan	    *result = rc;
373174993Srafan	} else
374166124Srafan#endif
375178866Srafan	    *result = fifo_pull(sp);
376174993Srafan	returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
37762449Speter    }
37850276Speter
379178866Srafan    if (win->_use_keypad != sp->_keypad_on)
380178866Srafan	_nc_keypad(sp, win->_use_keypad);
38197049Speter
382184989Srafan    recur_wrefresh(win);
38350276Speter
384184989Srafan    if (win->_notimeout || (win->_delay >= 0) || (sp->_cbreak > 1)) {
385166124Srafan	if (head == -1) {	/* fifo is empty */
386166124Srafan	    int delay;
387166124Srafan	    int rc;
38850276Speter
389166124Srafan	    TR(TRACE_IEVENT, ("timed delay in wgetch()"));
390178866Srafan	    if (sp->_cbreak > 1)
391178866Srafan		delay = (sp->_cbreak - 1) * 100;
392166124Srafan	    else
393166124Srafan		delay = win->_delay;
39450276Speter
395166124Srafan#ifdef NCURSES_WGETCH_EVENTS
396166124Srafan	    if (event_delay >= 0 && delay > event_delay)
397166124Srafan		delay = event_delay;
398166124Srafan#endif
39950276Speter
400166124Srafan	    TR(TRACE_IEVENT, ("delay is %d milliseconds", delay));
401166124Srafan
402178866Srafan	    rc = check_mouse_activity(sp, delay EVENTLIST_2nd(evl));
403166124Srafan
404166124Srafan#ifdef NCURSES_WGETCH_EVENTS
405166124Srafan	    if (rc & 4) {
406166124Srafan		*result = KEY_EVENT;
407174993Srafan		returnCode(KEY_CODE_YES);
408166124Srafan	    }
409166124Srafan#endif
410184989Srafan	    if (!rc) {
41162449Speter		returnCode(ERR);
412184989Srafan	    }
413166124Srafan	}
41462449Speter	/* else go on to read data available */
41562449Speter    }
41650276Speter
41762449Speter    if (win->_use_keypad) {
41862449Speter	/*
41962449Speter	 * This is tricky.  We only want to get special-key
42062449Speter	 * events one at a time.  But we want to accumulate
42162449Speter	 * mouse events until either (a) the mouse logic tells
42262449Speter	 * us it's picked up a complete gesture, or (b)
42362449Speter	 * there's a detectable time lapse after one.
42462449Speter	 *
42562449Speter	 * Note: if the mouse code starts failing to compose
42662449Speter	 * press/release events into clicks, you should probably
42762449Speter	 * increase the wait with mouseinterval().
42862449Speter	 */
42962449Speter	int runcount = 0;
430166124Srafan	int rc;
43150276Speter
43262449Speter	do {
433178866Srafan	    ch = kgetch(sp EVENTLIST_2nd(evl));
43462449Speter	    if (ch == KEY_MOUSE) {
43562449Speter		++runcount;
436178866Srafan		if (sp->_mouse_inline(sp))
43762449Speter		    break;
43862449Speter	    }
439178866Srafan	    if (sp->_maxclick < 0)
44097049Speter		break;
44162449Speter	} while
44262449Speter	    (ch == KEY_MOUSE
443178866Srafan	     && (((rc = check_mouse_activity(sp, sp->_maxclick
444166124Srafan					     EVENTLIST_2nd(evl))) != 0
445166124Srafan		  && !(rc & 4))
446184989Srafan		 || !sp->_mouse_parse(sp, runcount)));
447166124Srafan#ifdef NCURSES_WGETCH_EVENTS
448166124Srafan	if ((rc & 4) && !ch == KEY_EVENT) {
449178866Srafan	    _nc_ungetch(sp, ch);
450166124Srafan	    ch = KEY_EVENT;
45150276Speter	}
452166124Srafan#endif
453166124Srafan	if (runcount > 0 && ch != KEY_MOUSE) {
454166124Srafan#ifdef NCURSES_WGETCH_EVENTS
455166124Srafan	    /* mouse event sequence ended by an event, report event */
456166124Srafan	    if (ch == KEY_EVENT) {
457178866Srafan		_nc_ungetch(sp, KEY_MOUSE);	/* FIXME This interrupts a gesture... */
458166124Srafan	    } else
459166124Srafan#endif
460166124Srafan	    {
461166124Srafan		/* mouse event sequence ended by keystroke, store keystroke */
462178866Srafan		_nc_ungetch(sp, ch);
463166124Srafan		ch = KEY_MOUSE;
464166124Srafan	    }
465166124Srafan	}
46662449Speter    } else {
46762449Speter	if (head == -1)
468178866Srafan	    fifo_push(sp EVENTLIST_2nd(evl));
469178866Srafan	ch = fifo_pull(sp);
47062449Speter    }
47150276Speter
47262449Speter    if (ch == ERR) {
47350276Speter#if USE_SIZECHANGE
474178866Srafan	if (_nc_handle_sigwinch(sp)) {
475178866Srafan	    _nc_update_screensize(sp);
47662449Speter	    /* resizeterm can push KEY_RESIZE */
47762449Speter	    if (cooked_key_in_fifo()) {
478178866Srafan		*result = fifo_pull(sp);
479198490Srafan		/*
480198490Srafan		 * Get the ERR from queue -- it is from WINCH,
481198490Srafan		 * so we should take it out, the "error" is handled.
482198490Srafan		 */
483198490Srafan		if (fifo_peek(sp) == -1)
484198490Srafan		    fifo_pull(sp);
48598503Speter		returnCode(*result >= KEY_MIN ? KEY_CODE_YES : OK);
48650276Speter	    }
48762449Speter	}
48850276Speter#endif
48962449Speter	returnCode(ERR);
49062449Speter    }
49150276Speter
49262449Speter    /*
49362449Speter     * If echo() is in effect, display the printable version of the
49462449Speter     * key on the screen.  Carriage return and backspace are treated
49562449Speter     * specially by Solaris curses:
49662449Speter     *
49762449Speter     * If carriage return is defined as a function key in the
49862449Speter     * terminfo, e.g., kent, then Solaris may return either ^J (or ^M
49962449Speter     * if nonl() is set) or KEY_ENTER depending on the echo() mode.
50062449Speter     * We echo before translating carriage return based on nonl(),
50162449Speter     * since the visual result simply moves the cursor to column 0.
50262449Speter     *
50362449Speter     * Backspace is a different matter.  Solaris curses does not
50462449Speter     * translate it to KEY_BACKSPACE if kbs=^H.  This does not depend
50562449Speter     * on the stty modes, but appears to be a hardcoded special case.
50662449Speter     * This is a difference from ncurses, which uses the terminfo entry.
50762449Speter     * However, we provide the same visual result as Solaris, moving the
50862449Speter     * cursor to the left.
50962449Speter     */
510178866Srafan    if (sp->_echo && !(win->_flags & _ISPAD)) {
51162449Speter	chtype backup = (ch == KEY_BACKSPACE) ? '\b' : ch;
51262449Speter	if (backup < KEY_MIN)
51362449Speter	    wechochar(win, backup);
51462449Speter    }
51550276Speter
51662449Speter    /*
51762449Speter     * Simulate ICRNL mode
51862449Speter     */
519178866Srafan    if ((ch == '\r') && sp->_nl)
52062449Speter	ch = '\n';
52150276Speter
52262449Speter    /* Strip 8th-bit if so desired.  We do this only for characters that
52362449Speter     * are in the range 128-255, to provide compatibility with terminals
52462449Speter     * that display only 7-bit characters.  Note that 'ch' may be a
52562449Speter     * function key at this point, so we mustn't strip _those_.
52662449Speter     */
52797049Speter    if (!use_meta)
52897049Speter	if ((ch < KEY_MIN) && (ch & 0x80))
52962449Speter	    ch &= 0x7f;
53050276Speter
531184989Srafan    T(("wgetch returning : %s", _nc_tracechar(sp, ch)));
53250276Speter
53397049Speter    *result = ch;
53497049Speter    returnCode(ch >= KEY_MIN ? KEY_CODE_YES : OK);
53550276Speter}
53650276Speter
537166124Srafan#ifdef NCURSES_WGETCH_EVENTS
53897049SpeterNCURSES_EXPORT(int)
539166124Srafanwgetch_events(WINDOW *win, _nc_eventlist * evl)
540166124Srafan{
541166124Srafan    int code;
542166124Srafan    unsigned long value;
543166124Srafan
544166124Srafan    T((T_CALLED("wgetch_events(%p,%p)"), win, evl));
545166124Srafan    code = _nc_wgetch(win,
546166124Srafan		      &value,
547184989Srafan		      _nc_use_meta(win)
548166124Srafan		      EVENTLIST_2nd(evl));
549166124Srafan    if (code != ERR)
550166124Srafan	code = value;
551166124Srafan    returnCode(code);
552166124Srafan}
553166124Srafan#endif
554166124Srafan
555166124SrafanNCURSES_EXPORT(int)
55697049Speterwgetch(WINDOW *win)
55797049Speter{
55897049Speter    int code;
55997049Speter    unsigned long value;
56097049Speter
56197049Speter    T((T_CALLED("wgetch(%p)"), win));
562166124Srafan    code = _nc_wgetch(win,
563166124Srafan		      &value,
564184989Srafan		      _nc_use_meta(win)
565166124Srafan		      EVENTLIST_2nd((_nc_eventlist *) 0));
56697049Speter    if (code != ERR)
56797049Speter	code = value;
56897049Speter    returnCode(code);
56997049Speter}
57097049Speter
57150276Speter/*
57250276Speter**      int
57350276Speter**      kgetch()
57450276Speter**
57550276Speter**      Get an input character, but take care of keypad sequences, returning
57650276Speter**      an appropriate code when one matches the input.  After each character
57750276Speter**      is received, set an alarm call based on ESCDELAY.  If no more of the
57850276Speter**      sequence is received by the time the alarm goes off, pass through
57950276Speter**      the sequence gotten so far.
58050276Speter**
58197049Speter**	This function must be called when there are no cooked keys in queue.
58250276Speter**	(that is head==-1 || peek==head)
58350276Speter**
58450276Speter*/
58550276Speter
58650276Speterstatic int
587178866Srafankgetch(SCREEN *sp EVENTLIST_2nd(_nc_eventlist * evl))
58850276Speter{
589174993Srafan    TRIES *ptr;
59062449Speter    int ch = 0;
591178866Srafan    int timeleft = GetEscdelay(sp);
59250276Speter
59397049Speter    TR(TRACE_IEVENT, ("kgetch() called"));
59450276Speter
595178866Srafan    ptr = sp->_keytry;
59650276Speter
59762449Speter    for (;;) {
598178866Srafan	if (cooked_key_in_fifo() && sp->_fifo[head] >= KEY_MIN) {
599166124Srafan	    break;
600166124Srafan	} else if (!raw_key_in_fifo()) {
601178866Srafan	    ch = fifo_push(sp EVENTLIST_2nd(evl));
602166124Srafan	    if (ch == ERR) {
60362449Speter		peek = head;	/* the keys stay uninterpreted */
60462449Speter		return ERR;
60562449Speter	    }
606166124Srafan#ifdef NCURSES_WGETCH_EVENTS
607166124Srafan	    else if (ch == KEY_EVENT) {
608166124Srafan		peek = head;	/* the keys stay uninterpreted */
609178866Srafan		return fifo_pull(sp);	/* Remove KEY_EVENT from the queue */
610166124Srafan	    }
611166124Srafan#endif
61262449Speter	}
613166124Srafan
614178866Srafan	ch = fifo_peek(sp);
61562449Speter	if (ch >= KEY_MIN) {
616166124Srafan	    /* If not first in queue, somebody put this key there on purpose in
617166124Srafan	     * emergency.  Consider it higher priority than the unfinished
618166124Srafan	     * keysequence we are parsing.
619166124Srafan	     */
62062449Speter	    peek = head;
62162449Speter	    /* assume the key is the last in fifo */
62262449Speter	    t_dec();		/* remove the key */
62362449Speter	    return ch;
62462449Speter	}
62550276Speter
626184989Srafan	TR(TRACE_IEVENT, ("ch: %s", _nc_tracechar(sp, (unsigned char) ch)));
62762449Speter	while ((ptr != NULL) && (ptr->ch != (unsigned char) ch))
62862449Speter	    ptr = ptr->sibling;
62997049Speter
63062449Speter	if (ptr == NULL) {
63162449Speter	    TR(TRACE_IEVENT, ("ptr is null"));
63262449Speter	    break;
63397049Speter	}
63497049Speter	TR(TRACE_IEVENT, ("ptr=%p, ch=%d, value=%d",
63597049Speter			  ptr, ptr->ch, ptr->value));
63650276Speter
63762449Speter	if (ptr->value != 0) {	/* sequence terminated */
63862449Speter	    TR(TRACE_IEVENT, ("end of sequence"));
63962449Speter	    if (peek == tail)
640178866Srafan		fifo_clear(sp);
64162449Speter	    else
64262449Speter		head = peek;
64362449Speter	    return (ptr->value);
64462449Speter	}
64550276Speter
64662449Speter	ptr = ptr->child;
64750276Speter
64862449Speter	if (!raw_key_in_fifo()) {
649166124Srafan	    int rc;
650166124Srafan
65162449Speter	    TR(TRACE_IEVENT, ("waiting for rest of sequence"));
652178866Srafan	    rc = check_mouse_activity(sp, timeleft EVENTLIST_2nd(evl));
653166124Srafan#ifdef NCURSES_WGETCH_EVENTS
654166124Srafan	    if (rc & 4) {
655166124Srafan		TR(TRACE_IEVENT, ("interrupted by a user event"));
656166124Srafan		/* FIXME Should have preserved remainder timeleft for reuse... */
657166124Srafan		peek = head;	/* Restart interpreting later */
658166124Srafan		return KEY_EVENT;
659166124Srafan	    }
660166124Srafan#endif
661166124Srafan	    if (!rc) {
66262449Speter		TR(TRACE_IEVENT, ("ran out of time"));
66362449Speter		break;
66462449Speter	    }
66550276Speter	}
66662449Speter    }
667178866Srafan    ch = fifo_pull(sp);
66862449Speter    peek = head;
66962449Speter    return ch;
67050276Speter}
671