getch.c revision 1.65
1/* $NetBSD: getch.c,v 1.65 2017/01/31 09:17:53 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 35static char sccsid[] = "@(#)getch.c 8.2 (Berkeley) 5/4/94"; 36#else 37__RCSID("$NetBSD: getch.c,v 1.65 2017/01/31 09:17:53 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 49short state; /* state of the inkey function */ 50 51static 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 .... */ 204static const int num_tcs = (sizeof(tc) / sizeof(struct tcdata)); 205 206/* Key buffer */ 207#define INBUF_SZ 16 /* size of key buffer - must be larger than 208 * longest multi-key sequence */ 209static wchar_t inbuf[INBUF_SZ]; 210static int start, end, working; /* pointers for manipulating inbuf data */ 211 212/* prototypes for private functions */ 213static void add_key_sequence(SCREEN *screen, char *sequence, int key_type); 214static key_entry_t *add_new_key(keymap_t *current, char ch, int key_type, 215 int symbol); 216static void delete_key_sequence(keymap_t *current, int key_type); 217static void do_keyok(keymap_t *current, int key_type, bool set, bool flag, 218 int *retval); 219static keymap_t *new_keymap(void); /* create a new keymap */ 220static key_entry_t *new_key(void); /* create a new key entry */ 221static wchar_t inkey(int to, int delay); 222 223/* 224 * Free the storage associated with the given keymap 225 */ 226void 227_cursesi_free_keymap(keymap_t *map) 228{ 229 int i; 230 231 /* check for, and free, child keymaps */ 232 for (i = 0; i < MAX_CHAR; i++) { 233 if (map->mapping[i] >= 0) { 234 if (map->key[map->mapping[i]]->type == KEYMAP_MULTI) 235 _cursesi_free_keymap( 236 map->key[map->mapping[i]]->value.next); 237 } 238 } 239 240 /* now free any allocated keymap structs */ 241 for (i = 0; i < map->count; i += KEYMAP_ALLOC_CHUNK) { 242 free(map->key[i]); 243 } 244 245 free(map->key); 246 free(map); 247} 248 249 250/* 251 * Add a new key entry to the keymap pointed to by current. Entry 252 * contains the character to add to the keymap, type is the type of 253 * entry to add (either multikey or leaf) and symbol is the symbolic 254 * value for a leaf type entry. The function returns a pointer to the 255 * new keymap entry. 256 */ 257static key_entry_t * 258add_new_key(keymap_t *current, char chr, int key_type, int symbol) 259{ 260 key_entry_t *the_key; 261 int i, ki; 262 263#ifdef DEBUG 264 __CTRACE(__CTRACE_MISC, 265 "Adding character %s of type %d, symbol 0x%x\n", 266 unctrl(chr), key_type, symbol); 267#endif 268 if (current->mapping[(unsigned char)chr] < 0) { 269 if (current->mapping[(unsigned char)chr] == MAPPING_UNUSED) { 270 /* first time for this char */ 271 current->mapping[(unsigned char)chr] = 272 current->count; /* map new entry */ 273 ki = current->count; 274 275 /* make sure we have room in the key array first */ 276 if ((current->count & (KEYMAP_ALLOC_CHUNK - 1)) == 0) 277 { 278 if ((current->key = 279 realloc(current->key, 280 ki * sizeof(key_entry_t *) 281 + KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t *))) == NULL) { 282 fprintf(stderr, 283 "Could not malloc for key entry\n"); 284 exit(1); 285 } 286 287 the_key = new_key(); 288 for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) { 289 current->key[ki + i] = &the_key[i]; 290 } 291 } 292 } else { 293 /* the mapping was used but freed, reuse it */ 294 ki = - current->mapping[(unsigned char) chr]; 295 current->mapping[(unsigned char) chr] = ki; 296 } 297 298 current->count++; 299 300 /* point at the current key array element to use */ 301 the_key = current->key[ki]; 302 303 the_key->type = key_type; 304 305 switch (key_type) { 306 case KEYMAP_MULTI: 307 /* need for next key */ 308#ifdef DEBUG 309 __CTRACE(__CTRACE_MISC, "Creating new keymap\n"); 310#endif 311 the_key->value.next = new_keymap(); 312 the_key->enable = TRUE; 313 break; 314 315 case KEYMAP_LEAF: 316 /* the associated symbol for the key */ 317#ifdef DEBUG 318 __CTRACE(__CTRACE_MISC, "Adding leaf key\n"); 319#endif 320 the_key->value.symbol = symbol; 321 the_key->enable = TRUE; 322 break; 323 324 default: 325 fprintf(stderr, "add_new_key: bad type passed\n"); 326 exit(1); 327 } 328 } else { 329 /* the key is already known - just return the address. */ 330#ifdef DEBUG 331 __CTRACE(__CTRACE_MISC, "Keymap already known\n"); 332#endif 333 the_key = current->key[current->mapping[(unsigned char)chr]]; 334 } 335 336 return the_key; 337} 338 339/* 340 * Delete the given key symbol from the key mappings for the screen. 341 * 342 */ 343static void 344delete_key_sequence(keymap_t *current, int key_type) 345{ 346 key_entry_t *key; 347 int i; 348 349 /* 350 * we need to iterate over all the keys as there may be 351 * multiple instances of the leaf symbol. 352 */ 353 for (i = 0; i < MAX_CHAR; i++) { 354 if (current->mapping[i] < 0) 355 continue; /* no mapping for the key, next! */ 356 357 key = current->key[current->mapping[i]]; 358 359 if (key->type == KEYMAP_MULTI) { 360 /* have not found the leaf, recurse down */ 361 delete_key_sequence(key->value.next, key_type); 362 /* if we deleted the last key in the map, free */ 363 if (key->value.next->count == 0) 364 _cursesi_free_keymap(key->value.next); 365 } else if ((key->type == KEYMAP_LEAF) 366 && (key->value.symbol == key_type)) { 367#ifdef DEBUG 368 __CTRACE(__CTRACE_INPUT, "delete_key_sequence: found keysym %d, deleting\n", 369 key_type); 370#endif 371 key->enable = FALSE; 372 } 373 } 374} 375 376/* 377 * Add the sequence of characters given in sequence as the key mapping 378 * for the given key symbol. 379 */ 380static void 381add_key_sequence(SCREEN *screen, char *sequence, int key_type) 382{ 383 key_entry_t *tmp_key; 384 keymap_t *current; 385 int length, j, key_ent; 386 387#ifdef DEBUG 388 __CTRACE(__CTRACE_MISC, "add_key_sequence: add key sequence: %s(%s)\n", 389 sequence, keyname(key_type)); 390#endif /* DEBUG */ 391 current = screen->base_keymap; /* always start with 392 * base keymap. */ 393 length = (int)strlen(sequence); 394 395 /* 396 * OK - we really should never get a zero length string here, either 397 * the terminfo entry is there and it has a value or we are not called 398 * at all. Unfortunately, if someone assigns a terminfo string to the 399 * ^@ value we get passed a null string which messes up our length. 400 * So, if we get a null string then just insert a leaf value in 401 * the 0th char position of the root keymap. Note that we are 402 * totally screwed if someone terminates a multichar sequence 403 * with ^@... oh well. 404 */ 405 if (length == 0) 406 length = 1; 407 408 for (j = 0; j < length - 1; j++) { 409 /* add the entry to the struct */ 410 tmp_key = add_new_key(current, sequence[j], KEYMAP_MULTI, 0); 411 412 /* index into the key array - it's 413 clearer if we stash this */ 414 key_ent = current->mapping[(unsigned char) sequence[j]]; 415 416 current->key[key_ent] = tmp_key; 417 418 /* next key uses this map... */ 419 current = current->key[key_ent]->value.next; 420 } 421 422 /* 423 * This is the last key in the sequence (it may have been the 424 * only one but that does not matter) this means it is a leaf 425 * key and should have a symbol associated with it. 426 */ 427 tmp_key = add_new_key(current, sequence[length - 1], KEYMAP_LEAF, 428 key_type); 429 current->key[current->mapping[(int)sequence[length - 1]]] = tmp_key; 430} 431 432/* 433 * Init_getch - initialise all the pointers & structures needed to make 434 * getch work in keypad mode. 435 * 436 */ 437void 438__init_getch(SCREEN *screen) 439{ 440 char entry[1024], *p; 441 const char *s; 442 int i; 443 size_t limit, l; 444#ifdef DEBUG 445 int k, length; 446#endif 447 448 /* init the inkey state variable */ 449 state = INKEY_NORM; 450 451 /* init the base keymap */ 452 screen->base_keymap = new_keymap(); 453 454 /* key input buffer pointers */ 455 start = end = working = 0; 456 457 /* now do the terminfo snarfing ... */ 458 459 for (i = 0; i < num_tcs; i++) { 460 p = entry; 461 limit = 1023; 462 s = screen->term->strs[tc[i].code]; 463 if (s == NULL) 464 continue; 465 l = strlen(s) + 1; 466 if (limit < l) 467 continue; 468 strlcpy(p, s, limit); 469 p += l; 470 limit -= l; 471#ifdef DEBUG 472 __CTRACE(__CTRACE_INIT, 473 "Processing terminfo entry %d, sequence ", 474 tc[i].code); 475 length = (int) strlen(entry); 476 for (k = 0; k <= length -1; k++) 477 __CTRACE(__CTRACE_INIT, "%s", unctrl(entry[k])); 478 __CTRACE(__CTRACE_INIT, "\n"); 479#endif 480 add_key_sequence(screen, entry, tc[i].symbol); 481 } 482} 483 484 485/* 486 * new_keymap - allocates & initialises a new keymap structure. This 487 * function returns a pointer to the new keymap. 488 * 489 */ 490static keymap_t * 491new_keymap(void) 492{ 493 int i; 494 keymap_t *new_map; 495 496 if ((new_map = malloc(sizeof(keymap_t))) == NULL) { 497 perror("Inkey: Cannot allocate new keymap"); 498 exit(2); 499 } 500 501 /* Initialise the new map */ 502 new_map->count = 0; 503 for (i = 0; i < MAX_CHAR; i++) { 504 new_map->mapping[i] = MAPPING_UNUSED; /* no mapping for char */ 505 } 506 507 /* key array will be allocated when first key is added */ 508 new_map->key = NULL; 509 510 return new_map; 511} 512 513/* 514 * new_key - allocates & initialises a new key entry. This function returns 515 * a pointer to the newly allocated key entry. 516 * 517 */ 518static key_entry_t * 519new_key(void) 520{ 521 key_entry_t *new_one; 522 int i; 523 524 new_one = malloc(KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t)); 525 if (new_one == NULL) { 526 perror("inkey: Cannot allocate new key entry chunk"); 527 exit(2); 528 } 529 530 for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) { 531 new_one[i].type = 0; 532 new_one[i].value.next = NULL; 533 } 534 535 return new_one; 536} 537 538/* 539 * inkey - do the work to process keyboard input, check for multi-key 540 * sequences and return the appropriate symbol if we get a match. 541 * 542 */ 543 544static wchar_t 545inkey(int to, int delay) 546{ 547 wchar_t k; 548 int c, mapping; 549 keymap_t *current = _cursesi_screen->base_keymap; 550 FILE *infd = _cursesi_screen->infd; 551 552 k = 0; /* XXX gcc -Wuninitialized */ 553 554#ifdef DEBUG 555 __CTRACE(__CTRACE_INPUT, "inkey (%d, %d)\n", to, delay); 556#endif 557 for (;;) { /* loop until we get a complete key sequence */ 558reread: 559 if (state == INKEY_NORM) { 560 if (delay && __timeout(delay) == ERR) 561 return ERR; 562 c = fgetc(infd); 563 if (c == EOF) { 564 clearerr(infd); 565 return ERR; 566 } 567 568 if (delay && (__notimeout() == ERR)) 569 return ERR; 570 571 k = (wchar_t)c; 572#ifdef DEBUG 573 __CTRACE(__CTRACE_INPUT, 574 "inkey (state normal) got '%s'\n", unctrl(k)); 575#endif 576 577 working = start; 578 inbuf[working] = k; 579 INC_POINTER(working); 580 end = working; 581 state = INKEY_ASSEMBLING; /* go to the assembling 582 * state now */ 583 } else if (state == INKEY_BACKOUT) { 584 k = inbuf[working]; 585 INC_POINTER(working); 586 if (working == end) { /* see if we have run 587 * out of keys in the 588 * backlog */ 589 590 /* if we have then switch to assembling */ 591 state = INKEY_ASSEMBLING; 592 } 593 } else if (state == INKEY_ASSEMBLING) { 594 /* assembling a key sequence */ 595 if (delay) { 596 if (__timeout(to ? (ESCDELAY / 100) : delay) 597 == ERR) 598 return ERR; 599 } else { 600 if (to && (__timeout(ESCDELAY / 100) == ERR)) 601 return ERR; 602 } 603 604 c = fgetc(infd); 605 if (ferror(infd)) { 606 clearerr(infd); 607 return ERR; 608 } 609 610 if ((to || delay) && (__notimeout() == ERR)) 611 return ERR; 612 613#ifdef DEBUG 614 __CTRACE(__CTRACE_INPUT, 615 "inkey (state assembling) got '%s'\n", unctrl(k)); 616#endif 617 if (feof(infd) || c == -1) { /* inter-char timeout, 618 * start backing out */ 619 clearerr(infd); 620 if (start == end) 621 /* no chars in the buffer, restart */ 622 goto reread; 623 624 k = inbuf[start]; 625 state = INKEY_TIMEOUT; 626 } else { 627 k = (wchar_t) c; 628 inbuf[working] = k; 629 INC_POINTER(working); 630 end = working; 631 } 632 } else { 633 fprintf(stderr, "Inkey state screwed - exiting!!!"); 634 exit(2); 635 } 636 637 /* 638 * Check key has no special meaning and we have not 639 * timed out and the key has not been disabled 640 */ 641 mapping = current->mapping[k]; 642 if (((state == INKEY_TIMEOUT) || (mapping < 0)) 643 || ((current->key[mapping]->type == KEYMAP_LEAF) 644 && (current->key[mapping]->enable == FALSE))) { 645 /* return the first key we know about */ 646 k = inbuf[start]; 647 648 INC_POINTER(start); 649 working = start; 650 651 if (start == end) { /* only one char processed */ 652 state = INKEY_NORM; 653 } else {/* otherwise we must have more than one char 654 * to backout */ 655 state = INKEY_BACKOUT; 656 } 657 return k; 658 } else { /* must be part of a multikey sequence */ 659 /* check for completed key sequence */ 660 if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) { 661 start = working; /* eat the key sequence 662 * in inbuf */ 663 664 /* check if inbuf empty now */ 665 if (start == end) { 666 /* if it is go back to normal */ 667 state = INKEY_NORM; 668 } else { 669 /* otherwise go to backout state */ 670 state = INKEY_BACKOUT; 671 } 672 673 /* return the symbol */ 674 return current->key[current->mapping[k]]->value.symbol; 675 676 } else { 677 /* 678 * Step on to next part of the multi-key 679 * sequence. 680 */ 681 current = current->key[current->mapping[k]]->value.next; 682 } 683 } 684 } 685} 686 687#ifndef _CURSES_USE_MACROS 688/* 689 * getch -- 690 * Read in a character from stdscr. 691 */ 692int 693getch(void) 694{ 695 return wgetch(stdscr); 696} 697 698/* 699 * mvgetch -- 700 * Read in a character from stdscr at the given location. 701 */ 702int 703mvgetch(int y, int x) 704{ 705 return mvwgetch(stdscr, y, x); 706} 707 708/* 709 * mvwgetch -- 710 * Read in a character from stdscr at the given location in the 711 * given window. 712 */ 713int 714mvwgetch(WINDOW *win, int y, int x) 715{ 716 if (wmove(win, y, x) == ERR) 717 return ERR; 718 719 return wgetch(win); 720} 721 722#endif 723 724/* 725 * keyok -- 726 * Set the enable flag for a keysym, if the flag is false then 727 * getch will not return this keysym even if the matching key sequence 728 * is seen. 729 */ 730int 731keyok(int key_type, bool flag) 732{ 733 int result = ERR; 734 735 if (_cursesi_screen != NULL) 736 do_keyok(_cursesi_screen->base_keymap, key_type, 737 true, flag, &result); 738 return result; 739} 740 741/* 742 * do_keyok -- 743 * Does the actual work for keyok, we need to recurse through the 744 * keymaps finding the passed key symbol. 745 */ 746static void 747do_keyok(keymap_t *current, int key_type, bool set, bool flag, int *retval) 748{ 749 key_entry_t *key; 750 int i; 751 752 /* 753 * we need to iterate over all the keys as there may be 754 * multiple instances of the leaf symbol. 755 */ 756 for (i = 0; i < MAX_CHAR; i++) { 757 if (current->mapping[i] < 0) 758 continue; /* no mapping for the key, next! */ 759 760 key = current->key[current->mapping[i]]; 761 762 if (key->type == KEYMAP_MULTI) 763 do_keyok(key->value.next, key_type, set, flag, retval); 764 else if ((key->type == KEYMAP_LEAF) 765 && (key->value.symbol == key_type)) { 766 if (set) 767 key->enable = flag; 768 *retval = OK; /* we found at least one instance, ok */ 769 } 770 } 771} 772 773/* 774 * define_key -- 775 * Add a custom mapping of a key sequence to key symbol. 776 * 777 */ 778int 779define_key(char *sequence, int symbol) 780{ 781 782 if (symbol <= 0 || _cursesi_screen == NULL) 783 return ERR; 784 785 if (sequence == NULL) { 786#ifdef DEBUG 787 __CTRACE(__CTRACE_INPUT, "define_key: deleting keysym %d\n", 788 symbol); 789#endif 790 delete_key_sequence(_cursesi_screen->base_keymap, symbol); 791 } else 792 add_key_sequence(_cursesi_screen, sequence, symbol); 793 794 return OK; 795} 796 797/* 798 * wgetch -- 799 * Read in a character from the window. 800 */ 801int 802wgetch(WINDOW *win) 803{ 804 int inp, weset; 805 int c; 806 FILE *infd = _cursesi_screen->infd; 807 808#ifdef DEBUG 809 __CTRACE(__CTRACE_INPUT, "wgetch: win(%p)\n", win); 810#endif 811 if (win == NULL) 812 return ERR; 813 if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN) 814 && win->curx == win->maxx - 1 && win->cury == win->maxy - 1 815 && __echoit) 816 return ERR; 817 818 if (is_wintouched(win)) 819 wrefresh(win); 820#ifdef DEBUG 821 __CTRACE(__CTRACE_INPUT, "wgetch: __echoit = %d, " 822 "__rawmode = %d, __nl = %d, flags = %#.4x, delay = %d\n", 823 __echoit, __rawmode, _cursesi_screen->nl, win->flags, win->delay); 824#endif 825 if (_cursesi_screen->resized) { 826 _cursesi_screen->resized = 0; 827#ifdef DEBUG 828 __CTRACE(__CTRACE_INPUT, "wgetch returning KEY_RESIZE\n"); 829#endif 830 return KEY_RESIZE; 831 } 832 if (_cursesi_screen->unget_pos) { 833#ifdef DEBUG 834 __CTRACE(__CTRACE_INPUT, "wgetch returning char at %d\n", 835 _cursesi_screen->unget_pos); 836#endif 837 _cursesi_screen->unget_pos--; 838 c = _cursesi_screen->unget_list[_cursesi_screen->unget_pos]; 839 if (__echoit) 840 waddch(win, (chtype) c); 841 return c; 842 } 843 if (__echoit && !__rawmode) { 844 cbreak(); 845 weset = 1; 846 } else 847 weset = 0; 848 849 __save_termios(); 850 851 if (win->flags & __KEYPAD) { 852 switch (win->delay) 853 { 854 case -1: 855 inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0); 856 break; 857 case 0: 858 if (__nodelay() == ERR) 859 return ERR; 860 inp = inkey(0, 0); 861 break; 862 default: 863 inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay); 864 break; 865 } 866 } else { 867 switch (win->delay) 868 { 869 case -1: 870 if (__delay() == ERR) 871 return ERR; 872 break; 873 case 0: 874 if (__nodelay() == ERR) 875 return ERR; 876 break; 877 default: 878 if (__timeout(win->delay) == ERR) 879 return ERR; 880 break; 881 } 882 883 c = fgetc(infd); 884 if (feof(infd)) { 885 clearerr(infd); 886 __restore_termios(); 887 return ERR; /* we have timed out */ 888 } 889 890 if (ferror(infd)) { 891 clearerr(infd); 892 inp = ERR; 893 } else { 894 inp = c; 895 } 896 } 897#ifdef DEBUG 898 if (inp > 255) 899 /* we have a key symbol - treat it differently */ 900 /* XXXX perhaps __unctrl should be expanded to include 901 * XXXX the keysyms in the table.... 902 */ 903 __CTRACE(__CTRACE_INPUT, "wgetch assembled keysym 0x%x\n", inp); 904 else 905 __CTRACE(__CTRACE_INPUT, "wgetch got '%s'\n", unctrl(inp)); 906#endif 907 if (win->delay > -1) { 908 if (__delay() == ERR) 909 return ERR; 910 } 911 912 __restore_termios(); 913 914 if ((__echoit) && (inp < KEY_MIN)) 915 waddch(win, (chtype) inp); 916 917 if (weset) 918 nocbreak(); 919 920 if (_cursesi_screen->nl && inp == 13) 921 inp = 10; 922 923 return ((inp < 0) || (inp == ERR) ? ERR : inp); 924} 925 926/* 927 * ungetch -- 928 * Put the character back into the input queue. 929 */ 930int 931ungetch(int c) 932{ 933 return __unget((wint_t)c); 934} 935 936/* 937 * __unget -- 938 * Do the work for ungetch() and unget_wch(); 939 */ 940int 941__unget(wint_t c) 942{ 943 wchar_t *p; 944 int len; 945 946#ifdef DEBUG 947 __CTRACE(__CTRACE_INPUT, "__unget(%x)\n", c); 948#endif 949 if (_cursesi_screen == NULL) 950 return ERR; 951 if (_cursesi_screen->unget_pos >= _cursesi_screen->unget_len) { 952 len = _cursesi_screen->unget_len + 32; 953 if ((p = realloc(_cursesi_screen->unget_list, 954 sizeof(wchar_t) * len)) == NULL) { 955 /* Can't realloc(), so just lose the oldest entry */ 956 memmove(_cursesi_screen->unget_list, 957 _cursesi_screen->unget_list + sizeof(wchar_t), 958 _cursesi_screen->unget_len - 1); 959 _cursesi_screen->unget_list[_cursesi_screen->unget_len 960 - 1] = c; 961 _cursesi_screen->unget_pos = 962 _cursesi_screen->unget_len; 963 return OK; 964 } else { 965 _cursesi_screen->unget_pos = 966 _cursesi_screen->unget_len; 967 _cursesi_screen->unget_len = len; 968 _cursesi_screen->unget_list = p; 969 } 970 } 971 _cursesi_screen->unget_list[_cursesi_screen->unget_pos] = c; 972 _cursesi_screen->unget_pos++; 973 return OK; 974} 975 976int 977has_key(int key_type) 978{ 979 int result = ERR; 980 981 if (_cursesi_screen != NULL) 982 do_keyok(_cursesi_screen->base_keymap, key_type, 983 false, false, &result); 984 return result; 985} 986 987/* 988 * set_escdelay -- 989 * Sets the escape delay for the current screen. 990 */ 991int 992set_escdelay(int escdelay) 993{ 994 995 if (_cursesi_screen == NULL) 996 return ERR; 997 _cursesi_screen->ESCDELAY = escdelay; 998 ESCDELAY = escdelay; 999 return OK; 1000} 1001