예제 #1
0
class DoubleclickModifier(Modifier, HapticEnabledAction):
    COMMAND = "doubleclick"
    DEAFAULT_TIMEOUT = 0.2
    TIMEOUT_KEY = "time"
    PROFILE_KEY_PRIORITY = 3

    def __init__(self, doubleclickaction, normalaction=None, time=None):
        Modifier.__init__(self)
        HapticEnabledAction.__init__(self)
        self.action = doubleclickaction
        self.normalaction = normalaction or NoAction()
        self.holdaction = NoAction()
        self.actions = (self.action, self.normalaction, self.holdaction)
        self.timeout = time or DoubleclickModifier.DEAFAULT_TIMEOUT
        self.waiting = False
        self.pressed = False
        self.active = None

    def encode(self):
        if self.normalaction:
            rv = self.normalaction.encode()
        else:
            rv = {}
        rv[DoubleclickModifier.COMMAND] = self.action.encode()
        if self.holdaction:
            rv[HoldModifier.COMMAND] = self.holdaction.encode()
        if self.timeout != DoubleclickModifier.DEAFAULT_TIMEOUT:
            rv[DoubleclickModifier.TIMEOUT_KEY] = self.timeout
        if self.name:
            rv[NameModifier.COMMAND] = self.name
        return rv

    def get_child_actions(self):
        return self.actions

    @staticmethod
    def decode(data, a, parser, *b):
        args = [parser.from_json_data(data[DoubleclickModifier.COMMAND]), a]
        a = DoubleclickModifier(*args)
        if DoubleclickModifier.TIMEOUT_KEY in data:
            a.timeout = data[DoubleclickModifier.TIMEOUT_KEY]
        return a

    def strip(self):
        if self.holdaction:
            return self.holdaction.strip()
        return self.action.strip()

    def compress(self):
        self.action = self.action.compress()
        self.holdaction = self.holdaction.compress()
        self.normalaction = self.normalaction.compress()

        for a in (self.holdaction, self.normalaction):
            if isinstance(a, HoldModifier):
                self.holdaction = a.holdaction or self.holdaction
                self.normalaction = a.normalaction or self.normalaction

        if isinstance(self.action, HoldModifier):
            self.holdaction = self.action.holdaction
            self.action = self.action.normalaction
        return self

    def __str__(self):
        l = [self.action]
        if self.normalaction:
            l += [self.normalaction]
        return "<Modifier %s dbl='%s' hold='%s' normal='%s'>" % (
            self.COMMAND, self.action, self.holdaction, self.normalaction)

    __repr__ = __str__

    def describe(self, context):
        l = []
        if self.action:
            l += [self.action]
        if self.holdaction:
            l += [self.holdaction]
        if self.normalaction:
            l += [self.normalaction]
        return "\n".join([x.describe(context) for x in l])

    def to_string(self, multiline=False, pad=0):
        if self.action and self.normalaction and self.holdaction:
            return "doubleclick(%s, hold(%s, %s))" % (
                self.action.to_string(multiline, pad),
                self.holdaction.to_string(multiline, pad),
                self.normalaction.to_string(multiline, pad),
            )
        elif self.action and self.normalaction and not self.holdaction:
            return "doubleclick(%s, %s)" % (
                self.action.to_string(multiline, pad),
                self.normalaction.to_string(multiline, pad),
            )
        elif not self.action and self.normalaction and self.holdaction:
            return "hold(%s, %s)" % (
                self.holdaction.to_string(multiline, pad),
                self.normalaction.to_string(multiline, pad),
            )
        return ((self.action or self.normalaction
                 or self.holdaction).to_string(multiline, pad))

    def button_press(self, mapper):
        self.pressed = True
        if self.waiting:
            # Double-click happened
            mapper.remove_scheduled(self.on_timeout)
            self.waiting = False
            self.active = self.action
            self.active.button_press(mapper)
        else:
            # First click, start the timer
            self.waiting = True
            mapper.schedule(self.timeout, self.on_timeout)

    def button_release(self, mapper):
        self.pressed = False
        if self.waiting and self.active is None and not self.action:
            # In HoldModifier, button released before timeout
            mapper.remove_scheduled(self.on_timeout)
            self.waiting = False
            if self.normalaction:
                self.normalaction.button_press(mapper)
                self.normalaction.button_release(mapper)
        elif self.active:
            # Released held button
            self.active.button_release(mapper)
            self.active = None

    def on_timeout(self, mapper, *a):
        if self.waiting:
            self.waiting = False
            if self.pressed:
                # Timeouted while button is still pressed
                self.active = self.holdaction if self.holdaction else self.normalaction
                if self.haptic:
                    mapper.send_feedback(self.haptic)
                self.active.button_press(mapper)
            elif self.normalaction:
                # User did short click and nothing else
                self.normalaction.button_press(mapper)
                self.normalaction.button_release(mapper)
예제 #2
0
class Modifier(Action):
    def __init__(self, *params):
        Action.__init__(self, *params)
        params = list(params)
        for p in params:
            if isinstance(p, Action):
                self.action = p
                params.remove(p)
                break
        else:
            self.action = NoAction()
        self._mod_init(*params)

    def get_compatible_modifiers(self):
        return self.action.get_compatible_modifiers()

    def get_child_actions(self):
        return (self.action, )

    def _mod_init(self):
        """
		Initializes modifier with rest of parameters, after action nparameter
		was taken from it and stored in self.action
		"""
        pass  # not needed by default

    def _mod_to_string(self, params, multiline, pad):
        """ Adds action at end of params list and generates string """
        if multiline:
            childstr = self.action.to_string(True, pad + 2)
            if len(params) > 0:
                return "%s%s(%s,%s%s)" % (" " * pad, self.COMMAND, ", ".join([
                    nameof(s) for s in params
                ]), '\n' if '\n' in childstr else ' ', childstr)
            return "%s%s(%s)" % (" " * pad, self.COMMAND, childstr.strip())
        childstr = self.action.to_string(False, pad)
        if len(params) > 0:
            return "%s%s(%s, %s)" % (" " * pad, self.COMMAND, ", ".join(
                [nameof(s) for s in params]), childstr)

        return "%s%s(%s)" % (" " * pad, self.COMMAND, childstr)

    def strip_defaults(self):
        """
		Overrides Action.strip_defaults; Uses defaults from _mod_init instead
		of __init__, but does NOT include last of original parameters - action.
		"""
        argspec = inspect.getargspec(self.__class__._mod_init)
        required_count = len(argspec.args) - len(argspec.defaults) - 1
        l = list(self.parameters[0:-1])
        d = list(argspec.defaults)[0:len(l)]
        while len(d) and len(l) > required_count and d[-1] == l[-1]:
            d, l = d[:-1], l[:-1]
        return l

    def strip(self):
        return self.action.strip()

    def compress(self):
        if self.action:
            self.action = self.action.compress()
        return self

    def __str__(self):
        return "<Modifier '%s', %s>" % (self.COMMAND, self.action)

    __repr__ = __str__

    def encode(self):
        rv = self.action.encode()
        if self.name:
            rv[NameModifier.COMMAND] = self.name
        return rv
예제 #3
0
class ModeModifier(Modifier):
    COMMAND = "mode"
    PROFILE_KEYS = ("modes", )
    MIN_TRIGGER = 2  # When trigger is bellow this position, list of held_triggers is cleared
    MIN_STICK = 2  # When abs(stick) < MIN_STICK, stick is considered released and held_sticks is cleared
    PROFILE_KEY_PRIORITY = 2

    def __init__(self, *stuff):
        Modifier.__init__(self)
        self.default = None
        self.mods = {}
        self.held_buttons = set()
        self.held_sticks = set()
        self.held_triggers = {}
        self.order = []
        self.old_gyro = None
        self.timeout = DoubleclickModifier.DEAFAULT_TIMEOUT

        button = None
        for i in stuff:
            if self.default is not None:
                # Default has to be last parameter
                raise ValueError("Invalid parameters for 'mode'")
            if isinstance(i, Action):
                if button is None:
                    self.default = i
                    continue
                self.mods[button] = i
                self.order.append(button)
                button = None
            elif i in SCButtons:
                button = i
            else:
                raise ValueError("Invalid parameter for 'mode': %s" % (i, ))
        if self.default is None:
            self.default = NoAction()

    def get_child_actions(self):
        return [self.mods[key] for key in self.mods]

    def encode(self):
        rv = self.default.encode()
        modes = {}
        for key in self.mods:
            modes[key.name] = self.mods[key].encode()
        rv[ModeModifier.PROFILE_KEYS[0]] = modes
        if self.name:
            rv[NameModifier.COMMAND] = self.name
        return rv

    @staticmethod
    def decode(data, a, parser, *b):
        args = []
        for button in data[ModeModifier.PROFILE_KEYS[0]]:
            if hasattr(SCButtons, button):
                args += [
                    getattr(SCButtons, button),
                    parser.from_json_data(
                        data[ModeModifier.PROFILE_KEYS[0]][button])
                ]
        if a:
            args += [a]
        mm = ModeModifier(*args)
        if "name" in data:
            mm.name = data["name"]
        return mm

    def get_compatible_modifiers(self):
        rv = 0
        for key in self.mods:
            rv |= self.mods[key].get_compatible_modifiers()
        return rv

    def strip(self):
        # Returns default action or action assigned to first modifier
        if self.default:
            return self.default.strip()
        if len(self.order) > 0:
            return self.mods[self.order[0]].strip()
        # Empty ModeModifier
        return NoAction()

    def compress(self):
        if self.default:
            self.default = self.default.compress()
        for button in self.mods:
            self.mods[button] = self.mods[button].compress()
        return self

    def __str__(self):
        rv = []
        for key in self.mods:
            rv += [key.name, self.mods[key]]
        if self.default is not None:
            rv += [self.default]
        return "<Modifier '%s', %s>" % (self.COMMAND, rv)

    __repr__ = __str__

    def describe(self, context):
        if self.name: return self.name
        l = []
        if self.default: l.append(self.default)
        for x in self.order:
            l.append(self.mods[x])
        return "\n".join([x.describe(context) for x in l])

    def to_string(self, multiline=False, pad=0):
        if multiline:
            rv = [(" " * pad) + "mode("]
            for key in self.mods:
                a_str = self.mods[key].to_string(True).split("\n")
                a_str[0] = (" " * pad) + "  " + (key.name + ",").ljust(
                    11) + a_str[0]  # Key has to be one of SCButtons
                for i in xrange(1, len(a_str)):
                    a_str[i] = (" " * pad) + "  " + a_str[i]
                a_str[-1] = a_str[-1] + ","
                rv += a_str
            if self.default is not None:
                a_str = [(" " * pad) + "  " + x
                         for x in self.default.to_string(True).split("\n")]
                rv += a_str
            if rv[-1][-1] == ",":
                rv[-1] = rv[-1][0:-1]
            rv += [(" " * pad) + ")"]
            return "\n".join(rv)
        else:
            rv = []
            for key in self.mods:
                rv += [key.name, self.mods[key].to_string(False)]
            if self.default is not None:
                rv += [self.default.to_string(False)]
            return "mode(" + ", ".join(rv) + ")"

    def select(self, mapper):
        """
		Selects action by pressed button.
		"""
        for b in self.order:
            if mapper.is_pressed(b):
                return self.mods[b]
        return self.default

    def select_b(self, mapper):
        """
		Same as select but returns button as well.
		"""
        for b in self.order:
            if mapper.is_pressed(b):
                return b, self.mods[b]
        return None, self.default

    def button_press(self, mapper):
        sel = self.select(mapper)
        self.held_buttons.add(sel)
        return sel.button_press(mapper)

    def button_release(self, mapper):
        # Releases all held buttons, not just button that matches
        # currently pressed modifier
        for b in self.held_buttons:
            b.button_release(mapper)

    def trigger(self, mapper, position, old_position):
        if position < ModeModifier.MIN_TRIGGER:
            for b in self.held_triggers:
                b.trigger(mapper, 0, self.held_triggers[b])
            self.held_triggers = {}
            return False
        else:
            sel = self.select(mapper)
            self.held_triggers[sel] = position
            return sel.trigger(mapper, position, old_position)

    def axis(self, mapper, position, what):
        return self.select(mapper).axis(mapper, position, what)

    def gyro(self, mapper, pitch, yaw, roll, *q):
        sel = self.select(mapper)
        if sel is not self.old_gyro:
            if self.old_gyro:
                self.old_gyro.gyro(mapper, 0, 0, 0, *q)
            self.old_gyro = sel
        return sel.gyro(mapper, pitch, yaw, roll, *q)

    def pad(self, mapper, position, what):
        return self.select(mapper).pad(mapper, position, what)

    def whole(self, mapper, x, y, what):
        if what == STICK:
            if abs(x) < ModeModifier.MIN_STICK and abs(
                    y) < ModeModifier.MIN_STICK:
                for b in self.held_sticks:
                    b.whole(mapper, 0, 0, what)
                self.held_sticks.clear()
            else:
                self.held_sticks.add(self.select(mapper))
                for b in self.held_sticks:
                    b.whole(mapper, x, y, what)
        else:
            return self.select(mapper).whole(mapper, x, y, what)
예제 #4
0
class DoubleclickModifier(Modifier):
	COMMAND = "doubleclick"
	DEAFAULT_TIMEOUT = 0.2
	
	def __init__(self, doubleclickaction, normalaction=None):
		Modifier.__init__(self)
		self.action = doubleclickaction
		self.normalaction = normalaction or NoAction()
		self.holdaction = NoAction()
		self.timeout = self.DEAFAULT_TIMEOUT
		self.waiting = False
		self.pressed = False
		self.active = None
	
	
	def set_haptic(self, hapticdata):
		supports = self.action.set_haptic(hapticdata)
		if self.normalaction:
			supports = self.normalaction.set_haptic(hapticdata) or supports
		if self.holdaction:
			supports = self.holdaction.set_haptic(hapticdata) or supports
		return supports
	
	
	def set_speed(self, x, y, z):
		supports = self.action.set_speed(x, y, z)
		if self.normalaction:
			supports = self.normalaction.set_speed(x, y, z) or supports
		if self.holdaction:
			supports = self.holdaction.set_speed(x, y, z) or supports
		return supports
	
	
	def strip(self):
		if self.holdaction:
			return self.holdaction.strip()
		return self.action.strip()
	
	
	def compress(self):
		self.action = self.action.compress()
		self.holdaction = self.holdaction.compress()
		self.normalaction = self.normalaction.compress()
		
		if isinstance(self.normalaction, DoubleclickModifier):
			self.action = self.action.compress() or self.normalaction.action.compress()
			self.holdaction = self.holdaction.compress() or self.normalaction.holdaction.compress()
			self.normalaction = self.normalaction.normalaction.compress()
		elif isinstance(self.action, HoldModifier):
			self.holdaction = self.action.holdaction.compress()
			self.action = self.action.normalaction.compress()
		elif isinstance(self.holdaction, DoubleclickModifier):
			self.action = self.holdaction.action.compress()
			self.holdaction = self.holdaction.normalaction.compress()
		elif isinstance(self.holdaction, DoubleclickModifier):
			self.action = self.action.compress() or self.holdaction.action.compress()
			self.normalaction = self.normalaction.compress() or self.holdaction.normalaction.compress()
			self.holdaction = self.holdaction.holdaction.compress()
		return self
	
	
	def __str__(self):
		l = [ self.action ]
		if self.normalaction:
			l += [ self.normalaction ]
		return "<Modifier %s dbl='%s' hold='%s' normal='%s'>" % (
			self.COMMAND, self.action, self.holdaction, self.normalaction )
	
	__repr__ = __str__
	
	
	def describe(self, context):
		l = [ ]
		if self.action:
			l += [ self.action ]
		if self.holdaction:
			l += [ self.holdaction ]
		if self.normalaction:
			l += [ self.normalaction ]
		return "\n".join([ x.describe(context) for x in l ])
	
	
	def to_string(self, multiline=False, pad=0):
		firstline, lastline = "", ""
		if self.action:
			firstline += DoubleclickModifier.COMMAND + "(" + self.action.to_string() + ","
			lastline += ")"
		if self.holdaction:
			firstline += HoldModifier.COMMAND + "(" + self.holdaction.to_string() + ","
			lastline += ")"
		
		if multiline:
			if self.normalaction:
				rv = [ (" " * pad) + firstline ]
				rv += self.normalaction.to_string(True, pad+2).split("\n")
				rv += [ (" " * pad) + lastline ]
			else:
				rv = [ firstline.strip(",") + lastline ]
			return "\n".join(rv)
		elif self.normalaction:
			return firstline + self.normalaction.to_string() + lastline
		else:
			return firstline.strip(",") + lastline
	
	
	def encode(self):
		if self.normalaction:
			rv = self.normalaction.encode()
		else:
			rv = {}
		rv['doubleclick'] = self.action.encode()
		if self.holdaction:
			rv['hold'] = self.holdaction.encode()
		if self.name: rv['name'] = self.name
		return rv
	
	
	def button_press(self, mapper):
		self.pressed = True
		if self.waiting:
			# Double-click happened
			mapper.remove_scheduled(self.on_timeout)
			self.waiting = False
			self.active = self.action
			self.active.button_press(mapper)
		else:
			# First click, start the timer
			self.waiting = True
			mapper.schedule(self.timeout, self.on_timeout)
	
	
	def button_release(self, mapper):
		self.pressed = False
		if self.waiting and self.active is None and not self.action:
			# In HoldModifier, button released before timeout
			mapper.remove_scheduled(self.on_timeout)
			self.waiting = False
			if self.normalaction:
				self.normalaction.button_press(mapper)
				self.normalaction.button_release(mapper)
		elif self.active:
			# Released held button
			self.active.button_release(mapper)
			self.active = None
	
	
	def on_timeout(self, mapper, *a):
		if self.waiting:
			self.waiting = False
			if self.pressed:
				# Timeouted while button is still pressed
				self.active = self.holdaction if self.holdaction else self.normalaction
				self.active.button_press(mapper)
			elif self.normalaction:
				# User did short click and nothing else
				self.normalaction.button_press(mapper)
				self.normalaction.button_release(mapper)
예제 #5
0
class ModeModifier(Modifier):
	COMMAND = "mode"
	MIN_TRIGGER = 2		# When trigger is bellow this position, list of held_triggers is cleared
	MIN_STICK = 2		# When abs(stick) < MIN_STICK, stick is considered released and held_sticks is cleared
	
	def __init__(self, *stuff):
		Modifier.__init__(self)
		self.default = None
		self.mods = {}
		self.held_buttons = set()
		self.held_sticks = set()
		self.held_triggers = {}
		self.order = []
		self.old_gyro = None
		button = None
		for i in stuff:
			if self.default is not None:
				# Default has to be last parameter
				raise ValueError("Invalid parameters for 'mode'")
			if isinstance(i, Action):
				if button is None:
					self.default = i
					continue
				self.mods[button] = i
				self.order.append(button)
				button = None
			elif i in SCButtons:
				button = i
			else:
				raise ValueError("Invalid parameter for 'mode': %s" % (i,))
		if self.default is None:
			self.default = NoAction()
	
	
	def set_haptic(self, hapticdata):
		supports = False
		if self.default:
			supports = self.default.set_haptic(hapticdata) or supports
		for a in self.mods.values():
			supports = a.set_haptic(hapticdata) or supports
		return supports
	
	
	def set_speed(self, x, y, z):
		supports = False
		if self.default:
			supports = self.default.set_speed(x, y, z) or supports
		for a in self.mods.values():
			supports = a.set_speed(x, y, z) or supports
		return supports
	
	
	def strip(self):
		# Returns default action or action assigned to first modifier
		if self.default:
			return self.default.strip()
		if len(self.order) > 0:
			return self.mods[self.order[0]].strip()
		# Empty ModeModifier
		return NoAction()
	
	
	def compress(self):
		if self.default:
			self.default = self.default.compress()
		for button in self.mods:
			self.mods[button] = self.mods[button].compress()
		return self
	
	
	def __str__(self):
		rv = [ ]
		for key in self.mods:
			rv += [ key.name, self.mods[key] ]
		if self.default is not None:
			rv += [ self.default ]
		return "<Modifier '%s', %s>" % (self.COMMAND, rv)
	
	__repr__ = __str__
	
	
	def describe(self, context):
		l = []
		if self.default : l.append(self.default)
		for x in self.order:
			l.append(self.mods[x])
		return "\n".join([ x.describe(context) for x in l ])
	
	
	def to_string(self, multiline=False, pad=0):
		if multiline:
			rv = [ (" " * pad) + "mode(" ]
			for key in self.mods:
				a_str = self.mods[key].to_string(True).split("\n")
				a_str[0] = (" " * pad) + "  " + (key.name + ",").ljust(11) + a_str[0]	# Key has to be one of SCButtons
				for i in xrange(1, len(a_str)):
					a_str[i] = (" " * pad) + "  " + a_str[i]
				a_str[-1] = a_str[-1] + ","
				rv += a_str
			if self.default is not None:
				a_str = [
					(" " * pad) + "  " + x
					for x in  self.default.to_string(True).split("\n")
				]
				rv += a_str
			if rv[-1][-1] == ",":
				rv[-1] = rv[-1][0:-1]
			rv += [ (" " * pad) + ")" ]
			return "\n".join(rv)
		else:
			rv = [ ]
			for key in self.mods:
				rv += [ key.name, self.mods[key].to_string(False) ]
			if self.default is not None:
				rv += [ self.default.to_string(False) ]
			return "mode(" + ", ".join(rv) + ")"
	
	
	def encode(self):
		rv = self.default.encode()
		rv['modes'] = {}
		for key in self.mods:
			rv['modes'][key.name] = self.mods[key].encode()
		if self.name: rv['name'] = self.name
		return rv
	
	
	def select(self, mapper):
		"""
		Selects action by pressed button.
		"""
		for b in self.order:
			if mapper.is_pressed(b):
				return self.mods[b]
		return self.default
	
	
	def select_b(self, mapper):
		"""
		Same as select but returns button as well.
		"""
		for b in self.order:
			if mapper.is_pressed(b):
				return b, self.mods[b]
		return None, self.default
	
	
	def button_press(self, mapper):
		sel = self.select(mapper)
		self.held_buttons.add(sel)
		return sel.button_press(mapper)
	
	
	def button_release(self, mapper):
		# Releases all held buttons, not just button that matches
		# currently pressed modifier
		for b in self.held_buttons:
			b.button_release(mapper)
	
	
	def trigger(self, mapper, position, old_position):
		if position < ModeModifier.MIN_TRIGGER:
			for b in self.held_triggers:
				b.trigger(mapper, 0, self.held_triggers[b])
			self.held_triggers = {}
			return False
		else:
			sel = self.select(mapper)
			self.held_triggers[sel] = position
			return sel.trigger(mapper, position, old_position)
		
	
	def axis(self, mapper, position, what):
		return self.select(mapper).axis(mapper, position, what)
	
	
	def gyro(self, mapper, pitch, yaw, roll, *q):
		sel = self.select(mapper)
		if sel is not self.old_gyro:
			if self.old_gyro:
				self.old_gyro.gyro(mapper, 0, 0, 0, *q)
			self.old_gyro = sel
		return sel.gyro(mapper, pitch, yaw, roll, *q)
	
	def pad(self, mapper, position, what):
		return self.select(mapper).pad(mapper, position, what)
	
	def whole(self, mapper, x, y, what):
		if what == STICK:
			if abs(x) < ModeModifier.MIN_STICK and abs(y) < ModeModifier.MIN_STICK:
				for b in self.held_sticks:
					b.whole(mapper, 0, 0, what)
				self.held_sticks.clear()
			else:
				self.held_sticks.add(self.select(mapper))
				for b in self.held_sticks:
					b.whole(mapper, x, y, what)
		else:
			return self.select(mapper).whole(mapper, x, y, what)
예제 #6
0
class DoubleclickModifier(Modifier):
    COMMAND = "doubleclick"
    DEAFAULT_TIMEOUT = 0.2

    def __init__(self, doubleclickaction, normalaction=None):
        Modifier.__init__(self)
        self.action = doubleclickaction
        self.normalaction = normalaction or NoAction()
        self.holdaction = NoAction()
        self.timeout = self.DEAFAULT_TIMEOUT
        self.waiting = False
        self.pressed = False
        self.active = None

    def set_haptic(self, hapticdata):
        supports = self.action.set_haptic(hapticdata)
        if self.normalaction:
            supports = self.normalaction.set_haptic(hapticdata) or supports
        if self.holdaction:
            supports = self.holdaction.set_haptic(hapticdata) or supports
        return supports

    def set_speed(self, x, y, z):
        supports = self.action.set_speed(x, y, z)
        if self.normalaction:
            supports = self.normalaction.set_speed(x, y, z) or supports
        if self.holdaction:
            supports = self.holdaction.set_speed(x, y, z) or supports
        return supports

    def strip(self):
        if self.holdaction:
            return self.holdaction.strip()
        return self.action.strip()

    def compress(self):
        self.action = self.action.compress()
        self.holdaction = self.holdaction.compress()
        self.normalaction = self.normalaction.compress()

        if isinstance(self.normalaction, DoubleclickModifier):
            self.action = self.action.compress(
            ) or self.normalaction.action.compress()
            self.holdaction = self.holdaction.compress(
            ) or self.normalaction.holdaction.compress()
            self.normalaction = self.normalaction.normalaction.compress()
        elif isinstance(self.action, HoldModifier):
            self.holdaction = self.action.holdaction.compress()
            self.action = self.action.normalaction.compress()
        elif isinstance(self.holdaction, DoubleclickModifier):
            self.action = self.holdaction.action.compress()
            self.holdaction = self.holdaction.normalaction.compress()
        elif isinstance(self.holdaction, DoubleclickModifier):
            self.action = self.action.compress(
            ) or self.holdaction.action.compress()
            self.normalaction = self.normalaction.compress(
            ) or self.holdaction.normalaction.compress()
            self.holdaction = self.holdaction.holdaction.compress()
        return self

    def __str__(self):
        l = [self.action]
        if self.normalaction:
            l += [self.normalaction]
        return "<Modifier %s dbl='%s' hold='%s' normal='%s'>" % (
            self.COMMAND, self.action, self.holdaction, self.normalaction)

    __repr__ = __str__

    def describe(self, context):
        l = []
        if self.action:
            l += [self.action]
        if self.holdaction:
            l += [self.holdaction]
        if self.normalaction:
            l += [self.normalaction]
        return "\n".join([x.describe(context) for x in l])

    def to_string(self, multiline=False, pad=0):
        firstline, lastline = "", ""
        if self.action:
            firstline += DoubleclickModifier.COMMAND + "(" + self.action.to_string(
            ) + ","
            lastline += ")"
        if self.holdaction:
            firstline += HoldModifier.COMMAND + "(" + self.holdaction.to_string(
            ) + ","
            lastline += ")"

        if multiline:
            if self.normalaction:
                rv = [(" " * pad) + firstline]
                rv += self.normalaction.to_string(True, pad + 2).split("\n")
                rv += [(" " * pad) + lastline]
            else:
                rv = [firstline.strip(",") + lastline]
            return "\n".join(rv)
        elif self.normalaction:
            return firstline + self.normalaction.to_string() + lastline
        else:
            return firstline.strip(",") + lastline

    def encode(self):
        if self.normalaction:
            rv = self.normalaction.encode()
        else:
            rv = {}
        rv['doubleclick'] = self.action.encode()
        if self.holdaction:
            rv['hold'] = self.holdaction.encode()
        if self.name: rv['name'] = self.name
        return rv

    def button_press(self, mapper):
        self.pressed = True
        if self.waiting:
            # Double-click happened
            mapper.remove_scheduled(self.on_timeout)
            self.waiting = False
            self.active = self.action
            self.active.button_press(mapper)
        else:
            # First click, start the timer
            self.waiting = True
            mapper.schedule(self.timeout, self.on_timeout)

    def button_release(self, mapper):
        self.pressed = False
        if self.waiting and self.active is None and not self.action:
            # In HoldModifier, button released before timeout
            mapper.remove_scheduled(self.on_timeout)
            self.waiting = False
            if self.normalaction:
                self.normalaction.button_press(mapper)
                self.normalaction.button_release(mapper)
        elif self.active:
            # Released held button
            self.active.button_release(mapper)
            self.active = None

    def on_timeout(self, mapper, *a):
        if self.waiting:
            self.waiting = False
            if self.pressed:
                # Timeouted while button is still pressed
                self.active = self.holdaction if self.holdaction else self.normalaction
                self.active.button_press(mapper)
            elif self.normalaction:
                # User did short click and nothing else
                self.normalaction.button_press(mapper)
                self.normalaction.button_release(mapper)
예제 #7
0
class ModeModifier(Modifier):
    COMMAND = "mode"
    MIN_TRIGGER = 2  # When trigger is bellow this position, list of held_triggers is cleared
    MIN_STICK = 2  # When abs(stick) < MIN_STICK, stick is considered released and held_sticks is cleared

    def __init__(self, *stuff):
        Modifier.__init__(self)
        self.default = None
        self.mods = {}
        self.held_buttons = set()
        self.held_sticks = set()
        self.held_triggers = {}
        self.order = []
        self.old_gyro = None
        button = None
        for i in stuff:
            if self.default is not None:
                # Default has to be last parameter
                raise ValueError("Invalid parameters for 'mode'")
            if isinstance(i, Action):
                if button is None:
                    self.default = i
                    continue
                self.mods[button] = i
                self.order.append(button)
                button = None
            elif i in SCButtons:
                button = i
            else:
                raise ValueError("Invalid parameter for 'mode': %s" % (i, ))
        if self.default is None:
            self.default = NoAction()

    def set_haptic(self, hapticdata):
        supports = False
        if self.default:
            supports = self.default.set_haptic(hapticdata) or supports
        for a in self.mods.values():
            supports = a.set_haptic(hapticdata) or supports
        return supports

    def set_speed(self, x, y, z):
        supports = False
        if self.default:
            supports = self.default.set_speed(x, y, z) or supports
        for a in self.mods.values():
            supports = a.set_speed(x, y, z) or supports
        return supports

    def strip(self):
        # Returns default action or action assigned to first modifier
        if self.default:
            return self.default.strip()
        if len(self.order) > 0:
            return self.mods[self.order[0]].strip()
        # Empty ModeModifier
        return NoAction()

    def compress(self):
        if self.default:
            self.default = self.default.compress()
        for button in self.mods:
            self.mods[button] = self.mods[button].compress()
        return self

    def __str__(self):
        rv = []
        for key in self.mods:
            rv += [key.name, self.mods[key]]
        if self.default is not None:
            rv += [self.default]
        return "<Modifier '%s', %s>" % (self.COMMAND, rv)

    __repr__ = __str__

    def describe(self, context):
        l = []
        if self.default: l.append(self.default)
        for x in self.order:
            l.append(self.mods[x])
        return "\n".join([x.describe(context) for x in l])

    def to_string(self, multiline=False, pad=0):
        if multiline:
            rv = [(" " * pad) + "mode("]
            for key in self.mods:
                a_str = self.mods[key].to_string(True).split("\n")
                a_str[0] = (" " * pad) + "  " + (key.name + ",").ljust(
                    11) + a_str[0]  # Key has to be one of SCButtons
                for i in xrange(1, len(a_str)):
                    a_str[i] = (" " * pad) + "  " + a_str[i]
                a_str[-1] = a_str[-1] + ","
                rv += a_str
            if self.default is not None:
                a_str = [(" " * pad) + "  " + x
                         for x in self.default.to_string(True).split("\n")]
                rv += a_str
            if rv[-1][-1] == ",":
                rv[-1] = rv[-1][0:-1]
            rv += [(" " * pad) + ")"]
            return "\n".join(rv)
        else:
            rv = []
            for key in self.mods:
                rv += [key.name, self.mods[key].to_string(False)]
            if self.default is not None:
                rv += [self.default.to_string(False)]
            return "mode(" + ", ".join(rv) + ")"

    def encode(self):
        rv = self.default.encode()
        rv['modes'] = {}
        for key in self.mods:
            rv['modes'][key.name] = self.mods[key].encode()
        if self.name: rv['name'] = self.name
        return rv

    def select(self, mapper):
        """
		Selects action by pressed button.
		"""
        for b in self.order:
            if mapper.is_pressed(b):
                return self.mods[b]
        return self.default

    def select_b(self, mapper):
        """
		Same as select but returns button as well.
		"""
        for b in self.order:
            if mapper.is_pressed(b):
                return b, self.mods[b]
        return None, self.default

    def button_press(self, mapper):
        sel = self.select(mapper)
        self.held_buttons.add(sel)
        return sel.button_press(mapper)

    def button_release(self, mapper):
        # Releases all held buttons, not just button that matches
        # currently pressed modifier
        for b in self.held_buttons:
            b.button_release(mapper)

    def trigger(self, mapper, position, old_position):
        if position < ModeModifier.MIN_TRIGGER:
            for b in self.held_triggers:
                b.trigger(mapper, 0, self.held_triggers[b])
            self.held_triggers = {}
            return False
        else:
            sel = self.select(mapper)
            self.held_triggers[sel] = position
            return sel.trigger(mapper, position, old_position)

    def axis(self, mapper, position, what):
        return self.select(mapper).axis(mapper, position, what)

    def gyro(self, mapper, pitch, yaw, roll, *q):
        sel = self.select(mapper)
        if sel is not self.old_gyro:
            if self.old_gyro:
                self.old_gyro.gyro(mapper, 0, 0, 0, *q)
            self.old_gyro = sel
        return sel.gyro(mapper, pitch, yaw, roll, *q)

    def pad(self, mapper, position, what):
        return self.select(mapper).pad(mapper, position, what)

    def whole(self, mapper, x, y, what):
        if what == STICK:
            if abs(x) < ModeModifier.MIN_STICK and abs(
                    y) < ModeModifier.MIN_STICK:
                for b in self.held_sticks:
                    b.whole(mapper, 0, 0, what)
                self.held_sticks.clear()
            else:
                self.held_sticks.add(self.select(mapper))
                for b in self.held_sticks:
                    b.whole(mapper, x, y, what)
        else:
            return self.select(mapper).whole(mapper, x, y, what)
예제 #8
0
class DoubleclickModifier(Modifier):
	COMMAND = "doubleclick"
	DEAFAULT_TIMEOUT = 0.2
	TIMEOUT_KEY = "time"
	PROFILE_KEY_PRIORITY = 3
	
	def __init__(self, doubleclickaction, normalaction=None, time=None):
		Modifier.__init__(self)
		self.action = doubleclickaction
		self.normalaction = normalaction or NoAction()
		self.holdaction = NoAction()
		self.timeout = time or DoubleclickModifier.DEAFAULT_TIMEOUT
		self.waiting = False
		self.pressed = False
		self.active = None
	
	
	def encode(self):
		if self.normalaction:
			rv = self.normalaction.encode()
		else:
			rv = {}
		rv[DoubleclickModifier.COMMAND] = self.action.encode()
		if self.holdaction:
			rv[HoldModifier.COMMAND] = self.holdaction.encode()
		if self.timeout != DoubleclickModifier.DEAFAULT_TIMEOUT:
			rv[DoubleclickModifier.TIMEOUT_KEY] = self.timeout
		if self.name:
			rv[NameModifier.COMMAND] = self.name
		return rv
	
	
	@staticmethod
	def decode(data, a, parser, *b):
		args = [ parser.from_json_data(data[DoubleclickModifier.COMMAND]), a ]
		a = DoubleclickModifier(*args)
		if DoubleclickModifier.TIMEOUT_KEY in data:
			a.timeout = data[DoubleclickModifier.TIMEOUT_KEY]
		return a
	
	
	def strip(self):
		if self.holdaction:
			return self.holdaction.strip()
		return self.action.strip()
	
	
	def compress(self):
		self.action = self.action.compress()
		self.holdaction = self.holdaction.compress()
		self.normalaction = self.normalaction.compress()
		
		if isinstance(self.normalaction, DoubleclickModifier):
			self.action = self.action.compress() or self.normalaction.action.compress()
			self.holdaction = self.holdaction.compress() or self.normalaction.holdaction.compress()
			self.normalaction = self.normalaction.normalaction.compress()
		elif isinstance(self.action, HoldModifier):
			self.holdaction = self.action.holdaction.compress()
			self.action = self.action.normalaction.compress()
		elif isinstance(self.holdaction, DoubleclickModifier):
			self.action = self.holdaction.action.compress()
			self.holdaction = self.holdaction.normalaction.compress()
		elif isinstance(self.holdaction, DoubleclickModifier):
			self.action = self.action.compress() or self.holdaction.action.compress()
			self.normalaction = self.normalaction.compress() or self.holdaction.normalaction.compress()
			self.holdaction = self.holdaction.holdaction.compress()
		return self
	
	
	def __str__(self):
		l = [ self.action ]
		if self.normalaction:
			l += [ self.normalaction ]
		return "<Modifier %s dbl='%s' hold='%s' normal='%s'>" % (
			self.COMMAND, self.action, self.holdaction, self.normalaction )
	
	__repr__ = __str__
	
	
	def describe(self, context):
		l = [ ]
		if self.action:
			l += [ self.action ]
		if self.holdaction:
			l += [ self.holdaction ]
		if self.normalaction:
			l += [ self.normalaction ]
		return "\n".join([ x.describe(context) for x in l ])
	
	
	def to_string(self, multiline=False, pad=0):
		return self._mod_to_string(Action.strip_defaults(self), multiline, pad)
	
	
	def button_press(self, mapper):
		self.pressed = True
		if self.waiting:
			# Double-click happened
			mapper.remove_scheduled(self.on_timeout)
			self.waiting = False
			self.active = self.action
			self.active.button_press(mapper)
		else:
			# First click, start the timer
			self.waiting = True
			mapper.schedule(self.timeout, self.on_timeout)
	
	
	def button_release(self, mapper):
		self.pressed = False
		if self.waiting and self.active is None and not self.action:
			# In HoldModifier, button released before timeout
			mapper.remove_scheduled(self.on_timeout)
			self.waiting = False
			if self.normalaction:
				self.normalaction.button_press(mapper)
				self.normalaction.button_release(mapper)
		elif self.active:
			# Released held button
			self.active.button_release(mapper)
			self.active = None
	
	
	def on_timeout(self, mapper, *a):
		if self.waiting:
			self.waiting = False
			if self.pressed:
				# Timeouted while button is still pressed
				self.active = self.holdaction if self.holdaction else self.normalaction
				self.active.button_press(mapper)
			elif self.normalaction:
				# User did short click and nothing else
				self.normalaction.button_press(mapper)
				self.normalaction.button_release(mapper)
예제 #9
0
class ModeModifier(Modifier):
	COMMAND = "mode"
	PROFILE_KEYS = ("modes",)
	MIN_TRIGGER = 2		# When trigger is bellow this position, list of held_triggers is cleared
	MIN_STICK = 2		# When abs(stick) < MIN_STICK, stick is considered released and held_sticks is cleared
	PROFILE_KEY_PRIORITY = 2
	
	def __init__(self, *stuff):
		Modifier.__init__(self)
		self.default = None
		self.mods = {}
		self.held_buttons = set()
		self.held_sticks = set()
		self.held_triggers = {}
		self.order = []
		self.old_gyro = None
		self.timeout = DoubleclickModifier.DEAFAULT_TIMEOUT

		button = None
		for i in stuff:
			if self.default is not None:
				# Default has to be last parameter
				raise ValueError("Invalid parameters for 'mode'")
			if isinstance(i, Action):
				if button is None:
					self.default = i
					continue
				self.mods[button] = i
				self.order.append(button)
				button = None
			elif i in SCButtons:
				button = i
			else:
				raise ValueError("Invalid parameter for 'mode': %s" % (i,))
		if self.default is None:
			self.default = NoAction()
	
	
	def encode(self):
		rv = self.default.encode()
		modes = {}
		for key in self.mods:
			modes[key.name] = self.mods[key].encode()
		rv[ModeModifier.PROFILE_KEYS[0]] = modes
		if self.name:
			rv[NameModifier.COMMAND] = self.name
		return rv
	
	
	@staticmethod
	def decode(data, a, parser, *b):
		args = []
		for button in data[ModeModifier.PROFILE_KEYS[0]]:
			if hasattr(SCButtons, button):
				args += [ getattr(SCButtons, button), parser.from_json_data(data[ModeModifier.PROFILE_KEYS[0]][button]) ]
		if a:
			args += [ a ]
		mm = ModeModifier(*args)
		if "name" in data:
			mm.name = data["name"]
		return mm
	
	
	def strip(self):
		# Returns default action or action assigned to first modifier
		if self.default:
			return self.default.strip()
		if len(self.order) > 0:
			return self.mods[self.order[0]].strip()
		# Empty ModeModifier
		return NoAction()
	
	
	def compress(self):
		if self.default:
			self.default = self.default.compress()
		for button in self.mods:
			self.mods[button] = self.mods[button].compress()
		return self
	
	
	def __str__(self):
		rv = [ ]
		for key in self.mods:
			rv += [ key.name, self.mods[key] ]
		if self.default is not None:
			rv += [ self.default ]
		return "<Modifier '%s', %s>" % (self.COMMAND, rv)
	
	__repr__ = __str__
	
	
	def describe(self, context):
		if self.name: return self.name
		l = []
		if self.default : l.append(self.default)
		for x in self.order:
			l.append(self.mods[x])
		return "\n".join([ x.describe(context) for x in l ])
	
	
	def to_string(self, multiline=False, pad=0):
		if multiline:
			rv = [ (" " * pad) + "mode(" ]
			for key in self.mods:
				a_str = self.mods[key].to_string(True).split("\n")
				a_str[0] = (" " * pad) + "  " + (key.name + ",").ljust(11) + a_str[0]	# Key has to be one of SCButtons
				for i in xrange(1, len(a_str)):
					a_str[i] = (" " * pad) + "  " + a_str[i]
				a_str[-1] = a_str[-1] + ","
				rv += a_str
			if self.default is not None:
				a_str = [
					(" " * pad) + "  " + x
					for x in  self.default.to_string(True).split("\n")
				]
				rv += a_str
			if rv[-1][-1] == ",":
				rv[-1] = rv[-1][0:-1]
			rv += [ (" " * pad) + ")" ]
			return "\n".join(rv)
		else:
			rv = [ ]
			for key in self.mods:
				rv += [ key.name, self.mods[key].to_string(False) ]
			if self.default is not None:
				rv += [ self.default.to_string(False) ]
			return "mode(" + ", ".join(rv) + ")"
	
	
	def select(self, mapper):
		"""
		Selects action by pressed button.
		"""
		for b in self.order:
			if mapper.is_pressed(b):
				return self.mods[b]
		return self.default
	
	
	def select_b(self, mapper):
		"""
		Same as select but returns button as well.
		"""
		for b in self.order:
			if mapper.is_pressed(b):
				return b, self.mods[b]
		return None, self.default
	
	
	def button_press(self, mapper):
		sel = self.select(mapper)
		self.held_buttons.add(sel)
		return sel.button_press(mapper)
	
	
	def button_release(self, mapper):
		# Releases all held buttons, not just button that matches
		# currently pressed modifier
		for b in self.held_buttons:
			b.button_release(mapper)
	
	
	def trigger(self, mapper, position, old_position):
		if position < ModeModifier.MIN_TRIGGER:
			for b in self.held_triggers:
				b.trigger(mapper, 0, self.held_triggers[b])
			self.held_triggers = {}
			return False
		else:
			sel = self.select(mapper)
			self.held_triggers[sel] = position
			return sel.trigger(mapper, position, old_position)
		
	
	def axis(self, mapper, position, what):
		return self.select(mapper).axis(mapper, position, what)
	
	
	def gyro(self, mapper, pitch, yaw, roll, *q):
		sel = self.select(mapper)
		if sel is not self.old_gyro:
			if self.old_gyro:
				self.old_gyro.gyro(mapper, 0, 0, 0, *q)
			self.old_gyro = sel
		return sel.gyro(mapper, pitch, yaw, roll, *q)
	
	def pad(self, mapper, position, what):
		return self.select(mapper).pad(mapper, position, what)
	
	def whole(self, mapper, x, y, what):
		if what == STICK:
			if abs(x) < ModeModifier.MIN_STICK and abs(y) < ModeModifier.MIN_STICK:
				for b in self.held_sticks:
					b.whole(mapper, 0, 0, what)
				self.held_sticks.clear()
			else:
				self.held_sticks.add(self.select(mapper))
				for b in self.held_sticks:
					b.whole(mapper, x, y, what)
		else:
			return self.select(mapper).whole(mapper, x, y, what)
예제 #10
0
class Modifier(Action):
	def __init__(self, *params):
		Action.__init__(self, *params)
		params = list(params)
		for p in params:
			if isinstance(p, Action):
				self.action = p
				params.remove(p)
				break
		else:
			self.action = NoAction()
		self._mod_init(*params)
	
	
	def _mod_init(self):
		"""
		Initializes modifier with rest of parameters, after action nparameter
		was taken from it and stored in self.action
		"""
		pass # not needed by default
	
	
	def _mod_to_string(self, params, multiline, pad):
		""" Adds action at end of params list and generates string """
		if multiline:
			childstr = self.action.to_string(True, pad + 2)
			if len(params) > 0:
				return "%s%s(%s,%s%s)" % (
					" " * pad,
					self.COMMAND,
					", ".join([ nameof(s) for s in params ]),
					'\n' if '\n' in childstr else ' ',
					childstr
				)
		childstr = self.action.to_string(False, pad)
		if len(params) > 0:
			return "%s%s(%s, %s)" % (
				" " * pad,
				self.COMMAND,
				", ".join([ nameof(s) for s in params ]),
				childstr
			)
		
		return "%s%s(%s)" % (
			" " * pad,
			self.COMMAND,
			childstr
		)
	
	
	def strip_defaults(self):
		"""
		Overrides Action.strip_defaults; Uses defaults from _mod_init instead
		of __init__, but does NOT include last of original parameters - action.
		"""
		argspec = inspect.getargspec(self.__class__._mod_init)
		required_count = len(argspec.args) - len(argspec.defaults) - 1
		d = list(argspec.defaults)
		l = list(self.parameters[0:-1])
		while len(d) and len(l) > required_count and d[-1] == l[-1]:
			d, l = d[:-1], l[:-1]
		return l
	
	
	def strip(self):
		return self.action
	
	
	def compress(self):
		if self.action:
			self.action = self.action.compress()
		return self
	
	
	def __str__(self):
		return "<Modifier '%s', %s>" % (self.COMMAND, self.action)
	
	__repr__ = __str__
	
	
	def encode(self):
		rv = self.action.encode()
		if self.name:
			rv[NameModifier.COMMAND] = self.name
		return rv