diff options
Diffstat (limited to 'contrib/ncurses/ncurses/base/lib_getch.c')
-rw-r--r-- | contrib/ncurses/ncurses/base/lib_getch.c | 414 |
1 files changed, 414 insertions, 0 deletions
diff --git a/contrib/ncurses/ncurses/base/lib_getch.c b/contrib/ncurses/ncurses/base/lib_getch.c new file mode 100644 index 000000000000..b740885b8166 --- /dev/null +++ b/contrib/ncurses/ncurses/base/lib_getch.c @@ -0,0 +1,414 @@ +/**************************************************************************** + * Copyright (c) 1998 Free Software Foundation, Inc. * + * * + * Permission is hereby granted, free of charge, to any person obtaining a * + * copy of this software and associated documentation files (the * + * "Software"), to deal in the Software without restriction, including * + * without limitation the rights to use, copy, modify, merge, publish, * + * distribute, distribute with modifications, sublicense, and/or sell * + * copies of the Software, and to permit persons to whom the Software is * + * furnished to do so, subject to the following conditions: * + * * + * The above copyright notice and this permission notice shall be included * + * in all copies or substantial portions of the Software. * + * * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * + * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * + * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * + * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * + * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * + * * + * Except as contained in this notice, the name(s) of the above copyright * + * holders shall not be used in advertising or otherwise to promote the * + * sale, use or other dealings in this Software without prior written * + * authorization. * + ****************************************************************************/ + +/**************************************************************************** + * Author: Zeyd M. Ben-Halim <zmbenhal@netcom.com> 1992,1995 * + * and: Eric S. Raymond <esr@snark.thyrsus.com> * + ****************************************************************************/ + +/* +** lib_getch.c +** +** The routine getch(). +** +*/ + +#include <curses.priv.h> + +MODULE_ID("$Id: lib_getch.c,v 1.43 1999/03/08 02:35:10 tom Exp $") + +#include <fifo_defs.h> + +int ESCDELAY = 1000; /* max interval betw. chars in funkeys, in millisecs */ + +#ifdef USE_EMX_MOUSE +# include <sys/select.h> +static int +kbd_mouse_read(unsigned char *p) +{ +fd_set fdset; +int nums = SP->_ifd+1; + + for (;;) { + FD_ZERO(&fdset); + FD_SET(SP->_checkfd, &fdset); + if (SP->_mouse_fd >= 0) { + FD_SET(SP->_mouse_fd, &fdset); + if (SP->_mouse_fd > SP->_checkfd) + nums = SP->_mouse_fd+1; + } + if (select(nums, &fdset, NULL, NULL, NULL) >= 0) { + int n; + + if (FD_ISSET(SP->_mouse_fd, &fdset)) /* Prefer mouse */ + n = read(SP->_mouse_fd, p, 1); + else + n = read(SP->_ifd, p, 1); + return n; + } + if (errno != EINTR) + return -1; + } +} +#endif /* USE_EMX_MOUSE */ + +static inline int fifo_peek(void) +{ + int ch = SP->_fifo[peek]; + T(("peeking at %d", peek)); + + p_inc(); + return ch; +} + + +static inline int fifo_pull(void) +{ +int ch; + ch = SP->_fifo[head]; + T(("pulling %d from %d", ch, head)); + + if (peek == head) + { + h_inc(); + peek = head; + } + else + h_inc(); + +#ifdef TRACE + if (_nc_tracing & TRACE_IEVENT) _nc_fifo_dump(); +#endif + return ch; +} + +static inline int fifo_push(void) +{ +int n; +unsigned int ch; + + if (tail == -1) return ERR; + +#ifdef HIDE_EINTR +again: + errno = 0; +#endif + +#if USE_GPM_SUPPORT + if ((SP->_mouse_fd >= 0) + && (_nc_timed_wait(3, -1, (int *)0) & 2)) + { + SP->_mouse_event(SP); + ch = KEY_MOUSE; + n = 1; + } else +#endif + { + unsigned char c2=0; +#ifdef USE_EMX_MOUSE + n = kbd_mouse_read(&c2); +#else + n = read(SP->_ifd, &c2, 1); +#endif + ch = c2 & 0xff; + } + +#ifdef HIDE_EINTR + /* + * Under System V curses with non-restarting signals, getch() returns + * with value ERR when a handled signal keeps it from completing. + * If signals restart system calls, OTOH, the signal is invisible + * except to its handler. + * + * We don't want this difference to show. This piece of code + * tries to make it look like we always have restarting signals. + */ + if (n <= 0 && errno == EINTR) + goto again; +#endif + + if ((n == -1) || (n == 0)) + { + T(("read(%d,&ch,1)=%d, errno=%d", SP->_ifd, n, errno)); + return ERR; + } + T(("read %d characters", n)); + + SP->_fifo[tail] = ch; + SP->_fifohold = 0; + if (head == -1) + head = peek = tail; + t_inc(); + T(("pushed %#x at %d", ch, tail)); +#ifdef TRACE + if (_nc_tracing & TRACE_IEVENT) _nc_fifo_dump(); +#endif + return ch; +} + +static inline void fifo_clear(void) +{ +int i; + for (i = 0; i < FIFO_SIZE; i++) + SP->_fifo[i] = 0; + head = -1; tail = peek = 0; +} + +static int kgetch(WINDOW *); + +#define wgetch_should_refresh(win) (\ + (is_wintouched(win) || (win->_flags & _HASMOVED)) \ + && !(win->_flags & _ISPAD)) + +int +wgetch(WINDOW *win) +{ +int ch; + + T((T_CALLED("wgetch(%p)"), win)); + + if (!win) + returnCode(ERR); + + if (cooked_key_in_fifo()) + { + if (wgetch_should_refresh(win)) + wrefresh(win); + + ch = fifo_pull(); + T(("wgetch returning (pre-cooked): %#x = %s", ch, _trace_key(ch));) + returnCode(ch); + } + + /* + * Handle cooked mode. Grab a string from the screen, + * stuff its contents in the FIFO queue, and pop off + * the first character to return it. + */ + if (head == -1 && !SP->_raw && !SP->_cbreak) + { + char buf[MAXCOLUMNS], *sp; + + T(("filling queue in cooked mode")); + + wgetnstr(win, buf, MAXCOLUMNS); + + /* ungetch in reverse order */ + ungetch('\n'); + for (sp = buf+strlen(buf); sp>buf; sp--) + ungetch(sp[-1]); + + returnCode(fifo_pull()); + } + + if (wgetch_should_refresh(win)) + wrefresh(win); + + if (!win->_notimeout && (win->_delay >= 0 || SP->_cbreak > 1)) + { + int delay; + + T(("timed delay in wgetch()")); + if (SP->_cbreak > 1) + delay = (SP->_cbreak - 1) * 100; + else + delay = win->_delay; + + T(("delay is %d milliseconds", delay)); + + if (head == -1) /* fifo is empty */ + if (!_nc_timed_wait(3, delay, (int *)0)) + returnCode(ERR); + /* else go on to read data available */ + } + + if (win->_use_keypad) + { + /* + * This is tricky. We only want to get special-key + * events one at a time. But we want to accumulate + * mouse events until either (a) the mouse logic tells + * us it's picked up a complete gesture, or (b) + * there's a detectable time lapse after one. + * + * Note: if the mouse code starts failing to compose + * press/release events into clicks, you should probably + * increase the wait with mouseinterval(). + */ + int runcount = 0; + + do { + ch = kgetch(win); + if (ch == KEY_MOUSE) + { + ++runcount; + if (SP->_mouse_inline(SP)) + break; + } + } while + (ch == KEY_MOUSE + && (_nc_timed_wait(3, SP->_maxclick, (int *)0) + || !SP->_mouse_parse(runcount))); + if (runcount > 0 && ch != KEY_MOUSE) + { + /* mouse event sequence ended by keystroke, push it */ + ungetch(ch); + ch = KEY_MOUSE; + } + } else { + if (head == -1) + fifo_push(); + ch = fifo_pull(); + } + + if (ch == ERR) + { +#if USE_SIZECHANGE + if(SP->_sig_winch) + { + _nc_update_screensize(); + /* resizeterm can push KEY_RESIZE */ + if(cooked_key_in_fifo()) + { + ch = fifo_pull(); + T(("wgetch returning (pre-cooked): %#x = %s", ch, _trace_key(ch));) + returnCode(ch); + } + } +#endif + T(("wgetch returning ERR")); + returnCode(ERR); + } + + /* + * Simulate ICRNL mode + */ + if ((ch == '\r') && SP->_nl) + ch = '\n'; + + /* Strip 8th-bit if so desired. We do this only for characters that + * are in the range 128-255, to provide compatibility with terminals + * that display only 7-bit characters. Note that 'ch' may be a + * function key at this point, so we mustn't strip _those_. + */ + if ((ch < KEY_MIN) && (ch & 0x80)) + if (!SP->_use_meta) + ch &= 0x7f; + + if (SP->_echo && ch < KEY_MIN && !(win->_flags & _ISPAD)) + wechochar(win, (chtype)ch); + + T(("wgetch returning : %#x = %s", ch, _trace_key(ch))); + + returnCode(ch); +} + + +/* +** int +** kgetch() +** +** Get an input character, but take care of keypad sequences, returning +** an appropriate code when one matches the input. After each character +** is received, set an alarm call based on ESCDELAY. If no more of the +** sequence is received by the time the alarm goes off, pass through +** the sequence gotten so far. +** +** This function must be called when there is no cooked keys in queue. +** (that is head==-1 || peek==head) +** +*/ + +static int +kgetch(WINDOW *win GCC_UNUSED) +{ +struct tries *ptr; +int ch = 0; +int timeleft = ESCDELAY; + + TR(TRACE_IEVENT, ("kgetch(%p) called", win)); + + ptr = SP->_keytry; + + for(;;) + { + if (!raw_key_in_fifo()) + { + if(fifo_push() == ERR) + { + peek = head; /* the keys stay uninterpreted */ + return ERR; + } + } + ch = fifo_peek(); + if (ch >= KEY_MIN) + { + peek = head; + /* assume the key is the last in fifo */ + t_dec(); /* remove the key */ + return ch; + } + + TR(TRACE_IEVENT, ("ch: %s", _trace_key((unsigned char)ch))); + while ((ptr != NULL) && (ptr->ch != (unsigned char)ch)) + ptr = ptr->sibling; +#ifdef TRACE + if (ptr == NULL) + {TR(TRACE_IEVENT, ("ptr is null"));} + else + TR(TRACE_IEVENT, ("ptr=%p, ch=%d, value=%d", + ptr, ptr->ch, ptr->value)); +#endif /* TRACE */ + + if (ptr == NULL) + break; + + if (ptr->value != 0) { /* sequence terminated */ + TR(TRACE_IEVENT, ("end of sequence")); + if (peek == tail) + fifo_clear(); + else + head = peek; + return(ptr->value); + } + + ptr = ptr->child; + + if (!raw_key_in_fifo()) + { + TR(TRACE_IEVENT, ("waiting for rest of sequence")); + if (!_nc_timed_wait(3, timeleft, &timeleft)) { + TR(TRACE_IEVENT, ("ran out of time")); + break; + } + } + } + ch = fifo_pull(); + peek = head; + return ch; +} |