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