getch.c revision 1.10 1 1.10 mrg /* $NetBSD: getch.c,v 1.10 1999/04/13 14:08:18 mrg 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.10 mrg __RCSID("$NetBSD: getch.c,v 1.10 1999/04/13 14:08:18 mrg 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.10 mrg } 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.10 mrg int count; /* count of number of key structs allocated */
87 1.10 mrg 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.10 mrg char inbuf[INBUF_SZ];
95 1.10 mrg int start, end, working; /* pointers for manipulating inbuf data */
96 1.10 mrg
97 1.10 mrg #define INC_POINTER(ptr) do { \
98 1.10 mrg (ptr)++; \
99 1.10 mrg ptr %= INBUF_SZ; \
100 1.10 mrg } while(/*CONSTCOND*/0)
101 1.10 mrg
102 1.10 mrg short state; /* state of the inkey function */
103 1.10 mrg
104 1.10 mrg #define INKEY_NORM 0 /* no key backlog to process */
105 1.10 mrg #define INKEY_ASSEMBLING 1 /* assembling a multi-key sequence */
106 1.10 mrg #define INKEY_BACKOUT 2 /* recovering from an unrecognised key */
107 1.10 mrg #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.10 mrg char *name; /* name of termcap entry */
112 1.10 mrg int symbol; /* the symbol associated with it */
113 1.10 mrg };
114 1.10 mrg
115 1.10 mrg 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.10 mrg 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.10 mrg keymap_t *base_keymap;
159 1.10 mrg
160 1.10 mrg /* prototypes for private functions */
161 1.10 mrg keymap_t *
162 1.10 mrg new_keymap(void); /* create a new keymap */
163 1.10 mrg
164 1.10 mrg key_entry_t *
165 1.10 mrg new_key(void); /* create a new key entry */
166 1.10 mrg
167 1.10 mrg unsigned
168 1.10 mrg inkey(int, int);
169 1.10 mrg
170 1.10 mrg /*
171 1.10 mrg * Init_getch - initialise all the pointers & structures needed to make
172 1.10 mrg * getch work in keypad mode.
173 1.10 mrg *
174 1.10 mrg */
175 1.10 mrg void
176 1.10 mrg __init_getch(sp)
177 1.10 mrg char *sp;
178 1.10 mrg {
179 1.10 mrg int i, j, length;
180 1.10 mrg keymap_t *current;
181 1.10 mrg char termcap[1024], entry[1024], termname[1024], *p;
182 1.10 mrg key_entry_t *the_key;
183 1.10 mrg
184 1.10 mrg /* init the inkey state variable */
185 1.10 mrg state = INKEY_NORM;
186 1.10 mrg
187 1.10 mrg /* init the base keymap */
188 1.10 mrg base_keymap = new_keymap();
189 1.10 mrg
190 1.10 mrg /* key input buffer pointers */
191 1.10 mrg start = end = working = 0;
192 1.10 mrg
193 1.10 mrg /* now do the termcap snarfing ... */
194 1.10 mrg strncpy(termname, sp, 1022);
195 1.10 mrg termname[1023] = 0;
196 1.10 mrg
197 1.10 mrg if (tgetent(termcap, termname) > 0) {
198 1.10 mrg for (i = 0; i < num_tcs; i++) {
199 1.10 mrg p = entry;
200 1.10 mrg if (tgetstr(tc[i].name, &p) != NULL) {
201 1.10 mrg current = base_keymap; /* always start with
202 1.10 mrg * base keymap. */
203 1.10 mrg length = strlen(entry);
204 1.10 mrg
205 1.10 mrg for (j = 0; j < length - 1; j++) {
206 1.10 mrg if (current->mapping[(unsigned) entry[j]] < 0) {
207 1.10 mrg /* first time for this char */
208 1.10 mrg current->mapping[(unsigned) entry[j]] = current->count; /* map new entry */
209 1.10 mrg the_key = new_key();
210 1.10 mrg /* multikey coz we are here */
211 1.10 mrg the_key->type = KEYMAP_MULTI;
212 1.10 mrg
213 1.10 mrg /* need for next key */
214 1.10 mrg the_key->value.next
215 1.10 mrg = new_keymap();
216 1.10 mrg
217 1.10 mrg /* put into key array */
218 1.10 mrg if ((current->key = realloc(current->key, (current->count + 1) * sizeof(key_entry_t *))) == NULL) {
219 1.10 mrg fprintf(stderr,
220 1.10 mrg "Could not malloc for key entry\n");
221 1.10 mrg exit(1);
222 1.10 mrg }
223 1.10 mrg
224 1.10 mrg current->key[current->count++]
225 1.10 mrg = the_key;
226 1.10 mrg
227 1.10 mrg }
228 1.10 mrg /* next key uses this map... */
229 1.10 mrg current = current->key[current->mapping[(unsigned) entry[j]]]->value.next;
230 1.10 mrg }
231 1.10 mrg
232 1.10 mrg /* this is the last key in the sequence (it
233 1.10 mrg * may have been the only one but that does
234 1.10 mrg * not matter) this means it is a leaf key and
235 1.10 mrg * should have a symbol associated with it */
236 1.10 mrg if (current->count > 0) {
237 1.10 mrg /* if there were other keys then
238 1.10 mrg we need to extend the mapping
239 1.10 mrg array */
240 1.10 mrg if ((current->key =
241 1.10 mrg realloc(current->key,
242 1.10 mrg (current->count + 1) *
243 1.10 mrg sizeof(key_entry_t *)))
244 1.10 mrg == NULL) {
245 1.10 mrg fprintf(stderr,
246 1.10 mrg "Could not malloc for key entry\n");
247 1.10 mrg exit(1);
248 1.10 mrg }
249 1.10 mrg }
250 1.10 mrg current->mapping[(unsigned) entry[length - 1]]
251 1.10 mrg = current->count;
252 1.10 mrg the_key = new_key();
253 1.10 mrg the_key->type = KEYMAP_LEAF; /* leaf key */
254 1.10 mrg
255 1.10 mrg /* the associated symbol */
256 1.10 mrg the_key->value.symbol = tc[i].symbol;
257 1.10 mrg current->key[current->count++] = the_key;
258 1.10 mrg }
259 1.10 mrg }
260 1.10 mrg }
261 1.10 mrg }
262 1.10 mrg
263 1.10 mrg
264 1.10 mrg /*
265 1.10 mrg * new_keymap - allocates & initialises a new keymap structure. This
266 1.10 mrg * function returns a pointer to the new keymap.
267 1.10 mrg *
268 1.10 mrg */
269 1.10 mrg keymap_t *
270 1.10 mrg new_keymap(void)
271 1.10 mrg {
272 1.10 mrg int i;
273 1.10 mrg keymap_t *new_map;
274 1.10 mrg
275 1.10 mrg if ((new_map = malloc(sizeof(keymap_t))) == NULL) {
276 1.10 mrg perror("Inkey: Cannot allocate new keymap");
277 1.10 mrg exit(2);
278 1.10 mrg }
279 1.10 mrg /* initialise the new map */
280 1.10 mrg new_map->count = 0;
281 1.10 mrg for (i = 0; i < MAX_CHAR; i++) {
282 1.10 mrg new_map->mapping[i] = -1; /* no mapping for char */
283 1.10 mrg }
284 1.10 mrg
285 1.10 mrg /* one does assume there will be at least one key mapped.... */
286 1.10 mrg if ((new_map->key = malloc(sizeof(key_entry_t *))) == NULL) {
287 1.10 mrg perror("Could not malloc first key ent");
288 1.10 mrg exit(1);
289 1.10 mrg }
290 1.10 mrg
291 1.10 mrg return new_map;
292 1.10 mrg }
293 1.10 mrg
294 1.10 mrg /*
295 1.10 mrg * new_key - allocates & initialises a new key entry. This function returns
296 1.10 mrg * a pointer to the newly allocated key entry.
297 1.10 mrg *
298 1.10 mrg */
299 1.10 mrg key_entry_t *
300 1.10 mrg new_key(void)
301 1.10 mrg {
302 1.10 mrg key_entry_t *new_one;
303 1.10 mrg
304 1.10 mrg if ((new_one = malloc(sizeof(key_entry_t))) == NULL) {
305 1.10 mrg perror("inkey: Cannot allocate new key entry");
306 1.10 mrg exit(2);
307 1.10 mrg }
308 1.10 mrg new_one->type = 0;
309 1.10 mrg new_one->value.next = NULL;
310 1.10 mrg
311 1.10 mrg return new_one;
312 1.10 mrg }
313 1.10 mrg
314 1.10 mrg /*
315 1.10 mrg * inkey - do the work to process keyboard input, check for multi-key
316 1.10 mrg * sequences and return the appropriate symbol if we get a match.
317 1.10 mrg *
318 1.10 mrg */
319 1.10 mrg
320 1.10 mrg unsigned
321 1.10 mrg inkey(to, delay)
322 1.10 mrg int to, delay;
323 1.10 mrg {
324 1.10 mrg int k, nchar;
325 1.10 mrg char c;
326 1.10 mrg keymap_t *current = base_keymap;
327 1.10 mrg
328 1.10 mrg for (;;) { /* loop until we get a complete key sequence */
329 1.10 mrg reread:
330 1.10 mrg if (state == INKEY_NORM) {
331 1.10 mrg if (delay && __timeout(delay) == ERR)
332 1.10 mrg return ERR;
333 1.10 mrg if ((nchar = read(STDIN_FILENO, &c, sizeof(char))) < 0)
334 1.10 mrg return ERR;
335 1.10 mrg if (delay && (__notimeout() == ERR))
336 1.10 mrg return ERR;
337 1.10 mrg if (nchar == 0)
338 1.10 mrg return ERR; /* just in case we are nodelay
339 1.10 mrg * mode */
340 1.10 mrg k = (unsigned int) c;
341 1.10 mrg #ifdef DEBUG
342 1.10 mrg __CTRACE("inkey (state normal) got '%s'\n", unctrl(k));
343 1.10 mrg #endif
344 1.10 mrg
345 1.10 mrg working = start;
346 1.10 mrg inbuf[working] = k;
347 1.10 mrg INC_POINTER(working);
348 1.10 mrg end = working;
349 1.10 mrg state = INKEY_ASSEMBLING; /* go to the assembling
350 1.10 mrg * state now */
351 1.10 mrg } else
352 1.10 mrg if (state == INKEY_BACKOUT) {
353 1.10 mrg k = inbuf[working];
354 1.10 mrg INC_POINTER(working);
355 1.10 mrg if (working == end) { /* see if we have run
356 1.10 mrg * out of keys in the
357 1.10 mrg * backlog */
358 1.10 mrg
359 1.10 mrg /* if we have then switch to
360 1.10 mrg assembling */
361 1.10 mrg state = INKEY_ASSEMBLING;
362 1.10 mrg }
363 1.10 mrg } else if (state == INKEY_ASSEMBLING) {
364 1.10 mrg /* assembling a key sequence */
365 1.10 mrg if (delay)
366 1.10 mrg {
367 1.10 mrg if (__timeout(to ? DEFAULT_DELAY : delay) == ERR)
368 1.10 mrg return ERR;
369 1.10 mrg } else {
370 1.10 mrg if (to && (__timeout(DEFAULT_DELAY) == ERR))
371 1.10 mrg return ERR;
372 1.10 mrg }
373 1.10 mrg if ((nchar = read(STDIN_FILENO, &c,
374 1.10 mrg sizeof(char))) < 0)
375 1.10 mrg return ERR;
376 1.10 mrg if ((to || delay) && (__notimeout() == ERR))
377 1.10 mrg return ERR;
378 1.10 mrg
379 1.10 mrg k = (unsigned int) c;
380 1.10 mrg #ifdef DEBUG
381 1.10 mrg __CTRACE("inkey (state assembling) got '%s'\n", unctrl(k));
382 1.10 mrg #endif
383 1.10 mrg if (nchar == 0) { /* inter-char timeout,
384 1.10 mrg * start backing out */
385 1.10 mrg if (start == end)
386 1.10 mrg goto reread; /* no chars in the
387 1.10 mrg * buffer, restart */
388 1.10 mrg k = inbuf[start];
389 1.10 mrg state = INKEY_TIMEOUT;
390 1.10 mrg } else {
391 1.10 mrg inbuf[working] = k;
392 1.10 mrg INC_POINTER(working);
393 1.10 mrg end = working;
394 1.10 mrg }
395 1.10 mrg } else {
396 1.10 mrg fprintf(stderr,
397 1.10 mrg "Inkey state screwed - exiting!!!");
398 1.10 mrg exit(2);
399 1.10 mrg }
400 1.10 mrg
401 1.10 mrg /* Check key has no special meaning and we have not timed out */
402 1.10 mrg if ((current->mapping[k] < 0) || (state == INKEY_TIMEOUT)) {
403 1.10 mrg k = inbuf[start]; /* return the first key we
404 1.10 mrg * know about */
405 1.10 mrg
406 1.10 mrg INC_POINTER(start);
407 1.10 mrg working = start;
408 1.10 mrg
409 1.10 mrg if (start == end) { /* only one char processed */
410 1.10 mrg state = INKEY_NORM;
411 1.10 mrg } else {/* otherwise we must have more than one char
412 1.10 mrg * to backout */
413 1.10 mrg state = INKEY_BACKOUT;
414 1.10 mrg }
415 1.10 mrg return k;
416 1.10 mrg } else { /* must be part of a multikey sequence */
417 1.10 mrg /* check for completed key sequence */
418 1.10 mrg if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) {
419 1.10 mrg start = working; /* eat the key sequence
420 1.10 mrg * in inbuf */
421 1.10 mrg
422 1.10 mrg if (start == end) { /* check if inbuf empty
423 1.10 mrg * now */
424 1.10 mrg state = INKEY_NORM; /* if it is go
425 1.10 mrg back to normal */
426 1.10 mrg } else { /* otherwise go to backout
427 1.10 mrg * state */
428 1.10 mrg state = INKEY_BACKOUT;
429 1.10 mrg }
430 1.10 mrg
431 1.10 mrg /* return the symbol */
432 1.10 mrg return current->key[current->mapping[k]]->value.symbol;
433 1.10 mrg
434 1.10 mrg } else {/* step on to next part of the multi-key
435 1.10 mrg * sequence */
436 1.10 mrg current = current->key[current->mapping[k]]->value.next;
437 1.10 mrg }
438 1.10 mrg }
439 1.10 mrg }
440 1.10 mrg }
441 1.10 mrg
442 1.1 cgd /*
443 1.4 mycroft * wgetch --
444 1.4 mycroft * Read in a character from the window.
445 1.1 cgd */
446 1.4 mycroft int
447 1.1 cgd wgetch(win)
448 1.9 perry WINDOW *win;
449 1.4 mycroft {
450 1.10 mrg int inp, weset;
451 1.10 mrg int nchar;
452 1.10 mrg char c;
453 1.1 cgd
454 1.5 cgd if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN)
455 1.10 mrg && win->curx == win->maxx - 1 && win->cury == win->maxy - 1
456 1.10 mrg && __echoit)
457 1.4 mycroft return (ERR);
458 1.4 mycroft #ifdef DEBUG
459 1.5 cgd __CTRACE("wgetch: __echoit = %d, __rawmode = %d\n",
460 1.4 mycroft __echoit, __rawmode);
461 1.4 mycroft #endif
462 1.4 mycroft if (__echoit && !__rawmode) {
463 1.1 cgd cbreak();
464 1.4 mycroft weset = 1;
465 1.4 mycroft } else
466 1.4 mycroft weset = 0;
467 1.4 mycroft
468 1.10 mrg __save_termios();
469 1.10 mrg
470 1.10 mrg if (win->flags & __KEYPAD) {
471 1.10 mrg switch (win->delay)
472 1.10 mrg {
473 1.10 mrg case -1:
474 1.10 mrg inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0);
475 1.10 mrg break;
476 1.10 mrg case 0:
477 1.10 mrg if (__nodelay() == ERR) return ERR;
478 1.10 mrg inp = inkey(0, 0);
479 1.10 mrg break;
480 1.10 mrg default:
481 1.10 mrg inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay);
482 1.10 mrg break;
483 1.10 mrg }
484 1.10 mrg } else {
485 1.10 mrg switch (win->delay)
486 1.10 mrg {
487 1.10 mrg case -1:
488 1.10 mrg break;
489 1.10 mrg case 0:
490 1.10 mrg if (__nodelay() == ERR) {
491 1.10 mrg __restore_termios();
492 1.10 mrg return ERR;
493 1.10 mrg }
494 1.10 mrg break;
495 1.10 mrg default:
496 1.10 mrg if (__timeout(win->delay) == ERR) {
497 1.10 mrg __restore_termios();
498 1.10 mrg return ERR;
499 1.10 mrg }
500 1.10 mrg break;
501 1.10 mrg }
502 1.10 mrg if ((nchar = read(STDIN_FILENO, &c, sizeof(char))) < 0)
503 1.10 mrg inp = ERR;
504 1.10 mrg 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.10 mrg 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.10 mrg __restore_termios();
521 1.4 mycroft if (__echoit) {
522 1.4 mycroft mvwaddch(curscr,
523 1.10 mrg (int) (win->cury + win->begy), (int) (win->curx + win->begx), inp);
524 1.4 mycroft waddch(win, inp);
525 1.1 cgd }
526 1.1 cgd if (weset)
527 1.1 cgd nocbreak();
528 1.10 mrg return ((inp < 0) || (inp == ERR) ? ERR : inp);
529 1.1 cgd }
530