diff --git a/terminatorlib/config.py b/terminatorlib/config.py index d50e4e5c..4fbb907d 100644 --- a/terminatorlib/config.py +++ b/terminatorlib/config.py @@ -720,7 +720,20 @@ class ConfigBase(Borg): for section_name in ['global_config', 'keybindings']: dbg('Processing section: %s' % section_name) section = getattr(self, section_name) - parser[section_name] = dict_diff(DEFAULTS[section_name], section) + if section_name == 'keybindings': + from terminatorlib.plugin import KeyBindUtil + # for plugin KeyBindUtil assist in plugin_util + keybindutil = KeyBindUtil(); + keyb_keys = keybindutil.get_all_act_to_keys() + # we only need keys as a reference so to match them + # against new values + keyb_keys = dict.fromkeys(keyb_keys, "") + + default_merged_section = {**keyb_keys, **DEFAULTS[section_name]} + merged_section = {**keyb_keys, **section} + parser[section_name] = dict_diff(default_merged_section, merged_section) + else: + parser[section_name] = dict_diff(DEFAULTS[section_name], section) from .configjson import JSON_PROFILE_NAME, JSON_LAYOUT_NAME diff --git a/terminatorlib/plugin.py b/terminatorlib/plugin.py index ac9d3aa9..49a972e7 100644 --- a/terminatorlib/plugin.py +++ b/terminatorlib/plugin.py @@ -197,3 +197,138 @@ class MenuItem(Plugin): def callback(self, menuitems, menu, terminal): """Callback to transform the enclosed URL""" raise NotImplementedError + + +""" +-Basic plugin util for key-press handling, has all mapping to be used +in layout keybindings + +Vishweshwar Saran Singh Deo vssdeo@gmail.com +""" + +from gi.repository import Gtk, Gdk +from terminatorlib.keybindings import Keybindings, KeymapError + +PLUGIN_UTIL_DESC = 0 +PLUGIN_UTIL_ACT = 1 +PLUGIN_UTIL_KEYS = 2 + +class KeyBindUtil: + + keybindings = Keybindings() + + map_key_to_act = {} + map_act_to_keys = {} + map_act_to_desc = {} + + def __init__(self, config=None): + self.config = config + + #Example + # bind + # first param is desc, second is action str + # self.keyb.bindkey([PluginUrlFindNext , PluginUrlActFindNext, "j"]) + # + # get action name + # act = self.keyb.keyaction(event) + + # if act == "url_find_next": + + + #check map key_val_mask -> action + def _check_keybind_change(self, key): + act = key[PLUGIN_UTIL_ACT] + for key_val_mask in self.map_key_to_act: + old_act = self.map_key_to_act[key_val_mask] + if act == old_act: + return key_val_mask + return None + + #check in config before binding + def bindkey_check_config(self, key): + if not self.config: + raise Warning("bindkey_check_config called without config init") + + actstr = key[PLUGIN_UTIL_ACT] + kbsect = self.config.base.get_item('keybindings') + keystr = kbsect[actstr] if actstr in kbsect else "" + dbg("bindkey_check_config:action (%s) key str:(%s)" % (actstr, keystr)) + if len(keystr): + key[PLUGIN_UTIL_KEYS] = keystr + dbg("found new Action->KeyVal in config: (%s, %s)" + % (actstr, keystr)); + self.bindkey(key) + + def bindkey(self, key): + (keyval, mask) = self.keybindings._parsebinding(key[PLUGIN_UTIL_KEYS]) + keyval = Gdk.keyval_to_lower(keyval) + mask = Gdk.ModifierType(mask) + + ret = (keyval, mask) + dbg("bindkey: (%s) (%s)" % (key[PLUGIN_UTIL_KEYS], str(ret))) + + #remove if any old key_val_mask + old_key_val_mask = self._check_keybind_change(key) + if old_key_val_mask: + dbg("found old key binding, removing: (%s)" % str(old_key_val_mask)) + del self.map_key_to_act[old_key_val_mask] + + #map key-val-mask to action, used to ease key-press management + self.map_key_to_act[ret] = key[PLUGIN_UTIL_ACT] + + + #map action to key-combo-str, used in preferences->keybinding + self.map_act_to_keys[key[PLUGIN_UTIL_ACT]] = key[PLUGIN_UTIL_KEYS] + #map action to key-combo description, in used preferences->keybinding + self.map_act_to_desc[key[PLUGIN_UTIL_ACT]] = key[PLUGIN_UTIL_DESC] + + def unbindkey(self, key): + + # Suppose user changed the key-combo and its diff from + # what the plugin had set by default, we need to get + # current key-combo + act = key[PLUGIN_UTIL_ACT] + act_keys = self.map_act_to_keys[act] + + (keyval, mask) = self.keybindings._parsebinding(act_keys) + keyval = Gdk.keyval_to_lower(keyval) + mask = Gdk.ModifierType(mask) + + ret = (keyval, mask) + dbg("unbindkey: (%s) (%s)" % (key[PLUGIN_UTIL_KEYS], str(ret))) + + # FIXME keys should always be there, can also use .pop(key, None) + # lets do it after testing + del self.map_key_to_act[ret] + del self.map_act_to_keys[key[PLUGIN_UTIL_ACT]] + del self.map_act_to_desc[key[PLUGIN_UTIL_ACT]] + + + def keyaction(self, event): + #FIXME MOD2 mask comes in the event, remove + event.state &= ~Gdk.ModifierType.MOD2_MASK + + keyval = Gdk.keyval_to_lower(event.keyval) + ret = (keyval, event.state) + dbg("keyaction: (%s)" % str(ret)) + return self.map_key_to_act.get(ret, None) + + def get_act_to_keys(self, key): + return self.map_act_to_keys.get(key) + + def get_all_act_to_keys(self): + return self.map_act_to_keys + + def get_all_act_to_desc(self): + return self.map_act_to_desc + + def get_act_to_desc(self, act): + return self.map_act_to_desc.get(act) + + #get action to key binding from config + def get_act_to_keys_config(self, act): + if not self.config: + raise Warning("get_keyvalmask_for_act called without config init") + + keybindings = self.config["keybindings"] + return keybindings.get(act) diff --git a/terminatorlib/prefseditor.py b/terminatorlib/prefseditor.py index ed788513..d5933c4b 100755 --- a/terminatorlib/prefseditor.py +++ b/terminatorlib/prefseditor.py @@ -18,6 +18,8 @@ from .terminator import Terminator from .plugin import PluginRegistry from .version import APP_NAME +from .plugin import KeyBindUtil + def get_color_string(widcol): return('#%02x%02x%02x' % (widcol.red>>8, widcol.green>>8, widcol.blue>>8)) @@ -472,6 +474,15 @@ class PrefsEditor: liststore = widget.get_model() liststore.set_sort_column_id(0, Gtk.SortType.ASCENDING) keybindings = self.config['keybindings'] + + keybindutil = KeyBindUtil() + plugin_keyb_act = keybindutil.get_all_act_to_keys() + plugin_keyb_desc = keybindutil.get_all_act_to_desc() + #merge give preference to main bindings over plugin + keybindings = {**plugin_keyb_act, **keybindings} + self.keybindingnames = {**plugin_keyb_desc, **self.keybindingnames} + #dbg("appended actions %s names %s" % (keybindings, self.keybindingnames)) + for keybinding in keybindings: keyval = 0 mask = 0 @@ -1900,8 +1911,14 @@ class PrefsEditor: current_binding = liststore.get_value(liststore.get_iter(path), 0) parsed_accel = Gtk.accelerator_parse(accel) + keybindutil = KeyBindUtil() + keybindings = self.config["keybindings"] + #merge give preference to main bindings over plugin + plugin_keyb_act = keybindutil.get_all_act_to_keys() + keybindings = {**plugin_keyb_act, **keybindings} + duplicate_bindings = [] - for conf_binding, conf_accel in self.config["keybindings"].items(): + for conf_binding, conf_accel in keybindings.items(): if conf_accel is None: continue @@ -1944,6 +1961,16 @@ class PrefsEditor: binding = liststore.get_value(liststore.get_iter(path), 0) accel = Gtk.accelerator_name(key, mods) self.config['keybindings'][binding] = accel + + plugin_keyb_desc = keybindutil.get_act_to_desc(binding) + if plugin_keyb_desc: + dbg("modifying plugin binding: %s, %s, %s" % + (plugin_keyb_desc, binding, accel)) + keybindutil.bindkey([plugin_keyb_desc, binding, accel]) + else: + dbg("skipping: %s" % binding) + pass + self.config.save() def on_cellrenderer_accel_cleared(self, liststore, path):