|
|
1.1 root 1: # include "curses.ext"
2: # include <signal.h>
3: # include <errno.h>
4:
5: /* @(#) getch.c: 1.1 10/15/83 (1.16 3/16/83) */
6:
7: static int sig_caught;
8:
9: /*
10: * This routine reads in a character from the window.
11: *
12: * wgetch MUST return an int, not a char, because it can return
13: * things like ERR, meta characters, and function keys > 256.
14: */
15: int
16: wgetch(win)
17: register WINDOW *win;
18: {
19:
20: register int inp;
21: register int i, j;
22: char c;
23: int arg;
24: bool weset = FALSE;
25: FILE *inf;
26:
27: if (SP->fl_echoit && !win->_scroll && (win->_flags&_FULLWIN)
28: && win->_curx == win->_maxx && win->_cury == win->_maxy)
29: return ERR;
30: # ifdef DEBUG
31: if(outf) fprintf(outf, "WGETCH: SP->fl_echoit = %c, SP->fl_rawmode = %c\n", SP->fl_echoit ? 'T' : 'F', SP->fl_rawmode ? 'T' : 'F');
32: if (outf) fprintf(outf, "_use_keypad %d, kp_state %d\n", win->_use_keypad, SP->kp_state);
33: # endif
34: if (SP->fl_echoit && !SP->fl_rawmode) {
35: cbreak();
36: weset++;
37: }
38:
39: #ifdef KEYPAD
40: /* Make sure keypad on is in proper state */
41: if (win->_use_keypad != SP->kp_state) {
42: _kpmode(win->_use_keypad);
43: fflush(stdout);
44: }
45: #endif
46:
47: /* Make sure we are in proper nodelay state */
48: if (win->_nodelay != SP->fl_nodelay)
49: _fixdelay(SP->fl_nodelay, win->_nodelay);
50:
51: /* Check for pushed typeahead. We make the assumption that
52: * if a function key is being typed, there is no pushed
53: * typeahead from the previous key waiting.
54: */
55: if (SP->input_queue[0] >= 0) {
56: inp = SP->input_queue[0];
57: for (i=0; i<16; i++) {
58: SP->input_queue[i] = SP->input_queue[i+1];
59: if (SP->input_queue[i] < 0)
60: break;
61: }
62: goto gotit;
63: }
64:
65: inf = SP->input_file;
66: if (inf == stdout) /* so output can be teed somewhere */
67: inf = stdin;
68: #ifdef FIONREAD
69: if (win->_nodelay) {
70: ioctl(fileno(inf), FIONREAD, &arg);
71: #ifdef DEBUG
72: if (outf) fprintf(outf, "FIONREAD returns %d\n", arg);
73: #endif
74: if (arg < 1)
75: return -1;
76: }
77: #endif
78: for (i = -1; i<0; ) {
79: extern int errno;
80: sig_caught = 0;
81: i = read(fileno(inf), &c, 1);
82: /*
83: * I hope the system won't retern infinite EINTRS - maybe
84: * there should be a hop count here.
85: */
86: if (i < 0 && errno != EINTR && !sig_caught) {
87: inp = ERR;
88: goto gotit;
89: }
90: }
91: if (i > 0) {
92: inp = c;
93: if (!win->_use_meta)
94: inp &= 0177;
95: else
96: inp &= 0377;
97: } else {
98: inp = ERR;
99: goto gotit;
100: }
101: # ifdef DEBUG
102: if(outf) fprintf(outf,"WGETCH got '%s'\n",unctrl(inp));
103: # endif
104:
105: #ifdef KEYPAD
106: /* Check for arrow and function keys */
107: if (win->_use_keypad) {
108: SP->input_queue[0] = inp;
109: SP->input_queue[1] = -1;
110: for (i=0; SP->kp[i].keynum >= 0; i++) {
111: if (SP->kp[i].sends[0] == inp) {
112: for (j=0; ; j++) {
113: if (SP->kp[i].sends[j] <= 0)
114: break; /* found */
115: if (SP->input_queue[j] == -1) {
116: SP->input_queue[j] = _fpk(inf);
117: SP->input_queue[j+1] = -1;
118: }
119: if (SP->kp[i].sends[j] != SP->input_queue[j])
120: goto contouter; /* not this one */
121: }
122: /* It matched the function key. */
123: inp = SP->kp[i].keynum;
124: SP->input_queue[0] = -1;
125: goto gotit;
126: }
127: contouter:;
128: }
129: /* Didn't match any function keys. */
130: inp = SP->input_queue[0];
131: for (i=0; i<16; i++) {
132: SP->input_queue[i] = SP->input_queue[i+1];
133: if (SP->input_queue[i] < 0)
134: break;
135: }
136: goto gotit;
137: }
138: #endif
139:
140: if (SP->fl_echoit) {
141: waddch(win, (chtype) inp);
142: wrefresh(win);
143: }
144: gotit:
145: if (weset)
146: nocbreak();
147: #ifdef DEBUG
148: if(outf) fprintf(outf, "getch returns %o, pushed %o %o %o\n",
149: inp, SP->input_queue[0], SP->input_queue[1], SP->input_queue[2]);
150: #endif
151: return inp;
152: }
153: _catch_alarm()
154: {
155: sig_caught = 1;
156: }
157:
158: /*
159: * Fast peek key. Like getchar but if the right flags are set, times out
160: * quickly if there is nothing waiting, returning -1.
161: * f is an output stdio descriptor, we read from the fileno. win is the
162: * window this is supposed to have something to do with.
163: */
164: #ifndef FIONREAD
165: /*
166: * Traditional implementation. The best resolution we have is 1 second,
167: * so we set a 1 second alarm and try to read. If we fail for 1 second,
168: * we assume there is no key waiting. Problem here is that 1 second is
169: * too long, people can type faster than this.
170: */
171: static
172: _fpk(f)
173: FILE *f;
174: {
175: char c;
176: int rc;
177: int (*oldsig)();
178: int oldalarm;
179:
180: oldsig = signal(SIGALRM, _catch_alarm);
181: oldalarm = alarm(1);
182: sig_caught = 0;
183: rc = read(fileno(f), &c, 1);
184: if (sig_caught) {
185: sig_caught = 0;
186: alarm(oldalarm);
187: return -2;
188: }
189: signal(SIGALRM, oldsig);
190: alarm(oldalarm);
191: return rc == 1 ? c : -1;
192: }
193: #else FIONREAD
194: /*
195: * If we have the select system call, we can do much better.
196: * We wait for long enough for a terminal to send another character
197: * (at 15cps repeat rate, this is 67 ms, I'm using 100ms to allow
198: * a bit of a fudge factor) and time out more quickly. Even if we
199: * don't have the real 4.2BSD select, we can emulate it with napms
200: * and FIONREAD. napms might be done with only 1 second resolution,
201: * but this is no worse than what we have above.
202: */
203: static
204: _fpk(f)
205: FILE *f;
206: {
207: int infd, rc;
208: int *outfd, *exfd;
209: char c;
210:
211: infd = 1 << fileno(f);
212: outfd = exfd = (int *) NULL;
213: rc = select(20, &infd, outfd, exfd, 100);
214: if (rc < 0)
215: return -2;
216: rc = read(fileno(f), &c, 1);
217: return rc == 1 ? c : -1;
218: }
219: #endif FIONREAD
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.