1 /* keyboard.c - translate key codes to key meanings
2 *
3 * Copyright 1999, 2000 Jochen Voss. */
4
5 static const char rcsid[] = "$Id: keyboard.c 4839 2003-04-13 16:50:02Z voss $";
6
7 #ifdef HAVE_CONFIG_H
8 #include <config.h>
9 #endif
10
11 #include <stdio.h>
12 #include <string.h>
13 #include <stdlib.h>
14 #include <ctype.h>
15 #if HAVE_ERRNO_H
16 #include <errno.h>
17 #else
18 extern int errno;
19 #endif
20
21 #include "moon-buggy.h"
22
23
24 struct hash_entry {
25 struct hash_entry *next;
26 int key_code;
27 int meaning;
28 int priority;
29 };
30
31 #define HASH_SIZE 37
32 struct hash_entry *hash_table [HASH_SIZE];
33
34
35 static unsigned
m_mod(int x,int y)36 m_mod (int x, int y)
37 {
38 int r = x%y;
39 return r<0 ? (y<0 ? r-y : r+y) : r;
40 }
41
42 static struct hash_entry **
locate(int key_code)43 locate (int key_code)
44 {
45 int slot = m_mod (key_code, HASH_SIZE);
46 struct hash_entry **res = &hash_table[slot];
47 while (*res && (*res)->key_code != key_code) res = &((*res)->next);
48 return res;
49 }
50
51 static void
add_key(int key_code,enum mb_key meaning,int priority)52 add_key (int key_code, enum mb_key meaning, int priority)
53 {
54 struct hash_entry **entry_p;
55
56 #if NCURSES_VERSION_MAJOR >= 4
57 if ((key_code < 0 || key_code > 255) && ! has_key (key_code)) return;
58 #endif
59 entry_p = locate (key_code);
60 if (! *entry_p) {
61 *entry_p = xmalloc (sizeof (struct hash_entry));
62 (*entry_p)->next = NULL;
63 (*entry_p)->key_code = key_code;
64 (*entry_p)->meaning = 0;
65 (*entry_p)->priority = priority;
66 }
67 (*entry_p)->meaning |= meaning;
68 }
69
70 void
install_keys(void)71 install_keys (void)
72 {
73 int i;
74
75 for (i=0; i<HASH_SIZE; ++i) hash_table [i] = NULL;
76
77 add_key ('c', mbk_copyright, 100);
78
79 add_key (14, mbk_down, 80); /* \C-n */
80 #ifdef KEY_DOWN
81 add_key (KEY_DOWN, mbk_down, 100);
82 #endif
83
84 add_key ('q', mbk_end, 100);
85 add_key ('n', mbk_end, 90);
86 add_key (27, mbk_end, 80);
87
88 add_key ('a', mbk_fire, 100);
89 add_key ('l', mbk_fire, 60);
90
91 add_key ('<', mbk_first, 90);
92 #ifdef KEY_HOME
93 add_key (KEY_HOME, mbk_first, 100);
94 #endif
95
96 add_key (' ', mbk_jump, 100);
97 add_key ('j', mbk_jump, 50);
98
99 add_key ('>', mbk_last, 90);
100 #ifdef KEY_END
101 add_key (KEY_END, mbk_last, 100);
102 #endif
103
104 add_key (' ', mbk_pagedown, 90);
105 #ifdef KEY_NPAGE
106 add_key (KEY_NPAGE, mbk_pagedown, 100);
107 #endif
108
109 add_key ('b', mbk_pageup, 90);
110 #ifdef KEY_PPAGE
111 add_key (KEY_PPAGE, mbk_pageup, 100);
112 #endif
113
114 add_key ('y', mbk_start, 100);
115 add_key (' ', mbk_start, 90);
116 add_key (10, mbk_start, 80); /* RET */
117
118 add_key (16, mbk_up, 80); /* \C-p */
119 #ifdef KEY_UP
120 add_key (KEY_UP, mbk_up, 100);
121 #endif
122
123 add_key ('w', mbk_warranty, 100);
124
125 add_key ('s', mbk_scores, 100);
126
127 add_key ('r', mbk_redraw, 20);
128 add_key (12, mbk_redraw, 10); /* \C-l */
129 }
130
131 int
read_key(void)132 read_key (void)
133 {
134 int key_code;
135 struct hash_entry **entry_p;
136
137 do {
138 key_code = wgetch (moon);
139 } while (key_code == ERR && errno == EINTR);
140 if (key_code == ERR) fatal ("Cannot read keyboard input");
141 #ifdef KEY_RESIZE
142 if (key_code == KEY_RESIZE) return -1;
143 #endif
144 if (key_code < 256 && isalpha (key_code)) key_code = tolower (key_code);
145 entry_p = locate (key_code);
146 return *entry_p ? (*entry_p)->meaning : 0;
147 }
148
149 static int
function_key(int key)150 function_key (int key)
151 {
152 return key>255 || key == ' ' || key == 10;
153 }
154
155 static int
control_key(int key)156 control_key (int key)
157 {
158 return key >= 1 && key <= 26;
159 }
160
161 char *
key_name(int key)162 key_name (int key)
163 /* Convert a key code into a string.
164 * The retured string must not be modified by the caller. Subsequent
165 * calls to `key_name' may overwrite the returned string.
166 * If the key's name is unknown, NULL is returned. */
167 {
168 static char buffer [8];
169 int i;
170
171 #ifdef KEY_BACKSPACE
172 if (key == KEY_BACKSPACE) return "BS";
173 #endif
174 #ifdef KEY_BEG
175 if (key == KEY_BEG) return "BEG";
176 #endif
177 #ifdef KEY_BREAK
178 if (key == KEY_BREAK) return "BREAK";
179 #endif
180 #ifdef KEY_CANCEL
181 if (key == KEY_CANCEL) return "CANCEL";
182 #endif
183 #ifdef KEY_CLOSE
184 if (key == KEY_CLOSE) return "CLOSE";
185 #endif
186 #ifdef KEY_DC
187 if (key == KEY_DC) return "DEL";
188 #endif
189 #ifdef KEY_DOWN
190 if (key == KEY_DOWN) return "DOWN";
191 #endif
192 #ifdef KEY_END
193 if (key == KEY_END) return "END";
194 #endif
195 #ifdef KEY_ENTER
196 if (key == KEY_ENTER) return "ENTER";
197 #endif
198 #ifdef KEY_EXIT
199 if (key == KEY_EXIT) return "EXIT";
200 #endif
201 #ifdef KEY_HOME
202 if (key == KEY_HOME) return "HOME";
203 #endif
204 #ifdef KEY_IC
205 if (key == KEY_IC) return "INS";
206 #endif
207 #ifdef KEY_LEFT
208 if (key == KEY_LEFT) return "LEFT";
209 #endif
210 #ifdef KEY_NPAGE
211 if (key == KEY_NPAGE) return "NEXT";
212 #endif
213 #ifdef KEY_PPAGE
214 if (key == KEY_PPAGE) return "PREV";
215 #endif
216 #ifdef KEY_RIGHT
217 if (key == KEY_RIGHT) return "RIGHT";
218 #endif
219 #ifdef KEY_UNDO
220 if (key == KEY_UNDO) return "UNDO";
221 #endif
222 #ifdef KEY_UP
223 if (key == KEY_UP) return "UP";
224 #endif
225 #ifdef KEY_F0
226 for (i=0; i<64; ++i) {
227 if (key == KEY_F(i)) {
228 sprintf (buffer, "F%d", i);
229 return buffer;
230 }
231 }
232 #endif
233
234 if (key > 255) return NULL;
235 if (key == ' ') return "SPC";
236 if (key == 10) return "RET";
237 if (isgraph (key)) {
238 sprintf (buffer, "%c", key);
239 return buffer;
240 }
241 if (control_key (key)) {
242 sprintf (buffer, "C-%c", key+'a'-1);
243 return buffer;
244 }
245 return NULL;
246 }
247
248 #define MAX_KEYS 16
249 struct key_name {
250 char name [8];
251 int priority, base_priority;
252 } data [MAX_KEYS];
253 struct key_info {
254 int fn, ctrl, norm;
255 int k;
256 struct key_name data [MAX_KEYS];
257 };
258
259 static void
set_display_priorities(struct key_name * data,int k)260 set_display_priorities (struct key_name *data, int k)
261 {
262 int i;
263 for (i=0; i<k; ++i) data[i].priority = data[i].base_priority;
264 }
265
266 static int
compare_keys(const void * a,const void * b)267 compare_keys (const void *a, const void *b)
268 {
269 const struct key_name *aa = a;
270 const struct key_name *bb = b;
271
272 if (aa->priority < bb->priority) return +1;
273 if (aa->priority > bb->priority) return -1;
274 if (strlen (aa->name) < strlen (bb->name)) return -1;
275 if (strlen (aa->name) > strlen (bb->name)) return +1;
276 return strcmp (aa->name, bb->name);
277 }
278
279 static int
choose_keys(int * n,const struct binding * b,struct key_info * keys,int max_len)280 choose_keys (int *n, const struct binding *b, struct key_info *keys,
281 int max_len)
282 /* Choose the keys to explain, based on available display space.
283 * Input are *N key bindings in the array B and the corresponding key
284 * names in KEYS. The resulting explanation must fit within MAX_LEN
285 * characters.
286 *
287 * This function may decrease *N and clear the priority values of
288 * some keys in order to exclude keys from the explanation. */
289 {
290 int finished;
291 int *first;
292 int i, k, len;
293
294 /* Is there enough space to explain all functions? */
295 len = max_len;
296 for (i=0; i<*n; ++i) {
297 int x;
298 x = (i>0) ? 1 : 0; /* " " */
299 x += 2 + strlen(b[i].desc); /* "x:desc" */
300 if (len >= x) {
301 len -= x;
302 } else {
303 *n=i;
304 break;
305 }
306 }
307
308 /* How much space do we have left? */
309 len = max_len;
310 first = xmalloc (*n * sizeof(int));
311 for (i=0; i<*n; ++i) {
312 first[i] = 1;
313 if (i>0) --len; /* " " */
314 len -= 1 + strlen(b[i].desc); /* ":desc" */
315 }
316 finished = 0;
317 for (k=0; ! finished; ++k) {
318 finished = 1;
319 for (i=0; i<*n; ++i) {
320 if (k < keys[i].k) {
321 int x;
322
323 x = first[i] ? 0 : 1; /* "," */
324 x += strlen (keys[i].data[k].name);
325 if (x <= len) {
326 len -= x;
327 first[i] = 0;
328 } else {
329 keys[i].data[k].base_priority = 0;
330 }
331 finished = 0;
332 }
333 }
334 }
335 free (first);
336
337 for (i=0; i<*n; ++i) {
338 set_display_priorities (keys[i].data, keys[i].k);
339 qsort (keys[i].data, keys[i].k, sizeof (struct key_name), compare_keys);
340 }
341
342 return len;
343 }
344
345 void
describe_keys(int n,const struct binding * b)346 describe_keys (int n, const struct binding *b)
347 {
348 struct key_info *keys;
349 char* buffer;
350 int len, max_len;
351 int i, j, k;
352
353 keys = xmalloc (n*sizeof(struct key_info));
354 for (i=0; i<n; ++i) {
355 keys[i].fn = 0;
356 keys[i].ctrl = 0;
357 keys[i].norm = 0;
358 keys[i].k = 0;
359 }
360 for (j=0; j<HASH_SIZE; ++j) {
361 struct hash_entry *ent = hash_table[j];
362
363 while (ent) {
364 for (i=0; i<n; ++i) {
365 if (ent->meaning & b[i].meanings) {
366 char *name = key_name (ent->key_code);
367
368 if (name) {
369 k = keys[i].k++;
370 strncpy (keys[i].data[k].name, name, 7);
371 keys[i].data[k].name[7] = 0;
372 keys[i].data[k].base_priority = ent->priority;
373 keys[i].data[k].priority = ent->priority;
374 if (function_key (ent->key_code)) {
375 if (keys[i].fn == 0) keys[i].data[k].priority += 1050;
376 ++keys[i].fn;
377 } else if (control_key (ent->key_code)) {
378 if (keys[i].ctrl == 0) keys[i].data[k].priority += 1000;
379 ++keys[i].ctrl;
380 } else {
381 keys[i].data[k].priority += 1100;
382 ++keys[i].norm;
383 }
384 }
385 break;
386 }
387 }
388 ent = ent->next;
389 }
390 }
391 for (i=0; i<n; ++i) {
392 qsort (keys[i].data, keys[i].k, sizeof (struct key_name), compare_keys);
393 }
394
395 max_len = COLS;
396 len = choose_keys (&n, b, keys, max_len);
397 buffer = xmalloc (max_len+1);
398
399 buffer[0] = '\0';
400 for (i=0; i<n; ++i) {
401 int first = 1;
402 for (k=0; k<keys[i].k; ++k) {
403 if (keys[i].data[k].priority) {
404 if (! first) {
405 strcat (buffer, ",");
406 } else {
407 if (i>0) {
408 if (len > 0) {
409 --len;
410 strcat (buffer, " ");
411 } else {
412 strcat (buffer, " ");
413 }
414 }
415 first = 0;
416 }
417 strcat (buffer, keys[i].data[k].name);
418 }
419 }
420 if (keys[i].data[0].priority) {
421 strcat (buffer, ":");
422 strcat (buffer, b[i].desc);
423 }
424 }
425 print_message (buffer);
426
427 free (buffer);
428 free (keys);
429 }
430