getch.c revision 1.28
1/* $NetBSD: getch.c,v 1.28 2000/05/17 16:23:49 jdc 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.28 2000/05/17 16:23:49 jdc 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 */ 53extern 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 */ 70typedef struct keymap keymap_t; 71typedef struct key_entry key_entry_t; 72 73struct 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 94struct 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 */ 104static wchar_t inbuf[INBUF_SZ]; 105static 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 112static 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 */ 120struct tcdata { 121 const char *name; /* name of termcap entry */ 122 wchar_t symbol; /* the symbol associated with it */ 123}; 124 125static 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 .... */ 278static const int num_tcs = (sizeof(tc) / sizeof(struct tcdata)); 279 280/* The root keymap */ 281 282static keymap_t *base_keymap; 283 284/* prototypes for private functions */ 285static key_entry_t *add_new_key(keymap_t *current, char chr, int key_type, 286 int symbol); 287static keymap_t *new_keymap(void); /* create a new keymap */ 288static key_entry_t *new_key(void); /* create a new key entry */ 289static 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 */ 298static key_entry_t * 299add_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 */ 374void 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 */ 449static keymap_t * 450new_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 */ 477static key_entry_t * 478new_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 503wchar_t 504inkey(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 */ 513reread: 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 */ 638int 639getch(void) 640{ 641 return wgetch(stdscr); 642} 643 644/* 645 * mvgetch -- 646 * Read in a character from stdscr at the given location. 647 */ 648int 649mvgetch(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 */ 659int 660mvwgetch(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 */ 674int 675wgetch(WINDOW *win) 676{ 677 int inp, weset; 678 char 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 if (!(curscr->flags & __KEYPAD)) { 700 tputs(KS, 0, __cputchar); 701 curscr->flags |= __KEYPAD; 702 } 703 switch (win->delay) 704 { 705 case -1: 706 inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0); 707 break; 708 case 0: 709 if (__nodelay() == ERR) { 710 __restore_termios(); 711 return ERR; 712 } 713 inp = inkey(0, 0); 714 break; 715 default: 716 inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay); 717 break; 718 } 719 } else { 720 if (curscr->flags & __KEYPAD) { 721 tputs(KE, 0, __cputchar); 722 curscr->flags &= ~__KEYPAD; 723 } 724 switch (win->delay) 725 { 726 case -1: 727 break; 728 case 0: 729 if (__nodelay() == ERR) { 730 __restore_termios(); 731 return ERR; 732 } 733 break; 734 default: 735 if (__timeout(win->delay) == ERR) { 736 __restore_termios(); 737 return ERR; 738 } 739 break; 740 } 741 742 c = getchar(); 743 if (feof(stdin)) { 744 clearerr(stdin); 745 __restore_termios(); 746 return ERR; /* we have timed out */ 747 } 748 749 if (ferror(stdin)) { 750 clearerr(stdin); 751 inp = ERR; 752 } else { 753 inp = (unsigned int) c; 754 } 755 } 756#ifdef DEBUG 757 if (inp > 255) 758 /* we have a key symbol - treat it differently */ 759 /* XXXX perhaps __unctrl should be expanded to include 760 * XXXX the keysyms in the table.... 761 */ 762 __CTRACE("wgetch assembled keysym 0x%x\n", inp); 763 else 764 __CTRACE("wgetch got '%s'\n", unctrl(inp)); 765#endif 766 if (win->delay > -1) { 767 if (__delay() == ERR) { 768 __restore_termios(); 769 return ERR; 770 } 771 } 772 773 __restore_termios(); 774 775 if (__echoit) 776 waddch(win, (chtype) inp); 777 778 if (weset) 779 nocbreak(); 780 781 return ((inp < 0) || (inp == ERR) ? ERR : inp); 782} 783 784/* 785 * ungetch -- 786 * Put the character back into the input queue. 787 */ 788int 789ungetch(int c) 790{ 791 return ((ungetc(c, stdin) == EOF) ? ERR : OK); 792} 793