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