1 /* $NetBSD: getch.c,v 1.46 2006/07/25 21:45:00 christos 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.46 2006/07/25 21:45:00 christos 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 #ifdef DEBUG 598 __CTRACE("inkey (%d, %d)\n", to, delay); 599 #endif 600 for (;;) { /* loop until we get a complete key sequence */ 601 reread: 602 if (state == INKEY_NORM) { 603 if (delay && __timeout(delay) == ERR) 604 return ERR; 605 c = getchar(); 606 if (_cursesi_screen->resized) { 607 if (c != -1) 608 ungetch(c); 609 _cursesi_screen->resized = 0; 610 clearerr(infd); 611 return KEY_RESIZE; 612 } 613 if (c == EOF) { 614 clearerr(infd); 615 return ERR; 616 } 617 618 if (delay && (__notimeout() == ERR)) 619 return ERR; 620 621 k = (wchar_t) c; 622 #ifdef DEBUG 623 __CTRACE("inkey (state normal) got '%s'\n", unctrl(k)); 624 #endif 625 626 working = start; 627 inbuf[working] = k; 628 INC_POINTER(working); 629 end = working; 630 state = INKEY_ASSEMBLING; /* go to the assembling 631 * state now */ 632 } else if (state == INKEY_BACKOUT) { 633 k = inbuf[working]; 634 INC_POINTER(working); 635 if (working == end) { /* see if we have run 636 * out of keys in the 637 * backlog */ 638 639 /* if we have then switch to assembling */ 640 state = INKEY_ASSEMBLING; 641 } 642 } else if (state == INKEY_ASSEMBLING) { 643 /* assembling a key sequence */ 644 if (delay) { 645 if (__timeout(to ? (ESCDELAY / 100) : delay) 646 == ERR) 647 return ERR; 648 } else { 649 if (to && (__timeout(ESCDELAY / 100) == ERR)) 650 return ERR; 651 } 652 653 c = getchar(); 654 if (_cursesi_screen->resized) { 655 if (c != -1) 656 ungetch(c); 657 _cursesi_screen->resized = 0; 658 clearerr(infd); 659 return KEY_RESIZE; 660 } 661 if (c == -1 || ferror(infd)) { 662 clearerr(infd); 663 return ERR; 664 } 665 666 if ((to || delay) && (__notimeout() == ERR)) 667 return ERR; 668 669 k = (wchar_t) c; 670 #ifdef DEBUG 671 __CTRACE("inkey (state assembling) got '%s'\n", unctrl(k)); 672 #endif 673 if (feof(infd)) { /* inter-char timeout, 674 * start backing out */ 675 clearerr(infd); 676 if (start == end) 677 /* no chars in the buffer, restart */ 678 goto reread; 679 680 k = inbuf[start]; 681 state = INKEY_TIMEOUT; 682 } else { 683 inbuf[working] = k; 684 INC_POINTER(working); 685 end = working; 686 } 687 } else { 688 fprintf(stderr, "Inkey state screwed - exiting!!!"); 689 exit(2); 690 } 691 692 /* 693 * Check key has no special meaning and we have not 694 * timed out and the key has not been disabled 695 */ 696 mapping = current->mapping[k]; 697 if (((state == INKEY_TIMEOUT) || (mapping < 0)) 698 || ((current->key[mapping]->type == KEYMAP_LEAF) 699 && (current->key[mapping]->enable == FALSE))) { 700 /* return the first key we know about */ 701 k = inbuf[start]; 702 703 INC_POINTER(start); 704 working = start; 705 706 if (start == end) { /* only one char processed */ 707 state = INKEY_NORM; 708 } else {/* otherwise we must have more than one char 709 * to backout */ 710 state = INKEY_BACKOUT; 711 } 712 return k; 713 } else { /* must be part of a multikey sequence */ 714 /* check for completed key sequence */ 715 if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) { 716 start = working; /* eat the key sequence 717 * in inbuf */ 718 719 /* check if inbuf empty now */ 720 if (start == end) { 721 /* if it is go back to normal */ 722 state = INKEY_NORM; 723 } else { 724 /* otherwise go to backout state */ 725 state = INKEY_BACKOUT; 726 } 727 728 /* return the symbol */ 729 return current->key[current->mapping[k]]->value.symbol; 730 731 } else { 732 /* 733 * Step on to next part of the multi-key 734 * sequence. 735 */ 736 current = current->key[current->mapping[k]]->value.next; 737 } 738 } 739 } 740 } 741 742 #ifndef _CURSES_USE_MACROS 743 /* 744 * getch -- 745 * Read in a character from stdscr. 746 */ 747 int 748 getch(void) 749 { 750 return wgetch(stdscr); 751 } 752 753 /* 754 * mvgetch -- 755 * Read in a character from stdscr at the given location. 756 */ 757 int 758 mvgetch(int y, int x) 759 { 760 return mvwgetch(stdscr, y, x); 761 } 762 763 /* 764 * mvwgetch -- 765 * Read in a character from stdscr at the given location in the 766 * given window. 767 */ 768 int 769 mvwgetch(WINDOW *win, int y, int x) 770 { 771 if (wmove(win, y, x) == ERR) 772 return ERR; 773 774 return wgetch(win); 775 } 776 777 #endif 778 779 /* 780 * keyok -- 781 * Set the enable flag for a keysym, if the flag is false then 782 * getch will not return this keysym even if the matching key sequence 783 * is seen. 784 */ 785 int 786 keyok(int key_type, bool flag) 787 { 788 int result = ERR; 789 790 do_keyok(_cursesi_screen->base_keymap, key_type, flag, &result); 791 return result; 792 } 793 794 /* 795 * do_keyok -- 796 * Does the actual work for keyok, we need to recurse through the 797 * keymaps finding the passed key symbol. 798 */ 799 void 800 do_keyok(keymap_t *current, int key_type, bool flag, int *retval) 801 { 802 key_entry_t *key; 803 int i; 804 805 /* 806 * we need to iterate over all the keys as there may be 807 * multiple instances of the leaf symbol. 808 */ 809 for (i = 0; i < MAX_CHAR; i++) { 810 if (current->mapping[i] < 0) 811 continue; /* no mapping for the key, next! */ 812 813 key = current->key[current->mapping[i]]; 814 815 if (key->type == KEYMAP_MULTI) 816 do_keyok(key->value.next, key_type, flag, retval); 817 else if ((key->type == KEYMAP_LEAF) 818 && (key->value.symbol == key_type)) { 819 key->enable = flag; 820 *retval = OK; /* we found at least one instance, ok */ 821 } 822 } 823 } 824 825 /* 826 * define_key -- 827 * Add a custom mapping of a key sequence to key symbol. 828 * 829 */ 830 int 831 define_key(char *sequence, int symbol) 832 { 833 834 if (symbol <= 0) 835 return ERR; 836 837 if (sequence == NULL) 838 delete_key_sequence(_cursesi_screen->base_keymap, symbol); 839 else 840 add_key_sequence(_cursesi_screen, sequence, symbol); 841 842 return OK; 843 } 844 845 /* 846 * wgetch -- 847 * Read in a character from the window. 848 */ 849 int 850 wgetch(WINDOW *win) 851 { 852 int inp, weset; 853 int c; 854 FILE *infd = _cursesi_screen->infd; 855 856 if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN) 857 && win->curx == win->maxx - 1 && win->cury == win->maxy - 1 858 && __echoit) 859 return (ERR); 860 861 if (is_wintouched(win)) 862 wrefresh(win); 863 #ifdef DEBUG 864 __CTRACE("wgetch: __echoit = %d, __rawmode = %d, __nl = %d, flags = %#.4x\n", 865 __echoit, __rawmode, _cursesi_screen->nl, win->flags); 866 #endif 867 if (__echoit && !__rawmode) { 868 cbreak(); 869 weset = 1; 870 } else 871 weset = 0; 872 873 __save_termios(); 874 875 if (win->flags & __KEYPAD) { 876 switch (win->delay) 877 { 878 case -1: 879 inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0); 880 break; 881 case 0: 882 if (__nodelay() == ERR) { 883 __restore_termios(); 884 return ERR; 885 } 886 inp = inkey(0, 0); 887 break; 888 default: 889 inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay); 890 break; 891 } 892 } else { 893 switch (win->delay) 894 { 895 case -1: 896 if (__delay() == ERR) { 897 __restore_termios(); 898 return ERR; 899 } 900 break; 901 case 0: 902 if (__nodelay() == ERR) { 903 __restore_termios(); 904 return ERR; 905 } 906 break; 907 default: 908 if (__timeout(win->delay) == ERR) { 909 __restore_termios(); 910 return ERR; 911 } 912 break; 913 } 914 915 c = getchar(); 916 if (_cursesi_screen->resized) { 917 if (c != -1) 918 ungetch(c); 919 _cursesi_screen->resized = 0; 920 clearerr(infd); 921 __restore_termios(); 922 return KEY_RESIZE; 923 } 924 if (feof(infd)) { 925 clearerr(infd); 926 __restore_termios(); 927 return ERR; /* we have timed out */ 928 } 929 930 if (ferror(infd)) { 931 clearerr(infd); 932 inp = ERR; 933 } else { 934 inp = c; 935 } 936 } 937 #ifdef DEBUG 938 if (inp > 255) 939 /* we have a key symbol - treat it differently */ 940 /* XXXX perhaps __unctrl should be expanded to include 941 * XXXX the keysyms in the table.... 942 */ 943 __CTRACE("wgetch assembled keysym 0x%x\n", inp); 944 else 945 __CTRACE("wgetch got '%s'\n", unctrl(inp)); 946 #endif 947 if (win->delay > -1) { 948 if (__delay() == ERR) { 949 __restore_termios(); 950 return ERR; 951 } 952 } 953 954 __restore_termios(); 955 956 if (__echoit) 957 waddch(win, (chtype) inp); 958 959 if (weset) 960 nocbreak(); 961 962 if (_cursesi_screen->nl && inp == 13) 963 inp = 10; 964 965 return ((inp < 0) || (inp == ERR) ? ERR : inp); 966 } 967 968 /* 969 * ungetch -- 970 * Put the character back into the input queue. 971 */ 972 int 973 ungetch(int c) 974 { 975 return ((ungetc(c, _cursesi_screen->infd) == EOF) ? ERR : OK); 976 } 977