# The window can be dragged by touch-and-drag anywhere.
# If the window is dragged more than 1/2 off the screen, it disappears.
-import gtk, pango, gobject
+import gtk, pango, gobject, os, struct, time
from fakeinput import fakeinput
keymap = {}
keymap['lower'] = [
- ['0','1','Tab','2','3',' ','?','@','#'],
+ ['0','1','Tab','2','3','Delete','?','@','#'],
['b','c','d','f','g','h',' ','Down',' '],
['<','4','5','>','6','7','Return','{','}'],
['j','k','~','l','m','Right','n','p','`'],
['a','e','i','o',' ','u','r','s','t'],
['\\',';',':','Left','\'','"','|','(',')'],
- ['[',']',' ','8','9','=','+','-','_'],
+ ['[',']','Escape','8','9','=','+','-','_'],
[' ','Up',' ','q','v','w','x','y','z'],
['!','$','%','^','*','/','&',',','.'],
None,
['J','K','~','L','M','Right','N','P','`'],
['A','E','I','O',' ','U','R','S','T'],
['\\',';',':','Left','\'','"','|','(',')'],
- ['[',']',' ','8','9','=','+','-','_'],
+ ['[',']','Escape','8','9','=','+','-','_'],
[' ','Up',' ','Q','V','W','X','Y','Z'],
['!','$','%','^','*','/','&',',','.'],
None,
[' ',' ',' ',' ',' ',' ',' ','8',' '],
[' ',' ',' ',' ',' ',' ',' ',' ','9'],
None,
- [' ',' ',' ',' ',' ',' ','*',' ','#', ' ', '0', ' ']
+ ['+',' ','-','.',' ','/','*',' ','#', ' ', '0', ' ']
]
-04034
class TapInput(gtk.Window):
def __init__(self):
gtk.Window.__init__(self, type=gtk.WINDOW_POPUP)
- self.set_default_size(320, 420)
+ #self.keysize = 80 Small for opaque
+ #self.keysize = 130 a bit large for transparent
+ self.keysize = 90
+ self.width = int(3*self.keysize)
+ self.height = int(4.2*self.keysize)
+ self.set_default_size(self.width, self.height)
root = gtk.gdk.get_default_root_window()
(x,y,width,height,depth) = root.get_geometry()
- x = int((width-320)/2)
- y = int((height-420)/2)
+ x = int((width-self.width)/2)
+ y = int((height-self.width)/2)
self.move(x,y)
self.fi = fakeinput()
v.add(h)
fd = pango.FontDescription('sans 10')
- fd.set_absolute_size(30 * pango.SCALE)
+ fd.set_absolute_size(30 * pango.SCALE * self.keysize / 80)
b = self.add_button('abc', self.nextmode, None, h, fd)
self.modebutton = b
self.update_buttons()
self.connect("configure-event", self.update_buttons)
self.hide()
+ self.visible = False
+ self.set_opacity(0.4)
+
def add_button(self, label, click, arg, box, font = None):
if not label:
else:
b = gtk.Button(label)
b.show()
+ b.set_property('can-focus', False)
if font:
b.child.modify_font(font)
b.connect('button_press_event', self.press, arg)
size -= 12
if size <= 10 or size == self.size:
return
- print "update buttons", size
+ #print "update buttons", size
self.size = size
# For each button in 3x3 we need 10 images,
# one for initial state, and one for each of the new states
# So there are two fonts we want.
# First we make the initial images
- fd = pango.FontDescription('sans 10')
- fd.set_absolute_size(size / 4.5 * pango.SCALE)
- self.modify_font(fd)
+ fdsingle = pango.FontDescription('sans 10')
+ fdsingle.set_absolute_size(size / 3.5 * pango.SCALE)
+ fdword = pango.FontDescription('sans 10')
+ fdword.set_absolute_size(size / 4.5 * pango.SCALE)
bg = self.get_style().bg_gc[gtk.STATE_NORMAL]
- fg = self.get_style().fg_gc[gtk.STATE_NORMAL]
+ #fg = self.get_style().fg_gc[gtk.STATE_NORMAL]
+ fg = self.window.new_gc()
+ fg.set_foreground(self.get_colormap().alloc_color(gtk.gdk.color_parse('blue')))
red = self.window.new_gc()
red.set_foreground(self.get_colormap().alloc_color(gtk.gdk.color_parse('red')))
base_images = {}
if ypos != ypos%6:
ypos = ypos%6
colour = red
+ if len(sym) == 1:
+ self.modify_font(fdsingle)
+ else:
+ self.modify_font(fdword)
layout = self.create_pango_layout(sym[0:3])
(ink, (ex,ey,ew,eh)) = layout.get_pixel_extents()
pm.draw_layout(colour,
im.set_from_pixmap(pm, None)
base_images[mode][row*3+col] = im
self.base_images = base_images
+ fd = pango.FontDescription('sans 10')
fd.set_absolute_size(size / 1.5 * pango.SCALE)
self.modify_font(fd)
sup_images = {}
else:
pm = gtk.gdk.Pixmap(self.window, size, size)
pm.draw_rectangle(bg, True, 0, 0, size, size)
- layout = self.create_pango_layout(sym)
+ layout = self.create_pango_layout(sym[0:3])
(ink, (ex,ey,ew,eh)) = layout.get_pixel_extents()
pm.draw_layout(fg,
int((size - ew)/2), int((size - eh)/2),
self.startx, self.starty = self.get_position()
if arg != None and self.taps == 1 and self.button_timeout == None and self.prefix == None:
self.prefix1 = arg
- self.button_timeout = gobject.timeout_add(500, self.do_buttons)
+ if not self.button_timeout:
+ self.button_timeout = gobject.timeout_add(300, self.do_buttons)
+ if arg == None:
+ # press-and-hold makes us disappear
+ if not self.button_timeout:
+ self.button_timeout = gobject.timeout_add(300, self.disappear)
def release(self, widget, ev, click, arg):
self.dragx = None
self.dragy = None
+ if arg == None:
+ if self.button_timeout:
+ gobject.source_remove(self.button_timeout)
+ self.button_timeout = None
if self.moved:
self.moved = False
self.noprefix()
if xmid < 0 or xmid > rwidth or \
ymid < 0 or ymid > rheight:
self.hide()
+ self.visible = False
elif arg != None and self.taps == 1 and self.button_timeout:
# quick tap in single tap mode, just enter the symbol
gobject.source_remove(self.button_timeout)
self.fi.send_char(sym)
else:
click(arg)
+
def motion(self, widget, ev):
if self.dragx == None:
return
gtk.gdk.flush()
ev.window.get_pointer()
+ def disappear(self):
+ self.hide()
+ self.visible = False
+ self.dragx = None
+ self.dragy = None
def do_buttons(self):
self.set_button_images()
def nextmode(self, a):
if self.prefix:
return self.noprefix()
+ if self.prefix1:
+ self.noprefix()
if self.mode == 'lower':
self.mode = 'UPPER'
self.single = True
else:
self.mode = 'lower'
self.taps = 2
- self.modebutton.child.set_text('mode')
+ self.modebutton.child.set_text('abc')
self.set_button_images()
def delete(self, a):
def activate(self, *a):
root = gtk.gdk.get_default_root_window()
(x,y,width,height,depth) = root.get_geometry()
- x = int((width-320)/2)
- y = int((height-420)/2)
- self.move(x,y)
+ if self.window:
+ (wx,wy,ww,wh,wd) = self.window.get_geometry()
+ else:
+ wx,wy,ww,wh,wd = -1,-1,0,0,0
+ if wx < x or wy < y or wx+ww > width or wy+wh > height:
+ # partly off screen, so recentre
+ x = int((width-self.width)/2)
+ y = int((height-self.height)/2)
+ self.move(x,y)
+ else:
+ x,y = wx,wy
self.fi.new_window()
+ self.hide()
self.show()
+ self.visible = True
self.move(x,y)
+
+class EvDev:
+ def __init__(self, path, on_event):
+ self.f = os.open(path, os.O_RDWR|os.O_NONBLOCK);
+ self.ev = gobject.io_add_watch(self.f, gobject.IO_IN, self.read)
+ self.on_event = on_event
+ self.grabbed = False
+ self.down_count = 0
+ def read(self, x, y):
+ try:
+ str = os.read(self.f, 16)
+ except:
+ return True
+
+ if len(str) != 16:
+ return True
+ (sec,usec,typ,code,value) = struct.unpack_from("IIHHI", str)
+ if typ == 0x01:
+ # KEY event
+ if value == 0:
+ self.down_count -= 1
+ else:
+ self.down_count += 1
+ if self.down_count < 0:
+ self.down_count = 0
+ self.on_event(self.down_count, typ, code, value)
+ return True
+ def grab(self):
+ if self.grabbed:
+ return
+ #print "grab"
+ fcntl.ioctl(self.f, EVIOC_GRAB, 1)
+ self.grabbed = True
+ def ungrab(self):
+ if not self.grabbed:
+ return
+ #print "release"
+ fcntl.ioctl(self.f, EVIOC_GRAB, 0)
+ self.grabbed = False
+
+
+
class KeyboardIcon(gtk.StatusIcon):
- def __init__(self, x):
+ def __init__(self, win = None):
gtk.StatusIcon.__init__(self)
self.set_from_file('/usr/local/pixmaps/tapinput.png')
- self.connect('activate', x.activate)
+ if win:
+ self.connect('activate', win.activate)
+ def set_win(self, win):
+ if win:
+ self.connect('activate', win.activate)
+
+power_timer = None
+def power_pressed(cnt, type, code, value):
+ if type != 1:
+ # not a key press
+ return
+ if code != 116:
+ # not the power key
+ return
+ global power_timer
+ if value != 1:
+ # not a down press
+ if power_timer != None:
+ gobject.source_remove(power_timer)
+ power_timer = None
+ return
+ power_timer = gobject.timeout_add(300, power_held)
+
+def power_held():
+ global power_timer
+ power_timer = None
+ open("/sys/class/leds/neo1973:vibrator/trigger","w").write("default-on\n")
+ if win.visible:
+ win.hide()
+ win.visible = False
+ else:
+ win.activate()
+ open("/sys/class/leds/neo1973:vibrator/trigger","w").write("none\n")
+ return False
+
+last_tap = 0
+def tap_pressed(cnt, type, code, value):
+ global last_tap
+ if type != 1:
+ # not a key press
+ return
+ if code != 309:
+ # not BtnZ
+ return
+ if value != 1:
+ # only want dow, not up
+ return
+ now = time.time()
+ print now, last_tap
+ if now - last_tap < 0.2:
+ # two taps
+ if win.visible:
+ win.hide()
+ win.visible = False
+ else:
+ win.activate()
+ last_tap = 0
+ else:
+ last_tap = now
+ico = KeyboardIcon()
win = TapInput()
-ico = KeyboardIcon(win)
+ico.set_win(win)
+#try:
+pbtn = EvDev("/dev/input/event0", power_pressed)
+tbtn = EvDev("/dev/input/event3", tap_pressed)
+#except:
+# pass
+
gtk.main()