getch.c revision 1.36 1 /* $NetBSD: getch.c,v 1.36 2002/01/02 10:38:27 blymn Exp $ */
2
3 /*
4 * Copyright (c) 1981, 1993, 1994
5 * The Regents of the University of California. All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by the University of
18 * California, Berkeley and its contributors.
19 * 4. Neither the name of the University nor the names of its contributors
20 * may be used to endorse or promote products derived from this software
21 * without specific prior written permission.
22 *
23 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * SUCH DAMAGE.
34 */
35
36 #include <sys/cdefs.h>
37 #ifndef lint
38 #if 0
39 static char sccsid[] = "@(#)getch.c 8.2 (Berkeley) 5/4/94";
40 #else
41 __RCSID("$NetBSD: getch.c,v 1.36 2002/01/02 10:38:27 blymn Exp $");
42 #endif
43 #endif /* not lint */
44
45 #include <string.h>
46 #include <stdlib.h>
47 #include <unistd.h>
48 #include <stdio.h>
49 #include "curses.h"
50 #include "curses_private.h"
51
52 #define DEFAULT_DELAY 2 /* default delay for timeout() */
53
54 /*
55 * Keyboard input handler. Do this by snarfing
56 * all the info we can out of the termcap entry for TERM and putting it
57 * into a set of keymaps. A keymap is an array the size of all the possible
58 * single characters we can get, the contents of the array is a structure
59 * that contains the type of entry this character is (i.e. part/end of a
60 * multi-char sequence or a plain char) and either a pointer which will point
61 * to another keymap (in the case of a multi-char sequence) OR the data value
62 * that this key should return.
63 *
64 */
65
66 /* private data structures for holding the key definitions */
67 typedef struct key_entry key_entry_t;
68
69 struct key_entry {
70 short type; /* type of key this is */
71 union {
72 keymap_t *next; /* next keymap is key is multi-key sequence */
73 wchar_t symbol; /* key symbol if key is a leaf entry */
74 } value;
75 };
76 /* Types of key structures we can have */
77 #define KEYMAP_MULTI 1 /* part of a multi char sequence */
78 #define KEYMAP_LEAF 2 /* key has a symbol associated with it, either
79 * it is the end of a multi-char sequence or a
80 * single char key that generates a symbol */
81
82 /* allocate this many key_entry structs at once to speed start up must
83 * be a power of 2.
84 */
85 #define KEYMAP_ALLOC_CHUNK 4
86
87 /* The max number of different chars we can receive */
88 #define MAX_CHAR 256
89
90 struct keymap {
91 int count; /* count of number of key structs allocated */
92 short mapping[MAX_CHAR]; /* mapping of key to allocated structs */
93 key_entry_t **key; /* dynamic array of keys */
94 };
95
96
97 /* Key buffer */
98 #define INBUF_SZ 16 /* size of key buffer - must be larger than
99 * longest multi-key sequence */
100 static wchar_t inbuf[INBUF_SZ];
101 static int start, end, working; /* pointers for manipulating inbuf data */
102
103 #define INC_POINTER(ptr) do { \
104 (ptr)++; \
105 ptr %= INBUF_SZ; \
106 } while(/*CONSTCOND*/0)
107
108 static short state; /* state of the inkey function */
109
110 #define INKEY_NORM 0 /* no key backlog to process */
111 #define INKEY_ASSEMBLING 1 /* assembling a multi-key sequence */
112 #define INKEY_BACKOUT 2 /* recovering from an unrecognised key */
113 #define INKEY_TIMEOUT 3 /* multi-key sequence timeout */
114
115 /* The termcap data we are interested in and the symbols they map to */
116 struct tcdata {
117 const char *name; /* name of termcap entry */
118 wchar_t symbol; /* the symbol associated with it */
119 };
120
121 static const struct tcdata tc[] = {
122 {"!1", KEY_SSAVE},
123 {"!2", KEY_SSUSPEND},
124 {"!3", KEY_SUNDO},
125 {"#1", KEY_SHELP},
126 {"#2", KEY_SHOME},
127 {"#3", KEY_SIC},
128 {"#4", KEY_SLEFT},
129 {"%0", KEY_REDO},
130 {"%1", KEY_HELP},
131 {"%2", KEY_MARK},
132 {"%3", KEY_MESSAGE},
133 {"%4", KEY_MOVE},
134 {"%5", KEY_NEXT},
135 {"%6", KEY_OPEN},
136 {"%7", KEY_OPTIONS},
137 {"%8", KEY_PREVIOUS},
138 {"%9", KEY_PRINT},
139 {"%a", KEY_SMESSAGE},
140 {"%b", KEY_SMOVE},
141 {"%c", KEY_SNEXT},
142 {"%d", KEY_SOPTIONS},
143 {"%e", KEY_SPREVIOUS},
144 {"%f", KEY_SPRINT},
145 {"%g", KEY_SREDO},
146 {"%h", KEY_SREPLACE},
147 {"%i", KEY_SRIGHT},
148 {"%j", KEY_SRSUME},
149 {"&0", KEY_SCANCEL},
150 {"&1", KEY_REFERENCE},
151 {"&2", KEY_REFRESH},
152 {"&3", KEY_REPLACE},
153 {"&4", KEY_RESTART},
154 {"&5", KEY_RESUME},
155 {"&6", KEY_SAVE},
156 {"&7", KEY_SUSPEND},
157 {"&8", KEY_UNDO},
158 {"&9", KEY_SBEG},
159 {"*0", KEY_SFIND},
160 {"*1", KEY_SCOMMAND},
161 {"*2", KEY_SCOPY},
162 {"*3", KEY_SCREATE},
163 {"*4", KEY_SDC},
164 {"*5", KEY_SDL},
165 {"*6", KEY_SELECT},
166 {"*7", KEY_SEND},
167 {"*8", KEY_SEOL},
168 {"*9", KEY_SEXIT},
169 {"@0", KEY_FIND},
170 {"@1", KEY_BEG},
171 {"@2", KEY_CANCEL},
172 {"@3", KEY_CLOSE},
173 {"@4", KEY_COMMAND},
174 {"@5", KEY_COPY},
175 {"@6", KEY_CREATE},
176 {"@7", KEY_END},
177 {"@8", KEY_ENTER},
178 {"@9", KEY_EXIT},
179 {"F1", KEY_F(11)},
180 {"F2", KEY_F(12)},
181 {"F3", KEY_F(13)},
182 {"F4", KEY_F(14)},
183 {"F5", KEY_F(15)},
184 {"F6", KEY_F(16)},
185 {"F7", KEY_F(17)},
186 {"F8", KEY_F(18)},
187 {"F9", KEY_F(19)},
188 {"FA", KEY_F(20)},
189 {"FB", KEY_F(21)},
190 {"FC", KEY_F(22)},
191 {"FD", KEY_F(23)},
192 {"FE", KEY_F(24)},
193 {"FF", KEY_F(25)},
194 {"FG", KEY_F(26)},
195 {"FH", KEY_F(27)},
196 {"FI", KEY_F(28)},
197 {"FJ", KEY_F(29)},
198 {"FK", KEY_F(30)},
199 {"FL", KEY_F(31)},
200 {"FM", KEY_F(32)},
201 {"FN", KEY_F(33)},
202 {"FO", KEY_F(34)},
203 {"FP", KEY_F(35)},
204 {"FQ", KEY_F(36)},
205 {"FR", KEY_F(37)},
206 {"FS", KEY_F(38)},
207 {"FT", KEY_F(39)},
208 {"FU", KEY_F(40)},
209 {"FV", KEY_F(41)},
210 {"FW", KEY_F(42)},
211 {"FX", KEY_F(43)},
212 {"FY", KEY_F(44)},
213 {"FZ", KEY_F(45)},
214 {"Fa", KEY_F(46)},
215 {"Fb", KEY_F(47)},
216 {"Fc", KEY_F(48)},
217 {"Fd", KEY_F(49)},
218 {"Fe", KEY_F(50)},
219 {"Ff", KEY_F(51)},
220 {"Fg", KEY_F(52)},
221 {"Fh", KEY_F(53)},
222 {"Fi", KEY_F(54)},
223 {"Fj", KEY_F(55)},
224 {"Fk", KEY_F(56)},
225 {"Fl", KEY_F(57)},
226 {"Fm", KEY_F(58)},
227 {"Fn", KEY_F(59)},
228 {"Fo", KEY_F(60)},
229 {"Fp", KEY_F(61)},
230 {"Fq", KEY_F(62)},
231 {"Fr", KEY_F(63)},
232 {"K1", KEY_A1},
233 {"K2", KEY_B2},
234 {"K3", KEY_A3},
235 {"K4", KEY_C1},
236 {"K5", KEY_C3},
237 {"Km", KEY_MOUSE},
238 {"k0", KEY_F0},
239 {"k1", KEY_F(1)},
240 {"k2", KEY_F(2)},
241 {"k3", KEY_F(3)},
242 {"k4", KEY_F(4)},
243 {"k5", KEY_F(5)},
244 {"k6", KEY_F(6)},
245 {"k7", KEY_F(7)},
246 {"k8", KEY_F(8)},
247 {"k9", KEY_F(9)},
248 {"k;", KEY_F(10)},
249 {"kA", KEY_IL},
250 {"ka", KEY_CATAB},
251 {"kB", KEY_BTAB},
252 {"kb", KEY_BACKSPACE},
253 {"kC", KEY_CLEAR},
254 {"kD", KEY_DC},
255 {"kd", KEY_DOWN},
256 {"kE", KEY_EOL},
257 {"kF", KEY_SF},
258 {"kH", KEY_LL},
259 {"kh", KEY_HOME},
260 {"kI", KEY_IC},
261 {"kL", KEY_DL},
262 {"kl", KEY_LEFT},
263 {"kM", KEY_EIC},
264 {"kN", KEY_NPAGE},
265 {"kP", KEY_PPAGE},
266 {"kR", KEY_SR},
267 {"kr", KEY_RIGHT},
268 {"kS", KEY_EOS},
269 {"kT", KEY_STAB},
270 {"kt", KEY_CTAB},
271 {"ku", KEY_UP}
272 };
273 /* Number of TC entries .... */
274 static const int num_tcs = (sizeof(tc) / sizeof(struct tcdata));
275
276 /* prototypes for private functions */
277 static key_entry_t *add_new_key(keymap_t *current, char chr, int key_type,
278 int symbol);
279 static keymap_t *new_keymap(void); /* create a new keymap */
280 static key_entry_t *new_key(void); /* create a new key entry */
281 static wchar_t inkey(int to, int delay);
282
283 /*
284 * Free the storage associated with the given keymap
285 */
286 void
287 _cursesi_free_keymap(keymap_t *map)
288 {
289 int i;
290
291 /* check for, and free, child keymaps */
292 for (i = 0; i < MAX_CHAR; i++) {
293 if (map->mapping[i] >= 0) {
294 if (map->key[map->mapping[i]]->type == KEYMAP_MULTI)
295 _cursesi_free_keymap(
296 map->key[map->mapping[i]]->value.next);
297 }
298 }
299
300 /* now free any allocated keymap structs */
301 for (i = 0; i < map->count; i += KEYMAP_ALLOC_CHUNK) {
302 free(map->key[i]);
303 }
304
305 free(map->key);
306 free(map);
307 }
308
309
310 /*
311 * Add a new key entry to the keymap pointed to by current. Entry
312 * contains the character to add to the keymap, type is the type of
313 * entry to add (either multikey or leaf) and symbol is the symbolic
314 * value for a leaf type entry. The function returns a pointer to the
315 * new keymap entry.
316 */
317 static key_entry_t *
318 add_new_key(keymap_t *current, char chr, int key_type, int symbol)
319 {
320 key_entry_t *the_key;
321 int i;
322
323 #ifdef DEBUG
324 __CTRACE("Adding character %s of type %d, symbol 0x%x\n", unctrl(chr),
325 key_type, symbol);
326 #endif
327 if (current->mapping[(unsigned char) chr] < 0) {
328 /* first time for this char */
329 current->mapping[(unsigned char) chr] = current->count; /* map new entry */
330 /* make sure we have room in the key array first */
331 if ((current->count & (KEYMAP_ALLOC_CHUNK - 1)) == 0)
332 {
333 if ((current->key =
334 realloc(current->key,
335 (current->count) * sizeof(key_entry_t *)
336 + KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t *))) == NULL) {
337 fprintf(stderr,
338 "Could not malloc for key entry\n");
339 exit(1);
340 }
341
342 the_key = new_key();
343 for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) {
344 current->key[current->count + i]
345 = &the_key[i];
346 }
347 }
348
349 /* point at the current key array element to use */
350 the_key = current->key[current->count];
351
352 the_key->type = key_type;
353
354 switch (key_type) {
355 case KEYMAP_MULTI:
356 /* need for next key */
357 #ifdef DEBUG
358 __CTRACE("Creating new keymap\n");
359 #endif
360 the_key->value.next = new_keymap();
361 break;
362
363 case KEYMAP_LEAF:
364 /* the associated symbol for the key */
365 #ifdef DEBUG
366 __CTRACE("Adding leaf key\n");
367 #endif
368 the_key->value.symbol = symbol;
369 break;
370
371 default:
372 fprintf(stderr, "add_new_key: bad type passed\n");
373 exit(1);
374 }
375
376 current->count++;
377 } else {
378 /* the key is already known - just return the address. */
379 #ifdef DEBUG
380 __CTRACE("Keymap already known\n");
381 #endif
382 the_key = current->key[current->mapping[(unsigned char) chr]];
383 }
384
385 return the_key;
386 }
387
388 /*
389 * Init_getch - initialise all the pointers & structures needed to make
390 * getch work in keypad mode.
391 *
392 */
393 void
394 __init_getch(SCREEN *screen)
395 {
396 char entry[1024], *p;
397 int i, j, length, key_ent;
398 size_t limit;
399 key_entry_t *tmp_key;
400 keymap_t *current;
401 #ifdef DEBUG
402 int k;
403 #endif
404
405 /* init the inkey state variable */
406 state = INKEY_NORM;
407
408 /* init the base keymap */
409 screen->base_keymap = new_keymap();
410
411 /* key input buffer pointers */
412 start = end = working = 0;
413
414 /* now do the termcap snarfing ... */
415
416 for (i = 0; i < num_tcs; i++) {
417 p = entry;
418 limit = 1023;
419 if (t_getstr(screen->cursesi_genbuf, tc[i].name,
420 &p, &limit) != NULL) {
421 current = screen->base_keymap; /* always start with
422 * base keymap. */
423 length = (int) strlen(entry);
424 #ifdef DEBUG
425 __CTRACE("Processing termcap entry %s, sequence ",
426 tc[i].name);
427 for (k = 0; k <= length -1; k++)
428 __CTRACE("%s", unctrl(entry[k]));
429 __CTRACE("\n");
430 #endif
431 for (j = 0; j < length - 1; j++) {
432 /* add the entry to the struct */
433 tmp_key = add_new_key(current,
434 entry[j],
435 KEYMAP_MULTI, 0);
436
437 /* index into the key array - it's
438 clearer if we stash this */
439 key_ent = current->mapping[
440 (unsigned char) entry[j]];
441
442 current->key[key_ent] = tmp_key;
443
444 /* next key uses this map... */
445 current = current->key[key_ent]->value.next;
446 }
447
448 /* this is the last key in the sequence (it
449 * may have been the only one but that does
450 * not matter) this means it is a leaf key and
451 * should have a symbol associated with it.
452 */
453 tmp_key = add_new_key(current,
454 entry[length - 1],
455 KEYMAP_LEAF,
456 tc[i].symbol);
457 current->key[
458 current->mapping[(int)entry[length - 1]]] =
459 tmp_key;
460 }
461 }
462 }
463
464
465 /*
466 * new_keymap - allocates & initialises a new keymap structure. This
467 * function returns a pointer to the new keymap.
468 *
469 */
470 static keymap_t *
471 new_keymap(void)
472 {
473 int i;
474 keymap_t *new_map;
475
476 if ((new_map = malloc(sizeof(keymap_t))) == NULL) {
477 perror("Inkey: Cannot allocate new keymap");
478 exit(2);
479 }
480
481 /* Initialise the new map */
482 new_map->count = 0;
483 for (i = 0; i < MAX_CHAR; i++) {
484 new_map->mapping[i] = -1; /* no mapping for char */
485 }
486
487 /* key array will be allocated when first key is added */
488 new_map->key = NULL;
489
490 return new_map;
491 }
492
493 /*
494 * new_key - allocates & initialises a new key entry. This function returns
495 * a pointer to the newly allocated key entry.
496 *
497 */
498 static key_entry_t *
499 new_key(void)
500 {
501 key_entry_t *new_one;
502 int i;
503
504 if ((new_one = malloc(KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t)))
505 == NULL) {
506 perror("inkey: Cannot allocate new key entry chunk");
507 exit(2);
508 }
509
510 for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) {
511 new_one[i].type = 0;
512 new_one[i].value.next = NULL;
513 }
514
515 return new_one;
516 }
517
518 /*
519 * inkey - do the work to process keyboard input, check for multi-key
520 * sequences and return the appropriate symbol if we get a match.
521 *
522 */
523
524 wchar_t
525 inkey(int to, int delay)
526 {
527 wchar_t k;
528 int c;
529 keymap_t *current = _cursesi_screen->base_keymap;
530 FILE *infd = _cursesi_screen->infd;
531
532 k = 0; /* XXX gcc -Wuninitialized */
533
534 for (;;) { /* loop until we get a complete key sequence */
535 reread:
536 if (state == INKEY_NORM) {
537 if (delay && __timeout(delay) == ERR)
538 return ERR;
539 if ((c = getchar()) == EOF) {
540 clearerr(infd);
541 return ERR;
542 }
543
544 if (delay && (__notimeout() == ERR))
545 return ERR;
546
547 k = (wchar_t) c;
548 #ifdef DEBUG
549 __CTRACE("inkey (state normal) got '%s'\n", unctrl(k));
550 #endif
551
552 working = start;
553 inbuf[working] = k;
554 INC_POINTER(working);
555 end = working;
556 state = INKEY_ASSEMBLING; /* go to the assembling
557 * state now */
558 } else if (state == INKEY_BACKOUT) {
559 k = inbuf[working];
560 INC_POINTER(working);
561 if (working == end) { /* see if we have run
562 * out of keys in the
563 * backlog */
564
565 /* if we have then switch to
566 assembling */
567 state = INKEY_ASSEMBLING;
568 }
569 } else if (state == INKEY_ASSEMBLING) {
570 /* assembling a key sequence */
571 if (delay) {
572 if (__timeout(to ? DEFAULT_DELAY : delay) == ERR)
573 return ERR;
574 } else {
575 if (to && (__timeout(DEFAULT_DELAY) == ERR))
576 return ERR;
577 }
578
579 c = getchar();
580 if (ferror(infd)) {
581 clearerr(infd);
582 return ERR;
583 }
584
585 if ((to || delay) && (__notimeout() == ERR))
586 return ERR;
587
588 k = (wchar_t) c;
589 #ifdef DEBUG
590 __CTRACE("inkey (state assembling) got '%s'\n", unctrl(k));
591 #endif
592 if (feof(infd)) { /* inter-char timeout,
593 * start backing out */
594 clearerr(infd);
595 if (start == end)
596 /* no chars in the buffer, restart */
597 goto reread;
598
599 k = inbuf[start];
600 state = INKEY_TIMEOUT;
601 } else {
602 inbuf[working] = k;
603 INC_POINTER(working);
604 end = working;
605 }
606 } else {
607 fprintf(stderr, "Inkey state screwed - exiting!!!");
608 exit(2);
609 }
610
611 /* Check key has no special meaning and we have not timed out */
612 if ((state == INKEY_TIMEOUT) || (current->mapping[k] < 0)) {
613 /* return the first key we know about */
614 k = inbuf[start];
615
616 INC_POINTER(start);
617 working = start;
618
619 if (start == end) { /* only one char processed */
620 state = INKEY_NORM;
621 } else {/* otherwise we must have more than one char
622 * to backout */
623 state = INKEY_BACKOUT;
624 }
625 return k;
626 } else { /* must be part of a multikey sequence */
627 /* check for completed key sequence */
628 if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) {
629 start = working; /* eat the key sequence
630 * in inbuf */
631
632 /* check if inbuf empty now */
633 if (start == end) {
634 /* if it is go back to normal */
635 state = INKEY_NORM;
636 } else {
637 /* otherwise go to backout state */
638 state = INKEY_BACKOUT;
639 }
640
641 /* return the symbol */
642 return current->key[current->mapping[k]]->value.symbol;
643
644 } else {
645 /*
646 * Step on to next part of the multi-key
647 * sequence.
648 */
649 current = current->key[current->mapping[k]]->value.next;
650 }
651 }
652 }
653 }
654
655 #ifndef _CURSES_USE_MACROS
656 /*
657 * getch --
658 * Read in a character from stdscr.
659 */
660 int
661 getch(void)
662 {
663 return wgetch(stdscr);
664 }
665
666 /*
667 * mvgetch --
668 * Read in a character from stdscr at the given location.
669 */
670 int
671 mvgetch(int y, int x)
672 {
673 return mvwgetch(stdscr, y, x);
674 }
675
676 /*
677 * mvwgetch --
678 * Read in a character from stdscr at the given location in the
679 * given window.
680 */
681 int
682 mvwgetch(WINDOW *win, int y, int x)
683 {
684 if (wmove(win, y, x) == ERR)
685 return ERR;
686
687 return wgetch(win);
688 }
689
690 #endif
691
692 /*
693 * wgetch --
694 * Read in a character from the window.
695 */
696 int
697 wgetch(WINDOW *win)
698 {
699 int inp, weset;
700 int c;
701 FILE *infd = _cursesi_screen->infd;
702
703 if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN)
704 && win->curx == win->maxx - 1 && win->cury == win->maxy - 1
705 && __echoit)
706 return (ERR);
707
708 if (is_wintouched(win))
709 wrefresh(win);
710 #ifdef DEBUG
711 __CTRACE("wgetch: __echoit = %d, __rawmode = %d, flags = %0.2o\n",
712 __echoit, __rawmode, win->flags);
713 #endif
714 if (__echoit && !__rawmode) {
715 cbreak();
716 weset = 1;
717 } else
718 weset = 0;
719
720 __save_termios();
721
722 if (win->flags & __KEYPAD) {
723 switch (win->delay)
724 {
725 case -1:
726 inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0);
727 break;
728 case 0:
729 if (__nodelay() == ERR) {
730 __restore_termios();
731 return ERR;
732 }
733 inp = inkey(0, 0);
734 break;
735 default:
736 inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay);
737 break;
738 }
739 } else {
740 switch (win->delay)
741 {
742 case -1:
743 break;
744 case 0:
745 if (__nodelay() == ERR) {
746 __restore_termios();
747 return ERR;
748 }
749 break;
750 default:
751 if (__timeout(win->delay) == ERR) {
752 __restore_termios();
753 return ERR;
754 }
755 break;
756 }
757
758 c = getchar();
759 if (feof(infd)) {
760 clearerr(infd);
761 __restore_termios();
762 return ERR; /* we have timed out */
763 }
764
765 if (ferror(infd)) {
766 clearerr(infd);
767 inp = ERR;
768 } else {
769 inp = c;
770 }
771 }
772 #ifdef DEBUG
773 if (inp > 255)
774 /* we have a key symbol - treat it differently */
775 /* XXXX perhaps __unctrl should be expanded to include
776 * XXXX the keysyms in the table....
777 */
778 __CTRACE("wgetch assembled keysym 0x%x\n", inp);
779 else
780 __CTRACE("wgetch got '%s'\n", unctrl(inp));
781 #endif
782 if (win->delay > -1) {
783 if (__delay() == ERR) {
784 __restore_termios();
785 return ERR;
786 }
787 }
788
789 __restore_termios();
790
791 if (__echoit)
792 waddch(win, (chtype) inp);
793
794 if (weset)
795 nocbreak();
796
797 return ((inp < 0) || (inp == ERR) ? ERR : inp);
798 }
799
800 /*
801 * ungetch --
802 * Put the character back into the input queue.
803 */
804 int
805 ungetch(int c)
806 {
807 return ((ungetc(c, _cursesi_screen->infd) == EOF) ? ERR : OK);
808 }
809