/* 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 #include #include #include #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()); }