getch.c revision 1.51
1/* $NetBSD: getch.c,v 1.51 2008/04/14 20:32:53 jdc Exp $ */ 2 3/* 4 * Copyright (c) 1981, 1993, 1994 5 * The Regents of the University of California. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 3. Neither the name of the University nor the names of its contributors 16 * may be used to endorse or promote products derived from this software 17 * without specific prior written permission. 18 * 19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 29 * SUCH DAMAGE. 30 */ 31 32#include <sys/cdefs.h> 33#ifndef lint 34#if 0 35static char sccsid[] = "@(#)getch.c 8.2 (Berkeley) 5/4/94"; 36#else 37__RCSID("$NetBSD: getch.c,v 1.51 2008/04/14 20:32:53 jdc Exp $"); 38#endif 39#endif /* not lint */ 40 41#include <string.h> 42#include <stdlib.h> 43#include <unistd.h> 44#include <stdio.h> 45#include "curses.h" 46#include "curses_private.h" 47#include "keymap.h" 48 49short state; /* state of the inkey function */ 50 51static const struct tcdata tc[] = { 52 {"!1", KEY_SSAVE}, 53 {"!2", KEY_SSUSPEND}, 54 {"!3", KEY_SUNDO}, 55 {"#1", KEY_SHELP}, 56 {"#2", KEY_SHOME}, 57 {"#3", KEY_SIC}, 58 {"#4", KEY_SLEFT}, 59 {"%0", KEY_REDO}, 60 {"%1", KEY_HELP}, 61 {"%2", KEY_MARK}, 62 {"%3", KEY_MESSAGE}, 63 {"%4", KEY_MOVE}, 64 {"%5", KEY_NEXT}, 65 {"%6", KEY_OPEN}, 66 {"%7", KEY_OPTIONS}, 67 {"%8", KEY_PREVIOUS}, 68 {"%9", KEY_PRINT}, 69 {"%a", KEY_SMESSAGE}, 70 {"%b", KEY_SMOVE}, 71 {"%c", KEY_SNEXT}, 72 {"%d", KEY_SOPTIONS}, 73 {"%e", KEY_SPREVIOUS}, 74 {"%f", KEY_SPRINT}, 75 {"%g", KEY_SREDO}, 76 {"%h", KEY_SREPLACE}, 77 {"%i", KEY_SRIGHT}, 78 {"%j", KEY_SRSUME}, 79 {"&0", KEY_SCANCEL}, 80 {"&1", KEY_REFERENCE}, 81 {"&2", KEY_REFRESH}, 82 {"&3", KEY_REPLACE}, 83 {"&4", KEY_RESTART}, 84 {"&5", KEY_RESUME}, 85 {"&6", KEY_SAVE}, 86 {"&7", KEY_SUSPEND}, 87 {"&8", KEY_UNDO}, 88 {"&9", KEY_SBEG}, 89 {"*0", KEY_SFIND}, 90 {"*1", KEY_SCOMMAND}, 91 {"*2", KEY_SCOPY}, 92 {"*3", KEY_SCREATE}, 93 {"*4", KEY_SDC}, 94 {"*5", KEY_SDL}, 95 {"*6", KEY_SELECT}, 96 {"*7", KEY_SEND}, 97 {"*8", KEY_SEOL}, 98 {"*9", KEY_SEXIT}, 99 {"@0", KEY_FIND}, 100 {"@1", KEY_BEG}, 101 {"@2", KEY_CANCEL}, 102 {"@3", KEY_CLOSE}, 103 {"@4", KEY_COMMAND}, 104 {"@5", KEY_COPY}, 105 {"@6", KEY_CREATE}, 106 {"@7", KEY_END}, 107 {"@8", KEY_ENTER}, 108 {"@9", KEY_EXIT}, 109 {"F1", KEY_F(11)}, 110 {"F2", KEY_F(12)}, 111 {"F3", KEY_F(13)}, 112 {"F4", KEY_F(14)}, 113 {"F5", KEY_F(15)}, 114 {"F6", KEY_F(16)}, 115 {"F7", KEY_F(17)}, 116 {"F8", KEY_F(18)}, 117 {"F9", KEY_F(19)}, 118 {"FA", KEY_F(20)}, 119 {"FB", KEY_F(21)}, 120 {"FC", KEY_F(22)}, 121 {"FD", KEY_F(23)}, 122 {"FE", KEY_F(24)}, 123 {"FF", KEY_F(25)}, 124 {"FG", KEY_F(26)}, 125 {"FH", KEY_F(27)}, 126 {"FI", KEY_F(28)}, 127 {"FJ", KEY_F(29)}, 128 {"FK", KEY_F(30)}, 129 {"FL", KEY_F(31)}, 130 {"FM", KEY_F(32)}, 131 {"FN", KEY_F(33)}, 132 {"FO", KEY_F(34)}, 133 {"FP", KEY_F(35)}, 134 {"FQ", KEY_F(36)}, 135 {"FR", KEY_F(37)}, 136 {"FS", KEY_F(38)}, 137 {"FT", KEY_F(39)}, 138 {"FU", KEY_F(40)}, 139 {"FV", KEY_F(41)}, 140 {"FW", KEY_F(42)}, 141 {"FX", KEY_F(43)}, 142 {"FY", KEY_F(44)}, 143 {"FZ", KEY_F(45)}, 144 {"Fa", KEY_F(46)}, 145 {"Fb", KEY_F(47)}, 146 {"Fc", KEY_F(48)}, 147 {"Fd", KEY_F(49)}, 148 {"Fe", KEY_F(50)}, 149 {"Ff", KEY_F(51)}, 150 {"Fg", KEY_F(52)}, 151 {"Fh", KEY_F(53)}, 152 {"Fi", KEY_F(54)}, 153 {"Fj", KEY_F(55)}, 154 {"Fk", KEY_F(56)}, 155 {"Fl", KEY_F(57)}, 156 {"Fm", KEY_F(58)}, 157 {"Fn", KEY_F(59)}, 158 {"Fo", KEY_F(60)}, 159 {"Fp", KEY_F(61)}, 160 {"Fq", KEY_F(62)}, 161 {"Fr", KEY_F(63)}, 162 {"K1", KEY_A1}, 163 {"K2", KEY_B2}, 164 {"K3", KEY_A3}, 165 {"K4", KEY_C1}, 166 {"K5", KEY_C3}, 167 {"Km", KEY_MOUSE}, 168 {"k0", KEY_F0}, 169 {"k1", KEY_F(1)}, 170 {"k2", KEY_F(2)}, 171 {"k3", KEY_F(3)}, 172 {"k4", KEY_F(4)}, 173 {"k5", KEY_F(5)}, 174 {"k6", KEY_F(6)}, 175 {"k7", KEY_F(7)}, 176 {"k8", KEY_F(8)}, 177 {"k9", KEY_F(9)}, 178 {"k;", KEY_F(10)}, 179 {"kA", KEY_IL}, 180 {"ka", KEY_CATAB}, 181 {"kB", KEY_BTAB}, 182 {"kb", KEY_BACKSPACE}, 183 {"kC", KEY_CLEAR}, 184 {"kD", KEY_DC}, 185 {"kd", KEY_DOWN}, 186 {"kE", KEY_EOL}, 187 {"kF", KEY_SF}, 188 {"kH", KEY_LL}, 189 {"kh", KEY_HOME}, 190 {"kI", KEY_IC}, 191 {"kL", KEY_DL}, 192 {"kl", KEY_LEFT}, 193 {"kM", KEY_EIC}, 194 {"kN", KEY_NPAGE}, 195 {"kP", KEY_PPAGE}, 196 {"kR", KEY_SR}, 197 {"kr", KEY_RIGHT}, 198 {"kS", KEY_EOS}, 199 {"kT", KEY_STAB}, 200 {"kt", KEY_CTAB}, 201 {"ku", KEY_UP} 202}; 203/* Number of TC entries .... */ 204static const int num_tcs = (sizeof(tc) / sizeof(struct tcdata)); 205 206int 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 */ 211static wchar_t inbuf[INBUF_SZ]; 212static int start, end, working; /* pointers for manipulating inbuf data */ 213 214/* prototypes for private functions */ 215static void add_key_sequence(SCREEN *screen, char *sequence, int key_type); 216static key_entry_t *add_new_key(keymap_t *current, char ch, int key_type, 217 int symbol); 218static void delete_key_sequence(keymap_t *current, int key_type); 219static void do_keyok(keymap_t *current, int key_type, bool flag, int *retval); 220static keymap_t *new_keymap(void); /* create a new keymap */ 221static key_entry_t *new_key(void); /* create a new key entry */ 222static wchar_t inkey(int to, int delay); 223 224/* 225 * Free the storage associated with the given keymap 226 */ 227void 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 */ 258static key_entry_t * 259add_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 */ 344void 345delete_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 */ 384void 385add_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 */ 441void 442__init_getch(SCREEN *screen) 443{ 444 char entry[1024], *p; 445 int i; 446 size_t limit; 447#ifdef DEBUG 448 int k, length; 449#endif 450 451 /* init the inkey state variable */ 452 state = INKEY_NORM; 453 454 /* init the base keymap */ 455 screen->base_keymap = new_keymap(); 456 457 /* key input buffer pointers */ 458 start = end = working = 0; 459 460 /* now do the termcap snarfing ... */ 461 462 for (i = 0; i < num_tcs; i++) { 463 p = entry; 464 limit = 1023; 465 if (t_getstr(screen->cursesi_genbuf, tc[i].name, 466 &p, &limit) != (char *) NULL) { 467#ifdef DEBUG 468 __CTRACE(__CTRACE_INIT, 469 "Processing termcap entry %s, sequence ", 470 tc[i].name); 471 length = (int) strlen(entry); 472 for (k = 0; k <= length -1; k++) 473 __CTRACE(__CTRACE_INIT, "%s", unctrl(entry[k])); 474 __CTRACE(__CTRACE_INIT, "\n"); 475#endif 476 add_key_sequence(screen, entry, tc[i].symbol); 477 } 478 479 } 480} 481 482 483/* 484 * new_keymap - allocates & initialises a new keymap structure. This 485 * function returns a pointer to the new keymap. 486 * 487 */ 488static keymap_t * 489new_keymap(void) 490{ 491 int i; 492 keymap_t *new_map; 493 494 if ((new_map = malloc(sizeof(keymap_t))) == NULL) { 495 perror("Inkey: Cannot allocate new keymap"); 496 exit(2); 497 } 498 499 /* Initialise the new map */ 500 new_map->count = 0; 501 for (i = 0; i < MAX_CHAR; i++) { 502 new_map->mapping[i] = MAPPING_UNUSED; /* no mapping for char */ 503 } 504 505 /* key array will be allocated when first key is added */ 506 new_map->key = NULL; 507 508 return new_map; 509} 510 511/* 512 * new_key - allocates & initialises a new key entry. This function returns 513 * a pointer to the newly allocated key entry. 514 * 515 */ 516static key_entry_t * 517new_key(void) 518{ 519 key_entry_t *new_one; 520 int i; 521 522 if ((new_one = malloc(KEYMAP_ALLOC_CHUNK * sizeof(key_entry_t))) 523 == NULL) { 524 perror("inkey: Cannot allocate new key entry chunk"); 525 exit(2); 526 } 527 528 for (i = 0; i < KEYMAP_ALLOC_CHUNK; i++) { 529 new_one[i].type = 0; 530 new_one[i].value.next = NULL; 531 } 532 533 return new_one; 534} 535 536/* 537 * inkey - do the work to process keyboard input, check for multi-key 538 * sequences and return the appropriate symbol if we get a match. 539 * 540 */ 541 542wchar_t 543inkey(int to, int delay) 544{ 545 wchar_t k; 546 int c, mapping; 547 keymap_t *current = _cursesi_screen->base_keymap; 548 FILE *infd = _cursesi_screen->infd; 549 550 k = 0; /* XXX gcc -Wuninitialized */ 551 552#ifdef DEBUG 553 __CTRACE(__CTRACE_INPUT, "inkey (%d, %d)\n", to, delay); 554#endif 555 for (;;) { /* loop until we get a complete key sequence */ 556reread: 557 if (state == INKEY_NORM) { 558 if (delay && __timeout(delay) == ERR) 559 return ERR; 560 c = getchar(); 561 if (c == EOF) { 562 clearerr(infd); 563 return ERR; 564 } 565 566 if (delay && (__notimeout() == ERR)) 567 return ERR; 568 569 k = (wchar_t) c; 570#ifdef DEBUG 571 __CTRACE(__CTRACE_INPUT, 572 "inkey (state normal) got '%s'\n", unctrl(k)); 573#endif 574 575 working = start; 576 inbuf[working] = k; 577 INC_POINTER(working); 578 end = working; 579 state = INKEY_ASSEMBLING; /* go to the assembling 580 * state now */ 581 } else if (state == INKEY_BACKOUT) { 582 k = inbuf[working]; 583 INC_POINTER(working); 584 if (working == end) { /* see if we have run 585 * out of keys in the 586 * backlog */ 587 588 /* if we have then switch to assembling */ 589 state = INKEY_ASSEMBLING; 590 } 591 } else if (state == INKEY_ASSEMBLING) { 592 /* assembling a key sequence */ 593 if (delay) { 594 if (__timeout(to ? (ESCDELAY / 100) : delay) 595 == ERR) 596 return ERR; 597 } else { 598 if (to && (__timeout(ESCDELAY / 100) == ERR)) 599 return ERR; 600 } 601 602 c = getchar(); 603 if (c == -1 || ferror(infd)) { 604 clearerr(infd); 605 return ERR; 606 } 607 608 if ((to || delay) && (__notimeout() == ERR)) 609 return ERR; 610 611 k = (wchar_t) c; 612#ifdef DEBUG 613 __CTRACE(__CTRACE_INPUT, 614 "inkey (state assembling) got '%s'\n", unctrl(k)); 615#endif 616 if (feof(infd)) { /* inter-char timeout, 617 * start backing out */ 618 clearerr(infd); 619 if (start == end) 620 /* no chars in the buffer, restart */ 621 goto reread; 622 623 k = inbuf[start]; 624 state = INKEY_TIMEOUT; 625 } else { 626 inbuf[working] = k; 627 INC_POINTER(working); 628 end = working; 629 } 630 } else { 631 fprintf(stderr, "Inkey state screwed - exiting!!!"); 632 exit(2); 633 } 634 635 /* 636 * Check key has no special meaning and we have not 637 * timed out and the key has not been disabled 638 */ 639 mapping = current->mapping[k]; 640 if (((state == INKEY_TIMEOUT) || (mapping < 0)) 641 || ((current->key[mapping]->type == KEYMAP_LEAF) 642 && (current->key[mapping]->enable == FALSE))) { 643 /* return the first key we know about */ 644 k = inbuf[start]; 645 646 INC_POINTER(start); 647 working = start; 648 649 if (start == end) { /* only one char processed */ 650 state = INKEY_NORM; 651 } else {/* otherwise we must have more than one char 652 * to backout */ 653 state = INKEY_BACKOUT; 654 } 655 return k; 656 } else { /* must be part of a multikey sequence */ 657 /* check for completed key sequence */ 658 if (current->key[current->mapping[k]]->type == KEYMAP_LEAF) { 659 start = working; /* eat the key sequence 660 * in inbuf */ 661 662 /* check if inbuf empty now */ 663 if (start == end) { 664 /* if it is go back to normal */ 665 state = INKEY_NORM; 666 } else { 667 /* otherwise go to backout state */ 668 state = INKEY_BACKOUT; 669 } 670 671 /* return the symbol */ 672 return current->key[current->mapping[k]]->value.symbol; 673 674 } else { 675 /* 676 * Step on to next part of the multi-key 677 * sequence. 678 */ 679 current = current->key[current->mapping[k]]->value.next; 680 } 681 } 682 } 683} 684 685#ifndef _CURSES_USE_MACROS 686/* 687 * getch -- 688 * Read in a character from stdscr. 689 */ 690int 691getch(void) 692{ 693 return wgetch(stdscr); 694} 695 696/* 697 * mvgetch -- 698 * Read in a character from stdscr at the given location. 699 */ 700int 701mvgetch(int y, int x) 702{ 703 return mvwgetch(stdscr, y, x); 704} 705 706/* 707 * mvwgetch -- 708 * Read in a character from stdscr at the given location in the 709 * given window. 710 */ 711int 712mvwgetch(WINDOW *win, int y, int x) 713{ 714 if (wmove(win, y, x) == ERR) 715 return ERR; 716 717 return wgetch(win); 718} 719 720#endif 721 722/* 723 * keyok -- 724 * Set the enable flag for a keysym, if the flag is false then 725 * getch will not return this keysym even if the matching key sequence 726 * is seen. 727 */ 728int 729keyok(int key_type, bool flag) 730{ 731 int result = ERR; 732 733 do_keyok(_cursesi_screen->base_keymap, key_type, flag, &result); 734 return result; 735} 736 737/* 738 * do_keyok -- 739 * Does the actual work for keyok, we need to recurse through the 740 * keymaps finding the passed key symbol. 741 */ 742void 743do_keyok(keymap_t *current, int key_type, bool flag, int *retval) 744{ 745 key_entry_t *key; 746 int i; 747 748 /* 749 * we need to iterate over all the keys as there may be 750 * multiple instances of the leaf symbol. 751 */ 752 for (i = 0; i < MAX_CHAR; i++) { 753 if (current->mapping[i] < 0) 754 continue; /* no mapping for the key, next! */ 755 756 key = current->key[current->mapping[i]]; 757 758 if (key->type == KEYMAP_MULTI) 759 do_keyok(key->value.next, key_type, flag, retval); 760 else if ((key->type == KEYMAP_LEAF) 761 && (key->value.symbol == key_type)) { 762 key->enable = flag; 763 *retval = OK; /* we found at least one instance, ok */ 764 } 765 } 766} 767 768/* 769 * define_key -- 770 * Add a custom mapping of a key sequence to key symbol. 771 * 772 */ 773int 774define_key(char *sequence, int symbol) 775{ 776 777 if (symbol <= 0) 778 return ERR; 779 780 if (sequence == NULL) 781 delete_key_sequence(_cursesi_screen->base_keymap, symbol); 782 else 783 add_key_sequence(_cursesi_screen, sequence, symbol); 784 785 return OK; 786} 787 788/* 789 * wgetch -- 790 * Read in a character from the window. 791 */ 792int 793wgetch(WINDOW *win) 794{ 795 int inp, weset; 796 int c; 797 FILE *infd = _cursesi_screen->infd; 798 799#ifdef DEBUG 800 __CTRACE(__CTRACE_INPUT, "wgetch: win(%p)\n", win); 801#endif 802 if (!(win->flags & __SCROLLOK) && (win->flags & __FULLWIN) 803 && win->curx == win->maxx - 1 && win->cury == win->maxy - 1 804 && __echoit) 805 return (ERR); 806 807 if (is_wintouched(win)) 808 wrefresh(win); 809#ifdef DEBUG 810 __CTRACE(__CTRACE_INPUT, "wgetch: __echoit = %d, " 811 "__rawmode = %d, __nl = %d, flags = %#.4x\n", 812 __echoit, __rawmode, _cursesi_screen->nl, win->flags); 813#endif 814 if (_cursesi_screen->resized) { 815 _cursesi_screen->resized = 0; 816#ifdef DEBUG 817 __CTRACE(__CTRACE_INPUT, "wgetch returning KEY_RESIZE\n"); 818#endif 819 return KEY_RESIZE; 820 } 821 if (_cursesi_screen->unget_pos) { 822#ifdef DEBUG 823 __CTRACE(__CTRACE_INPUT, "wgetch returning char at %d\n", 824 _cursesi_screen->unget_pos); 825#endif 826 _cursesi_screen->unget_pos--; 827 c = _cursesi_screen->unget_list[_cursesi_screen->unget_pos]; 828 if (__echoit) 829 waddch(win, (chtype) c); 830 return c; 831 } 832 if (__echoit && !__rawmode) { 833 cbreak(); 834 weset = 1; 835 } else 836 weset = 0; 837 838 __save_termios(); 839 840 if (win->flags & __KEYPAD) { 841 switch (win->delay) 842 { 843 case -1: 844 inp = inkey (win->flags & __NOTIMEOUT ? 0 : 1, 0); 845 break; 846 case 0: 847 if (__nodelay() == ERR) { 848 __restore_termios(); 849 return ERR; 850 } 851 inp = inkey(0, 0); 852 break; 853 default: 854 inp = inkey(win->flags & __NOTIMEOUT ? 0 : 1, win->delay); 855 break; 856 } 857 } else { 858 switch (win->delay) 859 { 860 case -1: 861 if (__delay() == ERR) { 862 __restore_termios(); 863 return ERR; 864 } 865 break; 866 case 0: 867 if (__nodelay() == ERR) { 868 __restore_termios(); 869 return ERR; 870 } 871 break; 872 default: 873 if (__timeout(win->delay) == ERR) { 874 __restore_termios(); 875 return ERR; 876 } 877 break; 878 } 879 880 c = getchar(); 881 if (feof(infd)) { 882 clearerr(infd); 883 __restore_termios(); 884 return ERR; /* we have timed out */ 885 } 886 887 if (ferror(infd)) { 888 clearerr(infd); 889 inp = ERR; 890 } else { 891 inp = c; 892 } 893 } 894#ifdef DEBUG 895 if (inp > 255) 896 /* we have a key symbol - treat it differently */ 897 /* XXXX perhaps __unctrl should be expanded to include 898 * XXXX the keysyms in the table.... 899 */ 900 __CTRACE(__CTRACE_INPUT, "wgetch assembled keysym 0x%x\n", inp); 901 else 902 __CTRACE(__CTRACE_INPUT, "wgetch got '%s'\n", unctrl(inp)); 903#endif 904 if (win->delay > -1) { 905 if (__delay() == ERR) { 906 __restore_termios(); 907 return ERR; 908 } 909 } 910 911 __restore_termios(); 912 913 if (__echoit) 914 waddch(win, (chtype) inp); 915 916 if (weset) 917 nocbreak(); 918 919 if (_cursesi_screen->nl && inp == 13) 920 inp = 10; 921 922 return ((inp < 0) || (inp == ERR) ? ERR : inp); 923} 924 925/* 926 * ungetch -- 927 * Put the character back into the input queue. 928 */ 929int 930ungetch(int c) 931{ 932 return __unget((wint_t) c); 933} 934 935/* 936 * __unget -- 937 * Do the work for ungetch() and unget_wch(); 938 */ 939int 940__unget(wint_t c) 941{ 942 wchar_t *p; 943 int len; 944 945#ifdef DEBUG 946 __CTRACE(__CTRACE_INPUT, "__unget(%x)\n", c); 947#endif 948 if (_cursesi_screen->unget_pos >= _cursesi_screen->unget_len) { 949 len = _cursesi_screen->unget_len + 32; 950 if ((p = realloc(_cursesi_screen->unget_list, 951 sizeof(wchar_t) * len)) == NULL) { 952 /* Can't realloc(), so just lose the oldest entry */ 953 memmove(_cursesi_screen->unget_list, 954 _cursesi_screen->unget_list + sizeof(wchar_t), 955 _cursesi_screen->unget_len - 1); 956 _cursesi_screen->unget_list[_cursesi_screen->unget_len 957 - 1] = c; 958 _cursesi_screen->unget_pos = 959 _cursesi_screen->unget_len; 960 return OK; 961 } else { 962 _cursesi_screen->unget_pos = 963 _cursesi_screen->unget_len; 964 _cursesi_screen->unget_len = len; 965 _cursesi_screen->unget_list = p; 966 } 967 } 968 _cursesi_screen->unget_list[_cursesi_screen->unget_pos] = c; 969 _cursesi_screen->unget_pos++; 970 return OK; 971} 972