2 * ion/ioncore/conf-bindings.c
4 * Copyright (c) Tuomo Valkonen 1999-2009.
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"
31 static StringIntMap state_map[]={
34 {"Control", ControlMask},
40 {"AnyModifier", AnyModifier},
45 static StringIntMap button_map[]={
53 {"AnyButton", AnyButton},
58 bool ioncore_parse_keybut(const char *str, uint *mod_ret, uint *ksb_ret,
59 bool button, bool init_any)
62 int keysym=NoSymbol, i;
66 *mod_ret=(init_any && !button ? AnyModifier : 0);
82 keysym=XStringToKeysym(p);
83 #ifdef CF_SUN_F1X_REMAP
86 else if(keysym==XK_F12)
91 if(!button && keysym!=NoSymbol){
93 if(*ksb_ret!=NoSymbol){
94 warn_obj(str, TR("Insane key combination."));
97 if(XKeysymToKeycode(ioncore_g.dpy, keysym)==0){
98 ioncore_warn_nolog("%s: %s", str,
99 TR("Could not convert keysym to keycode."));
104 i=stringintmap_ndx(state_map, p);
107 i=stringintmap_ndx(button_map, p);
110 warn(TR("Unknown button \"%s\"."), p);
114 if(!button || *ksb_ret!=NoSymbol){
115 warn_obj(str, TR("Insane button combination."));
118 *ksb_ret=button_map[i].value;
120 if(*mod_ret==AnyModifier){
122 warn_obj(str, TR("Insane modifier combination."));
125 *mod_ret=state_map[i].value;
128 if(*mod_ret!=0 && state_map[i].value==AnyModifier){
129 warn_obj(str, TR("Insane modifier combination."));
132 *mod_ret|=state_map[i].value;
157 /*{{{ bindmap_defbindings */
160 static bool do_action(WBindmap *bindmap, const char *str,
161 ExtlFn func, uint act, uint mod, uint ksb,
167 warn(TR("Can not wait on modifiers when no modifiers set in \"%s\"."),
176 binding.kcb=(act==BINDING_KEYPRESS ? XKeysymToKeycode(ioncore_g.dpy, ksb) : ksb);
180 if(func!=extl_fn_none()){
181 binding.func=extl_ref_fn(func);
182 if(bindmap_add_binding(bindmap, &binding))
184 extl_unref_fn(binding.func);
185 warn(TR("Unable to add binding %s."), str);
188 if(bindmap_remove_binding(bindmap, &binding))
190 /*warn(TR("Unable to remove binding %s."), str);*/
197 static bool do_submap(WBindmap *bindmap, const char *str,
198 ExtlTab subtab, uint action, uint mod, uint ksb)
200 WBinding binding, *bnd;
203 if(action!=BINDING_KEYPRESS)
206 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},
242 {"submap_enter", BINDING_SUBMAP_ENTER},
243 {"submap_wait", BINDING_SUBMAP_RELEASEMOD},
244 /*{"submap_leave", BINDING_SUBMAP_LEAVE},*/
249 static bool do_entry(WBindmap *bindmap, ExtlTab tab,
250 const StringIntMap *areamap, bool init_any)
253 char *action_str=NULL, *ksb_str=NULL, *area_str=NULL;
262 if(!extl_table_gets_s(tab, "action", &action_str)){
263 warn(TR("Binding type not set."));
267 if(strcmp(action_str, "kpress_wait")==0){
268 action=BINDING_KEYPRESS;
271 action=stringintmap_value(action_map, action_str, -1);
273 warn(TR("Unknown binding type \"%s\"."), action_str);
278 if(!BINDING_IS_PSEUDO(action)){
279 if(!extl_table_gets_s(tab, "kcb", &ksb_str))
282 if(!ioncore_parse_keybut(ksb_str, &mod, &ksb,
283 (action!=BINDING_KEYPRESS && action!=-1),
289 if(extl_table_gets_t(tab, "submap", &subtab)){
290 ret=do_submap(bindmap, ksb_str, subtab, action, mod, ksb);
291 extl_unref_table(subtab);
294 if(extl_table_gets_s(tab, "area", &area_str)){
295 area=stringintmap_value(areamap, area_str, -1);
297 warn(TR("Unknown area \"%s\" for binding %s."),
304 if(!extl_table_gets_f(tab, "func", &func)){
305 /*warn("Function for binding %s not set/nil/undefined.", ksb_str);
309 ret=do_action(bindmap, ksb_str, func, action, mod, ksb, area, wr);
325 bool bindmap_defbindings(WBindmap *bindmap, ExtlTab tab, bool submap)
330 n=extl_table_get_n(tab);
333 if(extl_table_geti_t(tab, i, &ent)){
334 nok+=do_entry(bindmap, ent, bindmap->areamap, submap);
335 extl_unref_table(ent);
338 warn(TR("Unable to get bindmap entry %d."), i);
347 /*{{{ bindmap_getbindings */
350 static char *get_mods(uint state)
355 if(state==AnyModifier){
356 ret=scopy("AnyModifier+");
359 for(i=0; i<=MOD5_NDX; i++){
362 if((int)(state&state_map[i].value)==state_map[i].value){
364 ret=scat3(ret, state_map[i].string, "+");
374 static char *get_key(char *mods, uint ksb)
376 const char *s=XKeysymToString(ksb);
380 warn(TR("Unable to convert keysym to string."));
384 return scat(mods, s);
388 static char *get_button(char *mods, uint ksb)
390 const char *s=stringintmap_key(button_map, ksb, NULL);
394 warn(TR("Unable to convert button to string."));
398 return scat(mods, s);
402 static bool get_kpress(WBindmap *bindmap, WBinding *b, ExtlTab t)
408 extl_table_sets_s(t, "action", "kpress_wait");
410 extl_table_sets_s(t, "action", "kpress");
412 mods=get_mods(b->state);
417 key=get_key(mods, b->ksb);
424 extl_table_sets_s(t, "kcb", key);
429 ExtlTab stab=bindmap_getbindings(b->submap);
430 extl_table_sets_t(t, "submap", stab);
432 extl_table_sets_f(t, "func", b->func);
439 static bool get_mact(WBindmap *bindmap, WBinding *b, ExtlTab t)
444 extl_table_sets_s(t, "action", stringintmap_key(action_map, b->act, NULL));
446 mods=get_mods(b->state);
451 button=get_button(mods, b->ksb);
458 extl_table_sets_s(t, "kcb", button);
462 if(b->area!=0 && bindmap->areamap!=NULL)
463 extl_table_sets_s(t, "area",
464 stringintmap_key(bindmap->areamap, b->area, NULL));
466 extl_table_sets_f(t, "func", b->func);
472 static ExtlTab getbinding(WBindmap *bindmap, WBinding *b)
474 ExtlTab t=extl_create_table();
476 if(b->act==BINDING_KEYPRESS){
477 if(get_kpress(bindmap, b, t))
480 if(get_mact(bindmap, b, t))
484 return extl_unref_table(t);
488 ExtlTab bindmap_getbindings(WBindmap *bindmap)
496 tab=extl_create_table();
498 FOR_ALL_BINDINGS(b, node, bindmap->bindings){
499 btab=getbinding(bindmap, b);
500 extl_table_seti_t(tab, n+1, btab);
501 extl_unref_table(btab);