import clutter import gobject import pygtk import gtk ######################################################### # The input queue controls fast user input by queing up # signals and processing them one by one once any timelines # are complete ######################################################### class InputQueue(gobject.GObject): NORTH, EAST, SOUTH, WEST = range(4) #Setup signals __gsignals__ = { "queue-flushed": ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []), "entering-queue": ( gobject.SIGNAL_RUN_LAST, gobject.TYPE_NONE, []) } accelerating = False current_acceleration_factor = 1 acceleration_factor_base = 10 #Timelines will run at regular speed times this when accelerated acceleration_threshold = 3 #The queue size at which accleration kicks in (Make this higher to increase the delay before acceleration takes place) acceleration_time = 1000 #Time (in ms) it takes for the queue to accelerate/decelerate from nothing to full acceleration_steps = 5 #The number of steps in the acceleration process queue_max_size = 10 release_timeout = 500 #The time (in ms) that the queue waits for key-events before timing out def __init__(self): gobject.GObject.__init__(self) self.queue_north = 0 self.queue_east = 0 self.queue_south = 0 self.queue_west = 0 self.action_north = None self.action_east = None self.action_south = None self.action_west = None self.current_acceleration_step = 0 #self.stage = clutter.stage_get_default() self.poll_time = None self.release_timeout_id = None self.timeline = None #gtk.settings_get_default().set_long_property("gtk-timeout-repeat", 5000, "gloss") def set_timeline(self, timeline): if not self.timeline is None: self.timeline.disconnect(self.flush_id) self.timeline = timeline self.base_fps = self.timeline.get_speed() if self.accelerating: fps = self.timeline.get_speed() * self.current_acceleration_factor if fps < 1: fps = self.base_fps self.timeline.set_speed(fps) self.flush_id = self.timeline.connect('completed', self.flush_queue) def input(self, event): self.actor = event.source if not self.timeline.is_playing(): if (event.keyval == clutter.keysyms.Left) and (not self.action_west is None): self.action_west() if (event.keyval == clutter.keysyms.Right) and (not self.action_east is None): self.action_east() if (event.keyval == clutter.keysyms.Up) and (not self.action_north is None): self.action_north() if (event.keyval == clutter.keysyms.Down) and (not self.action_south is None): self.action_south() return True self.emit("entering-queue") #Poll for key release if self.accelerating: if not self.release_timeout_id is None: gobject.source_remove(self.release_timeout_id) self.release_timeout_id = gobject.timeout_add(self.release_timeout, self.decelerate) if event.keyval == clutter.keysyms.Left: self.queue_west += 1 return True elif event.keyval == clutter.keysyms.Right: self.queue_east += 1 return True elif event.keyval == clutter.keysyms.Down: self.queue_south += 1 return True elif event.keyval == clutter.keysyms.Up: self.queue_north += 1 return True #If we get to this point, we haven't handled the input, so return False return False def set_action(self, direction, function): if (direction == self.NORTH): self.action_north = function if (direction == self.EAST): self.action_east = function if (direction == self.SOUTH): self.action_south = function if (direction == self.WEST): self.action_west = function def flush_queue(self, data): if self.queue_north > self.queue_max_size: self.queue_north = self.queue_max_size if self.queue_east > self.queue_max_size: self.queue_east = self.queue_max_size if self.queue_south > self.queue_max_size: self.queue_south = self.queue_max_size if self.queue_west > self.queue_max_size: self.queue_west = self.queue_max_size #Consolodate north/south, east/west volumes if self.queue_north > self.queue_south: self.queue_north = self.queue_north - self.queue_south self.queue_south = 0 elif self.queue_south > self.queue_north: self.queue_south = self.queue_south - self.queue_north self.queue_north = 0 if self.queue_east > self.queue_west: self.queue_east = self.queue_east - self.queue_west self.queue_west = 0 elif self.queue_west > self.queue_east: self.queue_west = self.queue_west - self.queue_east self.queue_east = 0 if (self.queue_north > 0) or (self.queue_east > 0) or (self.queue_south > 0) or (self.queue_west > 0): self.timeline.connect('completed', self.flush_queue) absolute_queue_size = self.queue_north + self.queue_east + self.queue_south + self.queue_west if absolute_queue_size > self.acceleration_threshold: if not self.accelerating: self.accelerate() #print "Queue Size: N=%s E=%s S=%s W=%s" % (self.queue_north, self.queue_east, self.queue_south, self.queue_west) if self.queue_north > 0: self.queue_north -= 1 self.action_north() if self.queue_east > 0: self.queue_east -= 1 self.action_east() if self.queue_south > 0: self.queue_south -= 1 self.action_south() if self.queue_west > 0: self.queue_west -= 1 self.action_west() return else: self.queue_east = 0 self.queue_south = 0 self.queue_west = 0 self.queue_north = 0 if not self.accelerating: self.emit("queue-flushed") self.accelerating = False def is_in_queue(self): if self.accelerating: return True if (self.queue_north > 0) or (self.queue_south > 0) or (self.queue_east > 0) or (self.queue_west > 0): return True else: return False def accelerate(self): self.accelerating = True if self.current_acceleration_step < self.acceleration_steps: self.current_acceleration_step +=1 #print "accelerating: %s" % str(self.current_acceleration_step) self.current_acceleration_factor = self.current_acceleration_step * (self.acceleration_factor_base / self.acceleration_steps) fps = self.base_fps * self.current_acceleration_factor if fps < 1: fps = self.base_fps self.timeline.set_speed(fps) if self.current_acceleration_step == 1: gobject.timeout_add( (self.acceleration_time / self.acceleration_steps), self.accelerate) return True #print "Acceleration finished" return False def decelerate(self, actor=None, event=None): #print "Key released: %s" % str(gtk.gdk.keyval_name(event.keyval)) if self.current_acceleration_step > 0: self.current_acceleration_step -= 1 #print "decelerating: %s" % str(self.current_acceleration_step) self.current_acceleration_factor = self.current_acceleration_step * (self.acceleration_factor_base / self.acceleration_steps) fps = self.base_fps * self.current_acceleration_factor if fps < 1: fps = self.base_fps self.timeline.set_speed(fps) if self.current_acceleration_step == (self.acceleration_steps-1): gobject.timeout_add( (self.acceleration_time / self.acceleration_steps), self.decelerate) return True self.accelerating = False self.emit("queue-flushed") #print "Deceleration finished" return False