1 /* $NetBSD: getch.c,v 1.59 2012/04/21 12:27:28 roy 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.59 2012/04/21 12:27:28 roy 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 #ifdef DEBUG 369 __CTRACE(__CTRACE_INPUT, "delete_key_sequence: found keysym %d, deleting\n", 370 key_type); 371 #endif 372 key->enable = FALSE; 373 } 374 } 375 } 376 377 /* 378 * Add the sequence of characters given in sequence as the key mapping 379 * for the given key symbol. 380 */ 381 void 382 add_key_sequence(SCREEN *screen, char *sequence, int key_type) 383 { 384 key_entry_t *tmp_key; 385 keymap_t *current; 386 int length, j, key_ent; 387 388 #ifdef DEBUG 389 __CTRACE(__CTRACE_MISC, "add_key_sequence: add key sequence: %s(%s)\n", 390 sequence, keyname(key_type)); 391 #endif /* DEBUG */ 392 current = screen->base_keymap; /* always start with 393 * base keymap. */ 394 length = (int) strlen(sequence); 395 396 /* 397 * OK - we really should never get a zero length string here, either 398 * the terminfo entry is there and it has a value or we are not called 399 * at all. Unfortunately, if someone assigns a terminfo string to the 400 * ^@ value we get passed a null string which messes up our length. 401 * So, if we get a null string then just insert a leaf value in 402 * the 0th char position of the root keymap. Note that we are 403 * totally screwed if someone terminates a multichar sequence 404 * with ^@... oh well. 405 */ 406 if (length == 0) 407 length = 1; 408 409 for (j = 0; j < length - 1; j++) { 410 /* add the entry to the struct */ 411 tmp_key = add_new_key(current, sequence[j], KEYMAP_MULTI, 0); 412 413 /* index into the key array - it's 414 clearer if we stash this */ 415 key_ent = current->mapping[(unsigned char) sequence[j]]; 416 417 current->key[key_ent] = tmp_key; 418 419 /* next key uses this map... */ 420 current = current->key[key_ent]->value.next; 421 } 422 423 /* 424 * This is the last key in the sequence (it may have been the 425 * only one but that does not matter) this means it is a leaf 426 * key and should have a symbol associated with it. 427 */ 428 tmp_key = add_new_key(current, sequence[length - 1], KEYMAP_LEAF, 429 key_type); 430 current->key[current->mapping[(int)sequence[length - 1]]] = tmp_key; 431 } 432 433 /* 434 * Init_getch - initialise all the pointers & structures needed to make 435 * getch work in keypad mode. 436 * 437 */ 438 void 439 __init_getch(SCREEN *screen) 440 { 441 char entry[1024], *p; 442 const char *s; 443 int i; 444 size_t limit, l; 445 #ifdef DEBUG 446 int k, length; 447 #endif 448 449 /* init the inkey state variable */ 450 state = INKEY_NORM; 451 452 /* init the base keymap */ 453 screen->base_keymap = new_keymap(); 454 455 /* key input buffer pointers */ 456 start = end = working = 0; 457 458 /* now do the terminfo snarfing ... */ 459 460 for (i = 0; i < num_tcs; i++) { 461 p = entry; 462 limit = 1023; 463 s = screen->term->strs[tc[i].code]; 464 if (s == NULL) 465 continue; 466 l = strlen(s) + 1; 467 if (limit < l) 468 continue; 469 strlcpy(p, s, limit); 470 p += l; 471 limit -= l; 472 #ifdef DEBUG 473 __CTRACE(__CTRACE_INIT, 474 "Processing terminfo entry %d, sequence ", 475 tc[i].code); 476 length = (int) strlen(entry); 477 for (k = 0; k <= length -1; k++) 478 __CTRACE(__CTRACE_INIT, "%s", unctrl(entry[k])); 479 __CTRACE(__CTRACE_INIT, "\n"); 480 #endif 481 add_key_sequence(screen, entry, tc[i].symbol); 482 } 483 } 484 485 486 /* 487 * new_keymap - allocates & initialises a new keymap structure. This 488 * function returns a pointer to the new keymap. 489 * 490 */ 491 static keymap_t * 492 new_keymap(void) 493 { 494 int i; 495 keymap_t *new_map; 496 497 if ((new_map = malloc(sizeof(keymap_t))) == NULL) { 498 perror("Inkey: Cannot allocate new keymap"); 499 exit(2); 500 } 501 502 /* Initialise the new map */ 503 new_map->count = 0; 504 for (i = 0; i < MAX_CHAR; i++) { 505 new_map->mapping[i] = MAPPING_UNUSED; /* no mapping for char */ 506 } 507 508 /* key array will be allocated when first key is added */ 509 new_map->key = NULL; 510 511 return new_map; 512 } 513 514 /* 515 * new_key - allocates & initialises a new key entry. This function returns 516 * a pointer to the newly allocated key entry. 517 * 518 */ 519 static key_entry_t * 520 new_key(void) 521 { 522 key_entry_t *new_one; 523 int i; 524 525 if ((new_one = malloc(KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t))) 526 == NULL) { 527 perror("inkey: Cannot allocate new key entry chunk"); 528 exit(2); 529 } 530 531 for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) { 532 new_one[i].type = 0; 533 new_one[i].value.next = NULL; 534 } 535 536 return new_one; 537 } 538 539 /* 540 * inkey - do the work to process keyboard input, check for multi-key 541 * sequences and return the appropriate symbol if we get a match. 542 * 543 */ 544 545 wchar_t 546 inkey(int to, int delay) 547 { 548 wchar_t k; 549 int c, mapping; 550 keymap_t *current = _cursesi_screen->base_keymap; 551 FILE *infd = _cursesi_screen->infd; 552 553 k = 0; /* XXX gcc -Wuninitialized */ 554 555 #ifdef DEBUG 556 __CTRACE(__CTRACE_INPUT, "inkey (%d, %d)\n", to, delay); 557 #endif 558 for (;;) { /* loop until we get a complete key sequence */ 559 reread: 560 if (state == INKEY_NORM) { 561 if (delay && __timeout(delay) == ERR) 562 return ERR; 563 c = fgetc(infd); 564 if (c == EOF) { 565 clearerr(infd); 566 return ERR; 567 } 568 569 if (delay && (__notimeout() == ERR)) 570 return ERR; 571 572 k = (wchar_t) c; 573 #ifdef DEBUG 574 __CTRACE(__CTRACE_INPUT, 575 "inkey (state normal) got '%s'\n", unctrl(k)); 576 #endif 577 578 working = start; 579 inbuf[working] = k; 580 INC_POINTER(working); 581 end = working; 582 state = INKEY_ASSEMBLING; /* go to the assembling 583 * state now */ 584 } else if (state == INKEY_BACKOUT) { 585 k = inbuf[working]; 586 INC_POINTER(working); 587 if (working == end) { /* see if we have run 588 * out of keys in the 589 * backlog */ 590 591 /* if we have then switch to assembling */ 592 state = INKEY_ASSEMBLING; 593 } 594 } else if (state == INKEY_ASSEMBLING) { 595 /* assembling a key sequence */ 596 if (delay) { 597 if (__timeout(to ? (ESCDELAY / 100) : delay) 598 == ERR) 599 return ERR; 600 } else { 601 if (to && (__timeout(ESCDELAY / 100) == ERR)) 602 return ERR; 603 } 604 605 c = fgetc(infd); 606 if (ferror(infd)) { 607 clearerr(infd); 608 return ERR; 609 } 610 611 if ((to || delay) && (__notimeout() == ERR)) 612 return ERR; 613 614 #ifdef DEBUG 615 __CTRACE(__CTRACE_INPUT, 616 "inkey (state assembling) got '%s'\n", unctrl(k)); 617 #endif 618 if (feof(infd) || c == -1) { /* inter-char timeout, 619 * start backing out */ 620 clearerr(infd); 621 if (start == end) 622 /* no chars in the buffer, restart */ 623 goto reread; 624 625 k = inbuf[start]; 626 state = INKEY_TIMEOUT; 627 } else { 628 k = (wchar_t) c; 629 inbuf[working] = k; 630 INC_POINTER(working); 631 end = working; 632 } 633 } else { 634 fprintf(stderr, "Inkey state screwed - exiting!!!"); 635 exit(2); 636 } 637 638 /* 639 * Check key has no special meaning and we have not 640 * timed out and the key has not been disabled 641 */ 642 mapping = current->mapping[k]; 643 if (((state == INKEY_TIMEOUT) || (mapping < 0)) 644 || ((current->key[mapping]->type == KEYMAP_LEAF) 645 && (current->key[mapping]->enable == FALSE))) { 646 /* return the first key we know about */ 647 k = inbuf[start]; 648 649 INC_POINTER(start); 650 working = start; 651 652 if (start == end) { /* only one char processed */ 653 state = INKEY_NORM; 654 } else {/* otherwise we must have more than one char 655 * to backout */ 656 state = INKEY_BACKOUT; 657 } 658 return k; 659 } else { /* must be part of a multikey sequence */ 660 /* check for completed key sequence */ 661 if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) { 662 start = working; /* eat the key sequence 663 * in inbuf */ 664 665 /* check if inbuf empty now */ 666 if (start == end) { 667 /* if it is go back to normal */ 668 state = INKEY_NORM; 669 } else { 670 /* otherwise go to backout state */ 671 state = INKEY_BACKOUT; 672 } 673 674 /* return the symbol */ 675 return current->key[current->mapping[k]]->value.symbol; 676 677 } else { 678 /* 679 * Step on to next part of the multi-key 680 * sequence. 681 */ 682 current = current->key[current->mapping[k]]->value.next; 683 } 684 } 685 } 686 } 687 688 #ifndef _CURSES_USE_MACROS 689 /* 690 * getch -- 691 * Read in a character from stdscr. 692 */ 693 int 694 getch(void) 695 { 696 return wgetch(stdscr); 697 } 698 699 /* 700 * mvgetch -- 701 * Read in a character from stdscr at the given location. 702 */ 703 int 704 mvgetch(int y, int x) 705 { 706 return mvwgetch(stdscr, y, x); 707 } 708 709 /* 710 * mvwgetch -- 711 * Read in a character from stdscr at the given location in the 712 * given window. 713 */ 714 int 715 mvwgetch(WINDOW *win, int y, int x) 716 { 717 if (wmove(win, y, x) == ERR) 718 return ERR; 719 720 return wgetch(win); 721 } 722 723 #endif 724 725 /* 726 * keyok -- 727 * Set the enable flag for a keysym, if the flag is false then 728 * getch will not return this keysym even if the matching key sequence 729 * is seen. 730 */ 731 int 732 keyok(int key_type, bool flag) 733 { 734 int result = ERR; 735 736 do_keyok(_cursesi_screen->base_keymap, key_type, flag, &result); 737 return result; 738 } 739 740 /* 741 * do_keyok -- 742 * Does the actual work for keyok, we need to recurse through the 743 * keymaps finding the passed key symbol. 744 */ 745 void 746 do_keyok(keymap_t *current, int key_type, bool flag, int *retval) 747 { 748 key_entry_t *key; 749 int i; 750 751 /* 752 * we need to iterate over all the keys as there may be 753 * multiple instances of the leaf symbol. 754 */ 755 for (i = 0; i < MAX_CHAR; i++) { 756 if (current->mapping[i] < 0) 757 continue; /* no mapping for the key, next! */ 758 759 key = current->key[current->mapping[i]]; 760 761 if (key->type == KEYMAP_MULTI) 762 do_keyok(key->value.next, key_type, flag, retval); 763 else if ((key->type == KEYMAP_LEAF) 764 && (key->value.symbol == key_type)) { 765 key->enable = flag; 766 *retval = OK; /* we found at least one instance, ok */ 767 } 768 } 769 } 770 771 /* 772 * define_key -- 773 * Add a custom mapping of a key sequence to key symbol. 774 * 775 */ 776 int 777 define_key(char *sequence, int symbol) 778 { 779 780 if (symbol <= 0) 781 return ERR; 782 783 if (sequence == NULL) { 784 #ifdef DEBUG 785 __CTRACE(__CTRACE_INPUT, "define_key: deleting keysym %d\n", 786 symbol); 787 #endif 788 delete_key_sequence(_cursesi_screen->base_keymap, symbol); 789 } else 790 add_key_sequence(_cursesi_screen, sequence, symbol); 791 792 return OK; 793 } 794 795 /* 796 * wgetch -- 797 * Read in a character from the window. 798 */ 799 int 800 wgetch(WINDOW *win) 801 { 802 int inp, weset; 803 int c; 804 FILE *infd = _cursesi_screen->infd; 805 806 #ifdef DEBUG 807 __CTRACE(__CTRACE_INPUT, "wgetch: win(%p)\n", win); 808 #endif 809 if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN) 810 && win->curx == win->maxx - 1 && win->cury == win->maxy - 1 811 && __echoit) 812 return (ERR); 813 814 if (is_wintouched(win)) 815 wrefresh(win); 816 #ifdef DEBUG 817 __CTRACE(__CTRACE_INPUT, "wgetch: __echoit = %d, " 818 "__rawmode = %d, __nl = %d, flags = %#.4x, delay = %d\n", 819 __echoit, __rawmode, _cursesi_screen->nl, win->flags, win->delay); 820 #endif 821 if (_cursesi_screen->resized) { 822 _cursesi_screen->resized = 0; 823 #ifdef DEBUG 824 __CTRACE(__CTRACE_INPUT, "wgetch returning KEY_RESIZE\n"); 825 #endif 826 return KEY_RESIZE; 827 } 828 if (_cursesi_screen->unget_pos) { 829 #ifdef DEBUG 830 __CTRACE(__CTRACE_INPUT, "wgetch returning char at %d\n", 831 _cursesi_screen->unget_pos); 832 #endif 833 _cursesi_screen->unget_pos--; 834 c = _cursesi_screen->unget_list[_cursesi_screen->unget_pos]; 835 if (__echoit) 836 waddch(win, (chtype) c); 837 return c; 838 } 839 if (__echoit && !__rawmode) { 840 cbreak(); 841 weset = 1; 842 } else 843 weset = 0; 844 845 __save_termios(); 846 847 if (win->flags & __KEYPAD) { 848 switch (win->delay) 849 { 850 case -1: 851 inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0); 852 break; 853 case 0: 854 if (__nodelay() == ERR) 855 return ERR; 856 inp = inkey(0, 0); 857 break; 858 default: 859 inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay); 860 break; 861 } 862 } else { 863 switch (win->delay) 864 { 865 case -1: 866 if (__delay() == ERR) 867 return ERR; 868 break; 869 case 0: 870 if (__nodelay() == ERR) 871 return ERR; 872 break; 873 default: 874 if (__timeout(win->delay) == ERR) 875 return ERR; 876 break; 877 } 878 879 c = fgetc(infd); 880 if (feof(infd)) { 881 clearerr(infd); 882 __restore_termios(); 883 return ERR; /* we have timed out */ 884 } 885 886 if (ferror(infd)) { 887 clearerr(infd); 888 inp = ERR; 889 } else { 890 inp = c; 891 } 892 } 893 #ifdef DEBUG 894 if (inp > 255) 895 /* we have a key symbol - treat it differently */ 896 /* XXXX perhaps __unctrl should be expanded to include 897 * XXXX the keysyms in the table.... 898 */ 899 __CTRACE(__CTRACE_INPUT, "wgetch assembled keysym 0x%x\n", inp); 900 else 901 __CTRACE(__CTRACE_INPUT, "wgetch got '%s'\n", unctrl(inp)); 902 #endif 903 if (win->delay > -1) { 904 if (__delay() == ERR) 905 return ERR; 906 } 907 908 __restore_termios(); 909 910 if ((__echoit) && (inp < KEY_MIN)) 911 waddch(win, (chtype) inp); 912 913 if (weset) 914 nocbreak(); 915 916 if (_cursesi_screen->nl && inp == 13) 917 inp = 10; 918 919 return ((inp < 0) || (inp == ERR) ? ERR : inp); 920 } 921 922 /* 923 * ungetch -- 924 * Put the character back into the input queue. 925 */ 926 int 927 ungetch(int c) 928 { 929 return __unget((wint_t) c); 930 } 931 932 /* 933 * __unget -- 934 * Do the work for ungetch() and unget_wch(); 935 */ 936 int 937 __unget(wint_t c) 938 { 939 wchar_t *p; 940 int len; 941 942 #ifdef DEBUG 943 __CTRACE(__CTRACE_INPUT, "__unget(%x)\n", c); 944 #endif 945 if (_cursesi_screen->unget_pos >= _cursesi_screen->unget_len) { 946 len = _cursesi_screen->unget_len + 32; 947 if ((p = realloc(_cursesi_screen->unget_list, 948 sizeof(wchar_t) * len)) == NULL) { 949 /* Can't realloc(), so just lose the oldest entry */ 950 memmove(_cursesi_screen->unget_list, 951 _cursesi_screen->unget_list + sizeof(wchar_t), 952 _cursesi_screen->unget_len - 1); 953 _cursesi_screen->unget_list[_cursesi_screen->unget_len 954 - 1] = c; 955 _cursesi_screen->unget_pos = 956 _cursesi_screen->unget_len; 957 return OK; 958 } else { 959 _cursesi_screen->unget_pos = 960 _cursesi_screen->unget_len; 961 _cursesi_screen->unget_len = len; 962 _cursesi_screen->unget_list = p; 963 } 964 } 965 _cursesi_screen->unget_list[_cursesi_screen->unget_pos] = c; 966 _cursesi_screen->unget_pos++; 967 return OK; 968 } 969