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