freebsd-src/lib/libncurses/lib_getch.c
1995-05-30 05:51:47 +00:00

225 lines
4.6 KiB
C

/* 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>
#if defined(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;
T(("read %d characters", n));
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 {
if (head == -1)
fifo_push();
ch = fifo_pull();
}
/* This should be eliminated */
/* handle 8-bit input */
if (ch & 0x80)
if (!win->_use_meta)
ch &= 0x7f;
/* 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 = 1000;
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());
}