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