2 /***************************************************************************
4 ****************************************************************************
5 * ncurses is copyright (C) 1992-1995 *
7 * zmbenhal@netcom.com *
9 * esr@snark.thyrsus.com *
11 * Permission is hereby granted to reproduce and distribute ncurses *
12 * by any means and for any fee, whether alone or as part of a *
13 * larger distribution, in source or in binary form, PROVIDED *
14 * this notice is included with any such distribution, and is not *
15 * removed from any of its header files. Mention of ncurses in any *
16 * applications linked with it is highly appreciated. *
18 * ncurses comes AS IS with no warranty, implied or expressed. *
20 ***************************************************************************/
25 ** The routine getch().
29 #include <curses.priv.h>
31 MODULE_ID("$Id: lib_getch.c,v 1.24 1997/02/15 21:12:16 tom Exp $")
33 #define head SP->_fifohead
34 #define tail SP->_fifotail
35 #define peek SP->_fifopeek
37 #define h_inc() { head == FIFO_SIZE-1 ? head = 0 : head++; if (head == tail) head = -1, tail = 0;}
38 #define h_dec() { head == 0 ? head = FIFO_SIZE-1 : head--; if (head == tail) tail = -1;}
39 #define t_inc() { tail == FIFO_SIZE-1 ? tail = 0 : tail++; if (tail == head) tail = -1;}
40 #define p_inc() { peek == FIFO_SIZE-1 ? peek = 0 : peek++;}
42 int ESCDELAY = 1000; /* max interval betw. chars in funkeys, in millisecs */
44 static int fifo_peek(void)
46 T(("peeking at %d", peek+1));
47 return SP->_fifo[++peek];
51 static inline void fifo_dump(void)
54 T(("head = %d, tail = %d, peek = %d", head, tail, peek));
55 for (i = 0; i < 10; i++)
56 T(("char %d = %s", i, _trace_key(SP->_fifo[i])));
60 static inline int fifo_pull(void)
64 T(("pulling %d from %d", ch, head));
68 if (_nc_tracing & TRACE_IEVENT) fifo_dump();
86 if (_nc_tracing & TRACE_IEVENT) fifo_dump();
91 static inline int fifo_push(void)
96 if (tail == -1) return ERR;
101 if ((_nc_mouse_fd() >= 0)
102 && (_nc_timed_wait(3, -1, (int *)0) & 2))
111 n = read(SP->_ifd, &c2, 1);
116 * Under System V curses with non-restarting signals, getch() returns
117 * with value ERR when a handled signal keeps it from completing.
118 * If signals restart system calls, OTOH, the signal is invisible
119 * except to its handler.
121 * We don't want this difference to show. This piece of code
122 * tries to make it look like we always have restarting signals.
124 if (n <= 0 && errno == EINTR)
127 if ((n == -1) || (n == 0))
129 T(("read(%d,&ch,1)=%d", SP->_ifd, n));
132 T(("read %d characters", n));
134 SP->_fifo[tail] = ch;
135 if (head == -1) head = tail;
137 T(("pushed %#x at %d", ch, tail));
139 if (_nc_tracing & TRACE_IEVENT) fifo_dump();
144 static inline void fifo_clear(void)
147 for (i = 0; i < FIFO_SIZE; i++)
149 head = -1; tail = peek = 0;
152 static int kgetch(WINDOW *);
154 void _nc_backspace(WINDOW *win)
162 mvwaddstr(curscr, win->_begy + win->_cury + win->_yoffset,
163 win->_begx + win->_curx, "\b \b");
164 waddstr(win, "\b \b");
167 * This used to do the equivalent of _nc_outstr("\b \b"), which
168 * would fail on terminals with a non-backspace cursor_left
171 mvcur(win->_begy + win->_cury + win->_yoffset,
172 win->_begx + win->_curx,
173 win->_begy + win->_cury + win->_yoffset,
174 win->_begx + win->_curx - 1);
176 mvcur(win->_begy + win->_cury + win->_yoffset,
177 win->_begx + win->_curx,
178 win->_begy + win->_cury + win->_yoffset,
179 win->_begx + win->_curx - 1);
188 T((T_CALLED("wgetch(%p)"), win));
191 * Handle cooked mode. Grab a string from the screen,
192 * stuff its contents in the FIFO queue, and pop off
193 * the first character to return it.
195 if (head == -1 && !SP->_raw && !SP->_cbreak)
197 char buf[MAXCOLUMNS], *sp;
199 T(("filling queue in cooked mode"));
201 wgetnstr(win, buf, MAXCOLUMNS);
203 for (sp = buf; *sp; sp++)
210 /* this should be eliminated */
214 && (win->_flags & _FULLWIN)
215 && win->_curx == win->_maxx
216 && win->_cury == win->_maxy)
219 if ((is_wintouched(win) || (win->_flags & _HASMOVED)) && !(win->_flags & _ISPAD))
222 if (!win->_notimeout && (win->_delay >= 0 || SP->_cbreak > 1)) {
225 T(("timed delay in wgetch()"));
227 delay = (SP->_cbreak-1) * 100;
231 T(("delay is %d microseconds", delay));
233 if (head == -1) /* fifo is empty */
234 if (!_nc_timed_wait(3, delay, (int *)0))
236 /* else go on to read data available */
239 if (win->_use_keypad) {
241 * This is tricky. We only want to get special-key
242 * events one at a time. But we want to accumulate
243 * mouse events until either (a) the mouse logic tells
244 * us it's picked up a complete gesture, or (b)
245 * there's a detectable time lapse after one.
247 * Note: if the mouse code starts failing to compose
248 * press/release events into clicks, you should probably
249 * increase _nc_max_click_interval.
258 if (_nc_mouse_inline(SP))
263 && (_nc_timed_wait(3, _nc_max_click_interval, (int *)0)
264 || !_nc_mouse_parse(runcount)));
265 if (runcount > 0 && ch != KEY_MOUSE)
267 /* mouse event sequence ended by keystroke, push it */
279 T(("wgetch returning ERR"));
284 * Simulate ICRNL mode
286 if ((ch == '\r') && SP->_nl)
289 /* Strip 8th-bit if so desired. We do this only for characters that
290 * are in the range 128-255, to provide compatibility with terminals
291 * that display only 7-bit characters. Note that 'ch' may be a
292 * function key at this point, so we mustn't strip _those_.
294 if ((ch < KEY_MIN) && (ch & 0x80))
298 if (!(win->_flags & _ISPAD) && SP->_echo) {
299 /* there must be a simpler way of doing this */
300 if (ch == erasechar() || ch == KEY_BACKSPACE || ch == KEY_LEFT)
302 else if (ch < KEY_MIN) {
304 win->_begy + win->_cury + win->_yoffset,
305 win->_begx + win->_curx,
307 waddch(win, (chtype)ch);
313 T(("wgetch returning : %#x = %s", ch, _trace_key(ch));)
323 ** Get an input character, but take care of keypad sequences, returning
324 ** an appropriate code when one matches the input. After each character
325 ** is received, set an alarm call based on ESCDELAY. If no more of the
326 ** sequence is received by the time the alarm goes off, pass through
327 ** the sequence gotten so far.
332 kgetch(WINDOW *win GCC_UNUSED)
336 int timeleft = ESCDELAY;
338 TR(TRACE_IEVENT, ("kgetch(%p) called", win));
343 if ((ch = fifo_push()) == ERR)
346 while (ptr != NULL) {
347 TR(TRACE_IEVENT, ("ch: %s", _trace_key((unsigned char)ch)));
348 while ((ptr != NULL) && (ptr->ch != (unsigned char)ch))
352 {TR(TRACE_IEVENT, ("ptr is null"));}
354 TR(TRACE_IEVENT, ("ptr=%p, ch=%d, value=%d",
355 ptr, ptr->ch, ptr->value));
359 if (ptr->value != 0) { /* sequence terminated */
360 TR(TRACE_IEVENT, ("end of sequence"));
363 } else { /* go back for another character */
365 TR(TRACE_IEVENT, ("going back for more"));
369 TR(TRACE_IEVENT, ("waiting for rest of sequence"));
370 if (!_nc_timed_wait(3, timeleft, &timeleft)) {
371 TR(TRACE_IEVENT, ("ran out of time"));
374 TR(TRACE_IEVENT, ("got more!"));