Exemplo n.º 1
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
Exemplo n.º 2
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):
		# TODO: Better documentation for this. For now, using shell
		# TODO: and range as condition is not documented
		Modifier.__init__(self)
		self.default = None
		self.mods = OrderedDict()
		self.held_buttons = set()
		self.held_sticks = set()
		self.held_triggers = {}
		self.old_action = None
		self.shell_commands = {}
		self.shell_timeout = 0.5
		self.timeout = DoubleclickModifier.DEAFAULT_TIMEOUT
		
		# ShellCommandAction cannot be imported normally, it would create
		# import cycle of hell
		ShellCommandAction = Action.ALL['shell']
		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, ShellCommandAction) and button is None:
				# 'shell' can be used instead of button
				button = i
			elif isinstance(i, Action) and button is None:	
				self.default = i
			elif isinstance(i, Action):
				self.mods[button] = i
				button = None
			elif isinstance(i, RangeOP) or i in SCButtons:
				button = i
			else:
				raise ValueError("Invalid parameter for 'mode': %s" % (i,))
		self.make_checks()
		if self.default is None:
			if isinstance(button, ShellCommandAction):
				self.default = button
			else:
				self.default = NoAction()
	
	
	def make_checks(self):
		self.checks = []
		self.shell_commands = {}
		ShellCommandAction = Action.ALL['shell']
		for c, action in self.mods.items():
			if isinstance(c, RangeOP):
				self.checks.append(( c, action ))
			elif isinstance(c, ShellCommandAction):
				self.shell_commands[c.command] = c
				self.checks.append(( self.make_shell_check(c), action ))
			else:
				self.checks.append(( self.make_button_check(c), action ))
	
	
	def get_child_actions(self):
		rv = list(self.mods.values()) + list(self.shell_commands.values())
		if self.default is not None:
			rv += [ self.default ]
		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 action in self.mods.values():
			rv |= action.get_compatible_modifiers()
		if self.default:
			rv |= self.default.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.mods):
			return self.mods.values()[0].strip()
		# Empty ModeModifier
		return NoAction()
	
	
	def compress(self):
		if self.default:
			self.default = self.default.compress()
		for check in self.mods:
			self.mods[check] = self.mods[check].compress()
		self.make_checks()
		return self
	
	
	def __str__(self):
		rv = [ ]
		for check in self.mods:
			rv += [ nameof(check), self.mods[check] ]
		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 check in self.mods:
			l.append(self.mods[check])
		return "\n".join([ x.describe(context) for x in l ])
	
	
	def to_string(self, multiline=False, pad=0):
		if multiline:
			rv = [ (" " * pad) + "mode(" ]
			for check in self.mods:
				a_str = NameModifier.unstrip(self.mods[check]).to_string(True).split("\n")
				a_str[0] = (" " * pad) + "  " + (nameof(check) + ",").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 NameModifier.unstrip(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 check in self.mods:
				rv += [ nameof(check), NameModifier.unstrip(self.mods[check]).to_string(False) ]
			if self.default is not None:
				rv += [ NameModifier.unstrip(self.default).to_string(False) ]
			return "mode(" + ", ".join(rv) + ")"
	
	
	def cancel(self, mapper):
		for action in self.mods.values():
			action.cancel(mapper)
		self.default.cancel(mapper)
	
	
	def select(self, mapper):
		"""
		Selects action by pressed button.
		"""
		for check, action in self.checks:
			if check(mapper):
				return action
		return self.default
	
	
	def select_w_check(self, mapper):
		"""
		As select, but returns matched check as well.
		"""
		for check, action in self.checks:
			if check(mapper):
				return check, action
		return lambda *a:True, self.default
	
	
	@staticmethod
	def make_button_check(button):
		def cb(mapper):
			return mapper.is_pressed(button)
		
		cb.name = button.name	# So nameof() still works on keys in self.mods
		return cb
	
	
	@staticmethod
	def make_shell_check(c):
		def cb(mapper):
			try:
				return c.__proc.poll() == 0
			except:
				return False
		
		c.name = cb.name = c.to_string()	# So nameof() still works on keys in self.mods
		c.__proc = None
		return cb
	
	
	def button_press(self, mapper):
		if len(self.shell_commands) > 0:
			# https://github.com/kozec/sc-controller/issues/427
			# If 'shell' is used as any condition, all shell commands
			# are executed and ModeShift waits up to 500ms for them
			# to terminate. Then, if command returned zero exit code
			# it's considered as 'true' condition.
			for c in self.shell_commands.values():
				c.__proc = c.button_press(mapper)
			self.shell_timeout = 0.5
			mapper.schedule(0, self.check_shell_commands)
			return
		
		sel = self.select(mapper)
		self.held_buttons.add(sel)
		return sel.button_press(mapper)
	
	
	def check_shell_commands(self, mapper):
		for c in self.shell_commands.values():
			if c.__proc and c.__proc.poll() == 0:
				sel = self.select(mapper)
				self.kill_shell_commands()
				self.held_buttons.add(sel)
				return sel.button_press(mapper)
		
		self.shell_timeout -= 0.05
		if self.shell_timeout > 0:
			mapper.schedule(0.05, self.check_shell_commands)
		else:
			# time is up, kill all processes and execute what's left
			self.kill_shell_commands()
			sel = self.select(mapper)
			self.held_buttons.add(sel)
			return sel.button_press(mapper)
	
	
	def kill_shell_commands(self):
		for c in self.shell_commands.values():
			try:
				if c.__proc: c.__proc.kill()
			except: pass
			c.__proc = None
	
	
	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_action:
			if self.old_action:
				self.old_action.gyro(mapper, 0, 0, 0, *q)
			self.old_action = 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 check, action in self.held_sticks:
					action.whole(mapper, 0, 0, what)
				self.held_sticks.clear()
			else:
				ac, active = self.select_w_check(mapper)
				self.held_sticks.add(( ac, active ))
				for check, action in list(self.held_sticks):
					if check == ac or check(mapper):
						action.whole(mapper, x, y, what)
					else:
						action.whole(mapper, 0, 0, what)
						self.held_sticks.remove(( check, action ))
			mapper.force_event.add(FE_STICK)
		else:
			sel = self.select(mapper)
			if sel is not self.old_action:
				mapper.set_button(what, False)
				if self.old_action:
					self.old_action.whole(mapper, 0, 0, what)
				self.old_action = sel
				rv = sel.whole(mapper, x, y, what)
				mapper.set_button(what, True)
				return rv
			else:
				return sel.whole(mapper, x, y, what)
Exemplo n.º 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 = OrderedDict()
        self.held_buttons = set()
        self.held_sticks = set()
        self.held_triggers = {}
        self.old_action = 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) and button is None:
                self.default = i
            elif isinstance(i, Action):
                self.mods[button] = i
                button = None
            elif isinstance(i, RangeOP) or i in SCButtons:
                button = i
            else:
                raise ValueError("Invalid parameter for 'mode': %s" % (i, ))
        self.make_checks()
        if self.default is None:
            self.default = NoAction()

    def make_checks(self):
        self.checks = []
        for button, action in self.mods.items():
            if isinstance(button, RangeOP):
                self.checks.append((button, action))
            else:
                self.checks.append((self.make_button_check(button), action))

    def get_child_actions(self):
        return self.mods.values()

    def encode(self):
        return {'action': self.to_string(False)}

    @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 action in self.mods.values():
            rv |= action.get_compatible_modifiers()
        if self.default:
            rv |= self.default.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.mods):
            return self.mods.values()[0].strip()
        # Empty ModeModifier
        return NoAction()

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

    def __str__(self):
        rv = []
        for check in self.mods:
            rv += [nameof(check), self.mods[check]]
        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 check in self.mods:
            l.append(self.mods[check])
        return "\n".join([x.describe(context) for x in l])

    def to_string(self, multiline=False, pad=0):
        if multiline:
            rv = [(" " * pad) + "mode("]
            for check in self.mods:
                a_str = self.mods[check].to_string(True).split("\n")
                a_str[0] = (" " * pad) + "  " + (nameof(check) + ",").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 check in self.mods:
                rv += [nameof(check), self.mods[check].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 check, action in self.checks:
            if check(mapper):
                return action
        return self.default

    @staticmethod
    def make_button_check(button):
        def cb(mapper):
            return mapper.is_pressed(button)

        cb.name = button.name  # So nameof() still works on keys in self.mods
        return cb

    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_action:
            if self.old_action:
                self.old_action.gyro(mapper, 0, 0, 0, *q)
            self.old_action = 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:
            sel = self.select(mapper)
            if sel is not self.old_action:
                mapper.set_button(what, False)
                if self.old_action:
                    self.old_action.whole(mapper, 0, 0, what)
                self.old_action = sel
                rv = sel.whole(mapper, x, y, what)
                mapper.set_button(what, True)
                return rv
            else:
                return sel.whole(mapper, x, y, what)
Exemplo n.º 4
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 cancel(self, mapper):
		self.action.cancel(mapper)
	
	
	def get_child_actions(self):
		return (self.action, )
	
	
	def _mod_init(self):
		"""
		Initializes modifier with rest of parameters, after action parameter
		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__