Web   ·   Wiki   ·   Activities   ·   Blog   ·   Lists   ·   Chat   ·   Meeting   ·   Bugs   ·   Git   ·   Translate   ·   Archive   ·   People   ·   Donate
summaryrefslogtreecommitdiffstats
path: root/keyboard.py
diff options
context:
space:
mode:
authorWade Brainerd <wadetb@gmail.com>2008-11-21 20:07:50 (GMT)
committer Wade Brainerd <wadetb@gmail.com>2008-11-21 20:07:50 (GMT)
commitcf326419e00e8a6ca24e2c8e8af9f912ee31002d (patch)
treeec38ce811b7877cdb852f25ff49fe4384a0dd10b /keyboard.py
parentde8987bf9a2477563796269933485506fceccd84 (diff)
Keyboard internationalized.
Diffstat (limited to 'keyboard.py')
-rw-r--r--keyboard.py207
1 files changed, 117 insertions, 90 deletions
diff --git a/keyboard.py b/keyboard.py
index 6960a08..1243f77 100644
--- a/keyboard.py
+++ b/keyboard.py
@@ -64,14 +64,8 @@ KEY_PROPS = [
# Keyboard scan code for this key.
{ 'name': 'key-scan', 'default': 0 },
- # Text label to be displayed on keys which do not generate ASCII keys.
+ # Text label to be displayed on keys which do not generate keys.
{ 'name': 'key-label', 'default': '' },
-
- # Character generated by the key, when no modifier keys are pressed.
- { 'name': 'key-normal', 'default': '' },
-
- # Character generated by the key with shift pressed.
- { 'name': 'key-shift', 'default': '' },
]
# This is an example keyboard layout.
@@ -105,13 +99,13 @@ DEFAULT_LAYOUT = {
'key-height': 35,
'keys': [
- {'key-normal':"",'key-shift':""}, # Escape
- {'key-normal':"",'key-shift':""}, # Show Source
- {'key-normal':"",'key-shift':"",'key-width':182}, # Zoom
- {'key-normal':"",'key-shift':"",'key-width':182}, # Size
- {'key-normal':"",'key-shift':"",'key-width':181}, # Volume
- {'key-normal':"",'key-shift':""}, # Window
- {'key-normal':"",'key-shift':""}, # Frame
+ {}, # Escape
+ {}, # Show Source
+ {'key-width':182}, # Zoom
+ {'key-width':182}, # Size
+ {'key-width':181}, # Volume
+ {}, # Window
+ {}, # Frame
]
},
{
@@ -120,19 +114,19 @@ DEFAULT_LAYOUT = {
'group-y': 50,
'keys': [
- {'key-scan':0x31,'key-normal':"`",'key-shift':"~",'key-width':35},
- {'key-scan':0x0a,'key-normal':"1",'key-shift':"!"},
- {'key-scan':0x0b,'key-normal':"2",'key-shift':"@"},
- {'key-scan':0x0c,'key-normal':"3",'key-shift':"#"},
- {'key-scan':0x0d,'key-normal':"4",'key-shift':"$"},
- {'key-scan':0x0e,'key-normal':"5",'key-shift':"%"},
- {'key-scan':0x0f,'key-normal':"6",'key-shift':"^"},
- {'key-scan':0x10,'key-normal':"7",'key-shift':"&"},
- {'key-scan':0x11,'key-normal':"8",'key-shift':"*"},
- {'key-scan':0x12,'key-normal':"9",'key-shift':"("},
- {'key-scan':0x13,'key-normal':"0",'key-shift':")"},
- {'key-scan':0x14,'key-normal':"-",'key-shift':"_"},
- {'key-scan':0x15,'key-normal':"=",'key-shift':"+",'key-width':65},
+ {'key-scan':0x31,'key-width':35},
+ {'key-scan':0x0a},
+ {'key-scan':0x0b},
+ {'key-scan':0x0c},
+ {'key-scan':0x0d},
+ {'key-scan':0x0e},
+ {'key-scan':0x0f},
+ {'key-scan':0x10},
+ {'key-scan':0x11},
+ {'key-scan':0x12},
+ {'key-scan':0x13},
+ {'key-scan':0x14},
+ {'key-scan':0x15,'key-width':65},
{'key-scan':0x16,'key-label':"erase",'key-width':95}
]
},
@@ -143,18 +137,18 @@ DEFAULT_LAYOUT = {
'keys': [
{'key-scan':0x17,'key-label':"tab"},
- {'key-scan':0x18,'key-normal':"q",'key-shift':"Q"},
- {'key-scan':0x19,'key-normal':"w",'key-shift':"W"},
- {'key-scan':0x1a,'key-normal':"e",'key-shift':"E"},
- {'key-scan':0x1b,'key-normal':"r",'key-shift':"R"},
- {'key-scan':0x1c,'key-normal':"t",'key-shift':"T"},
- {'key-scan':0x1d,'key-normal':"y",'key-shift':"Y"},
- {'key-scan':0x1e,'key-normal':"u",'key-shift':"U"},
- {'key-scan':0x1f,'key-normal':"i",'key-shift':"I"},
- {'key-scan':0x20,'key-normal':"o",'key-shift':"O"},
- {'key-scan':0x21,'key-normal':"p",'key-shift':"P"},
- {'key-scan':0x22,'key-normal':"[",'key-shift':"{"},
- {'key-scan':0x23,'key-normal':"]",'key-shift':"}",'key-width':55},
+ {'key-scan':0x18},
+ {'key-scan':0x19},
+ {'key-scan':0x1a},
+ {'key-scan':0x1b},
+ {'key-scan':0x1c},
+ {'key-scan':0x1d},
+ {'key-scan':0x1e},
+ {'key-scan':0x1f},
+ {'key-scan':0x20},
+ {'key-scan':0x21},
+ {'key-scan':0x22},
+ {'key-scan':0x23,'key-width':55},
{'key-scan':0x24,'key-label':"enter",'key-width':95,'key-height':95}
]
},
@@ -165,18 +159,18 @@ DEFAULT_LAYOUT = {
'keys': [
{'key-scan':0x25,'key-label':"ctrl",'key-width':55},
- {'key-scan':0x26,'key-normal':"a",'key-shift':"A"},
- {'key-scan':0x27,'key-normal':"s",'key-shift':"S"},
- {'key-scan':0x28,'key-normal':"d",'key-shift':"D"},
- {'key-scan':0x29,'key-normal':"f",'key-shift':"F"},
- {'key-scan':0x2a,'key-normal':"g",'key-shift':"G"},
- {'key-scan':0x2b,'key-normal':"h",'key-shift':"H"},
- {'key-scan':0x2c,'key-normal':"j",'key-shift':"J"},
- {'key-scan':0x2d,'key-normal':"k",'key-shift':"K"},
- {'key-scan':0x2e,'key-normal':"l",'key-shift':"L"},
- {'key-scan':0x2f,'key-normal':";",'key-shift':":"},
- {'key-scan':0x30,'key-normal':"'",'key-shift':")"},
- {'key-scan':0x33,'key-normal':"\\",'key-shift':"|"}
+ {'key-scan':0x26},
+ {'key-scan':0x27},
+ {'key-scan':0x28},
+ {'key-scan':0x29},
+ {'key-scan':0x2a},
+ {'key-scan':0x2b},
+ {'key-scan':0x2c},
+ {'key-scan':0x2d},
+ {'key-scan':0x2e},
+ {'key-scan':0x2f},
+ {'key-scan':0x30},
+ {'key-scan':0x33}
]
},
{
@@ -186,19 +180,19 @@ DEFAULT_LAYOUT = {
'keys': [
{'key-scan':0x32,'key-label':"shift",'key-width':75},
- {'key-scan':0x34,'key-normal':"z",'key-shift':"Z"},
- {'key-scan':0x35,'key-normal':"x",'key-shift':"X"},
- {'key-scan':0x36,'key-normal':"c",'key-shift':"C"},
- {'key-scan':0x37,'key-normal':"v",'key-shift':"V"},
- {'key-scan':0x38,'key-normal':"b",'key-shift':"B"},
- {'key-scan':0x39,'key-normal':"n",'key-shift':"N"},
- {'key-scan':0x3a,'key-normal':"m",'key-shift':"M"},
- {'key-scan':0x3b,'key-normal':",",'key-shift':"<"},
- {'key-scan':0x3c,'key-normal':".",'key-shift':">"},
- {'key-scan':0x3d,'key-normal':"/",'key-shift':"?"},
+ {'key-scan':0x34},
+ {'key-scan':0x35},
+ {'key-scan':0x36},
+ {'key-scan':0x37},
+ {'key-scan':0x38},
+ {'key-scan':0x39},
+ {'key-scan':0x3a},
+ {'key-scan':0x3b},
+ {'key-scan':0x3c},
+ {'key-scan':0x3d},
{'key-scan':0x3e,'key-label':"shift",'key-width':75},
- {'key-scan':0x6f,'key-label':"",'key-shift':""}, # Up
- {'key-label':"",'key-shift':""}, # Multiply
+ {'key-scan':0x6f,'key-label':""}, # Up
+ {'key-label':""}, # Language key
]
},
{
@@ -210,7 +204,7 @@ DEFAULT_LAYOUT = {
{'key-label':"fn",'key-width':35},
{'key-label':"",'key-width':55}, # LHand
{'key-scan':0x40,'key-label':"alt",'key-width':55}, # LAlt
- {'key-scan':0x41,'key-normal':" ",'key-shift':" ", 'key-width':325},
+ {'key-scan':0x41,'key-width':325}, # Spacebar
{'key-scan':0x6c,'key-label':"alt",'key-width':55}, # RAlt
{'key-label':"",'key-width':55}, # RHand
{'key-scan':0x71,'key-label':""}, # Left
@@ -247,19 +241,29 @@ class Keyboard(gtk.EventBox):
def __init__(self, root_window):
gtk.EventBox.__init__(self)
-
+
self.root_window = root_window
-
+
+ # Create the drawing area.
self.area = gtk.DrawingArea()
self.area.connect("expose-event", self._expose_cb)
self.add(self.area)
-
+
+ # Access the current GTK keymap.
+ self.keymap = gtk.gdk.keymap_get_default()
+
+ # Active language group and modifier state.
+ # See http://www.pygtk.org/docs/pygtk/class-gdkkeymap.html for more
+ # information about key group and state.
+ self.active_group = 0
+ self.active_state = 0
+
# This array contains the current keyboard layout.
self.keys = None
- self.key_map = None
-
+ self.key_scan_map = None
+
self.shift_down = False
-
+
# Connect keyboard grabbing and releasing callbacks.
self.connect('realize', self._realize_cb)
self.connect('unrealize', self._unrealize_cb)
@@ -279,7 +283,7 @@ class Keyboard(gtk.EventBox):
Also fills in derived and inherited key properties.
The layout description can be discarded afterwards."""
self.keys = []
- self.key_map = {}
+ self.key_scan_map = {}
group_count = 0
for g in layout['groups']:
@@ -305,7 +309,7 @@ class Keyboard(gtk.EventBox):
props[pname] = layout[pname]
else:
props[pname] = p['default']
-
+
# Add to internal list.
key = Key(props)
self.keys.append(key)
@@ -313,7 +317,7 @@ class Keyboard(gtk.EventBox):
# Add to scan code mapping table.
if props['key-scan']:
- self.key_map[props['key-scan']] = key
+ self.key_scan_map[props['key-scan']] = key
group_count += 1
@@ -429,12 +433,18 @@ class Keyboard(gtk.EventBox):
cr.clip()
# Inner text.
+ text = ''
if k.props['key-label']:
text = k.props['key-label']
- elif self.shift_down:
- text = k.props['key-shift']
else:
- text = k.props['key-normal']
+ info = self.keymap.translate_keyboard_state(
+ k.props['key-scan'], self.active_state, self.active_group)
+ if info:
+ key = gtk.gdk.keyval_to_unicode(info[0])
+ try:
+ text = unichr(key).encode('utf-8')
+ except:
+ pass
cr.set_font_size(16)
x_bearing, y_bearing, width, height = cr.text_extents(text)[:4]
@@ -447,22 +457,32 @@ class Keyboard(gtk.EventBox):
return True
def _key_press_cb(self, widget, event):
- if self.key_map.has_key(event.hardware_keycode):
- key = self.key_map[event.hardware_keycode]
+ key = self.key_scan_map.get(event.hardware_keycode)
+ if key:
key.pressed = True
- if key.props['key-label'] == 'shift':
- self.shift_down = True
-
+
+ self.active_group = event.group
+ self.active_state = event.state
+
+ # Hack to get the current modifier state - which will not be represented by the event.
+ self.active_state = gtk.gdk.device_get_core_pointer().get_state(self.window)[1]
+ #print "press %d state=%x group=%d" % (event.hardware_keycode, self.active_state, event.group)
+
self.queue_draw()
return False
def _key_release_cb(self, widget, event):
- if self.key_map.has_key(event.hardware_keycode):
- key = self.key_map[event.hardware_keycode]
+ key = self.key_scan_map.get(event.hardware_keycode)
+ if key:
key.pressed = False
- if key.props['key-label'] == 'shift':
- self.shift_down = False
-
+
+ self.active_group = event.group
+ self.active_state = event.state
+
+ # Hack to get the current modifier state - which will not be represented by the event.
+ self.active_state = gtk.gdk.device_get_core_pointer().get_state(self.window)[1]
+ #print "release %d state=%x group=%d" % (event.hardware_keycode, self.active_state, event.group)
+
self.queue_draw()
return False
@@ -471,10 +491,17 @@ class Keyboard(gtk.EventBox):
k.hilite = False
def find_key_by_letter(self, letter):
- for k in self.keys:
- if k.props['key-normal'] == letter or k.props['key-shift'] == letter:
- return k
- return None
+ # Convert unicode to GDK keyval.
+ keyval = gtk.gdk.unicode_to_keyval(ord(letter))
+
+ # Find list of key combinations that can generate this keyval.
+ # If found, return the key whose scan code matches the first combo.
+ entries = self.keymap.get_entries_for_keyval(keyval)
+ if entries:
+ code = entries[0][0]
+ return self.key_scan_map.get(code)
+ else:
+ return None
if __name__ == "__main__":
window = gtk.Window(gtk.WINDOW_TOPLEVEL)