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