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