# include "curses.ext" # include <signal.h> # include <errno.h> /* @(#) getch.c: 1.1 10/15/83 (1.16 3/16/83) */ static int sig_caught; /* * This routine reads in a character from the window. * * wgetch MUST return an int, not a char, because it can return * things like ERR, meta characters, and function keys > 256. */ int wgetch(win) register WINDOW *win; { register int inp; register int i, j; char c; int arg; bool weset = FALSE; FILE *inf; if (SP->fl_echoit && !win->_scroll && (win->_flags&_FULLWIN) && win->_curx == win->_maxx && win->_cury == win->_maxy) return ERR; # ifdef DEBUG if(outf) fprintf(outf, "WGETCH: SP->fl_echoit = %c, SP->fl_rawmode = %c\n", SP->fl_echoit ? 'T' : 'F', SP->fl_rawmode ? 'T' : 'F'); if (outf) fprintf(outf, "_use_keypad %d, kp_state %d\n", win->_use_keypad, SP->kp_state); # endif if (SP->fl_echoit && !SP->fl_rawmode) { cbreak(); weset++; } #ifdef KEYPAD /* Make sure keypad on is in proper state */ if (win->_use_keypad != SP->kp_state) { _kpmode(win->_use_keypad); fflush(stdout); } #endif /* Make sure we are in proper nodelay state */ if (win->_nodelay != SP->fl_nodelay) _fixdelay(SP->fl_nodelay, win->_nodelay); /* Check for pushed typeahead. We make the assumption that * if a function key is being typed, there is no pushed * typeahead from the previous key waiting. */ if (SP->input_queue[0] >= 0) { inp = SP->input_queue[0]; for (i=0; i<16; i++) { SP->input_queue[i] = SP->input_queue[i+1]; if (SP->input_queue[i] < 0) break; } goto gotit; } inf = SP->input_file; if (inf == stdout) /* so output can be teed somewhere */ inf = stdin; #ifdef FIONREAD if (win->_nodelay) { ioctl(fileno(inf), FIONREAD, &arg); #ifdef DEBUG if (outf) fprintf(outf, "FIONREAD returns %d\n", arg); #endif if (arg < 1) return -1; } #endif for (i = -1; i<0; ) { extern int errno; sig_caught = 0; i = read(fileno(inf), &c, 1); /* * I hope the system won't retern infinite EINTRS - maybe * there should be a hop count here. */ if (i < 0 && errno != EINTR && !sig_caught) { inp = ERR; goto gotit; } } if (i > 0) { inp = c; if (!win->_use_meta) inp &= 0177; else inp &= 0377; } else { inp = ERR; goto gotit; } # ifdef DEBUG if(outf) fprintf(outf,"WGETCH got '%s'\n",unctrl(inp)); # endif #ifdef KEYPAD /* Check for arrow and function keys */ if (win->_use_keypad) { SP->input_queue[0] = inp; SP->input_queue[1] = -1; for (i=0; SP->kp[i].keynum >= 0; i++) { if (SP->kp[i].sends[0] == inp) { for (j=0; ; j++) { if (SP->kp[i].sends[j] <= 0) break; /* found */ if (SP->input_queue[j] == -1) { SP->input_queue[j] = _fpk(inf); SP->input_queue[j+1] = -1; } if (SP->kp[i].sends[j] != SP->input_queue[j]) goto contouter; /* not this one */ } /* It matched the function key. */ inp = SP->kp[i].keynum; SP->input_queue[0] = -1; goto gotit; } contouter:; } /* Didn't match any function keys. */ inp = SP->input_queue[0]; for (i=0; i<16; i++) { SP->input_queue[i] = SP->input_queue[i+1]; if (SP->input_queue[i] < 0) break; } goto gotit; } #endif if (SP->fl_echoit) { waddch(win, (chtype) inp); wrefresh(win); } gotit: if (weset) nocbreak(); #ifdef DEBUG if(outf) fprintf(outf, "getch returns %o, pushed %o %o %o\n", inp, SP->input_queue[0], SP->input_queue[1], SP->input_queue[2]); #endif return inp; } _catch_alarm() { sig_caught = 1; } /* * Fast peek key. Like getchar but if the right flags are set, times out * quickly if there is nothing waiting, returning -1. * f is an output stdio descriptor, we read from the fileno. win is the * window this is supposed to have something to do with. */ #ifndef FIONREAD /* * Traditional implementation. The best resolution we have is 1 second, * so we set a 1 second alarm and try to read. If we fail for 1 second, * we assume there is no key waiting. Problem here is that 1 second is * too long, people can type faster than this. */ static _fpk(f) FILE *f; { char c; int rc; int (*oldsig)(); int oldalarm; oldsig = signal(SIGALRM, _catch_alarm); oldalarm = alarm(1); sig_caught = 0; rc = read(fileno(f), &c, 1); if (sig_caught) { sig_caught = 0; alarm(oldalarm); return -2; } signal(SIGALRM, oldsig); alarm(oldalarm); return rc == 1 ? c : -1; } #else FIONREAD /* * If we have the select system call, we can do much better. * We wait for long enough for a terminal to send another character * (at 15cps repeat rate, this is 67 ms, I'm using 100ms to allow * a bit of a fudge factor) and time out more quickly. Even if we * don't have the real 4.2BSD select, we can emulate it with napms * and FIONREAD. napms might be done with only 1 second resolution, * but this is no worse than what we have above. */ static _fpk(f) FILE *f; { int infd, rc; int *outfd, *exfd; char c; infd = 1 << fileno(f); outfd = exfd = (int *) NULL; rc = select(20, &infd, outfd, exfd, 100); if (rc < 0) return -2; rc = read(fileno(f), &c, 1); return rc == 1 ? c : -1; } #endif FIONREAD