source: keymap.c @ 7d4fbcd

barnowl_perlaimdebianowlrelease-1.4release-1.5release-1.6release-1.7release-1.8release-1.9
Last change on this file since 7d4fbcd was 7d4fbcd, checked in by James M. Kretchmar <kretch@mit.edu>, 18 years ago
Initial check in
  • Property mode set to 100644
File size: 8.3 KB
Line 
1#include <string.h>
2#include "owl.h"
3
4/* returns 0 on success */
5int owl_keymap_init(owl_keymap *km, char *name, char *desc, void (*default_fn)(int), void (*prealways_fn)(int), void (*postalways_fn)(int)) {
6  if (!name || !desc) return(-1);
7  if ((km->name = owl_strdup(name)) == NULL) return(-1);
8  if ((km->desc = owl_strdup(desc)) == NULL) return(-1);
9  if (0 != owl_list_create(&km->bindings)) return(-1);
10  km->submap = NULL;
11  km->default_fn = default_fn;
12  km->prealways_fn = prealways_fn;
13  km->postalways_fn = postalways_fn;
14  return(0);
15}
16
17/* note that this will free the memory for the bindings! */
18void owl_keymap_free(owl_keymap *km) {
19  owl_free(km->name);
20  owl_free(km->desc);
21  owl_list_free_all(&km->bindings, (void(*)(void*))owl_keybinding_free_all);
22}
23
24void owl_keymap_set_submap(owl_keymap *km, owl_keymap *submap) {
25  km->submap = submap;
26}
27
28/* creates and adds a key binding */
29int owl_keymap_create_binding(owl_keymap *km, char *keyseq, char *command, void (*function_fn)(void), char *desc) {
30  owl_keybinding *kb, *curkb;
31  int i;
32
33  if ((kb = owl_malloc(sizeof(owl_keybinding))) == NULL) return(-1);
34  if (0 != owl_keybinding_init(kb, keyseq, command, function_fn, desc)) {
35    owl_free(kb);
36    return(-1);
37  }
38  /* see if another matching binding, and if so remove it.
39   * otherwise just add this one.
40   */
41  for (i = owl_list_get_size(&km->bindings)-1; i>=0; i--) {
42    curkb = (owl_keybinding*)owl_list_get_element(&km->bindings, i);
43    if (owl_keybinding_equal(curkb, kb)) {
44      owl_list_remove_element(&km->bindings, i);
45      owl_keybinding_free_all(curkb);
46    }
47  }
48  return owl_list_append_element(&km->bindings, kb); 
49}
50
51/* returns a summary line describing this keymap.  the caller must free. */
52char *owl_keymap_summary(owl_keymap *km) {
53  char *s;
54  int slen;
55  if (!km || !km->name || !km->desc) return NULL;
56  slen = strlen(km->name)+strlen(km->desc)+20;
57  s = owl_malloc(slen);
58  snprintf(s, slen-1, "%-15s - %s", km->name, km->desc);
59  return s;
60}
61
62/* Appends details about the keymap to fm */
63void owl_keymap_get_details(owl_keymap *km, owl_fmtext *fm) {
64  int i, nbindings; 
65  owl_keybinding *kb;
66 
67  owl_fmtext_append_bold(fm, "KEYMAP - ");
68  owl_fmtext_append_bold(fm, km->name);
69  owl_fmtext_append_normal(fm, "\n");
70  if (km->desc) {
71    owl_fmtext_append_normal(fm, OWL_TABSTR "Purpose:    ");
72    owl_fmtext_append_normal(fm, km->desc);
73    owl_fmtext_append_normal(fm, "\n");
74  }
75  if (km->submap) {
76    owl_fmtext_append_normal(fm, OWL_TABSTR "Has submap: ");
77    owl_fmtext_append_normal(fm, km->submap->name);
78    owl_fmtext_append_normal(fm, "\n");
79  }
80    owl_fmtext_append_normal(fm, "\n");
81  if (km->default_fn) {
82    owl_fmtext_append_normal(fm, OWL_TABSTR
83     "Has a default keypress handler (default_fn).\n");
84  }
85  if (km->prealways_fn) {
86    owl_fmtext_append_normal(fm, OWL_TABSTR
87     "Executes a function (prealways_fn) on every keypress.\n");
88  }
89  if (km->postalways_fn) {
90    owl_fmtext_append_normal(fm, OWL_TABSTR
91     "Executes a function (postalways_fn) after handling every keypress.\n");
92  }
93
94  owl_fmtext_append_bold(fm, "\nKey bindings:\n\n"); 
95  nbindings = owl_list_get_size(&km->bindings);
96  for (i=0; i<nbindings; i++) {
97    char buff[100];
98    owl_cmd *cmd;
99    char *tmpdesc, *desc = "";
100
101    kb = owl_list_get_element(&km->bindings, i);
102    owl_keybinding_tostring(kb, buff, 100);
103    owl_fmtext_append_normal(fm, OWL_TABSTR);
104    owl_fmtext_append_normal(fm, buff);
105    owl_fmtext_append_spaces(fm, 11-strlen(buff));
106    owl_fmtext_append_normal(fm, " - ");
107    if (kb->desc && *kb->desc) {
108      desc = kb->desc;
109    } else if ((cmd=owl_function_get_cmd(kb->command))
110               && (tmpdesc = owl_cmd_get_summary(cmd))) {
111      desc = tmpdesc;
112    }
113    owl_fmtext_append_normal(fm, desc);
114    if (kb->command && *(kb->command)) {
115      owl_fmtext_append_normal(fm, "   [");
116      owl_fmtext_append_normal(fm, kb->command);
117      owl_fmtext_append_normal(fm, "]");
118    } 
119    owl_fmtext_append_normal(fm, "\n");
120  }
121}
122
123
124
125/***********************************************************************/
126/***************************** KEYHANDLER ******************************/
127/***********************************************************************/
128
129/* NOTE: keyhandler has private access to the internals of keymap */
130
131int owl_keyhandler_init(owl_keyhandler *kh) {
132  if (0 != owl_dict_create(&kh->keymaps)) return(-1); 
133  kh->active = NULL;
134  owl_keyhandler_reset(kh);
135  return(0);
136}
137
138/* adds a new keymap */
139void owl_keyhandler_add_keymap(owl_keyhandler *kh, owl_keymap *km) {
140  owl_dict_insert_element(&kh->keymaps, km->name, km, NULL);
141}
142
143owl_keymap *owl_keyhandler_create_and_add_keymap(owl_keyhandler *kh, char *name, char *desc, void (*default_fn)(int), void (*prealways_fn)(int), void (*postalways_fn)(int)) {
144  owl_keymap *km;
145  km = (owl_keymap*)owl_malloc(sizeof(owl_keymap));
146  if (!km) return NULL;
147  owl_keymap_init(km, name, desc, default_fn, prealways_fn, postalways_fn);
148  owl_keyhandler_add_keymap(kh, km);
149  return km;
150}
151
152/* resets state and clears out key stack */
153void owl_keyhandler_reset(owl_keyhandler *kh) {
154  kh->in_esc = 0;
155  memset(kh->kpstack, 0, (OWL_KEYMAP_MAXSTACK+1)*sizeof(int));
156  kh->kpstackpos = -1;
157}
158
159owl_keymap *owl_keyhandler_get_keymap(owl_keyhandler *kh, char *mapname) {
160  return (owl_keymap*)owl_dict_find_element(&kh->keymaps, mapname);
161}
162
163/* free the list with owl_cmddict_namelist_free */
164void owl_keyhandler_get_keymap_names(owl_keyhandler *kh, owl_list *l) {
165  owl_dict_get_keys(&kh->keymaps, l);
166}
167
168void owl_keyhandler_keymap_namelist_free(owl_list *l) {
169  owl_list_free_all(l, owl_free);
170}
171
172
173
174/* sets the active keymap, which will also reset any key state.
175 * returns the new keymap, or NULL on failure. */
176owl_keymap *owl_keyhandler_activate(owl_keyhandler *kh, char *mapname) {
177  owl_keymap *km;
178  if (kh->active && !strcmp(mapname, kh->active->name)) return(kh->active);
179  km = (owl_keymap*)owl_dict_find_element(&kh->keymaps, mapname);
180  if (!km) return(NULL);
181  owl_keyhandler_reset(kh);
182  kh->active = km;
183  return(km);
184}
185
186/* processes a keypress.  returns 0 if the keypress was handled,
187 * 1 if not handled, -1 on error, and -2 if j==ERR. */
188int owl_keyhandler_process(owl_keyhandler *kh, int j) {
189  owl_keymap     *km;
190  owl_keybinding *kb;
191  int i, match;
192
193  if (!kh->active) {
194    owl_function_makemsg("No active keymap!!!");
195    return(-1);
196  }
197  if (j==ERR) {
198        return(-1);
199  }
200
201  owl_function_debugmsg("processkey: got key %d, active keymap %s, stack at %d",
202                        j, kh->active->name, kh->kpstackpos);
203
204  /* deal with ESC prefixing */
205  if (!kh->in_esc && j==27) {
206    kh->in_esc = 1;
207    return(0);
208  }
209  if (kh->in_esc) {
210    j = META(j);
211    kh->in_esc = 0;
212  }
213 
214  kh->kpstack[++(kh->kpstackpos)] = j;
215  if (kh->kpstackpos >= OWL_KEYMAP_MAXSTACK) {
216    owl_keyhandler_reset(kh);
217    owl_function_makemsg("Too many prefix keys pressed...");
218    return(-1);
219  }
220
221  /* deal with the always_fn for the map and submaps */
222  for (km=kh->active; km; km=km->submap) {
223    if (km->prealways_fn) {
224      km->prealways_fn(j);
225    }
226  }
227
228  /* search for a match.  goes through active keymap and then
229   * through submaps... TODO:  clean this up so we can pull
230   * keyhandler and keymap apart.  */
231  for (km=kh->active; km; km=km->submap) {
232    for (i=owl_list_get_size(&km->bindings)-1; i>=0; i--) {
233      kb = (owl_keybinding*)owl_list_get_element(&km->bindings, i);
234      match = owl_keybinding_match(kb, kh->kpstack);
235      if (match == 1) {         /* subset match */
236        owl_function_debugmsg("processkey: found subset match in %s", km->name);
237        return(0);
238      } else if (match == 2) {  /* exact match */
239        owl_function_debugmsg("processkey: found exact match in %s", km->name);
240        owl_keybinding_execute(kb, j);
241        owl_keyhandler_reset(kh);
242        if (km->postalways_fn) {
243          km->postalways_fn(j);
244        }
245        return(0);
246      }
247    }
248  }
249
250  /* see if a default action exists for the active keymap */
251  if (kh->active->default_fn && kh->kpstackpos<1) {
252    owl_function_debugmsg("processkey: executing default_fn");
253    kh->active->default_fn(j);
254    owl_keyhandler_reset(kh);
255    if (kh->active->postalways_fn) {
256      kh->active->postalways_fn(j);
257    }
258    return(0);
259  }
260
261  owl_keyhandler_invalidkey(kh);
262  /* unable to handle */
263  return(1); 
264}
265
266void owl_keyhandler_invalidkey(owl_keyhandler *kh) {
267    char kbbuff[500];
268    owl_keybinding_stack_tostring(kh->kpstack, kbbuff, 500);
269    owl_function_makemsg("'%s' is not a valid key in this context.", kbbuff);
270    owl_keyhandler_reset(kh);
271}
Note: See TracBrowser for help on using the repository browser.