1 /* $NetBSD: getch.c,v 1.57 2010/12/07 22:02:52 joerg 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.57 2010/12/07 22:02:52 joerg 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 #include "keymap.h" 48 49 short state; /* state of the inkey function */ 50 51 static const struct tcdata tc[] = { 52 {TICODE_kSAV, KEY_SSAVE}, 53 {TICODE_kSPD, KEY_SSUSPEND}, 54 {TICODE_kUND, KEY_SUNDO}, 55 {TICODE_kHLP, KEY_SHELP}, 56 {TICODE_kHOM, KEY_SHOME}, 57 {TICODE_kIC, KEY_SIC}, 58 {TICODE_kLFT, KEY_SLEFT}, 59 {TICODE_krdo, KEY_REDO}, 60 {TICODE_khlp, KEY_HELP}, 61 {TICODE_kmrk, KEY_MARK}, 62 {TICODE_kmsg, KEY_MESSAGE}, 63 {TICODE_kmov, KEY_MOVE}, 64 {TICODE_knxt, KEY_NEXT}, 65 {TICODE_kopn, KEY_OPEN}, 66 {TICODE_kopt, KEY_OPTIONS}, 67 {TICODE_kprv, KEY_PREVIOUS}, 68 {TICODE_kprt, KEY_PRINT}, 69 {TICODE_kMSG, KEY_SMESSAGE}, 70 {TICODE_kMOV, KEY_SMOVE}, 71 {TICODE_kNXT, KEY_SNEXT}, 72 {TICODE_kOPT, KEY_SOPTIONS}, 73 {TICODE_kPRV, KEY_SPREVIOUS}, 74 {TICODE_kPRT, KEY_SPRINT}, 75 {TICODE_kRDO, KEY_SREDO}, 76 {TICODE_kRPL, KEY_SREPLACE}, 77 {TICODE_kRIT, KEY_SRIGHT}, 78 {TICODE_kRES, KEY_SRSUME}, 79 {TICODE_kCAN, KEY_SCANCEL}, 80 {TICODE_kref, KEY_REFERENCE}, 81 {TICODE_krfr, KEY_REFRESH}, 82 {TICODE_krpl, KEY_REPLACE}, 83 {TICODE_krst, KEY_RESTART}, 84 {TICODE_kres, KEY_RESUME}, 85 {TICODE_ksav, KEY_SAVE}, 86 {TICODE_kspd, KEY_SUSPEND}, 87 {TICODE_kund, KEY_UNDO}, 88 {TICODE_kBEG, KEY_SBEG}, 89 {TICODE_kFND, KEY_SFIND}, 90 {TICODE_kCMD, KEY_SCOMMAND}, 91 {TICODE_kCPY, KEY_SCOPY}, 92 {TICODE_kCRT, KEY_SCREATE}, 93 {TICODE_kDC, KEY_SDC}, 94 {TICODE_kDL, KEY_SDL}, 95 {TICODE_kslt, KEY_SELECT}, 96 {TICODE_kEND, KEY_SEND}, 97 {TICODE_kEOL, KEY_SEOL}, 98 {TICODE_kEXT, KEY_SEXIT}, 99 {TICODE_kfnd, KEY_FIND}, 100 {TICODE_kbeg, KEY_BEG}, 101 {TICODE_kcan, KEY_CANCEL}, 102 {TICODE_kclo, KEY_CLOSE}, 103 {TICODE_kcmd, KEY_COMMAND}, 104 {TICODE_kcpy, KEY_COPY}, 105 {TICODE_kcrt, KEY_CREATE}, 106 {TICODE_kend, KEY_END}, 107 {TICODE_kent, KEY_ENTER}, 108 {TICODE_kext, KEY_EXIT}, 109 {TICODE_kf11, KEY_F(11)}, 110 {TICODE_kf12, KEY_F(12)}, 111 {TICODE_kf13, KEY_F(13)}, 112 {TICODE_kf14, KEY_F(14)}, 113 {TICODE_kf15, KEY_F(15)}, 114 {TICODE_kf16, KEY_F(16)}, 115 {TICODE_kf17, KEY_F(17)}, 116 {TICODE_kf18, KEY_F(18)}, 117 {TICODE_kf19, KEY_F(19)}, 118 {TICODE_kf20, KEY_F(20)}, 119 {TICODE_kf21, KEY_F(21)}, 120 {TICODE_kf22, KEY_F(22)}, 121 {TICODE_kf23, KEY_F(23)}, 122 {TICODE_kf24, KEY_F(24)}, 123 {TICODE_kf25, KEY_F(25)}, 124 {TICODE_kf26, KEY_F(26)}, 125 {TICODE_kf27, KEY_F(27)}, 126 {TICODE_kf28, KEY_F(28)}, 127 {TICODE_kf29, KEY_F(29)}, 128 {TICODE_kf30, KEY_F(30)}, 129 {TICODE_kf31, KEY_F(31)}, 130 {TICODE_kf32, KEY_F(32)}, 131 {TICODE_kf33, KEY_F(33)}, 132 {TICODE_kf34, KEY_F(34)}, 133 {TICODE_kf35, KEY_F(35)}, 134 {TICODE_kf36, KEY_F(36)}, 135 {TICODE_kf37, KEY_F(37)}, 136 {TICODE_kf38, KEY_F(38)}, 137 {TICODE_kf39, KEY_F(39)}, 138 {TICODE_kf40, KEY_F(40)}, 139 {TICODE_kf41, KEY_F(41)}, 140 {TICODE_kf42, KEY_F(42)}, 141 {TICODE_kf43, KEY_F(43)}, 142 {TICODE_kf44, KEY_F(44)}, 143 {TICODE_kf45, KEY_F(45)}, 144 {TICODE_kf46, KEY_F(46)}, 145 {TICODE_kf47, KEY_F(47)}, 146 {TICODE_kf48, KEY_F(48)}, 147 {TICODE_kf49, KEY_F(49)}, 148 {TICODE_kf50, KEY_F(50)}, 149 {TICODE_kf51, KEY_F(51)}, 150 {TICODE_kf52, KEY_F(52)}, 151 {TICODE_kf53, KEY_F(53)}, 152 {TICODE_kf54, KEY_F(54)}, 153 {TICODE_kf55, KEY_F(55)}, 154 {TICODE_kf56, KEY_F(56)}, 155 {TICODE_kf57, KEY_F(57)}, 156 {TICODE_kf58, KEY_F(58)}, 157 {TICODE_kf59, KEY_F(59)}, 158 {TICODE_kf60, KEY_F(60)}, 159 {TICODE_kf61, KEY_F(61)}, 160 {TICODE_kf62, KEY_F(62)}, 161 {TICODE_kf63, KEY_F(63)}, 162 {TICODE_ka1, KEY_A1}, 163 {TICODE_kb2, KEY_B2}, 164 {TICODE_ka3, KEY_A3}, 165 {TICODE_kc1, KEY_C1}, 166 {TICODE_kc3, KEY_C3}, 167 {TICODE_kmous, KEY_MOUSE}, 168 {TICODE_kf0, KEY_F0}, 169 {TICODE_kf1, KEY_F(1)}, 170 {TICODE_kf2, KEY_F(2)}, 171 {TICODE_kf3, KEY_F(3)}, 172 {TICODE_kf4, KEY_F(4)}, 173 {TICODE_kf5, KEY_F(5)}, 174 {TICODE_kf6, KEY_F(6)}, 175 {TICODE_kf7, KEY_F(7)}, 176 {TICODE_kf8, KEY_F(8)}, 177 {TICODE_kf9, KEY_F(9)}, 178 {TICODE_kf10, KEY_F(10)}, 179 {TICODE_kil1, KEY_IL}, 180 {TICODE_ktbc, KEY_CATAB}, 181 {TICODE_kcbt, KEY_BTAB}, 182 {TICODE_kbs, KEY_BACKSPACE}, 183 {TICODE_kclr, KEY_CLEAR}, 184 {TICODE_kdch1, KEY_DC}, 185 {TICODE_kcud1, KEY_DOWN}, 186 {TICODE_kel, KEY_EOL}, 187 {TICODE_kind, KEY_SF}, 188 {TICODE_kll, KEY_LL}, 189 {TICODE_khome, KEY_HOME}, 190 {TICODE_kich1, KEY_IC}, 191 {TICODE_kdl1, KEY_DL}, 192 {TICODE_kcub1, KEY_LEFT}, 193 {TICODE_krmir, KEY_EIC}, 194 {TICODE_knp, KEY_NPAGE}, 195 {TICODE_kpp, KEY_PPAGE}, 196 {TICODE_kri, KEY_SR}, 197 {TICODE_kcuf1, KEY_RIGHT}, 198 {TICODE_ked, KEY_EOS}, 199 {TICODE_khts, KEY_STAB}, 200 {TICODE_kctab, KEY_CTAB}, 201 {TICODE_kcuu1, KEY_UP} 202 }; 203 /* Number of TC entries .... */ 204 static const int num_tcs = (sizeof(tc) / sizeof(struct tcdata)); 205 206 int ESCDELAY = 300; /* Delay in ms between keys for esc seq's */ 207 208 /* Key buffer */ 209 #define INBUF_SZ 16 /* size of key buffer - must be larger than 210 * longest multi-key sequence */ 211 static wchar_t inbuf[INBUF_SZ]; 212 static int start, end, working; /* pointers for manipulating inbuf data */ 213 214 /* prototypes for private functions */ 215 static void add_key_sequence(SCREEN *screen, char *sequence, int key_type); 216 static key_entry_t *add_new_key(keymap_t *current, char ch, int key_type, 217 int symbol); 218 static void delete_key_sequence(keymap_t *current, int key_type); 219 static void do_keyok(keymap_t *current, int key_type, bool flag, int *retval); 220 static keymap_t *new_keymap(void); /* create a new keymap */ 221 static key_entry_t *new_key(void); /* create a new key entry */ 222 static wchar_t inkey(int to, int delay); 223 224 /* 225 * Free the storage associated with the given keymap 226 */ 227 void 228 _cursesi_free_keymap(keymap_t *map) 229 { 230 int i; 231 232 /* check for, and free, child keymaps */ 233 for (i = 0; i < MAX_CHAR; i++) { 234 if (map->mapping[i] >= 0) { 235 if (map->key[map->mapping[i]]->type == KEYMAP_MULTI) 236 _cursesi_free_keymap( 237 map->key[map->mapping[i]]->value.next); 238 } 239 } 240 241 /* now free any allocated keymap structs */ 242 for (i = 0; i < map->count; i += KEYMAP_ALLOC_CHUNK) { 243 free(map->key[i]); 244 } 245 246 free(map->key); 247 free(map); 248 } 249 250 251 /* 252 * Add a new key entry to the keymap pointed to by current. Entry 253 * contains the character to add to the keymap, type is the type of 254 * entry to add (either multikey or leaf) and symbol is the symbolic 255 * value for a leaf type entry. The function returns a pointer to the 256 * new keymap entry. 257 */ 258 static key_entry_t * 259 add_new_key(keymap_t *current, char chr, int key_type, int symbol) 260 { 261 key_entry_t *the_key; 262 int i, ki; 263 264 #ifdef DEBUG 265 __CTRACE(__CTRACE_MISC, 266 "Adding character %s of type %d, symbol 0x%x\n", 267 unctrl(chr), key_type, symbol); 268 #endif 269 if (current->mapping[(unsigned char) chr] < 0) { 270 if (current->mapping[(unsigned char) chr] == MAPPING_UNUSED) { 271 /* first time for this char */ 272 current->mapping[(unsigned char) chr] = 273 current->count; /* map new entry */ 274 ki = current->count; 275 276 /* make sure we have room in the key array first */ 277 if ((current->count & (KEYMAP_ALLOC_CHUNK - 1)) == 0) 278 { 279 if ((current->key = 280 realloc(current->key, 281 ki * sizeof(key_entry_t *) 282 + KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t *))) == NULL) { 283 fprintf(stderr, 284 "Could not malloc for key entry\n"); 285 exit(1); 286 } 287 288 the_key = new_key(); 289 for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) { 290 current->key[ki + i] = &the_key[i]; 291 } 292 } 293 } else { 294 /* the mapping was used but freed, reuse it */ 295 ki = - current->mapping[(unsigned char) chr]; 296 current->mapping[(unsigned char) chr] = ki; 297 } 298 299 current->count++; 300 301 /* point at the current key array element to use */ 302 the_key = current->key[ki]; 303 304 the_key->type = key_type; 305 306 switch (key_type) { 307 case KEYMAP_MULTI: 308 /* need for next key */ 309 #ifdef DEBUG 310 __CTRACE(__CTRACE_MISC, "Creating new keymap\n"); 311 #endif 312 the_key->value.next = new_keymap(); 313 the_key->enable = TRUE; 314 break; 315 316 case KEYMAP_LEAF: 317 /* the associated symbol for the key */ 318 #ifdef DEBUG 319 __CTRACE(__CTRACE_MISC, "Adding leaf key\n"); 320 #endif 321 the_key->value.symbol = symbol; 322 the_key->enable = TRUE; 323 break; 324 325 default: 326 fprintf(stderr, "add_new_key: bad type passed\n"); 327 exit(1); 328 } 329 } else { 330 /* the key is already known - just return the address. */ 331 #ifdef DEBUG 332 __CTRACE(__CTRACE_MISC, "Keymap already known\n"); 333 #endif 334 the_key = current->key[current->mapping[(unsigned char) chr]]; 335 } 336 337 return the_key; 338 } 339 340 /* 341 * Delete the given key symbol from the key mappings for the screen. 342 * 343 */ 344 void 345 delete_key_sequence(keymap_t *current, int key_type) 346 { 347 key_entry_t *key; 348 int i; 349 350 /* 351 * we need to iterate over all the keys as there may be 352 * multiple instances of the leaf symbol. 353 */ 354 for (i = 0; i < MAX_CHAR; i++) { 355 if (current->mapping[i] < 0) 356 continue; /* no mapping for the key, next! */ 357 358 key = current->key[current->mapping[i]]; 359 360 if (key->type == KEYMAP_MULTI) { 361 /* have not found the leaf, recurse down */ 362 delete_key_sequence(key->value.next, key_type); 363 /* if we deleted the last key in the map, free */ 364 if (key->value.next->count == 0) 365 _cursesi_free_keymap(key->value.next); 366 } else if ((key->type == KEYMAP_LEAF) 367 && (key->value.symbol == key_type)) { 368 /* 369 * delete the mapping by negating the current 370 * index - this "holds" the position in the 371 * allocation just in case we later re-add 372 * the key for that mapping. 373 */ 374 current->mapping[i] = - current->mapping[i]; 375 current->count--; 376 } 377 } 378 } 379 380 /* 381 * Add the sequence of characters given in sequence as the key mapping 382 * for the given key symbol. 383 */ 384 void 385 add_key_sequence(SCREEN *screen, char *sequence, int key_type) 386 { 387 key_entry_t *tmp_key; 388 keymap_t *current; 389 int length, j, key_ent; 390 391 #ifdef DEBUG 392 __CTRACE(__CTRACE_MISC, "add_key_sequence: add key sequence: %s(%s)\n", 393 sequence, keyname(key_type)); 394 #endif /* DEBUG */ 395 current = screen->base_keymap; /* always start with 396 * base keymap. */ 397 length = (int) strlen(sequence); 398 399 /* 400 * OK - we really should never get a zero length string here, either 401 * the termcap entry is there and it has a value or we are not called 402 * at all. Unfortunately, if someone assigns a termcap string to the 403 * ^@ value we get passed a null string which messes up our length. 404 * So, if we get a null string then just insert a leaf value in 405 * the 0th char position of the root keymap. Note that we are 406 * totally screwed if someone terminates a multichar sequence 407 * with ^@... oh well. 408 */ 409 if (length == 0) 410 length = 1; 411 412 for (j = 0; j < length - 1; j++) { 413 /* add the entry to the struct */ 414 tmp_key = add_new_key(current, sequence[j], KEYMAP_MULTI, 0); 415 416 /* index into the key array - it's 417 clearer if we stash this */ 418 key_ent = current->mapping[(unsigned char) sequence[j]]; 419 420 current->key[key_ent] = tmp_key; 421 422 /* next key uses this map... */ 423 current = current->key[key_ent]->value.next; 424 } 425 426 /* 427 * This is the last key in the sequence (it may have been the 428 * only one but that does not matter) this means it is a leaf 429 * key and should have a symbol associated with it. 430 */ 431 tmp_key = add_new_key(current, sequence[length - 1], KEYMAP_LEAF, 432 key_type); 433 current->key[current->mapping[(int)sequence[length - 1]]] = tmp_key; 434 } 435 436 /* 437 * Init_getch - initialise all the pointers & structures needed to make 438 * getch work in keypad mode. 439 * 440 */ 441 void 442 __init_getch(SCREEN *screen) 443 { 444 char entry[1024], *p; 445 const char *s; 446 int i; 447 size_t limit, l; 448 #ifdef DEBUG 449 int k, length; 450 #endif 451 452 /* init the inkey state variable */ 453 state = INKEY_NORM; 454 455 /* init the base keymap */ 456 screen->base_keymap = new_keymap(); 457 458 /* key input buffer pointers */ 459 start = end = working = 0; 460 461 /* now do the terminfo snarfing ... */ 462 463 for (i = 0; i < num_tcs; i++) { 464 p = entry; 465 limit = 1023; 466 s = screen->term->strs[tc[i].code]; 467 if (s == NULL) 468 continue; 469 l = strlen(s) + 1; 470 if (limit < l) 471 continue; 472 strlcpy(p, s, limit); 473 p += l; 474 limit -= l; 475 #ifdef DEBUG 476 __CTRACE(__CTRACE_INIT, 477 "Processing termcap entry %d, sequence ", 478 tc[i].code); 479 length = (int) strlen(entry); 480 for (k = 0; k <= length -1; k++) 481 __CTRACE(__CTRACE_INIT, "%s", unctrl(entry[k])); 482 __CTRACE(__CTRACE_INIT, "\n"); 483 #endif 484 add_key_sequence(screen, entry, tc[i].symbol); 485 } 486 } 487 488 489 /* 490 * new_keymap - allocates & initialises a new keymap structure. This 491 * function returns a pointer to the new keymap. 492 * 493 */ 494 static keymap_t * 495 new_keymap(void) 496 { 497 int i; 498 keymap_t *new_map; 499 500 if ((new_map = malloc(sizeof(keymap_t))) == NULL) { 501 perror("Inkey: Cannot allocate new keymap"); 502 exit(2); 503 } 504 505 /* Initialise the new map */ 506 new_map->count = 0; 507 for (i = 0; i < MAX_CHAR; i++) { 508 new_map->mapping[i] = MAPPING_UNUSED; /* no mapping for char */ 509 } 510 511 /* key array will be allocated when first key is added */ 512 new_map->key = NULL; 513 514 return new_map; 515 } 516 517 /* 518 * new_key - allocates & initialises a new key entry. This function returns 519 * a pointer to the newly allocated key entry. 520 * 521 */ 522 static key_entry_t * 523 new_key(void) 524 { 525 key_entry_t *new_one; 526 int i; 527 528 if ((new_one = malloc(KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t))) 529 == NULL) { 530 perror("inkey: Cannot allocate new key entry chunk"); 531 exit(2); 532 } 533 534 for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) { 535 new_one[i].type = 0; 536 new_one[i].value.next = NULL; 537 } 538 539 return new_one; 540 } 541 542 /* 543 * inkey - do the work to process keyboard input, check for multi-key 544 * sequences and return the appropriate symbol if we get a match. 545 * 546 */ 547 548 wchar_t 549 inkey(int to, int delay) 550 { 551 wchar_t k; 552 int c, mapping; 553 keymap_t *current = _cursesi_screen->base_keymap; 554 FILE *infd = _cursesi_screen->infd; 555 556 k = 0; /* XXX gcc -Wuninitialized */ 557 558 #ifdef DEBUG 559 __CTRACE(__CTRACE_INPUT, "inkey (%d, %d)\n", to, delay); 560 #endif 561 for (;;) { /* loop until we get a complete key sequence */ 562 reread: 563 if (state == INKEY_NORM) { 564 if (delay && __timeout(delay) == ERR) 565 return ERR; 566 c = fgetc(infd); 567 if (c == EOF) { 568 clearerr(infd); 569 return ERR; 570 } 571 572 if (delay && (__notimeout() == ERR)) 573 return ERR; 574 575 k = (wchar_t) c; 576 #ifdef DEBUG 577 __CTRACE(__CTRACE_INPUT, 578 "inkey (state normal) got '%s'\n", unctrl(k)); 579 #endif 580 581 working = start; 582 inbuf[working] = k; 583 INC_POINTER(working); 584 end = working; 585 state = INKEY_ASSEMBLING; /* go to the assembling 586 * state now */ 587 } else if (state == INKEY_BACKOUT) { 588 k = inbuf[working]; 589 INC_POINTER(working); 590 if (working == end) { /* see if we have run 591 * out of keys in the 592 * backlog */ 593 594 /* if we have then switch to assembling */ 595 state = INKEY_ASSEMBLING; 596 } 597 } else if (state == INKEY_ASSEMBLING) { 598 /* assembling a key sequence */ 599 if (delay) { 600 if (__timeout(to ? (ESCDELAY / 100) : delay) 601 == ERR) 602 return ERR; 603 } else { 604 if (to && (__timeout(ESCDELAY / 100) == ERR)) 605 return ERR; 606 } 607 608 c = fgetc(infd); 609 if (ferror(infd)) { 610 clearerr(infd); 611 return ERR; 612 } 613 614 if ((to || delay) && (__notimeout() == ERR)) 615 return ERR; 616 617 #ifdef DEBUG 618 __CTRACE(__CTRACE_INPUT, 619 "inkey (state assembling) got '%s'\n", unctrl(k)); 620 #endif 621 if (feof(infd) || c == -1) { /* inter-char timeout, 622 * start backing out */ 623 clearerr(infd); 624 if (start == end) 625 /* no chars in the buffer, restart */ 626 goto reread; 627 628 k = inbuf[start]; 629 state = INKEY_TIMEOUT; 630 } else { 631 k = (wchar_t) c; 632 inbuf[working] = k; 633 INC_POINTER(working); 634 end = working; 635 } 636 } else { 637 fprintf(stderr, "Inkey state screwed - exiting!!!"); 638 exit(2); 639 } 640 641 /* 642 * Check key has no special meaning and we have not 643 * timed out and the key has not been disabled 644 */ 645 mapping = current->mapping[k]; 646 if (((state == INKEY_TIMEOUT) || (mapping < 0)) 647 || ((current->key[mapping]->type == KEYMAP_LEAF) 648 && (current->key[mapping]->enable == FALSE))) { 649 /* return the first key we know about */ 650 k = inbuf[start]; 651 652 INC_POINTER(start); 653 working = start; 654 655 if (start == end) { /* only one char processed */ 656 state = INKEY_NORM; 657 } else {/* otherwise we must have more than one char 658 * to backout */ 659 state = INKEY_BACKOUT; 660 } 661 return k; 662 } else { /* must be part of a multikey sequence */ 663 /* check for completed key sequence */ 664 if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) { 665 start = working; /* eat the key sequence 666 * in inbuf */ 667 668 /* check if inbuf empty now */ 669 if (start == end) { 670 /* if it is go back to normal */ 671 state = INKEY_NORM; 672 } else { 673 /* otherwise go to backout state */ 674 state = INKEY_BACKOUT; 675 } 676 677 /* return the symbol */ 678 return current->key[current->mapping[k]]->value.symbol; 679 680 } else { 681 /* 682 * Step on to next part of the multi-key 683 * sequence. 684 */ 685 current = current->key[current->mapping[k]]->value.next; 686 } 687 } 688 } 689 } 690 691 #ifndef _CURSES_USE_MACROS 692 /* 693 * getch -- 694 * Read in a character from stdscr. 695 */ 696 int 697 getch(void) 698 { 699 return wgetch(stdscr); 700 } 701 702 /* 703 * mvgetch -- 704 * Read in a character from stdscr at the given location. 705 */ 706 int 707 mvgetch(int y, int x) 708 { 709 return mvwgetch(stdscr, y, x); 710 } 711 712 /* 713 * mvwgetch -- 714 * Read in a character from stdscr at the given location in the 715 * given window. 716 */ 717 int 718 mvwgetch(WINDOW *win, int y, int x) 719 { 720 if (wmove(win, y, x) == ERR) 721 return ERR; 722 723 return wgetch(win); 724 } 725 726 #endif 727 728 /* 729 * keyok -- 730 * Set the enable flag for a keysym, if the flag is false then 731 * getch will not return this keysym even if the matching key sequence 732 * is seen. 733 */ 734 int 735 keyok(int key_type, bool flag) 736 { 737 int result = ERR; 738 739 do_keyok(_cursesi_screen->base_keymap, key_type, flag, &result); 740 return result; 741 } 742 743 /* 744 * do_keyok -- 745 * Does the actual work for keyok, we need to recurse through the 746 * keymaps finding the passed key symbol. 747 */ 748 void 749 do_keyok(keymap_t *current, int key_type, bool flag, int *retval) 750 { 751 key_entry_t *key; 752 int i; 753 754 /* 755 * we need to iterate over all the keys as there may be 756 * multiple instances of the leaf symbol. 757 */ 758 for (i = 0; i < MAX_CHAR; i++) { 759 if (current->mapping[i] < 0) 760 continue; /* no mapping for the key, next! */ 761 762 key = current->key[current->mapping[i]]; 763 764 if (key->type == KEYMAP_MULTI) 765 do_keyok(key->value.next, key_type, flag, retval); 766 else if ((key->type == KEYMAP_LEAF) 767 && (key->value.symbol == key_type)) { 768 key->enable = flag; 769 *retval = OK; /* we found at least one instance, ok */ 770 } 771 } 772 } 773 774 /* 775 * define_key -- 776 * Add a custom mapping of a key sequence to key symbol. 777 * 778 */ 779 int 780 define_key(char *sequence, int symbol) 781 { 782 783 if (symbol <= 0) 784 return ERR; 785 786 if (sequence == NULL) 787 delete_key_sequence(_cursesi_screen->base_keymap, symbol); 788 else 789 add_key_sequence(_cursesi_screen, sequence, symbol); 790 791 return OK; 792 } 793 794 /* 795 * wgetch -- 796 * Read in a character from the window. 797 */ 798 int 799 wgetch(WINDOW *win) 800 { 801 int inp, weset; 802 int c; 803 FILE *infd = _cursesi_screen->infd; 804 805 #ifdef DEBUG 806 __CTRACE(__CTRACE_INPUT, "wgetch: win(%p)\n", win); 807 #endif 808 if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN) 809 && win->curx == win->maxx - 1 && win->cury == win->maxy - 1 810 && __echoit) 811 return (ERR); 812 813 if (is_wintouched(win)) 814 wrefresh(win); 815 #ifdef DEBUG 816 __CTRACE(__CTRACE_INPUT, "wgetch: __echoit = %d, " 817 "__rawmode = %d, __nl = %d, flags = %#.4x, delay = %d\n", 818 __echoit, __rawmode, _cursesi_screen->nl, win->flags, win->delay); 819 #endif 820 if (_cursesi_screen->resized) { 821 _cursesi_screen->resized = 0; 822 #ifdef DEBUG 823 __CTRACE(__CTRACE_INPUT, "wgetch returning KEY_RESIZE\n"); 824 #endif 825 return KEY_RESIZE; 826 } 827 if (_cursesi_screen->unget_pos) { 828 #ifdef DEBUG 829 __CTRACE(__CTRACE_INPUT, "wgetch returning char at %d\n", 830 _cursesi_screen->unget_pos); 831 #endif 832 _cursesi_screen->unget_pos--; 833 c = _cursesi_screen->unget_list[_cursesi_screen->unget_pos]; 834 if (__echoit) 835 waddch(win, (chtype) c); 836 return c; 837 } 838 if (__echoit && !__rawmode) { 839 cbreak(); 840 weset = 1; 841 } else 842 weset = 0; 843 844 __save_termios(); 845 846 if (win->flags & __KEYPAD) { 847 switch (win->delay) 848 { 849 case -1: 850 inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0); 851 break; 852 case 0: 853 if (__nodelay() == ERR) 854 return ERR; 855 inp = inkey(0, 0); 856 break; 857 default: 858 inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay); 859 break; 860 } 861 } else { 862 switch (win->delay) 863 { 864 case -1: 865 if (__delay() == ERR) 866 return ERR; 867 break; 868 case 0: 869 if (__nodelay() == ERR) 870 return ERR; 871 break; 872 default: 873 if (__timeout(win->delay) == ERR) 874 return ERR; 875 break; 876 } 877 878 c = fgetc(infd); 879 if (feof(infd)) { 880 clearerr(infd); 881 __restore_termios(); 882 return ERR; /* we have timed out */ 883 } 884 885 if (ferror(infd)) { 886 clearerr(infd); 887 inp = ERR; 888 } else { 889 inp = c; 890 } 891 } 892 #ifdef DEBUG 893 if (inp > 255) 894 /* we have a key symbol - treat it differently */ 895 /* XXXX perhaps __unctrl should be expanded to include 896 * XXXX the keysyms in the table.... 897 */ 898 __CTRACE(__CTRACE_INPUT, "wgetch assembled keysym 0x%x\n", inp); 899 else 900 __CTRACE(__CTRACE_INPUT, "wgetch got '%s'\n", unctrl(inp)); 901 #endif 902 if (win->delay > -1) { 903 if (__delay() == ERR) 904 return ERR; 905 } 906 907 __restore_termios(); 908 909 if ((__echoit) && (inp < KEY_MIN)) 910 waddch(win, (chtype) inp); 911 912 if (weset) 913 nocbreak(); 914 915 if (_cursesi_screen->nl && inp == 13) 916 inp = 10; 917 918 return ((inp < 0) || (inp == ERR) ? ERR : inp); 919 } 920 921 /* 922 * ungetch -- 923 * Put the character back into the input queue. 924 */ 925 int 926 ungetch(int c) 927 { 928 return __unget((wint_t) c); 929 } 930 931 /* 932 * __unget -- 933 * Do the work for ungetch() and unget_wch(); 934 */ 935 int 936 __unget(wint_t c) 937 { 938 wchar_t *p; 939 int len; 940 941 #ifdef DEBUG 942 __CTRACE(__CTRACE_INPUT, "__unget(%x)\n", c); 943 #endif 944 if (_cursesi_screen->unget_pos >= _cursesi_screen->unget_len) { 945 len = _cursesi_screen->unget_len + 32; 946 if ((p = realloc(_cursesi_screen->unget_list, 947 sizeof(wchar_t) * len)) == NULL) { 948 /* Can't realloc(), so just lose the oldest entry */ 949 memmove(_cursesi_screen->unget_list, 950 _cursesi_screen->unget_list + sizeof(wchar_t), 951 _cursesi_screen->unget_len - 1); 952 _cursesi_screen->unget_list[_cursesi_screen->unget_len 953 - 1] = c; 954 _cursesi_screen->unget_pos = 955 _cursesi_screen->unget_len; 956 return OK; 957 } else { 958 _cursesi_screen->unget_pos = 959 _cursesi_screen->unget_len; 960 _cursesi_screen->unget_len = len; 961 _cursesi_screen->unget_list = p; 962 } 963 } 964 _cursesi_screen->unget_list[_cursesi_screen->unget_pos] = c; 965 _cursesi_screen->unget_pos++; 966 return OK; 967 } 968