getch.c revision 1.13 1 1.13 simonb /* $NetBSD: getch.c,v 1.13 1999/06/15 04:50:28 simonb Exp $ */
2 1.8 mikel
3 1.1 cgd /*
4 1.7 cgd * Copyright (c) 1981, 1993, 1994
5 1.5 cgd * The Regents of the University of California. All rights reserved.
6 1.1 cgd *
7 1.1 cgd * Redistribution and use in source and binary forms, with or without
8 1.1 cgd * modification, are permitted provided that the following conditions
9 1.1 cgd * are met:
10 1.1 cgd * 1. Redistributions of source code must retain the above copyright
11 1.1 cgd * notice, this list of conditions and the following disclaimer.
12 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
13 1.1 cgd * notice, this list of conditions and the following disclaimer in the
14 1.1 cgd * documentation and/or other materials provided with the distribution.
15 1.1 cgd * 3. All advertising materials mentioning features or use of this software
16 1.1 cgd * must display the following acknowledgement:
17 1.1 cgd * This product includes software developed by the University of
18 1.1 cgd * California, Berkeley and its contributors.
19 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
20 1.1 cgd * may be used to endorse or promote products derived from this software
21 1.1 cgd * without specific prior written permission.
22 1.1 cgd *
23 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 1.1 cgd * SUCH DAMAGE.
34 1.1 cgd */
35 1.1 cgd
36 1.8 mikel #include <sys/cdefs.h>
37 1.1 cgd #ifndef lint
38 1.8 mikel #if 0
39 1.7 cgd static char sccsid[] = "@(#)getch.c 8.2 (Berkeley) 5/4/94";
40 1.8 mikel #else
41 1.13 simonb __RCSID("$NetBSD: getch.c,v 1.13 1999/06/15 04:50:28 simonb Exp $");
42 1.8 mikel #endif
43 1.10 mrg #endif /* not lint */
44 1.1 cgd
45 1.10 mrg #include <string.h>
46 1.10 mrg #include <stdlib.h>
47 1.10 mrg #include <unistd.h>
48 1.10 mrg #include <stdio.h>
49 1.7 cgd #include "curses.h"
50 1.1 cgd
51 1.10 mrg #define DEFAULT_DELAY 2 /* default delay for timeout() */
52 1.10 mrg
53 1.10 mrg /*
54 1.10 mrg * Keyboard input handler. Do this by snarfing
55 1.10 mrg * all the info we can out of the termcap entry for TERM and putting it
56 1.10 mrg * into a set of keymaps. A keymap is an array the size of all the possible
57 1.10 mrg * single characters we can get, the contents of the array is a structure
58 1.10 mrg * that contains the type of entry this character is (i.e. part/end of a
59 1.10 mrg * multi-char sequence or a plain char) and either a pointer which will point
60 1.10 mrg * to another keymap (in the case of a multi-char sequence) OR the data value
61 1.10 mrg * that this key should return.
62 1.10 mrg *
63 1.10 mrg */
64 1.10 mrg
65 1.10 mrg /* private data structures for holding the key definitions */
66 1.10 mrg typedef struct keymap keymap_t;
67 1.10 mrg typedef struct key_entry key_entry_t;
68 1.10 mrg
69 1.10 mrg struct key_entry {
70 1.10 mrg short type; /* type of key this is */
71 1.10 mrg union {
72 1.10 mrg keymap_t *next; /* next keymap is key is multi-key sequence */
73 1.10 mrg int symbol; /* key symbol if key is a leaf entry */
74 1.12 pk } value;
75 1.10 mrg };
76 1.10 mrg /* Types of key structures we can have */
77 1.10 mrg #define KEYMAP_MULTI 1 /* part of a multi char sequence */
78 1.10 mrg #define KEYMAP_LEAF 2 /* key has a symbol associated with it, either
79 1.10 mrg * it is the end of a multi-char sequence or a
80 1.10 mrg * single char key that generates a symbol */
81 1.10 mrg
82 1.10 mrg /* The max number of different chars we can receive */
83 1.10 mrg #define MAX_CHAR 256
84 1.10 mrg
85 1.10 mrg struct keymap {
86 1.12 pk int count; /* count of number of key structs allocated */
87 1.12 pk short mapping[MAX_CHAR]; /* mapping of key to allocated structs */
88 1.10 mrg key_entry_t **key; /* dynamic array of keys */};
89 1.10 mrg
90 1.10 mrg
91 1.10 mrg /* Key buffer */
92 1.10 mrg #define INBUF_SZ 16 /* size of key buffer - must be larger than
93 1.10 mrg * longest multi-key sequence */
94 1.13 simonb static char inbuf[INBUF_SZ];
95 1.13 simonb static int start, end, working; /* pointers for manipulating inbuf data */
96 1.10 mrg
97 1.12 pk #define INC_POINTER(ptr) do { \
98 1.12 pk (ptr)++; \
99 1.12 pk ptr %= INBUF_SZ; \
100 1.10 mrg } while(/*CONSTCOND*/0)
101 1.10 mrg
102 1.13 simonb static short state; /* state of the inkey function */
103 1.10 mrg
104 1.12 pk #define INKEY_NORM 0 /* no key backlog to process */
105 1.10 mrg #define INKEY_ASSEMBLING 1 /* assembling a multi-key sequence */
106 1.12 pk #define INKEY_BACKOUT 2 /* recovering from an unrecognised key */
107 1.12 pk #define INKEY_TIMEOUT 3 /* multi-key sequence timeout */
108 1.10 mrg
109 1.10 mrg /* The termcap data we are interested in and the symbols they map to */
110 1.10 mrg struct tcdata {
111 1.12 pk char *name; /* name of termcap entry */
112 1.12 pk int symbol; /* the symbol associated with it */
113 1.10 mrg };
114 1.10 mrg
115 1.13 simonb static const struct tcdata tc[] = {
116 1.10 mrg {"K1", KEY_A1},
117 1.10 mrg {"K2", KEY_B2},
118 1.10 mrg {"K3", KEY_A3},
119 1.10 mrg {"K4", KEY_C1},
120 1.10 mrg {"K5", KEY_C3},
121 1.10 mrg {"k0", KEY_F0},
122 1.10 mrg {"k1", KEY_F(1)},
123 1.10 mrg {"k2", KEY_F(2)},
124 1.10 mrg {"k3", KEY_F(3)},
125 1.10 mrg {"k4", KEY_F(4)},
126 1.10 mrg {"k5", KEY_F(5)},
127 1.10 mrg {"k6", KEY_F(6)},
128 1.10 mrg {"k7", KEY_F(7)},
129 1.10 mrg {"k8", KEY_F(8)},
130 1.10 mrg {"k9", KEY_F(9)},
131 1.10 mrg {"kA", KEY_IL},
132 1.10 mrg {"ka", KEY_CATAB},
133 1.10 mrg {"kb", KEY_BACKSPACE},
134 1.10 mrg {"kC", KEY_CLEAR},
135 1.10 mrg {"kD", KEY_DC},
136 1.10 mrg {"kd", KEY_DOWN},
137 1.10 mrg {"kE", KEY_EOL},
138 1.10 mrg {"kF", KEY_SF},
139 1.10 mrg {"kH", KEY_LL},
140 1.10 mrg {"kh", KEY_HOME},
141 1.10 mrg {"kI", KEY_IC},
142 1.10 mrg {"kL", KEY_DL},
143 1.10 mrg {"kl", KEY_LEFT},
144 1.10 mrg {"kN", KEY_NPAGE},
145 1.10 mrg {"kP", KEY_PPAGE},
146 1.10 mrg {"kR", KEY_SR},
147 1.10 mrg {"kr", KEY_RIGHT},
148 1.10 mrg {"kS", KEY_EOS},
149 1.10 mrg {"kT", KEY_STAB},
150 1.10 mrg {"kt", KEY_CTAB},
151 1.10 mrg {"ku", KEY_UP}
152 1.10 mrg };
153 1.10 mrg /* Number of TC entries .... */
154 1.13 simonb static const int num_tcs = (sizeof(tc) / sizeof(struct tcdata));
155 1.10 mrg
156 1.10 mrg /* The root keymap */
157 1.10 mrg
158 1.13 simonb static keymap_t *base_keymap;
159 1.10 mrg
160 1.10 mrg /* prototypes for private functions */
161 1.13 simonb static keymap_t *new_keymap(void); /* create a new keymap */
162 1.13 simonb static key_entry_t *new_key(void); /* create a new key entry */
163 1.13 simonb static unsigned inkey(int, int);
164 1.10 mrg
165 1.10 mrg /*
166 1.10 mrg * Init_getch - initialise all the pointers & structures needed to make
167 1.10 mrg * getch work in keypad mode.
168 1.10 mrg *
169 1.10 mrg */
170 1.10 mrg void
171 1.10 mrg __init_getch(sp)
172 1.10 mrg char *sp;
173 1.10 mrg {
174 1.12 pk static char termcap[1024];
175 1.12 pk char entry[1024], termname[1024], *p;
176 1.12 pk int i, j, length;
177 1.10 mrg keymap_t *current;
178 1.10 mrg key_entry_t *the_key;
179 1.10 mrg
180 1.10 mrg /* init the inkey state variable */
181 1.10 mrg state = INKEY_NORM;
182 1.10 mrg
183 1.10 mrg /* init the base keymap */
184 1.10 mrg base_keymap = new_keymap();
185 1.10 mrg
186 1.10 mrg /* key input buffer pointers */
187 1.10 mrg start = end = working = 0;
188 1.10 mrg
189 1.10 mrg /* now do the termcap snarfing ... */
190 1.10 mrg strncpy(termname, sp, 1022);
191 1.10 mrg termname[1023] = 0;
192 1.10 mrg
193 1.12 pk if (tgetent(termcap, termname) <= 0)
194 1.12 pk return;
195 1.12 pk
196 1.12 pk for (i = 0; i < num_tcs; i++) {
197 1.10 mrg
198 1.12 pk p = entry;
199 1.12 pk if (tgetstr(tc[i].name, &p) == NULL)
200 1.12 pk continue;
201 1.12 pk
202 1.12 pk current = base_keymap; /* always start with base keymap. */
203 1.12 pk length = strlen(entry);
204 1.12 pk
205 1.12 pk for (j = 0; j < length - 1; j++) {
206 1.12 pk if (current->mapping[(unsigned) entry[j]] < 0) {
207 1.12 pk /* first time for this char */
208 1.12 pk current->mapping[(unsigned) entry[j]] = current->count; /* map new entry */
209 1.10 mrg the_key = new_key();
210 1.12 pk /* multikey coz we are here */
211 1.12 pk the_key->type = KEYMAP_MULTI;
212 1.10 mrg
213 1.12 pk /* need for next key */
214 1.12 pk the_key->value.next = new_keymap();
215 1.12 pk
216 1.12 pk /* put into key array */
217 1.12 pk if ((current->key = realloc(current->key, (current->count + 1) * sizeof(key_entry_t *))) == NULL) {
218 1.12 pk fprintf(stderr,
219 1.12 pk "Could not malloc for key entry\n");
220 1.12 pk exit(1);
221 1.12 pk }
222 1.12 pk
223 1.10 mrg current->key[current->count++] = the_key;
224 1.12 pk
225 1.12 pk }
226 1.12 pk /* next key uses this map... */
227 1.12 pk current = current->key[current->mapping[(unsigned) entry[j]]]->value.next;
228 1.12 pk }
229 1.12 pk
230 1.12 pk /*
231 1.12 pk * This is the last key in the sequence (it may have been
232 1.12 pk * the only one but that does not matter) this means it is
233 1.12 pk * a leaf key and should have a symbol associated with it.
234 1.12 pk */
235 1.12 pk if (current->count > 0) {
236 1.12 pk /*
237 1.12 pk * If there were other keys then we need to
238 1.12 pk * extend the mapping array.
239 1.12 pk */
240 1.12 pk if ((current->key =
241 1.12 pk realloc(current->key,
242 1.12 pk (current->count + 1) *
243 1.12 pk sizeof(key_entry_t *))) == NULL) {
244 1.12 pk
245 1.12 pk fprintf(stderr,
246 1.12 pk "Could not malloc for key entry\n");
247 1.12 pk exit(1);
248 1.10 mrg }
249 1.10 mrg }
250 1.12 pk current->mapping[(unsigned) entry[length - 1]] = current->count;
251 1.12 pk the_key = new_key();
252 1.12 pk the_key->type = KEYMAP_LEAF; /* leaf key */
253 1.12 pk
254 1.12 pk /* the associated symbol */
255 1.12 pk the_key->value.symbol = tc[i].symbol;
256 1.12 pk current->key[current->count++] = the_key;
257 1.10 mrg }
258 1.10 mrg }
259 1.10 mrg
260 1.10 mrg
261 1.10 mrg /*
262 1.10 mrg * new_keymap - allocates & initialises a new keymap structure. This
263 1.10 mrg * function returns a pointer to the new keymap.
264 1.10 mrg *
265 1.10 mrg */
266 1.13 simonb static keymap_t *
267 1.10 mrg new_keymap(void)
268 1.10 mrg {
269 1.10 mrg int i;
270 1.10 mrg keymap_t *new_map;
271 1.10 mrg
272 1.10 mrg if ((new_map = malloc(sizeof(keymap_t))) == NULL) {
273 1.10 mrg perror("Inkey: Cannot allocate new keymap");
274 1.10 mrg exit(2);
275 1.10 mrg }
276 1.12 pk
277 1.12 pk /* Initialise the new map */
278 1.10 mrg new_map->count = 0;
279 1.10 mrg for (i = 0; i < MAX_CHAR; i++) {
280 1.10 mrg new_map->mapping[i] = -1; /* no mapping for char */
281 1.10 mrg }
282 1.10 mrg
283 1.12 pk /* one does assume there will be at least one key mapped.... */
284 1.10 mrg if ((new_map->key = malloc(sizeof(key_entry_t *))) == NULL) {
285 1.10 mrg perror("Could not malloc first key ent");
286 1.10 mrg exit(1);
287 1.10 mrg }
288 1.10 mrg
289 1.12 pk return (new_map);
290 1.10 mrg }
291 1.10 mrg
292 1.10 mrg /*
293 1.10 mrg * new_key - allocates & initialises a new key entry. This function returns
294 1.10 mrg * a pointer to the newly allocated key entry.
295 1.10 mrg *
296 1.10 mrg */
297 1.13 simonb static key_entry_t *
298 1.10 mrg new_key(void)
299 1.10 mrg {
300 1.10 mrg key_entry_t *new_one;
301 1.10 mrg
302 1.10 mrg if ((new_one = malloc(sizeof(key_entry_t))) == NULL) {
303 1.10 mrg perror("inkey: Cannot allocate new key entry");
304 1.10 mrg exit(2);
305 1.10 mrg }
306 1.10 mrg new_one->type = 0;
307 1.10 mrg new_one->value.next = NULL;
308 1.10 mrg
309 1.12 pk return (new_one);
310 1.10 mrg }
311 1.10 mrg
312 1.10 mrg /*
313 1.10 mrg * inkey - do the work to process keyboard input, check for multi-key
314 1.10 mrg * sequences and return the appropriate symbol if we get a match.
315 1.10 mrg *
316 1.10 mrg */
317 1.10 mrg
318 1.10 mrg unsigned
319 1.10 mrg inkey(to, delay)
320 1.10 mrg int to, delay;
321 1.10 mrg {
322 1.10 mrg int k, nchar;
323 1.10 mrg char c;
324 1.10 mrg keymap_t *current = base_keymap;
325 1.10 mrg
326 1.10 mrg for (;;) { /* loop until we get a complete key sequence */
327 1.10 mrg reread:
328 1.10 mrg if (state == INKEY_NORM) {
329 1.10 mrg if (delay && __timeout(delay) == ERR)
330 1.10 mrg return ERR;
331 1.10 mrg if ((nchar = read(STDIN_FILENO, &c, sizeof(char))) < 0)
332 1.10 mrg return ERR;
333 1.10 mrg if (delay && (__notimeout() == ERR))
334 1.10 mrg return ERR;
335 1.10 mrg if (nchar == 0)
336 1.10 mrg return ERR; /* just in case we are nodelay
337 1.10 mrg * mode */
338 1.10 mrg k = (unsigned int) c;
339 1.10 mrg #ifdef DEBUG
340 1.10 mrg __CTRACE("inkey (state normal) got '%s'\n", unctrl(k));
341 1.10 mrg #endif
342 1.10 mrg
343 1.10 mrg working = start;
344 1.10 mrg inbuf[working] = k;
345 1.10 mrg INC_POINTER(working);
346 1.10 mrg end = working;
347 1.10 mrg state = INKEY_ASSEMBLING; /* go to the assembling
348 1.10 mrg * state now */
349 1.12 pk } else if (state == INKEY_BACKOUT) {
350 1.12 pk k = inbuf[working];
351 1.12 pk INC_POINTER(working);
352 1.12 pk if (working == end) { /* see if we have run
353 1.12 pk * out of keys in the
354 1.12 pk * backlog */
355 1.12 pk
356 1.12 pk /* if we have then switch to
357 1.12 pk assembling */
358 1.12 pk state = INKEY_ASSEMBLING;
359 1.12 pk }
360 1.12 pk } else if (state == INKEY_ASSEMBLING) {
361 1.12 pk /* assembling a key sequence */
362 1.12 pk if (delay) {
363 1.12 pk if (__timeout(to ? DEFAULT_DELAY : delay) == ERR)
364 1.10 mrg return ERR;
365 1.12 pk } else {
366 1.12 pk if (to && (__timeout(DEFAULT_DELAY) == ERR))
367 1.10 mrg return ERR;
368 1.12 pk }
369 1.12 pk if ((nchar = read(STDIN_FILENO, &c,
370 1.12 pk sizeof(char))) < 0)
371 1.12 pk return ERR;
372 1.12 pk if ((to || delay) && (__notimeout() == ERR))
373 1.10 mrg return ERR;
374 1.10 mrg
375 1.12 pk k = (unsigned int) c;
376 1.10 mrg #ifdef DEBUG
377 1.12 pk __CTRACE("inkey (state assembling) got '%s'\n", unctrl(k));
378 1.10 mrg #endif
379 1.12 pk if (nchar == 0) { /* inter-char timeout,
380 1.12 pk * start backing out */
381 1.12 pk if (start == end)
382 1.12 pk /* no chars in the buffer, restart */
383 1.12 pk goto reread;
384 1.12 pk
385 1.12 pk k = inbuf[start];
386 1.12 pk state = INKEY_TIMEOUT;
387 1.10 mrg } else {
388 1.12 pk inbuf[working] = k;
389 1.12 pk INC_POINTER(working);
390 1.12 pk end = working;
391 1.10 mrg }
392 1.12 pk } else {
393 1.12 pk fprintf(stderr, "Inkey state screwed - exiting!!!");
394 1.12 pk exit(2);
395 1.12 pk }
396 1.10 mrg
397 1.10 mrg /* Check key has no special meaning and we have not timed out */
398 1.10 mrg if ((current->mapping[k] < 0) || (state == INKEY_TIMEOUT)) {
399 1.12 pk /* return the first key we know about */
400 1.12 pk k = inbuf[start];
401 1.10 mrg
402 1.10 mrg INC_POINTER(start);
403 1.10 mrg working = start;
404 1.10 mrg
405 1.10 mrg if (start == end) { /* only one char processed */
406 1.10 mrg state = INKEY_NORM;
407 1.10 mrg } else {/* otherwise we must have more than one char
408 1.10 mrg * to backout */
409 1.10 mrg state = INKEY_BACKOUT;
410 1.10 mrg }
411 1.10 mrg return k;
412 1.10 mrg } else { /* must be part of a multikey sequence */
413 1.10 mrg /* check for completed key sequence */
414 1.10 mrg if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) {
415 1.10 mrg start = working; /* eat the key sequence
416 1.10 mrg * in inbuf */
417 1.10 mrg
418 1.12 pk /* check if inbuf empty now */
419 1.12 pk if (start == end) {
420 1.12 pk /* if it is go back to normal */
421 1.12 pk state = INKEY_NORM;
422 1.12 pk } else {
423 1.12 pk /* otherwise go to backout state */
424 1.10 mrg state = INKEY_BACKOUT;
425 1.10 mrg }
426 1.10 mrg
427 1.10 mrg /* return the symbol */
428 1.10 mrg return current->key[current->mapping[k]]->value.symbol;
429 1.10 mrg
430 1.12 pk } else {
431 1.12 pk /*
432 1.12 pk * Step on to next part of the multi-key
433 1.12 pk * sequence.
434 1.12 pk */
435 1.10 mrg current = current->key[current->mapping[k]]->value.next;
436 1.10 mrg }
437 1.10 mrg }
438 1.10 mrg }
439 1.10 mrg }
440 1.10 mrg
441 1.1 cgd /*
442 1.4 mycroft * wgetch --
443 1.4 mycroft * Read in a character from the window.
444 1.1 cgd */
445 1.4 mycroft int
446 1.1 cgd wgetch(win)
447 1.9 perry WINDOW *win;
448 1.4 mycroft {
449 1.10 mrg int inp, weset;
450 1.10 mrg int nchar;
451 1.10 mrg char c;
452 1.1 cgd
453 1.5 cgd if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN)
454 1.10 mrg && win->curx == win->maxx - 1 && win->cury == win->maxy - 1
455 1.10 mrg && __echoit)
456 1.4 mycroft return (ERR);
457 1.4 mycroft #ifdef DEBUG
458 1.5 cgd __CTRACE("wgetch: __echoit = %d, __rawmode = %d\n",
459 1.4 mycroft __echoit, __rawmode);
460 1.4 mycroft #endif
461 1.4 mycroft if (__echoit && !__rawmode) {
462 1.1 cgd cbreak();
463 1.4 mycroft weset = 1;
464 1.4 mycroft } else
465 1.4 mycroft weset = 0;
466 1.4 mycroft
467 1.10 mrg __save_termios();
468 1.10 mrg
469 1.10 mrg if (win->flags & __KEYPAD) {
470 1.10 mrg switch (win->delay)
471 1.10 mrg {
472 1.10 mrg case -1:
473 1.10 mrg inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0);
474 1.10 mrg break;
475 1.10 mrg case 0:
476 1.10 mrg if (__nodelay() == ERR) return ERR;
477 1.10 mrg inp = inkey(0, 0);
478 1.10 mrg break;
479 1.10 mrg default:
480 1.10 mrg inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay);
481 1.10 mrg break;
482 1.10 mrg }
483 1.10 mrg } else {
484 1.10 mrg switch (win->delay)
485 1.10 mrg {
486 1.10 mrg case -1:
487 1.10 mrg break;
488 1.10 mrg case 0:
489 1.10 mrg if (__nodelay() == ERR) {
490 1.10 mrg __restore_termios();
491 1.10 mrg return ERR;
492 1.10 mrg }
493 1.10 mrg break;
494 1.10 mrg default:
495 1.10 mrg if (__timeout(win->delay) == ERR) {
496 1.10 mrg __restore_termios();
497 1.10 mrg return ERR;
498 1.10 mrg }
499 1.10 mrg break;
500 1.10 mrg }
501 1.12 pk
502 1.12 pk if ((nchar = read(STDIN_FILENO, &c, sizeof(char))) < 0) {
503 1.10 mrg inp = ERR;
504 1.12 pk } else {
505 1.10 mrg if (nchar == 0) {
506 1.10 mrg __restore_termios();
507 1.10 mrg return ERR; /* we have timed out */
508 1.10 mrg }
509 1.10 mrg inp = (unsigned int) c;
510 1.10 mrg }
511 1.10 mrg }
512 1.4 mycroft #ifdef DEBUG
513 1.5 cgd __CTRACE("wgetch got '%s'\n", unctrl(inp));
514 1.4 mycroft #endif
515 1.12 pk if (win->delay > -1) {
516 1.10 mrg if (__delay() == ERR) {
517 1.10 mrg __restore_termios();
518 1.10 mrg return ERR;
519 1.10 mrg }
520 1.12 pk }
521 1.12 pk
522 1.10 mrg __restore_termios();
523 1.4 mycroft if (__echoit) {
524 1.4 mycroft mvwaddch(curscr,
525 1.10 mrg (int) (win->cury + win->begy), (int) (win->curx + win->begx), inp);
526 1.4 mycroft waddch(win, inp);
527 1.1 cgd }
528 1.1 cgd if (weset)
529 1.1 cgd nocbreak();
530 1.12 pk
531 1.10 mrg return ((inp < 0) || (inp == ERR) ? ERR : inp);
532 1.1 cgd }
533