blob: 723e651244a253292231489636184c64d9408b8b [file] [log] [blame]
#!/usr/bin/python
#
# Copyright (c) 2010 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
import cairo
import gobject
import gtk
import sys
import time
import os
_OUTPUT_HEADER = \
'''
# AUTOMATICALLY GENERATED -- This data structure is printed out by
# BindingsSetup during execution, and modifications can be pasted from
# there back to here.
'''
class BindingsSetup:
"""Facilitate generation of the binding map for the actual
KeyboardTest -- it takes the name of a png keyboard image file and
optionally a corresponding bindings file as its first and second
command line arguments, respectively. On each assignment of a new
binding, it will output the contents for a new bindings file to
stdout (a bit verbose, but simple).
UI -- select key region to be highlighted with the mouse, hit
corresponding key, double click to active tweak mode, fine tune
highlighted region with the arrow keys (hold shift for neg
effect), double click to confirm and output current bindings
datastructure, repeat."""
# Allow tweak mode adjustment of coords using the arrow keys.
tweak_keys = {
0xff51 : [1, 0, 0, 0],
0xff52 : [0, 1, 0, 0],
0xff53 : [0, 0, 1, 0],
0xff54 : [0, 0, 0, 1]}
def __init__(self, kbd_image, bindings):
self._kbd_image = kbd_image
self._press_xy = None
self._last_coords = None
self._last_key = None
self._tweak_mode = False
self._bindings = bindings
def fmt_coords(self, coords):
return '%3d,%-3d %2dx%-2d' % coords
def fmt_key(self, key):
return '%4x,%-4x' % key
def fmt_binding(self, binding):
key, coords = binding
return '0x%-4x : %s' % (key, '(%3d,%3d,%3d,%3d)' % coords)
def tweak_coords(self, d_lft, d_top, d_rgt, d_bot):
xmin, ymin, xdelta, ydelta = self._last_coords
xmin -= d_lft
ymin -= d_top
xdelta += d_lft + d_rgt
ydelta += d_top + d_bot
self._last_coords = (xmin, ymin, xdelta, ydelta)
def confirm_binding(self):
kc, kv = self._last_key
self._bindings[kc] = self._last_coords
binding_list = [self.fmt_binding(b) for b in
sorted(self._bindings.items())]
print _OUTPUT_HEADER
print ('\n{\n%s\n}' % ',\n'.join(' %s' % b for b in binding_list))
def expose_event(self, widget, event):
context = widget.window.cairo_create()
context.set_source_surface(self._kbd_image, 0, 0)
context.paint()
if self._last_coords:
context.rectangle(*self._last_coords)
context.set_source_rgba(0, 0.5, 0, 0.6)
context.fill()
return False
def button_press_event(self, widget, event):
if not event.button == 1:
return False
if self._tweak_mode:
if event.type == gtk.gdk._2BUTTON_PRESS:
self.confirm_binding()
self._tweak_mode = False
self._press_xy = None
self._last_coords = None
self._last_key = None
else:
if (event.type == gtk.gdk._2BUTTON_PRESS and
self._last_coords and self._last_key):
self._tweak_mode = True
print 'tweak mode'
else:
self._press_xy = (event.x, event.y)
return True
def button_release_event(self, widget, event):
if not event.button == 1:
return False
if (not self._tweak_mode) and self._press_xy:
px, py = self._press_xy
xmin, xmax = sorted([px, event.x])
ymin, ymax = sorted([py, event.y])
xdelta = xmax - xmin
ydelta = ymax - ymin
if xdelta and ydelta:
self._last_coords = (xmin, ymin, xdelta, ydelta)
print 'coords %s' % self.fmt_coords(self._last_coords)
widget.queue_draw()
return True
def key_press_event(self, widget, event):
key = (event.keyval, event.hardware_keycode)
if self._tweak_mode:
delta = BindingsSetup.tweak_keys.get(event.keyval)
if delta:
if 'GDK_SHIFT_MASK' in event.state.value_names:
# Reverse the effect if SHIFT is being held down.
delta = map((lambda x: 0 - x), delta)
self.tweak_coords(*delta)
print 'tweak %s --> %s' % (self.fmt_key(self._last_key),
self.fmt_coords(self._last_coords))
widget.queue_draw()
else:
self._last_key = key
print 'key %s %s' % (self.fmt_key(key), repr(event.string))
return True
def main():
window = gtk.Window(gtk.WINDOW_TOPLEVEL)
window.connect('destroy', lambda w: gtk.main_quit())
window.set_default_size(981, 450)
bg_color = gtk.gdk.color_parse('midnight blue')
window.modify_bg(gtk.STATE_NORMAL, bg_color)
kbd_image = cairo.ImageSurface.create_from_png(sys.argv[1])
kbd_image_size = (kbd_image.get_width(), kbd_image.get_height())
bindings = {}
if len(sys.argv) == 3 and os.path.exists(sys.argv[2]):
f = open(sys.argv[2], 'r')
bindings = eval(f.read())
f.close()
drawing_area = gtk.DrawingArea()
drawing_area.set_size_request(*kbd_image_size)
kt = BindingsSetup(kbd_image, bindings)
window.connect('key-press-event', kt.key_press_event)
drawing_area.connect('button_release_event', kt.button_release_event)
drawing_area.connect('button_press_event', kt.button_press_event)
drawing_area.connect('expose_event', kt.expose_event)
drawing_area.show()
align = gtk.Alignment(xalign=0.5, yalign=0.5)
align.add(drawing_area)
align.show()
drawing_area.set_events(gtk.gdk.EXPOSURE_MASK |
gtk.gdk.KEY_PRESS_MASK |
gtk.gdk.BUTTON_PRESS_MASK |
gtk.gdk.BUTTON_RELEASE_MASK)
window.add(align)
window.show()
gtk.main()
if __name__ == '__main__':
main()