2 * ion/ioncore/conf-bindings.c
4 * Copyright (c) Tuomo Valkonen 1999-2007.
6 * See the included file LICENSE for details.
12 #include <X11/keysymdef.h>
14 #include <libtu/map.h>
18 #include <libextl/readconfig.h>
20 #include <libextl/extl.h>
21 #include "conf-bindings.h"
30 static StringIntMap state_map[]={
33 {"Control", ControlMask},
39 {"AnyModifier", AnyModifier},
44 static StringIntMap button_map[]={
52 {"AnyButton", AnyButton},
57 bool ioncore_parse_keybut(const char *str, uint *mod_ret, uint *ksb_ret,
58 bool button, bool init_any)
61 int keysym=NoSymbol, i;
65 *mod_ret=(init_any && !button ? AnyModifier : 0);
81 keysym=XStringToKeysym(p);
82 #ifdef CF_SUN_F1X_REMAP
85 else if(keysym==XK_F12)
90 if(!button && keysym!=NoSymbol){
92 if(*ksb_ret!=NoSymbol){
93 warn_obj(str, TR("Insane key combination."));
96 if(XKeysymToKeycode(ioncore_g.dpy, keysym)==0){
97 warn_obj(str, TR("Could not convert keysym to keycode."));
102 i=stringintmap_ndx(state_map, p);
105 i=stringintmap_ndx(button_map, p);
108 warn(TR("Unknown button \"%s\"."), p);
112 if(!button || *ksb_ret!=NoSymbol){
113 warn_obj(str, TR("Insane button combination."));
116 *ksb_ret=button_map[i].value;
118 if(*mod_ret==AnyModifier){
120 warn_obj(str, TR("Insane modifier combination."));
123 *mod_ret=state_map[i].value;
126 if(*mod_ret!=0 && state_map[i].value==AnyModifier){
127 warn_obj(str, TR("Insane modifier combination."));
130 *mod_ret|=state_map[i].value;
155 /*{{{ bindmap_defbindings */
158 static bool do_action(WBindmap *bindmap, const char *str,
159 ExtlFn func, uint act, uint mod, uint ksb,
165 warn(TR("Can not wait on modifiers when no modifiers set in \"%s\"."),
174 binding.kcb=(act==BINDING_KEYPRESS ? XKeysymToKeycode(ioncore_g.dpy, ksb) : ksb);
178 if(func!=extl_fn_none()){
179 binding.func=extl_ref_fn(func);
180 if(bindmap_add_binding(bindmap, &binding))
182 extl_unref_fn(binding.func);
183 warn(TR("Unable to add binding %s."), str);
186 if(bindmap_remove_binding(bindmap, &binding))
188 warn(TR("Unable to remove binding %s."), str);
195 static bool do_submap(WBindmap *bindmap, const char *str,
196 ExtlTab subtab, uint action, uint mod, uint ksb)
198 WBinding binding, *bnd;
201 if(action!=BINDING_KEYPRESS)
204 kcb=XKeysymToKeycode(ioncore_g.dpy, ksb);
206 bnd=bindmap_lookup_binding(bindmap, action, mod, kcb);
208 if(bnd!=NULL && bnd->submap!=NULL && bnd->state==mod)
209 return bindmap_defbindings(bnd->submap, subtab, TRUE);
212 binding.act=BINDING_KEYPRESS;
217 binding.func=extl_fn_none();
218 binding.submap=create_bindmap();
220 if(binding.submap==NULL)
223 if(bindmap_add_binding(bindmap, &binding))
224 return bindmap_defbindings(binding.submap, subtab, TRUE);
226 binding_deinit(&binding);
228 warn(TR("Unable to add submap for binding %s."), str);
234 static StringIntMap action_map[]={
235 {"kpress", BINDING_KEYPRESS},
236 {"mpress", BINDING_BUTTONPRESS},
237 {"mclick", BINDING_BUTTONCLICK},
238 {"mdblclick", BINDING_BUTTONDBLCLICK},
239 {"mdrag", BINDING_BUTTONMOTION},
240 {"submap_enter", BINDING_SUBMAP_ENTER},
241 {"submap_wait", BINDING_SUBMAP_RELEASEMOD},
242 /*{"submap_leave", BINDING_SUBMAP_LEAVE},*/
247 static bool do_entry(WBindmap *bindmap, ExtlTab tab,
248 const StringIntMap *areamap, bool init_any)
251 char *action_str=NULL, *ksb_str=NULL, *area_str=NULL;
260 if(!extl_table_gets_s(tab, "action", &action_str)){
261 warn(TR("Binding type not set."));
265 if(strcmp(action_str, "kpress_wait")==0){
266 action=BINDING_KEYPRESS;
269 action=stringintmap_value(action_map, action_str, -1);
271 warn(TR("Unknown binding type \"%s\"."), action_str);
276 if(!BINDING_IS_PSEUDO(action)){
277 if(!extl_table_gets_s(tab, "kcb", &ksb_str))
280 if(!ioncore_parse_keybut(ksb_str, &mod, &ksb,
281 (action!=BINDING_KEYPRESS && action!=-1),
287 if(extl_table_gets_t(tab, "submap", &subtab)){
288 ret=do_submap(bindmap, ksb_str, subtab, action, mod, ksb);
289 extl_unref_table(subtab);
292 if(extl_table_gets_s(tab, "area", &area_str)){
293 area=stringintmap_value(areamap, area_str, -1);
295 warn(TR("Unknown area \"%s\" for binding %s."),
302 if(!extl_table_gets_f(tab, "func", &func)){
303 /*warn("Function for binding %s not set/nil/undefined.", ksb_str);
307 ret=do_action(bindmap, ksb_str, func, action, mod, ksb, area, wr);
323 bool bindmap_defbindings(WBindmap *bindmap, ExtlTab tab, bool submap)
328 n=extl_table_get_n(tab);
331 if(extl_table_geti_t(tab, i, &ent)){
332 nok+=do_entry(bindmap, ent, bindmap->areamap, submap);
333 extl_unref_table(ent);
336 warn(TR("Unable to get bindmap entry %d."), i);
345 /*{{{ bindmap_getbindings */
348 static char *get_mods(uint state)
353 if(state==AnyModifier){
354 ret=scopy("AnyModifier+");
357 for(i=0; i<=MOD5_NDX; i++){
360 if((int)(state&state_map[i].value)==state_map[i].value){
362 ret=scat3(ret, state_map[i].string, "+");
372 static char *get_key(char *mods, uint ksb)
374 const char *s=XKeysymToString(ksb);
378 warn(TR("Unable to convert keysym to string."));
382 return scat(mods, s);
386 static char *get_button(char *mods, uint ksb)
388 const char *s=stringintmap_key(button_map, ksb, NULL);
392 warn(TR("Unable to convert button to string."));
396 return scat(mods, s);
400 static bool get_kpress(WBindmap *bindmap, WBinding *b, ExtlTab t)
406 extl_table_sets_s(t, "action", "kpress_wait");
408 extl_table_sets_s(t, "action", "kpress");
410 mods=get_mods(b->state);
415 key=get_key(mods, b->ksb);
422 extl_table_sets_s(t, "kcb", key);
427 ExtlTab stab=bindmap_getbindings(b->submap);
428 extl_table_sets_t(t, "submap", stab);
430 extl_table_sets_f(t, "func", b->func);
437 static bool get_mact(WBindmap *bindmap, WBinding *b, ExtlTab t)
442 extl_table_sets_s(t, "action", stringintmap_key(action_map, b->act, NULL));
444 mods=get_mods(b->state);
449 button=get_button(mods, b->ksb);
456 extl_table_sets_s(t, "kcb", button);
460 if(b->area!=0 && bindmap->areamap!=NULL)
461 extl_table_sets_s(t, "area",
462 stringintmap_key(bindmap->areamap, b->area, NULL));
464 extl_table_sets_f(t, "func", b->func);
470 static ExtlTab getbinding(WBindmap *bindmap, WBinding *b)
472 ExtlTab t=extl_create_table();
474 if(b->act==BINDING_KEYPRESS){
475 if(get_kpress(bindmap, b, t))
478 if(get_mact(bindmap, b, t))
482 return extl_unref_table(t);
486 ExtlTab bindmap_getbindings(WBindmap *bindmap)
494 tab=extl_create_table();
496 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
497 btab=getbinding(bindmap, b);
498 extl_table_seti_t(tab, n+1, btab);
499 extl_unref_table(btab);