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