source: keymap.c @ 7131cf2

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