~ubuntu-branches/ubuntu/saucy/terminator/saucy

« back to all changes in this revision

Viewing changes to terminatorlib/keybindings.py

  • Committer: Bazaar Package Importer
  • Author(s): Nicolas Valcárcel Scerpella (Canonical)
  • Date: 2010-04-07 17:10:31 UTC
  • mfrom: (1.1.7 upstream)
  • Revision ID: james.westby@ubuntu.com-20100407171031-35nsuj0tmbub0bj5
Tags: 0.92-0ubuntu1
* New upstream release
* Remove python-xdg from Recommends. (Closes: #567967)
* Downgrade python-gnome2 to Recommends.
* Update python-gtk2 dependency to (>= 2.14.0)
* Add python-keybinder to Recommends

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
#!/usr/bin/python
2
 
#    Terminator - multiple gnome terminals in one window
3
 
#    Copyright (C) 2006-2008  cmsj@tenshu.net
 
2
#  Terminator - multiple gnome terminals in one window
 
3
#   Copyright (C) 2006-2010  cmsj@tenshu.net
4
4
#
5
5
# This program is free software; you can redistribute it and/or modify
6
6
# it under the terms of the GNU General Public License as published by
24
24
 
25
25
import re
26
26
import gtk
27
 
from terminatorlib.config import err
 
27
from util import err
28
28
 
29
29
class KeymapError(Exception):
30
 
  """Custom exception for errors in keybinding configurations"""
31
 
  def __init__(self, value):
32
 
    Exception.__init__(self, value)
33
 
    self.value = value
34
 
    self.action = 'unknown'
 
30
    """Custom exception for errors in keybinding configurations"""
 
31
    def __init__(self, value):
 
32
        Exception.__init__(self, value)
 
33
        self.value = value
 
34
        self.action = 'unknown'
35
35
 
36
 
  def __str__(self):
37
 
    return "Keybinding '%s' invalid: %s" % (self.action, self.value)
 
36
    def __str__(self):
 
37
        return "Keybinding '%s' invalid: %s" % (self.action, self.value)
38
38
 
39
39
MODIFIER = re.compile('<([^<]+)>')
40
 
class TerminatorKeybindings:
41
 
  """Class to handle loading and lookup of Terminator keybindings"""
42
 
 
43
 
  modifiers = {
44
 
    'ctrl':  gtk.gdk.CONTROL_MASK,
45
 
    'control':  gtk.gdk.CONTROL_MASK,
46
 
    'shift': gtk.gdk.SHIFT_MASK,
47
 
    'alt':   gtk.gdk.MOD1_MASK,
48
 
    'super': gtk.gdk.SUPER_MASK,
49
 
  }
50
 
 
51
 
  empty = {}
52
 
  keys = None
53
 
  _masks = None
54
 
  _lookup = None
55
 
 
56
 
  def __init__(self):
57
 
    self.keymap = gtk.gdk.keymap_get_default()
58
 
    self.configure({})
59
 
 
60
 
  def configure(self, bindings):
61
 
    """Accept new bindings and reconfigure with them"""
62
 
    self.keys = bindings
63
 
    self.reload()
64
 
 
65
 
  def reload(self):
66
 
    """Parse bindings and mangle into an appropriate form"""
67
 
    self._lookup = {}
68
 
    self._masks = 0
69
 
    for action, bindings in self.keys.items():
70
 
      if not isinstance(bindings, tuple):
71
 
        bindings = (bindings,)
72
 
 
73
 
      for binding in bindings:
74
 
        if binding is None or binding == "None":
75
 
          continue
76
 
 
77
 
        try:
78
 
          keyval, mask = self._parsebinding(binding)
79
 
          # Does much the same, but with poorer error handling.
80
 
          #keyval, mask = gtk.accelerator_parse(binding)
81
 
        except KeymapError, ex:
82
 
          continue
83
 
        else:
84
 
          if mask & gtk.gdk.SHIFT_MASK:
85
 
            if keyval == gtk.keysyms.Tab:
86
 
              keyval = gtk.keysyms.ISO_Left_Tab
87
 
              mask &= ~gtk.gdk.SHIFT_MASK
88
 
            else:
89
 
              keyvals = gtk.gdk.keyval_convert_case(keyval)
90
 
              if keyvals[0] != keyvals[1]:
91
 
                keyval = keyvals[1]
92
 
                mask &= ~gtk.gdk.SHIFT_MASK
93
 
          else:
94
 
            keyval = gtk.gdk.keyval_to_lower(keyval)
95
 
          self._lookup.setdefault(mask, {})
96
 
          self._lookup[mask][keyval] = action
97
 
          self._masks |= mask
98
 
 
99
 
  def _parsebinding(self, binding):
100
 
    """Parse an individual binding using gtk's binding function"""
101
 
    mask = 0
102
 
    modifiers = re.findall(MODIFIER, binding)
103
 
    if modifiers:
104
 
      for modifier in modifiers:
105
 
        mask |= self._lookup_modifier(modifier)
106
 
    key = re.sub(MODIFIER, '', binding)
107
 
    if key == '':
108
 
      raise KeymapError('No key found')
109
 
    keyval = gtk.gdk.keyval_from_name(key)
110
 
    if keyval == 0:
111
 
      raise KeymapError("Key '%s' is unrecognised" % key)
112
 
    return (keyval, mask)
113
 
 
114
 
  def _lookup_modifier(self, modifier):
115
 
    """Map modifier names to gtk values"""
116
 
    try:
117
 
      return self.modifiers[modifier.lower()]
118
 
    except KeyError:
119
 
      raise KeymapError("Unhandled modifier '<%s>'" % modifier)
120
 
 
121
 
  def lookup(self, event):
122
 
    """Translate a keyboard event into a mapped key"""
123
 
    try:
124
 
      keyval, egroup, level, consumed = self.keymap.translate_keyboard_state(
125
 
                                        event.hardware_keycode, 
126
 
                                        event.state & ~gtk.gdk.LOCK_MASK, 
127
 
                                        event.group)
128
 
    except TypeError:
129
 
      err ("keybindings.lookup failed to translate keyboard event: %s" % 
130
 
           dir(event))
131
 
      return None
132
 
    mask = (event.state & ~consumed) & self._masks
133
 
    return self._lookup.get(mask, self.empty).get(keyval, None)
 
40
class Keybindings:
 
41
    """Class to handle loading and lookup of Terminator keybindings"""
 
42
 
 
43
    modifiers = {
 
44
        'ctrl':     gtk.gdk.CONTROL_MASK,
 
45
        'control':  gtk.gdk.CONTROL_MASK,
 
46
        'shift':    gtk.gdk.SHIFT_MASK,
 
47
        'alt':      gtk.gdk.MOD1_MASK,
 
48
        'super':    gtk.gdk.SUPER_MASK,
 
49
    }
 
50
 
 
51
    empty = {}
 
52
    keys = None
 
53
    _masks = None
 
54
    _lookup = None
 
55
 
 
56
    def __init__(self):
 
57
        self.keymap = gtk.gdk.keymap_get_default()
 
58
        self.configure({})
 
59
 
 
60
    def configure(self, bindings):
 
61
        """Accept new bindings and reconfigure with them"""
 
62
        self.keys = bindings
 
63
        self.reload()
 
64
 
 
65
    def reload(self):
 
66
        """Parse bindings and mangle into an appropriate form"""
 
67
        self._lookup = {}
 
68
        self._masks = 0
 
69
        for action, bindings in self.keys.items():
 
70
            if not isinstance(bindings, tuple):
 
71
                bindings = (bindings,)
 
72
 
 
73
            for binding in bindings:
 
74
                if binding is None or binding == "None":
 
75
                    continue
 
76
 
 
77
                try:
 
78
                    keyval, mask = self._parsebinding(binding)
 
79
                    # Does much the same, but with poorer error handling.
 
80
                    #keyval, mask = gtk.accelerator_parse(binding)
 
81
                except KeymapError:
 
82
                    continue
 
83
                else:
 
84
                    if mask & gtk.gdk.SHIFT_MASK:
 
85
                        if keyval == gtk.keysyms.Tab:
 
86
                            keyval = gtk.keysyms.ISO_Left_Tab
 
87
                            mask &= ~gtk.gdk.SHIFT_MASK
 
88
                        else:
 
89
                            keyvals = gtk.gdk.keyval_convert_case(keyval)
 
90
                            if keyvals[0] != keyvals[1]:
 
91
                                keyval = keyvals[1]
 
92
                                mask &= ~gtk.gdk.SHIFT_MASK
 
93
                    else:
 
94
                        keyval = gtk.gdk.keyval_to_lower(keyval)
 
95
                    self._lookup.setdefault(mask, {})
 
96
                    self._lookup[mask][keyval] = action
 
97
                    self._masks |= mask
 
98
 
 
99
    def _parsebinding(self, binding):
 
100
        """Parse an individual binding using gtk's binding function"""
 
101
        mask = 0
 
102
        modifiers = re.findall(MODIFIER, binding)
 
103
        if modifiers:
 
104
            for modifier in modifiers:
 
105
                mask |= self._lookup_modifier(modifier)
 
106
        key = re.sub(MODIFIER, '', binding)
 
107
        if key == '':
 
108
            raise KeymapError('No key found')
 
109
        keyval = gtk.gdk.keyval_from_name(key)
 
110
        if keyval == 0:
 
111
            raise KeymapError("Key '%s' is unrecognised" % key)
 
112
        return (keyval, mask)
 
113
 
 
114
    def _lookup_modifier(self, modifier):
 
115
        """Map modifier names to gtk values"""
 
116
        try:
 
117
            return self.modifiers[modifier.lower()]
 
118
        except KeyError:
 
119
            raise KeymapError("Unhandled modifier '<%s>'" % modifier)
 
120
 
 
121
    def lookup(self, event):
 
122
        """Translate a keyboard event into a mapped key"""
 
123
        try:
 
124
            keyval, _egp, _lvl, consumed = self.keymap.translate_keyboard_state(
 
125
                                              event.hardware_keycode, 
 
126
                                              event.state & ~gtk.gdk.LOCK_MASK, 
 
127
                                              event.group)
 
128
        except TypeError:
 
129
            err ("keybindings.lookup failed to translate keyboard event: %s" % 
 
130
                     dir(event))
 
131
            return None
 
132
        mask = (event.state & ~consumed) & self._masks
 
133
        return self._lookup.get(mask, self.empty).get(keyval, None)
134
134