diff options
author | ache <ache@FreeBSD.org> | 1994-10-07 08:58:58 +0000 |
---|---|---|
committer | ache <ache@FreeBSD.org> | 1994-10-07 08:58:58 +0000 |
commit | a80c0624fbd8bd1c784b0b5b7a0fd20b09d317b9 (patch) | |
tree | 4a94ca97fb2fc2fdc1fcdd522a66e39c6e763138 /lib/libncurses/lib_getch.c | |
download | FreeBSD-src-a80c0624fbd8bd1c784b0b5b7a0fd20b09d317b9.zip FreeBSD-src-a80c0624fbd8bd1c784b0b5b7a0fd20b09d317b9.tar.gz |
Moved from ports with several enhancements
Diffstat (limited to 'lib/libncurses/lib_getch.c')
-rw-r--r-- | lib/libncurses/lib_getch.c | 217 |
1 files changed, 217 insertions, 0 deletions
diff --git a/lib/libncurses/lib_getch.c b/lib/libncurses/lib_getch.c new file mode 100644 index 0000000..47192c2 --- /dev/null +++ b/lib/libncurses/lib_getch.c @@ -0,0 +1,217 @@ + +/* This work is copyrighted. See COPYRIGHT.OLD & COPYRIGHT.NEW for * +* details. If they are missing then this copy is in violation of * +* the copyright conditions. */ + +/* +** lib_getch.c +** +** The routine getch(). +** +*/ + +#include <sys/types.h> +#include <string.h> +#include <signal.h> +#include <errno.h> +#ifdef BRAINDEAD +extern int errno; +#endif +#include "curses.priv.h" + +#define head SP->_fifohead +#define tail SP->_fifotail +#define peek SP->_fifopeek + +#define h_inc() { head == FIFO_SIZE-1 ? head = 0 : head++; if (head == tail) head = -1, tail = 0;} +#define h_dec() { head == 0 ? head = FIFO_SIZE-1 : head--; if (head == tail) tail = -1;} +#define t_inc() { tail == FIFO_SIZE-1 ? tail = 0 : tail++; if (tail == head) tail = -1;} +#define p_inc() { peek == FIFO_SIZE-1 ? peek = 0 : peek++;} + +static int fifo_peek() +{ + T(("peeking at %d", peek+1)); + return SP->_fifo[++peek]; +} + +static inline void fifo_dump() +{ +int i; + T(("head = %d, tail = %d, peek = %d", head, tail, peek)); + for (i = 0; i < 10; i++) + T(("char %d = %d (%c)", i, SP->_fifo[i], (unsigned char)SP->_fifo[i])); +} + +static inline int fifo_pull() +{ +int ch; + ch = SP->_fifo[head]; + T(("pulling %d from %d", ch, head)); + + h_inc(); + fifo_dump(); + return ch; +} + +int ungetch(int ch) +{ + if (tail == -1) + return ERR; + if (head == -1) { + head = 0; + t_inc() + } else + h_dec(); + + SP->_fifo[head] = ch; + T(("ungetch ok")); + fifo_dump(); + return OK; +} + +static inline int fifo_push() +{ +int n; +unsigned char ch; + + if (tail == -1) return ERR; +again: + n = read(fileno(SP->_ifp), &ch, 1); + if (n == -1 && errno == EINTR) + goto again; + SP->_fifo[tail] = ch; + if (head == -1) head = tail; + t_inc(); + T(("pushed %d at %d", ch, tail)); + fifo_dump(); + return ch; +} + +static inline void fifo_clear() +{ +int i; + for (i = 0; i < FIFO_SIZE; i++) + SP->_fifo[i] = 0; + head = -1; tail = peek = 0; +} + +static int kgetch(WINDOW *); + +int +wgetch(WINDOW *win) +{ +bool setHere = FALSE; /* cbreak mode was set here */ +int ch; + + T(("wgetch(%x) called", win)); + + /* this should be eliminated */ + if (! win->_scroll && (SP->_echo) && (win->_flags & _FULLWIN) + && win->_curx == win->_maxx && win->_cury == win->_maxy) + return(ERR); + + if ((is_wintouched(win) || (win->_flags & _HASMOVED)) && + !(win->_flags & _ISPAD)) + wrefresh(win); + + if (SP->_echo && ! (SP->_raw || SP->_cbreak)) { + cbreak(); + setHere = TRUE; + } + + if (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 microseconds", delay)); + + if (head == -1) /* fifo is empty */ + if (timed_wait(fileno(SP->_ifp), delay, NULL) == 0) + return ERR; + /* else go on to read data available */ + } + + if (win->_use_keypad) + ch = kgetch(win); + else { + fifo_push(); + ch = fifo_pull(); + } + + /* there must be a simpler way of doing this */ + if (!(win->_flags & _ISPAD) && + SP->_echo && ch < 0400) { /* ch < 0400 => not a keypad key */ + mvwaddch(curscr, win->_begy + win->_cury, + win->_begx + win->_curx, ch | win->_attrs); + waddch(win, ch | win->_attrs); + } + if (setHere) + nocbreak(); + + T(("wgetch returning : '%c', '0x%x'", ch, ch)); + + return(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 a one-second alarm call. If no more of the sequence +** is received by the time the alarm goes off, pass through the sequence +** gotten so far. +** +*/ + +static int +kgetch(WINDOW *win) +{ +struct try *ptr; +int ch = 0; +int timeleft = 2000; + + T(("kgetch(%x) called", win)); + + ptr = SP->_keytry; + + if (head == -1) { + ch = fifo_push(); + peek = 0; + while (ptr != NULL) { + T(("ch = %d", ch)); + while ((ptr != NULL) && (ptr->ch != (unsigned char)ch)) + ptr = ptr->sibling; + + if (ptr != NULL) + if (ptr->value != 0) { /* sequence terminated */ + T(("end of sequence")); + fifo_clear(); + return(ptr->value); + } else { /* go back for another character */ + ptr = ptr->child; + T(("going back for more")); + } + else + break; + + T(("waiting for rest of sequence")); + if (timed_wait(fileno(SP->_ifp), timeleft, &timeleft) < 1) { + T(("ran out of time")); + return(fifo_pull()); + } else { + T(("got more!")); + fifo_push(); + ch = fifo_peek(); + } + } + } + return(fifo_pull()); +} |