From: NeilBrown Date: Sun, 6 Feb 2011 09:16:49 +0000 (+1100) Subject: tapinput - various updates X-Git-Url: http://git.neil.brown.name/?a=commitdiff_plain;h=15c4ca803df4fefe50b9ab894d4c76baf54cff82;p=freerunner.git tapinput - various updates Signed-off-by: NeilBrown --- diff --git a/input/tapinput.py b/input/tapinput.py index 2e5f39f..7c8e9cb 100644 --- a/input/tapinput.py +++ b/input/tapinput.py @@ -19,19 +19,19 @@ # 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, @@ -45,7 +45,7 @@ keymap['UPPER'] = [ ['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, @@ -62,18 +62,22 @@ keymap['number'] = [ [' ',' ',' ',' ',' ',' ',' ','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() @@ -114,7 +118,7 @@ class TapInput(gtk.Window): 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 @@ -132,6 +136,9 @@ class TapInput(gtk.Window): 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: @@ -144,6 +151,7 @@ class TapInput(gtk.Window): 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) @@ -165,19 +173,22 @@ class TapInput(gtk.Window): 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 = {} @@ -208,6 +219,10 @@ class TapInput(gtk.Window): 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, @@ -218,6 +233,7 @@ class TapInput(gtk.Window): 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 = {} @@ -243,7 +259,7 @@ class TapInput(gtk.Window): 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), @@ -290,11 +306,20 @@ class TapInput(gtk.Window): 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() @@ -307,6 +332,7 @@ class TapInput(gtk.Window): 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) @@ -316,6 +342,7 @@ class TapInput(gtk.Window): self.fi.send_char(sym) else: click(arg) + def motion(self, widget, ev): if self.dragx == None: return @@ -333,6 +360,11 @@ class TapInput(gtk.Window): 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() @@ -343,6 +375,8 @@ class TapInput(gtk.Window): 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 @@ -357,7 +391,7 @@ class TapInput(gtk.Window): 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): @@ -386,21 +420,138 @@ class TapInput(gtk.Window): 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()