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