terminator/terminatorlib/keybindings.py
2009-05-07 01:44:59 +01:00

98 lines
2.8 KiB
Python

import re, gtk
import terminatorlib.config
from terminatorlib.config import err
class KeymapError(Exception):
def __init__(self, value):
Exception.__init__(self, value)
self.value = value
self.action = 'unknown'
def __str__(self):
return "Keybinding '%s' invalid: %s" % (self.action, self.value)
Modifier = re.compile('<([^<]+)>')
class TerminatorKeybindings:
modifiers = {
'ctrl': gtk.gdk.CONTROL_MASK,
'control': gtk.gdk.CONTROL_MASK,
'shift': gtk.gdk.SHIFT_MASK,
'alt': gtk.gdk.MOD1_MASK
}
empty = {}
def __init__(self):
self.keymap = gtk.gdk.keymap_get_default()
self.configure({})
def configure(self, bindings):
self.keys = bindings
self.reload()
def reload(self):
self._lookup = {}
self._masks = 0
for action, bindings in self.keys.items():
if not isinstance(bindings, tuple):
bindings = (bindings,)
for binding in bindings:
if binding is None:
continue
try:
keyval, mask = self._parsebinding(binding)
# Does much the same, but with poorer error handling.
#keyval, mask = gtk.accelerator_parse(binding)
except KeymapError, e:
e.action = action
raise e
else:
if mask & gtk.gdk.SHIFT_MASK:
if keyval == gtk.keysyms.Tab:
keyval = gtk.keysyms.ISO_Left_Tab
mask &= ~gtk.gdk.SHIFT_MASK
else:
keyvals = gtk.gdk.keyval_convert_case(keyval)
if keyvals[0] != keyvals[1]:
keyval = keyvals[1]
mask &= ~gtk.gdk.SHIFT_MASK
else:
keyval = gtk.gdk.keyval_to_lower(keyval)
self._lookup.setdefault(mask, {})
self._lookup[mask][keyval] = action
self._masks |= mask
def _parsebinding(self, binding):
mask = 0
modifiers = re.findall(Modifier, binding)
if modifiers:
for modifier in modifiers:
mask |= self._lookup_modifier(modifier)
key = re.sub(Modifier, '', binding)
if key == '':
raise KeymapError('No key found')
keyval = gtk.gdk.keyval_from_name(key)
if keyval == 0:
raise KeymapError("Key '%s' is unrecognised" % key)
return (keyval, mask)
def _lookup_modifier(self, modifier):
try:
return self.modifiers[modifier.lower()]
except KeyError:
raise KeymapError("Unhandled modifier '<%s>'" % modifier)
def lookup(self, event):
try:
keyval, egroup, level, consumed = self.keymap.translate_keyboard_state(event.hardware_keycode, event.state & ~gtk.gdk.LOCK_MASK, event.group)
except TypeError:
err ("keybindings.lookup failed to translate keyboard event: %s"%dir(event))
return None
mask = (event.state & ~consumed) & self._masks
return self._lookup.get(mask, self.empty).get(keyval, None)