getch.c revision 1.16 1 1.16 blymn /* $NetBSD: getch.c,v 1.16 2000/04/11 13:57:09 blymn 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.16 blymn __RCSID("$NetBSD: getch.c,v 1.16 2000/04/11 13:57:09 blymn 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.16 blymn #include "curses_private.h"
51 1.1 cgd
52 1.10 mrg #define DEFAULT_DELAY 2 /* default delay for timeout() */
53 1.10 mrg
54 1.10 mrg /*
55 1.10 mrg * Keyboard input handler. Do this by snarfing
56 1.10 mrg * all the info we can out of the termcap entry for TERM and putting it
57 1.10 mrg * into a set of keymaps. A keymap is an array the size of all the possible
58 1.10 mrg * single characters we can get, the contents of the array is a structure
59 1.10 mrg * that contains the type of entry this character is (i.e. part/end of a
60 1.10 mrg * multi-char sequence or a plain char) and either a pointer which will point
61 1.10 mrg * to another keymap (in the case of a multi-char sequence) OR the data value
62 1.10 mrg * that this key should return.
63 1.10 mrg *
64 1.10 mrg */
65 1.10 mrg
66 1.10 mrg /* private data structures for holding the key definitions */
67 1.10 mrg typedef struct keymap keymap_t;
68 1.10 mrg typedef struct key_entry key_entry_t;
69 1.10 mrg
70 1.10 mrg struct key_entry {
71 1.10 mrg short type; /* type of key this is */
72 1.10 mrg union {
73 1.10 mrg keymap_t *next; /* next keymap is key is multi-key sequence */
74 1.16 blymn wchar_t symbol; /* key symbol if key is a leaf entry */
75 1.12 pk } value;
76 1.10 mrg };
77 1.10 mrg /* Types of key structures we can have */
78 1.10 mrg #define KEYMAP_MULTI 1 /* part of a multi char sequence */
79 1.10 mrg #define KEYMAP_LEAF 2 /* key has a symbol associated with it, either
80 1.10 mrg * it is the end of a multi-char sequence or a
81 1.10 mrg * single char key that generates a symbol */
82 1.10 mrg
83 1.10 mrg /* The max number of different chars we can receive */
84 1.10 mrg #define MAX_CHAR 256
85 1.10 mrg
86 1.10 mrg struct keymap {
87 1.12 pk int count; /* count of number of key structs allocated */
88 1.12 pk short mapping[MAX_CHAR]; /* mapping of key to allocated structs */
89 1.10 mrg key_entry_t **key; /* dynamic array of keys */};
90 1.10 mrg
91 1.10 mrg
92 1.10 mrg /* Key buffer */
93 1.10 mrg #define INBUF_SZ 16 /* size of key buffer - must be larger than
94 1.10 mrg * longest multi-key sequence */
95 1.16 blymn static wchar_t inbuf[INBUF_SZ];
96 1.13 simonb static int start, end, working; /* pointers for manipulating inbuf data */
97 1.10 mrg
98 1.12 pk #define INC_POINTER(ptr) do { \
99 1.12 pk (ptr)++; \
100 1.12 pk ptr %= INBUF_SZ; \
101 1.10 mrg } while(/*CONSTCOND*/0)
102 1.10 mrg
103 1.13 simonb static short state; /* state of the inkey function */
104 1.10 mrg
105 1.12 pk #define INKEY_NORM 0 /* no key backlog to process */
106 1.10 mrg #define INKEY_ASSEMBLING 1 /* assembling a multi-key sequence */
107 1.12 pk #define INKEY_BACKOUT 2 /* recovering from an unrecognised key */
108 1.12 pk #define INKEY_TIMEOUT 3 /* multi-key sequence timeout */
109 1.10 mrg
110 1.10 mrg /* The termcap data we are interested in and the symbols they map to */
111 1.10 mrg struct tcdata {
112 1.12 pk char *name; /* name of termcap entry */
113 1.16 blymn wchar_t symbol; /* the symbol associated with it */
114 1.10 mrg };
115 1.10 mrg
116 1.13 simonb static const struct tcdata tc[] = {
117 1.10 mrg {"K1", KEY_A1},
118 1.10 mrg {"K2", KEY_B2},
119 1.10 mrg {"K3", KEY_A3},
120 1.10 mrg {"K4", KEY_C1},
121 1.10 mrg {"K5", KEY_C3},
122 1.10 mrg {"k0", KEY_F0},
123 1.10 mrg {"k1", KEY_F(1)},
124 1.10 mrg {"k2", KEY_F(2)},
125 1.10 mrg {"k3", KEY_F(3)},
126 1.10 mrg {"k4", KEY_F(4)},
127 1.10 mrg {"k5", KEY_F(5)},
128 1.10 mrg {"k6", KEY_F(6)},
129 1.10 mrg {"k7", KEY_F(7)},
130 1.10 mrg {"k8", KEY_F(8)},
131 1.10 mrg {"k9", KEY_F(9)},
132 1.10 mrg {"kA", KEY_IL},
133 1.10 mrg {"ka", KEY_CATAB},
134 1.10 mrg {"kb", KEY_BACKSPACE},
135 1.10 mrg {"kC", KEY_CLEAR},
136 1.10 mrg {"kD", KEY_DC},
137 1.10 mrg {"kd", KEY_DOWN},
138 1.10 mrg {"kE", KEY_EOL},
139 1.10 mrg {"kF", KEY_SF},
140 1.10 mrg {"kH", KEY_LL},
141 1.10 mrg {"kh", KEY_HOME},
142 1.10 mrg {"kI", KEY_IC},
143 1.10 mrg {"kL", KEY_DL},
144 1.10 mrg {"kl", KEY_LEFT},
145 1.10 mrg {"kN", KEY_NPAGE},
146 1.10 mrg {"kP", KEY_PPAGE},
147 1.10 mrg {"kR", KEY_SR},
148 1.10 mrg {"kr", KEY_RIGHT},
149 1.10 mrg {"kS", KEY_EOS},
150 1.10 mrg {"kT", KEY_STAB},
151 1.10 mrg {"kt", KEY_CTAB},
152 1.10 mrg {"ku", KEY_UP}
153 1.10 mrg };
154 1.10 mrg /* Number of TC entries .... */
155 1.13 simonb static const int num_tcs = (sizeof(tc) / sizeof(struct tcdata));
156 1.10 mrg
157 1.10 mrg /* The root keymap */
158 1.10 mrg
159 1.13 simonb static keymap_t *base_keymap;
160 1.10 mrg
161 1.10 mrg /* prototypes for private functions */
162 1.13 simonb static keymap_t *new_keymap(void); /* create a new keymap */
163 1.13 simonb static key_entry_t *new_key(void); /* create a new key entry */
164 1.16 blymn static wchar_t inkey(int, int);
165 1.10 mrg
166 1.10 mrg /*
167 1.10 mrg * Init_getch - initialise all the pointers & structures needed to make
168 1.10 mrg * getch work in keypad mode.
169 1.10 mrg *
170 1.10 mrg */
171 1.10 mrg void
172 1.10 mrg __init_getch(sp)
173 1.10 mrg char *sp;
174 1.10 mrg {
175 1.12 pk static char termcap[1024];
176 1.12 pk char entry[1024], termname[1024], *p;
177 1.12 pk int i, j, length;
178 1.10 mrg keymap_t *current;
179 1.10 mrg key_entry_t *the_key;
180 1.10 mrg
181 1.10 mrg /* init the inkey state variable */
182 1.10 mrg state = INKEY_NORM;
183 1.10 mrg
184 1.10 mrg /* init the base keymap */
185 1.10 mrg base_keymap = new_keymap();
186 1.10 mrg
187 1.10 mrg /* key input buffer pointers */
188 1.10 mrg start = end = working = 0;
189 1.10 mrg
190 1.10 mrg /* now do the termcap snarfing ... */
191 1.16 blymn (void) strncpy(termname, sp, (size_t) 1022);
192 1.10 mrg termname[1023] = 0;
193 1.10 mrg
194 1.12 pk if (tgetent(termcap, termname) <= 0)
195 1.12 pk return;
196 1.12 pk
197 1.12 pk for (i = 0; i < num_tcs; i++) {
198 1.10 mrg
199 1.12 pk p = entry;
200 1.12 pk if (tgetstr(tc[i].name, &p) == NULL)
201 1.12 pk continue;
202 1.12 pk
203 1.12 pk current = base_keymap; /* always start with base keymap. */
204 1.16 blymn length = (int) strlen(entry);
205 1.12 pk
206 1.12 pk for (j = 0; j < length - 1; j++) {
207 1.12 pk if (current->mapping[(unsigned) entry[j]] < 0) {
208 1.12 pk /* first time for this char */
209 1.12 pk current->mapping[(unsigned) entry[j]] = current->count; /* map new entry */
210 1.10 mrg the_key = new_key();
211 1.12 pk /* multikey coz we are here */
212 1.12 pk the_key->type = KEYMAP_MULTI;
213 1.10 mrg
214 1.12 pk /* need for next key */
215 1.12 pk the_key->value.next = new_keymap();
216 1.14 simonb
217 1.12 pk /* put into key array */
218 1.12 pk if ((current->key = realloc(current->key, (current->count + 1) * sizeof(key_entry_t *))) == NULL) {
219 1.12 pk fprintf(stderr,
220 1.12 pk "Could not malloc for key entry\n");
221 1.12 pk exit(1);
222 1.12 pk }
223 1.14 simonb
224 1.10 mrg current->key[current->count++] = the_key;
225 1.12 pk
226 1.12 pk }
227 1.12 pk /* next key uses this map... */
228 1.12 pk current = current->key[current->mapping[(unsigned) entry[j]]]->value.next;
229 1.12 pk }
230 1.12 pk
231 1.12 pk /*
232 1.12 pk * This is the last key in the sequence (it may have been
233 1.12 pk * the only one but that does not matter) this means it is
234 1.12 pk * a leaf key and should have a symbol associated with it.
235 1.12 pk */
236 1.12 pk if (current->count > 0) {
237 1.12 pk /*
238 1.12 pk * If there were other keys then we need to
239 1.12 pk * extend the mapping array.
240 1.12 pk */
241 1.12 pk if ((current->key =
242 1.12 pk realloc(current->key,
243 1.12 pk (current->count + 1) *
244 1.12 pk sizeof(key_entry_t *))) == NULL) {
245 1.12 pk
246 1.12 pk fprintf(stderr,
247 1.12 pk "Could not malloc for key entry\n");
248 1.12 pk exit(1);
249 1.10 mrg }
250 1.10 mrg }
251 1.12 pk current->mapping[(unsigned) entry[length - 1]] = current->count;
252 1.12 pk the_key = new_key();
253 1.12 pk the_key->type = KEYMAP_LEAF; /* leaf key */
254 1.12 pk
255 1.12 pk /* the associated symbol */
256 1.12 pk the_key->value.symbol = tc[i].symbol;
257 1.12 pk 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 * new_keymap - allocates & initialises a new keymap structure. This
264 1.10 mrg * function returns a pointer to the new keymap.
265 1.10 mrg *
266 1.10 mrg */
267 1.13 simonb static keymap_t *
268 1.10 mrg new_keymap(void)
269 1.10 mrg {
270 1.10 mrg int i;
271 1.10 mrg keymap_t *new_map;
272 1.10 mrg
273 1.10 mrg if ((new_map = malloc(sizeof(keymap_t))) == NULL) {
274 1.10 mrg perror("Inkey: Cannot allocate new keymap");
275 1.10 mrg exit(2);
276 1.10 mrg }
277 1.12 pk
278 1.12 pk /* Initialise the new map */
279 1.10 mrg new_map->count = 0;
280 1.10 mrg for (i = 0; i < MAX_CHAR; i++) {
281 1.10 mrg new_map->mapping[i] = -1; /* no mapping for char */
282 1.10 mrg }
283 1.10 mrg
284 1.12 pk /* one does assume there will be at least one key mapped.... */
285 1.10 mrg if ((new_map->key = malloc(sizeof(key_entry_t *))) == NULL) {
286 1.10 mrg perror("Could not malloc first key ent");
287 1.10 mrg exit(1);
288 1.10 mrg }
289 1.14 simonb
290 1.12 pk return (new_map);
291 1.10 mrg }
292 1.10 mrg
293 1.10 mrg /*
294 1.10 mrg * new_key - allocates & initialises a new key entry. This function returns
295 1.10 mrg * a pointer to the newly allocated key entry.
296 1.10 mrg *
297 1.10 mrg */
298 1.13 simonb static key_entry_t *
299 1.10 mrg new_key(void)
300 1.10 mrg {
301 1.10 mrg key_entry_t *new_one;
302 1.10 mrg
303 1.10 mrg if ((new_one = malloc(sizeof(key_entry_t))) == NULL) {
304 1.10 mrg perror("inkey: Cannot allocate new key entry");
305 1.10 mrg exit(2);
306 1.10 mrg }
307 1.10 mrg new_one->type = 0;
308 1.10 mrg new_one->value.next = NULL;
309 1.10 mrg
310 1.12 pk return (new_one);
311 1.10 mrg }
312 1.10 mrg
313 1.10 mrg /*
314 1.10 mrg * inkey - do the work to process keyboard input, check for multi-key
315 1.10 mrg * sequences and return the appropriate symbol if we get a match.
316 1.10 mrg *
317 1.10 mrg */
318 1.10 mrg
319 1.16 blymn wchar_t
320 1.10 mrg inkey(to, delay)
321 1.10 mrg int to, delay;
322 1.10 mrg {
323 1.16 blymn wchar_t k;
324 1.16 blymn ssize_t nchar;
325 1.16 blymn 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.16 blymn k = (wchar_t) 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.12 pk } else if (state == INKEY_BACKOUT) {
352 1.12 pk k = inbuf[working];
353 1.12 pk INC_POINTER(working);
354 1.12 pk if (working == end) { /* see if we have run
355 1.12 pk * out of keys in the
356 1.12 pk * backlog */
357 1.12 pk
358 1.12 pk /* if we have then switch to
359 1.12 pk assembling */
360 1.12 pk state = INKEY_ASSEMBLING;
361 1.12 pk }
362 1.12 pk } else if (state == INKEY_ASSEMBLING) {
363 1.12 pk /* assembling a key sequence */
364 1.12 pk if (delay) {
365 1.12 pk if (__timeout(to ? DEFAULT_DELAY : delay) == ERR)
366 1.10 mrg return ERR;
367 1.12 pk } else {
368 1.12 pk if (to && (__timeout(DEFAULT_DELAY) == ERR))
369 1.10 mrg return ERR;
370 1.12 pk }
371 1.12 pk if ((nchar = read(STDIN_FILENO, &c,
372 1.12 pk sizeof(char))) < 0)
373 1.12 pk return ERR;
374 1.12 pk if ((to || delay) && (__notimeout() == ERR))
375 1.10 mrg return ERR;
376 1.14 simonb
377 1.16 blymn k = (wchar_t) c;
378 1.10 mrg #ifdef DEBUG
379 1.12 pk __CTRACE("inkey (state assembling) got '%s'\n", unctrl(k));
380 1.10 mrg #endif
381 1.12 pk if (nchar == 0) { /* inter-char timeout,
382 1.12 pk * start backing out */
383 1.12 pk if (start == end)
384 1.12 pk /* no chars in the buffer, restart */
385 1.12 pk goto reread;
386 1.12 pk
387 1.12 pk k = inbuf[start];
388 1.12 pk state = INKEY_TIMEOUT;
389 1.10 mrg } else {
390 1.12 pk inbuf[working] = k;
391 1.12 pk INC_POINTER(working);
392 1.12 pk end = working;
393 1.10 mrg }
394 1.12 pk } else {
395 1.12 pk fprintf(stderr, "Inkey state screwed - exiting!!!");
396 1.12 pk exit(2);
397 1.12 pk }
398 1.10 mrg
399 1.10 mrg /* Check key has no special meaning and we have not timed out */
400 1.10 mrg if ((current->mapping[k] < 0) || (state == INKEY_TIMEOUT)) {
401 1.12 pk /* return the first key we know about */
402 1.12 pk k = inbuf[start];
403 1.10 mrg
404 1.10 mrg INC_POINTER(start);
405 1.10 mrg working = start;
406 1.10 mrg
407 1.10 mrg if (start == end) { /* only one char processed */
408 1.10 mrg state = INKEY_NORM;
409 1.10 mrg } else {/* otherwise we must have more than one char
410 1.10 mrg * to backout */
411 1.10 mrg state = INKEY_BACKOUT;
412 1.10 mrg }
413 1.10 mrg return k;
414 1.10 mrg } else { /* must be part of a multikey sequence */
415 1.10 mrg /* check for completed key sequence */
416 1.10 mrg if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) {
417 1.10 mrg start = working; /* eat the key sequence
418 1.10 mrg * in inbuf */
419 1.10 mrg
420 1.12 pk /* check if inbuf empty now */
421 1.12 pk if (start == end) {
422 1.12 pk /* if it is go back to normal */
423 1.12 pk state = INKEY_NORM;
424 1.12 pk } else {
425 1.12 pk /* otherwise go to backout state */
426 1.10 mrg state = INKEY_BACKOUT;
427 1.10 mrg }
428 1.10 mrg
429 1.10 mrg /* return the symbol */
430 1.10 mrg return current->key[current->mapping[k]]->value.symbol;
431 1.10 mrg
432 1.12 pk } else {
433 1.12 pk /*
434 1.12 pk * Step on to next part of the multi-key
435 1.12 pk * sequence.
436 1.12 pk */
437 1.10 mrg current = current->key[current->mapping[k]]->value.next;
438 1.10 mrg }
439 1.10 mrg }
440 1.10 mrg }
441 1.10 mrg }
442 1.10 mrg
443 1.1 cgd /*
444 1.4 mycroft * wgetch --
445 1.4 mycroft * Read in a character from the window.
446 1.1 cgd */
447 1.4 mycroft int
448 1.1 cgd wgetch(win)
449 1.9 perry WINDOW *win;
450 1.4 mycroft {
451 1.10 mrg int inp, weset;
452 1.16 blymn ssize_t nchar;
453 1.10 mrg char c;
454 1.1 cgd
455 1.5 cgd if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN)
456 1.10 mrg && win->curx == win->maxx - 1 && win->cury == win->maxy - 1
457 1.10 mrg && __echoit)
458 1.4 mycroft return (ERR);
459 1.4 mycroft #ifdef DEBUG
460 1.5 cgd __CTRACE("wgetch: __echoit = %d, __rawmode = %d\n",
461 1.4 mycroft __echoit, __rawmode);
462 1.4 mycroft #endif
463 1.4 mycroft if (__echoit && !__rawmode) {
464 1.1 cgd cbreak();
465 1.4 mycroft weset = 1;
466 1.4 mycroft } else
467 1.4 mycroft weset = 0;
468 1.4 mycroft
469 1.10 mrg __save_termios();
470 1.10 mrg
471 1.10 mrg if (win->flags & __KEYPAD) {
472 1.10 mrg switch (win->delay)
473 1.10 mrg {
474 1.10 mrg case -1:
475 1.10 mrg inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0);
476 1.10 mrg break;
477 1.10 mrg case 0:
478 1.10 mrg if (__nodelay() == ERR) return ERR;
479 1.10 mrg inp = inkey(0, 0);
480 1.10 mrg break;
481 1.10 mrg default:
482 1.10 mrg inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay);
483 1.10 mrg break;
484 1.10 mrg }
485 1.10 mrg } else {
486 1.10 mrg switch (win->delay)
487 1.10 mrg {
488 1.10 mrg case -1:
489 1.10 mrg break;
490 1.10 mrg case 0:
491 1.10 mrg if (__nodelay() == ERR) {
492 1.10 mrg __restore_termios();
493 1.10 mrg return ERR;
494 1.10 mrg }
495 1.10 mrg break;
496 1.10 mrg default:
497 1.10 mrg if (__timeout(win->delay) == ERR) {
498 1.10 mrg __restore_termios();
499 1.10 mrg return ERR;
500 1.10 mrg }
501 1.10 mrg break;
502 1.10 mrg }
503 1.12 pk
504 1.12 pk if ((nchar = read(STDIN_FILENO, &c, sizeof(char))) < 0) {
505 1.10 mrg inp = ERR;
506 1.12 pk } else {
507 1.10 mrg if (nchar == 0) {
508 1.10 mrg __restore_termios();
509 1.10 mrg return ERR; /* we have timed out */
510 1.10 mrg }
511 1.10 mrg inp = (unsigned int) c;
512 1.10 mrg }
513 1.10 mrg }
514 1.4 mycroft #ifdef DEBUG
515 1.15 simonb if (inp > 255)
516 1.16 blymn /* we have a key symbol - treat it differently */
517 1.16 blymn /* XXXX perhaps __unctrl should be expanded to include
518 1.16 blymn * XXXX the keysyms in the table....
519 1.16 blymn */
520 1.15 simonb __CTRACE("wgetch assembled keysym 0x%x\n", inp);
521 1.15 simonb else
522 1.15 simonb __CTRACE("wgetch got '%s'\n", unctrl(inp));
523 1.4 mycroft #endif
524 1.12 pk if (win->delay > -1) {
525 1.10 mrg if (__delay() == ERR) {
526 1.10 mrg __restore_termios();
527 1.10 mrg return ERR;
528 1.10 mrg }
529 1.12 pk }
530 1.12 pk
531 1.10 mrg __restore_termios();
532 1.4 mycroft if (__echoit) {
533 1.4 mycroft mvwaddch(curscr,
534 1.16 blymn (int) (win->cury + win->begy), (int) (win->curx + win->begx), (chtype) inp);
535 1.16 blymn waddch(win, (chtype) inp);
536 1.1 cgd }
537 1.1 cgd if (weset)
538 1.1 cgd nocbreak();
539 1.12 pk
540 1.10 mrg return ((inp < 0) || (inp == ERR) ? ERR : inp);
541 1.1 cgd }
542