2 * ion/ioncore/conf-bindings.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * Ion is free software; you can redistribute it and/or modify it under
7 * the terms of the GNU Lesser General Public License as published by
8 * the Free Software Foundation; either version 2.1 of the License, or
9 * (at your option) any later version.
15 #include <X11/keysymdef.h>
17 #include <libtu/map.h>
21 #include <libextl/readconfig.h>
23 #include <libextl/extl.h>
24 #include "conf-bindings.h"
33 static StringIntMap state_map[]={
36 {"Control", ControlMask},
42 {"AnyModifier", AnyModifier},
47 static StringIntMap button_map[]={
55 {"AnyButton", AnyButton},
60 bool ioncore_parse_keybut(const char *str, uint *mod_ret, uint *ksb_ret,
61 bool button, bool init_any)
64 int keysym=NoSymbol, i;
68 *mod_ret=(init_any && !button ? AnyModifier : 0);
84 keysym=XStringToKeysym(p);
85 #ifdef CF_SUN_F1X_REMAP
88 else if(keysym==XK_F12)
93 if(!button && keysym!=NoSymbol){
95 if(*ksb_ret!=NoSymbol){
96 warn_obj(str, TR("Insane key combination."));
99 if(XKeysymToKeycode(ioncore_g.dpy, keysym)==0){
100 warn_obj(str, TR("Could not convert keysym to keycode."));
105 i=stringintmap_ndx(state_map, p);
108 i=stringintmap_ndx(button_map, p);
111 warn(TR("Unknown button \"%s\"."), p);
115 if(!button || *ksb_ret!=NoSymbol){
116 warn_obj(str, TR("Insane button combination."));
119 *ksb_ret=button_map[i].value;
121 if(*mod_ret==AnyModifier){
123 warn_obj(str, TR("Insane modifier combination."));
126 *mod_ret=state_map[i].value;
129 if(*mod_ret!=0 && state_map[i].value==AnyModifier){
130 warn_obj(str, TR("Insane modifier combination."));
133 *mod_ret|=state_map[i].value;
158 /*{{{ bindmap_defbindings */
161 static bool do_action(WBindmap *bindmap, const char *str,
162 ExtlFn func, uint act, uint mod, uint ksb,
168 warn(TR("Can not wait on modifiers when no modifiers set in \"%s\"."),
177 binding.kcb=(act==BINDING_KEYPRESS ? XKeysymToKeycode(ioncore_g.dpy, ksb) : ksb);
181 if(func!=extl_fn_none()){
182 binding.func=extl_ref_fn(func);
183 if(bindmap_add_binding(bindmap, &binding))
185 extl_unref_fn(binding.func);
186 warn(TR("Unable to add binding %s."), str);
189 if(bindmap_remove_binding(bindmap, &binding))
191 warn(TR("Unable to remove binding %s."), str);
198 static bool do_submap(WBindmap *bindmap, const char *str,
199 ExtlTab subtab, uint action, uint mod, uint ksb)
201 WBinding binding, *bnd;
204 if(action!=BINDING_KEYPRESS)
207 kcb=XKeysymToKeycode(ioncore_g.dpy, ksb);
208 bnd=bindmap_lookup_binding(bindmap, action, mod, kcb);
210 if(bnd!=NULL && bnd->submap!=NULL && bnd->state==mod)
211 return bindmap_defbindings(bnd->submap, subtab, TRUE);
214 binding.act=BINDING_KEYPRESS;
219 binding.func=extl_fn_none();
220 binding.submap=create_bindmap();
222 if(binding.submap==NULL)
225 if(bindmap_add_binding(bindmap, &binding))
226 return bindmap_defbindings(binding.submap, subtab, TRUE);
228 binding_deinit(&binding);
230 warn(TR("Unable to add submap for binding %s."), str);
236 static StringIntMap action_map[]={
237 {"kpress", BINDING_KEYPRESS},
238 {"mpress", BINDING_BUTTONPRESS},
239 {"mclick", BINDING_BUTTONCLICK},
240 {"mdblclick", BINDING_BUTTONDBLCLICK},
241 {"mdrag", BINDING_BUTTONMOTION},
246 static bool do_entry(WBindmap *bindmap, ExtlTab tab,
247 const StringIntMap *areamap, bool init_any)
250 char *action_str=NULL, *ksb_str=NULL, *area_str=NULL;
259 if(!extl_table_gets_s(tab, "action", &action_str)){
260 warn(TR("Binding type not set."));
264 if(strcmp(action_str, "kpress_wait")==0){
265 action=BINDING_KEYPRESS;
268 action=stringintmap_value(action_map, action_str, -1);
270 warn(TR("Unknown binding type \"%s\"."), action_str);
275 if(!extl_table_gets_s(tab, "kcb", &ksb_str))
278 if(!ioncore_parse_keybut(ksb_str, &mod, &ksb,
279 (action!=BINDING_KEYPRESS && action!=-1),
284 if(extl_table_gets_t(tab, "submap", &subtab)){
285 ret=do_submap(bindmap, ksb_str, subtab, action, mod, ksb);
286 extl_unref_table(subtab);
289 if(extl_table_gets_s(tab, "area", &area_str)){
290 area=stringintmap_value(areamap, area_str, -1);
292 warn(TR("Unknown area \"%s\" for binding %s."),
299 if(!extl_table_gets_f(tab, "func", &func)){
300 /*warn("Function for binding %s not set/nil/undefined.", ksb_str);
304 ret=do_action(bindmap, ksb_str, func, action, mod, ksb, area, wr);
320 bool bindmap_defbindings(WBindmap *bindmap, ExtlTab tab, bool submap)
325 n=extl_table_get_n(tab);
328 if(extl_table_geti_t(tab, i, &ent)){
329 nok+=do_entry(bindmap, ent, bindmap->areamap, submap);
330 extl_unref_table(ent);
333 warn(TR("Unable to get bindmap entry %d."), i);
342 /*{{{ bindmap_getbindings */
345 static char *get_mods(uint state)
350 if(state==AnyModifier){
351 ret=scopy("AnyModifier+");
354 for(i=0; i<=MOD5_NDX; i++){
357 if((int)(state&state_map[i].value)==state_map[i].value){
359 ret=scat3(ret, state_map[i].string, "+");
369 static char *get_key(char *mods, uint ksb)
371 const char *s=XKeysymToString(ksb);
375 warn(TR("Unable to convert keysym to string."));
379 return scat(mods, s);
383 static char *get_button(char *mods, uint ksb)
385 const char *s=stringintmap_key(button_map, ksb, NULL);
389 warn(TR("Unable to convert button to string."));
393 return scat(mods, s);
397 static bool get_kpress(WBindmap *bindmap, WBinding *b, ExtlTab t)
403 extl_table_sets_s(t, "action", "kpress_wait");
405 extl_table_sets_s(t, "action", "kpress");
407 mods=get_mods(b->state);
412 key=get_key(mods, b->ksb);
419 extl_table_sets_s(t, "kcb", key);
424 ExtlTab stab=bindmap_getbindings(b->submap);
425 extl_table_sets_t(t, "submap", stab);
427 extl_table_sets_f(t, "func", b->func);
434 static bool get_mact(WBindmap *bindmap, WBinding *b, ExtlTab t)
439 extl_table_sets_s(t, "action", stringintmap_key(action_map, b->act, NULL));
441 mods=get_mods(b->state);
446 button=get_button(mods, b->ksb);
453 extl_table_sets_s(t, "kcb", button);
457 if(b->area!=0 && bindmap->areamap!=NULL)
458 extl_table_sets_s(t, "area",
459 stringintmap_key(bindmap->areamap, b->area, NULL));
461 extl_table_sets_f(t, "func", b->func);
467 static ExtlTab getbinding(WBindmap *bindmap, WBinding *b)
469 ExtlTab t=extl_create_table();
471 if(b->act==BINDING_KEYPRESS){
472 if(get_kpress(bindmap, b, t))
475 if(get_mact(bindmap, b, t))
479 return extl_unref_table(t);
483 ExtlTab bindmap_getbindings(WBindmap *bindmap)
491 tab=extl_create_table();
493 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
494 btab=getbinding(bindmap, b);
495 extl_table_seti_t(tab, n+1, btab);
496 extl_unref_table(btab);