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