コード例 #1
0
ファイル: mapper.py プロジェクト: varlesh/sc-controller
	def create_gamepad(self, enabled, poller):
		""" Parses gamepad configuration and creates apropriate unput device """
		if not enabled or "SCC_NOGAMEPAD" in os.environ:
			# Completly undocumented and for debuging purposes only.
			# If set, no gamepad is emulated
			self.gamepad = Dummy()
			return
		cfg = Config()
		keys = ALL_BUTTONS[0:cfg["output"]["buttons"]]
		vendor = int(cfg["output"]["vendor"], 16)
		product = int(cfg["output"]["product"], 16)
		version = int(cfg["output"]["version"], 16)
		name = cfg["output"]["name"]
		rumble = cfg["output"]["rumble"] and poller != None
		axes = []
		i = 0
		for min, max in cfg["output"]["axes"]:
			fuzz, flat = 0, 0
			if abs(max - min) > 32768:
				fuzz, flat = 16, 128
			try:
				axes.append(( ALL_AXES[i], min, max, fuzz, flat ))
			except IndexError:
				# Out of axes
				break
			i += 1
		
		ui = UInput(vendor=vendor, product=product, version=version,
			name=name, keys=keys, axes=axes, rels=[], rumble=rumble)
		if poller and rumble:
			poller.register(ui.getDescriptor(), poller.POLLIN, self._rumble_ready)
		return ui
コード例 #2
0
 def __init__(self, *a, **b):
     Dummy.__init__(self, *a, **b)
     self.pressed = set([])
     self.mouse_x = 0
     self.mouse_y = 0
     self.scroll_x = 0
     self.scroll_y = 0
     self.axes = {}
コード例 #3
0
ファイル: mapper.py プロジェクト: wendeldr/sc-controller
    def __init__(self,
                 profile,
                 keyboard=b"SCController Keyboard",
                 mouse=b"SCController Mouse",
                 gamepad=b"Microsoft X-Box 360 pad"):
        """
		If any of keyboard, mouse or gamepad is set to None, that device
		will not be emulated.
		"""
        self.profile = profile
        self.controller = None
        self.xdisplay = None

        # Create virtual devices
        log.debug("Creating virtual devices")
        self.keyboard = Keyboard(name=keyboard) if keyboard else Dummy()
        log.debug("Keyboard: %s" % (self.keyboard, ))
        self.mouse = Mouse(name=mouse) if mouse else Dummy()
        log.debug("Mouse:    %s" % (self.mouse, ))
        self.gamepad = Gamepad(name=gamepad) if gamepad else Dummy()
        log.debug("Gamepad:  %s" % (self.gamepad, ))

        self.mouse.updateParams(friction=Mouse.DEFAULT_FRICTION,
                                xscale=Mouse.DEFAULT_XSCALE,
                                yscale=Mouse.DEFAULT_YSCALE)
        self.mouse.updateScrollParams(
            friction=0.1,  # Mouse.DEFAULT_SCR_FRICTION
            xscale=Mouse.DEFAULT_SCR_XSCALE,
            yscale=Mouse.DEFAULT_SCR_XSCALE)

        # Set by SCCDaemon instance; Used to handle actions
        # from scc.special_actions
        self._sa_handler = None

        # Setup emulation
        self.keypress_list = []
        self.keyrelease_list = []
        self.mouse_dq = [
            deque(maxlen=8),
            deque(maxlen=8),
            deque(maxlen=8),
            deque(maxlen=8)
        ]  # x, y, wheel, hwheel
        self.mouse_tb = [False, False]  # trackball mode for mouse / wheel
        self.mouse_feedback = [None, None]  # for mouse / wheel
        self.travelled = [
            0, 0
        ]  # for mouse / wheel, used when generating "rolling ball" feedback
        self.syn_list = set()
        self.scheduled_tasks = []
        self.buttons, self.old_buttons = 0, 0
        self.state, self.old_state = SCI_NULL, SCI_NULL
        self.mouse_movements = [None, None, None, None]
        self.force_event = set()
コード例 #4
0
ファイル: mapper.py プロジェクト: kozec/sc-controller
	def create_gamepad(self, enabled, poller):
		""" Parses gamepad configuration and creates apropriate unput device """
		if not enabled or "SCC_NOGAMEPAD" in os.environ:
			# Completly undocumented and for debuging purposes only.
			# If set, no gamepad is emulated
			self.gamepad = Dummy()
			return
		cfg = Config()
		keys = ALL_BUTTONS[0:cfg["output"]["buttons"]]
		vendor = int(cfg["output"]["vendor"], 16)
		product = int(cfg["output"]["product"], 16)
		version = int(cfg["output"]["version"], 16)
		name = cfg["output"]["name"]
		rumble = cfg["output"]["rumble"] and poller != None
		axes = []
		i = 0
		for min, max in cfg["output"]["axes"]:
			fuzz, flat = 0, 0
			if abs(max - min) > 32768:
				fuzz, flat = 16, 128
			try:
				axes.append(( ALL_AXES[i], min, max, fuzz, flat ))
			except IndexError:
				# Out of axes
				break
			i += 1
		
		ui = UInput(vendor=vendor, product=product, version=version,
			name=name, keys=keys, axes=axes, rels=[], rumble=rumble)
		if poller and rumble:
			poller.register(ui.getDescriptor(), poller.POLLIN, self._rumble_ready)
		return ui
コード例 #5
0
ファイル: mapper.py プロジェクト: GovanifY/sc-controller
    def __init__(self,
                 profile,
                 scheduler,
                 keyboard=b"SCController Keyboard",
                 mouse=b"SCController Mouse",
                 gamepad=True,
                 poller=None):
        """
		If any of keyboard, mouse or gamepad is set to None, that device
		will not be emulated.
		Emulated gamepad will have rumble enabled only if poller is set to
		instance and configuration allows it.
		"""
        self.profile = profile
        self.controller = None
        self.xdisplay = None
        self.scheduler = scheduler

        # Create virtual devices
        log.debug("Creating virtual devices")
        self.keyboard = self.create_keyboard(keyboard) if keyboard else Dummy()
        log.debug("Keyboard: %s" % (self.keyboard, ))
        self.mouse = self.create_mouse(mouse) if mouse else Dummy()
        log.debug("Mouse:    %s" % (self.mouse, ))
        self.gamepad = self.create_gamepad(gamepad,
                                           poller) if gamepad else Dummy()
        log.debug("Gamepad:  %s" % (self.gamepad, ))

        # Set by SCCDaemon instance; Used to handle actions
        # from scc.special_actions
        self._sa_handler = None

        # Setup emulation
        self.keypress_list = []
        self.keyrelease_list = []
        self.mouse_movements = [0, 0, 0,
                                0]  # mouse x, y, wheel vertical, horisontal
        self.feedbacks = [None, None]  # left, right
        self.pressed = {
        }  # for ButtonAction, holds number of times virtual button was pressed without releasing it first
        self.syn_list = set()
        self.buttons, self.old_buttons = 0, 0
        self.lpad_touched = False
        self.state, self.old_state = None, None
        self.force_event = set()
コード例 #6
0
    def __init__(self,
                 profile,
                 keyboard=b"SCController Keyboard",
                 mouse=b"SCController Mouse",
                 gamepad=b"Microsoft X-Box 360 pad"):
        """
		If any of keyboard, mouse or gamepad is set to None, that device
		will not be emulated.
		"""
        self.profile = profile
        self.controller = None
        self.xdisplay = None

        # Create virtual devices
        log.debug("Creating virtual devices")
        self.keyboard = Keyboard(name=keyboard) if keyboard else Dummy()
        log.debug("Keyboard: %s" % (self.keyboard, ))
        self.mouse = Mouse(name=mouse) if mouse else Dummy()
        log.debug("Mouse:    %s" % (self.mouse, ))
        self.gamepad = Gamepad(name=gamepad) if gamepad else Dummy()
        log.debug("Gamepad:  %s" % (self.gamepad, ))

        # Set by SCCDaemon instance; Used to handle actions
        # from scc.special_actions
        self._sa_handler = None

        # Setup emulation
        self.keypress_list = []
        self.keyrelease_list = []
        self.mouse_movements = [0, 0, 0,
                                0]  # mouse x, y, wheel vertical, horisontal
        self.feedbacks = [None, None]  # left, right
        self.pressed = {
        }  # for ButtonAction, holds number of times virtual button was pressed without releasing it first
        self.syn_list = set()
        self.scheduled_tasks = []
        self.buttons, self.old_buttons = 0, 0
        self.state, self.old_state = SCI_NULL, SCI_NULL
        self.force_event = set()
コード例 #7
0
class Mapper(object):
    DEBUG = False

    def __init__(self,
                 profile,
                 keyboard=b"SCController Keyboard",
                 mouse=b"SCController Mouse",
                 gamepad=True,
                 poller=None):
        """
		If any of keyboard, mouse or gamepad is set to None, that device
		will not be emulated.
		Emulated gamepad will have rumble enabled only if poller is set to
		instance and configuration allows it.
		"""
        self.profile = profile
        self.controller = None
        self.xdisplay = None

        # Create virtual devices
        log.debug("Creating virtual devices")
        self.keyboard = Keyboard(name=keyboard) if keyboard else Dummy()
        log.debug("Keyboard: %s" % (self.keyboard, ))
        self.mouse = Mouse(name=mouse) if mouse else Dummy()
        log.debug("Mouse:    %s" % (self.mouse, ))
        self.gamepad = self._create_gamepad(gamepad,
                                            poller) if gamepad else Dummy()
        log.debug("Gamepad:  %s" % (self.gamepad, ))

        # Set by SCCDaemon instance; Used to handle actions
        # from scc.special_actions
        self._sa_handler = None

        # Setup emulation
        self.keypress_list = []
        self.keyrelease_list = []
        self.mouse_movements = [0, 0, 0,
                                0]  # mouse x, y, wheel vertical, horisontal
        self.feedbacks = [None, None]  # left, right
        self.pressed = {
        }  # for ButtonAction, holds number of times virtual button was pressed without releasing it first
        self.syn_list = set()
        self.scheduled_tasks = []
        self.buttons, self.old_buttons = 0, 0
        self.lpad_touched = False
        self.state, self.old_state = None, None
        self.force_event = set()

    def _create_gamepad(self, enabled, poller):
        """ Parses gamepad configuration and creates apropriate unput device """
        if not enabled or "SCC_NOGAMEPAD" in os.environ:
            # Completly undocumented and for debuging purposes only.
            # If set, no gamepad is emulated
            self.gamepad = Dummy()
            return
        cfg = Config()
        keys = ALL_BUTTONS[0:cfg["output"]["buttons"]]
        vendor = int(cfg["output"]["vendor"], 16)
        product = int(cfg["output"]["product"], 16)
        version = int(cfg["output"]["version"], 16)
        name = cfg["output"]["name"]
        rumble = cfg["output"]["rumble"] and poller != None
        axes = []
        i = 0
        for min, max in cfg["output"]["axes"]:
            fuzz, flat = 0, 0
            if abs(max - min) > 32768:
                fuzz, flat = 16, 128
            try:
                axes.append((ALL_AXES[i], min, max, fuzz, flat))
            except IndexError:
                # Out of axes
                break
            i += 1

        ui = UInput(vendor=vendor,
                    product=product,
                    version=version,
                    name=name,
                    keys=keys,
                    axes=axes,
                    rels=[],
                    rumble=rumble)
        if poller:
            poller.register(ui.getDescriptor(), poller.POLLIN,
                            self._rumble_ready)
        return ui

    def _rumble_ready(self, fd, event):
        ef = self.gamepad.ff_read()
        if ef:  # tale of...
            self.send_feedback(
                HapticData(HapticPos.BOTH,
                           period=32760,
                           amplitude=ef.level,
                           count=min(0x7FFF,
                                     ef.duration * ef.repetitions / 30)))

    def get_gamepad_name(self):
        """
		Returns name of emulated gamepad (as displayed by jstest & co)
		or None if Dummy is assigned.
		"""
        if isinstance(self.gamepad, Dummy):
            return None
        return self.gamepad.name

    def sync(self):
        """ Syncs generated events """
        if len(self.syn_list):
            for dev in self.syn_list:
                dev.synEvent()
            self.syn_list = set()

    def set_controller(self, c):
        """ Sets controller device, used by some (one so far) actions """
        self.controller = c

    def get_controller(self):
        """ Returns assigned controller device or None if no controller is set """
        return self.controller

    def set_special_actions_handler(self, sa):
        self._sa_handler = sa

    def get_special_actions_handler(self):
        return self._sa_handler

    def set_xdisplay(self, x):
        self.xdisplay = x

    def get_xdisplay(self):
        return self.xdisplay

    def get_current_window(self):
        """
		Returns window id of current window or None if xdisplay is not set
		"""
        if self.xdisplay:
            return X.get_current_window(self.xdisplay)
        return None

    def schedule(self, delay, cb):
        """
		Schedules callback to be ran no sooner than after delay.
		Delay is float number in seconds.
		Callback is called with mapper as only argument.
		"""
        when = time.time() + delay
        self.scheduled_tasks.append((when, cb))
        self.scheduled_tasks.sort(key=lambda a: a[0])

    def remove_scheduled(self, cb):
        """ Removes scheduled task by callback. """
        self.scheduled_tasks = [(w, c) for (w, c) in self.scheduled_tasks
                                if cb != c]

    def mouse_move(self, dx, dy):
        """
		Schedules mouse movement to be done at end of processing callback.
		Called from actions while callback is being processed.
		"""
        self.mouse_movements[0] += dx
        self.mouse_movements[1] += dy

    def mouse_wheel(self, wx, wy):
        """
		Schedules mouse wheel movement to be done at end of processing callback.
		Called from actions while callback is being processed.
		"""
        self.mouse_movements[2] += wx
        self.mouse_movements[3] += wy

    def send_feedback(self, hapticdata):
        """
		Schedules haptic feedback to be sent at end of processing callback.
		Called from actions while callback is being processed.
		"""
        if hapticdata.get_position() == HapticPos.BOTH:
            # HapticPos.BOTH is special case as controller doesn't
            # really support doing that by itself.
            self.feedbacks[0] = hapticdata.with_position(HapticPos.LEFT)
            self.feedbacks[1] = hapticdata.with_position(HapticPos.RIGHT)
        else:
            self.feedbacks[hapticdata.get_position()] = hapticdata

    def is_touched(self, what):
        """
		Returns True if specified pad is being touched.
		May randomly return False for aphephobic pads.
		
		'what' should be LEFT or RIGHT (from scc.constants)
		"""
        if what == LEFT:
            return self.buttons & SCButtons.LPADTOUCH
        elif what == RIGHT:
            return self.buttons & SCButtons.RPADTOUCH
        else:
            return False

    def was_touched(self, what):
        """
		As is_touched, but returns True if pad *was* touched
		in previous known state.
		
		This is used as:
		is_touched() and not was_touched() -> pad was just pressed
		not is_touched() and was_touched() -> pad was just released
		"""
        if what == LEFT:
            return self.old_buttons & SCButtons.LPADTOUCH
        elif what == RIGHT:
            return self.old_buttons & SCButtons.RPADTOUCH
        else:
            return False

    def is_pressed(self, button):
        """
		Returns True if button is pressed
		"""
        return self.buttons & button

    def was_pressed(self, button):
        """
		Returns True if button was pressed in previous known state
		"""
        return self.old_buttons & button

    def get_pressed_button(self):
        """
		Gets button that was pressed by very last handled event or None,
		if last event doesn't involved button pressing.
		"""
        for x in SCButtons:
            if x & self.buttons & ~self.old_buttons:
                return x
        return None

    def set_button(self, button, state):
        """
		Sets button state on input.
		Set value will stay only for durration of one event loop iteration.
		
		Used _temporarely_ by RingAction to emulate finger lifting from pad.
		"""
        if button == LEFT:
            button = SCButtons.LPADTOUCH
        elif button == RIGHT:
            button = SCButtons.RPADTOUCH

        if state:
            self.buttons |= button
        else:
            self.buttons &= ~button

    def set_was_pressed(self, button, state):
        """
		As set_button, but changes value remembered
		from loop iteration before current.
		
		Used _temporarely_ by RingAction to emulate finger lifting from pad.
		"""
        if button == LEFT:
            button = SCButtons.LPADTOUCH
        elif button == RIGHT:
            button = SCButtons.RPADTOUCH

        if state:
            self.old_buttons |= button
        else:
            self.old_buttons &= ~button

    def release_virtual_buttons(self):
        """
		Called when daemon is killed or USB dongle is disconnected.
		Sends button release event for every virtual button that is still being
		pressed.
		"""
        to_release, self.pressed = self.pressed, {}
        for x in to_release:
            ButtonAction._button_release(self, x, True)

    def reset_gyros(self):
        for a in self.profile.get_actions():
            if isinstance(a, GyroAbsAction):
                a.reset()

    def input(self, controller, now, old_state, state):
        # Store states
        self.old_state = old_state
        self.old_buttons = self.buttons

        self.state = state
        self.buttons = state.buttons

        if self.buttons & SCButtons.LPAD and not self.buttons & SCButtons.LPADTOUCH:
            self.buttons = (self.buttons & ~SCButtons.LPAD) | SCButtons.STICK

        fe = self.force_event
        self.force_event = set()

        # Check buttons
        xor = self.old_buttons ^ self.buttons
        btn_rem = xor & self.old_buttons
        btn_add = xor & self.buttons

        try:
            if btn_add or btn_rem:
                # At least one button was pressed
                for x in self.profile.buttons:
                    if x & btn_add:
                        self.profile.buttons[x].button_press(self)
                    elif x & btn_rem:
                        self.profile.buttons[x].button_release(self)

            # Check stick
            if not self.buttons & SCButtons.LPADTOUCH:
                if FE_STICK in fe or self.old_state.lpad_x != state.lpad_x or self.old_state.lpad_y != state.lpad_y:
                    self.profile.stick.whole(self, state.lpad_x, state.lpad_y,
                                             STICK)

            # Check gyro
            if controller.get_gyro_enabled():
                self.profile.gyro.gyro(self, state.gpitch, state.gyaw,
                                       state.groll, state.q1, state.q2,
                                       state.q3, state.q4)

            # Check triggers
            if FE_TRIGGER in fe or state.ltrig != self.old_state.ltrig:
                if LEFT in self.profile.triggers:
                    self.profile.triggers[LEFT].trigger(
                        self, state.ltrig, self.old_state.ltrig)
            if FE_TRIGGER in fe or state.rtrig != self.old_state.rtrig:
                if RIGHT in self.profile.triggers:
                    self.profile.triggers[RIGHT].trigger(
                        self, state.rtrig, self.old_state.rtrig)

            # Check pads
            # RPAD
            if FE_PAD in fe or self.buttons & SCButtons.RPADTOUCH or SCButtons.RPADTOUCH & btn_rem:
                self.profile.pads[RIGHT].whole(self, state.rpad_x,
                                               state.rpad_y, RIGHT)

            # LPAD
            if self.buttons & SCButtons.LPADTOUCH:
                # Pad is being touched now
                if not self.lpad_touched:
                    self.lpad_touched = True
                self.profile.pads[LEFT].whole(self, state.lpad_x, state.lpad_y,
                                              LEFT)
            elif not self.buttons & STICK_TILT:
                # Pad is not being touched
                if self.lpad_touched:
                    self.lpad_touched = False
                    self.profile.pads[LEFT].whole(self, 0, 0, LEFT)
        except Exception, e:
            # Log error but don't crash here, it breaks too many things at once
            log.error("Error while processing controller event")
            log.error(traceback.format_exc())

        self.run_scheduled(now)
        self.generate_events()
        self.generate_feedback()
コード例 #8
0
ファイル: mapper.py プロジェクト: kozec/sc-controller
class Mapper(object):
	DEBUG = False
	
	def __init__(self, profile, scheduler, keyboard=b"SCController Keyboard",
				mouse=b"SCController Mouse",
				gamepad=True, poller=None):
		"""
		If any of keyboard, mouse or gamepad is set to None, that device
		will not be emulated.
		Emulated gamepad will have rumble enabled only if poller is set to
		instance and configuration allows it.
		"""
		self.profile = profile
		self.controller = None
		self.xdisplay = None
		self.scheduler = scheduler
		
		# Create virtual devices
		log.debug("Creating virtual devices")
		self.keyboard = self.create_keyboard(keyboard) if keyboard else Dummy()
		log.debug("Keyboard: %s" % (self.keyboard, ))
		self.mouse = self.create_mouse(mouse) if mouse else Dummy()
		log.debug("Mouse:    %s" % (self.mouse, ))
		self.gamepad = self.create_gamepad(gamepad, poller) if gamepad else Dummy()
		log.debug("Gamepad:  %s" % (self.gamepad, ))
		
		# Set by SCCDaemon instance; Used to handle actions
		# from scc.special_actions
		self._sa_handler = None
		
		# Setup emulation
		self.keypress_list = []
		self.keyrelease_list = []
		self.mouse_movements = [0, 0, 0, 0]		# mouse x, y, wheel vertical, horisontal
		self.feedbacks = [ None, None ]			# left, right
		self.pressed = {}						# for ButtonAction, holds number of times virtual button was pressed without releasing it first
		self.syn_list = set()
		self.buttons, self.old_buttons = 0, 0
		self.lpad_touched = False
		self.state, self.old_state = None, None
		self.force_event = set()
	
	
	def create_gamepad(self, enabled, poller):
		""" Parses gamepad configuration and creates apropriate unput device """
		if not enabled or "SCC_NOGAMEPAD" in os.environ:
			# Completly undocumented and for debuging purposes only.
			# If set, no gamepad is emulated
			self.gamepad = Dummy()
			return
		cfg = Config()
		keys = ALL_BUTTONS[0:cfg["output"]["buttons"]]
		vendor = int(cfg["output"]["vendor"], 16)
		product = int(cfg["output"]["product"], 16)
		version = int(cfg["output"]["version"], 16)
		name = cfg["output"]["name"]
		rumble = cfg["output"]["rumble"] and poller != None
		axes = []
		i = 0
		for min, max in cfg["output"]["axes"]:
			fuzz, flat = 0, 0
			if abs(max - min) > 32768:
				fuzz, flat = 16, 128
			try:
				axes.append(( ALL_AXES[i], min, max, fuzz, flat ))
			except IndexError:
				# Out of axes
				break
			i += 1
		
		ui = UInput(vendor=vendor, product=product, version=version,
			name=name, keys=keys, axes=axes, rels=[], rumble=rumble)
		if poller and rumble:
			poller.register(ui.getDescriptor(), poller.POLLIN, self._rumble_ready)
		return ui
	
	
	def create_keyboard(self, name):
		return Keyboard(name=name)
	
	
	def create_mouse(self, name):
		return Mouse(name=name)
	
	
	def _rumble_ready(self, fd, event):
		ef = self.gamepad.ff_read()
		if ef:	# tale of...
			self.send_feedback(HapticData(
				HapticPos.BOTH,
				period = 32760,
				amplitude = max(0, ef.level),
				count = min(0x7FFF, ef.duration * ef.repetitions / 30)
			))
	
	
	def get_gamepad_name(self):
		"""
		Returns name of emulated gamepad (as displayed by jstest & co)
		or None if Dummy is assigned.
		"""
		if isinstance(self.gamepad, Dummy):
			return None
		return self.gamepad.name
	
	
	def sync(self):
		""" Syncs generated events """
		if len(self.syn_list):
			for dev in self.syn_list:
				dev.synEvent()
			self.syn_list = set()
	
	
	def set_controller(self, c):
		""" Sets controller device, used by some (one so far) actions """
		self.controller = c
	
	
	def get_controller(self):
		""" Returns assigned controller device or None if no controller is set """
		return self.controller
	
	
	def set_special_actions_handler(self, sa):
		self._sa_handler = sa
	
	
	def get_special_actions_handler(self):
		return self._sa_handler
	
	
	def set_xdisplay(self, x):
		self.xdisplay = x
	
	
	def get_xdisplay(self):
		return self.xdisplay
	
	
	def get_current_window(self):
		"""
		Returns window id of current window or None if xdisplay is not set
		"""
		if self.xdisplay:
			return X.get_current_window(self.xdisplay)
		return None
	
	
	def schedule(self, delay, cb):
		"""
		Schedules callback to be ran no sooner than after delay.
		Delay is float number in seconds.
		Callback is called with mapper as only argument.
		"""
		return self.scheduler.schedule(delay, cb, self)
	
	
	def cancel_task(self, task):
		""" Removes scheduled task. """
		return self.scheduler.cancel_task(task)
	
	
	def mouse_move(self, dx, dy):
		"""
		Schedules mouse movement to be done at end of processing callback.
		Called from actions while callback is being processed.
		"""
		self.mouse_movements[0] += dx
		self.mouse_movements[1] += dy
	
	
	def mouse_wheel(self, wx, wy):
		"""
		Schedules mouse wheel movement to be done at end of processing callback.
		Called from actions while callback is being processed.
		"""
		self.mouse_movements[2] += wx
		self.mouse_movements[3] += wy
	
	
	def send_feedback(self, hapticdata):
		"""
		Schedules haptic feedback to be sent at end of processing callback.
		Called from actions while callback is being processed.
		"""
		if hapticdata.get_position() == HapticPos.BOTH:
			# HapticPos.BOTH is special case as controller doesn't
			# really support doing that by itself.
			self.feedbacks[0]  = hapticdata.with_position(HapticPos.LEFT)
			self.feedbacks[1]  = hapticdata.with_position(HapticPos.RIGHT)
		else:
			self.feedbacks[hapticdata.get_position()] = hapticdata
	
	
	def controller_flags(self):
		"""
		Returns controller flags or, if there is no controller set to
		this mapper, sc_by_cable driver matching defaults.
		"""
		return 0 if self.controller is None else self.controller.flags
	
	
	def is_touched(self, what):
		"""
		Returns True if specified pad is being touched.
		May randomly return False for aphephobic pads.
		
		'what' should be LEFT or RIGHT (from scc.constants)
		"""
		if what == LEFT:
			return self.buttons & SCButtons.LPADTOUCH
		elif what == RIGHT:
			return self.buttons & SCButtons.RPADTOUCH
		elif what == CPAD:
			return self.buttons & SCButtons.CPADTOUCH
		else:
			return False
	
	
	def was_touched(self, what):
		"""
		As is_touched, but returns True if pad *was* touched
		in previous known state.
		
		This is used as:
		is_touched() and not was_touched() -> pad was just pressed
		not is_touched() and was_touched() -> pad was just released
		"""
		if what == LEFT:
			return self.old_buttons & SCButtons.LPADTOUCH
		elif what == RIGHT:
			return self.old_buttons & SCButtons.RPADTOUCH
		elif what == CPAD:
			return self.old_buttons & SCButtons.CPADTOUCH
		else:
			return False
	
	
	def is_pressed(self, button):
		"""
		Returns True if button is pressed
		"""
		if button == LEFT:
			button = SCButtons.LPAD
		elif button == RIGHT:
			button = SCButtons.RPAD
		return self.buttons & button
	
	
	def was_pressed(self, button):
		"""
		Returns True if button was pressed in previous known state
		"""
		if button == LEFT:
			button = SCButtons.LPAD
		elif button == RIGHT:
			button = SCButtons.RPAD
		return self.old_buttons & button
	
	
	def get_pressed_button(self):
		"""
		Gets button that was pressed by very last handled event or None,
		if last event doesn't involved button pressing.
		"""
		for x in SCButtons:
			if x & self.buttons & ~self.old_buttons:
				return x
		return None
	
	
	def set_button(self, button, state):
		"""
		Sets button state on input.
		Set value will stay only for durration of one event loop iteration.
		
		Used _temporarely_ by RingAction to emulate finger lifting from pad.
		"""
		if button == LEFT:
			button = SCButtons.LPADTOUCH
		elif button == RIGHT:
			button = SCButtons.RPADTOUCH
		
		if state:
			self.buttons |= button
		else:
			self.buttons &= ~button
	
	
	def set_was_pressed(self, button, state):
		"""
		As set_button, but changes value remembered
		from loop iteration before current.
		
		Used _temporarely_ by RingAction to emulate finger lifting from pad.
		"""
		if button == LEFT:
			button = SCButtons.LPADTOUCH
		elif button == RIGHT:
			button = SCButtons.RPADTOUCH
		
		if state:
			self.old_buttons |= button
		else:
			self.old_buttons &= ~button
	
	
	def release_virtual_buttons(self):
		"""
		Called when daemon is killed or USB dongle is disconnected.
		Sends button release event for every virtual button that is still being
		pressed.
		"""
		to_release, self.pressed = self.pressed, {}
		for x in to_release:
			ButtonAction._button_release(self, x, True)
	
	
	def cancel_all(self):
		"""
		Called when profile is changed to let all actions to cancel
		long-running effects they may have created
		"""
		for a in self.profile.get_actions():
			a.cancel(self)
	
	
	def reset_gyros(self):
		for a in self.profile.get_all_actions():
			if isinstance(a, GyroAbsAction):
				a.reset()
	
	
	def input(self, controller, old_state, state):
		# Store states
		self.old_state = old_state
		self.old_buttons = self.buttons
		
		self.state = state
		self.buttons = state.buttons
		
		if self.buttons & SCButtons.LPAD and not self.buttons & SCButtons.LPADTOUCH:
			self.buttons = (self.buttons & ~SCButtons.LPAD) | SCButtons.STICKPRESS
		
		fe = self.force_event
		self.force_event = set()
		
		# Check buttons
		xor = self.old_buttons ^ self.buttons
		btn_rem = xor & self.old_buttons
		btn_add = xor & self.buttons
		
		try:
			if btn_add or btn_rem:
				# At least one button was pressed
				for x in self.profile.buttons:
					if x & btn_add:
						self.profile.buttons[x].button_press(self)
					elif x & btn_rem:
						self.profile.buttons[x].button_release(self)
			
			
			# Check stick
			if self.controller.flags & ControllerFlags.SEPARATE_STICK:
				if FE_STICK in fe or self.old_state.stick_x != state.stick_x or self.old_state.stick_y != state.stick_y:
					self.profile.stick.whole(self, state.stick_x, state.stick_y, STICK)
			elif not self.buttons & SCButtons.LPADTOUCH:
				if FE_STICK in fe or self.old_state.lpad_x != state.lpad_x or self.old_state.lpad_y != state.lpad_y:
					self.profile.stick.whole(self, state.lpad_x, state.lpad_y, STICK)
			
			# Check gyro
			if controller.get_gyro_enabled():
				self.profile.gyro.gyro(self, state.gpitch, state.gyaw, state.groll, state.q1, state.q2, state.q3, state.q4)
			
			# Check triggers
			if FE_TRIGGER in fe or state.ltrig != self.old_state.ltrig:
				if LEFT in self.profile.triggers:
					self.profile.triggers[LEFT].trigger(self, state.ltrig, self.old_state.ltrig)
			if FE_TRIGGER in fe or state.rtrig != self.old_state.rtrig:
				if RIGHT in self.profile.triggers:
					self.profile.triggers[RIGHT].trigger(self, state.rtrig, self.old_state.rtrig)
			
			# Check pads
			# RPAD
			if controller.flags & ControllerFlags.HAS_RSTICK:
				if FE_PAD in fe or self.old_state.rpad_x != state.rpad_x or self.old_state.rpad_y != state.rpad_y:
					self.profile.pads[RIGHT].whole(self, state.rpad_x, state.rpad_y, RIGHT)
			elif FE_PAD in fe or self.buttons & SCButtons.RPADTOUCH or SCButtons.RPADTOUCH & btn_rem:
				self.profile.pads[RIGHT].whole(self, state.rpad_x, state.rpad_y, RIGHT)
			
			# LPAD
			if self.controller.flags & ControllerFlags.SEPARATE_STICK:
				if FE_PAD in fe or self.old_state.lpad_x != state.lpad_x or self.old_state.lpad_y != state.lpad_y:
					self.profile.pads[LEFT].whole(self, state.lpad_x, state.lpad_y, LEFT)
			else:
				if self.buttons & SCButtons.LPADTOUCH:
					# Pad is being touched now
					if not self.lpad_touched:
						self.lpad_touched = True
					self.profile.pads[LEFT].whole(self, state.lpad_x, state.lpad_y, LEFT)
				elif not self.buttons & STICKTILT:
					# Pad is not being touched
					if self.lpad_touched:
						self.lpad_touched = False
						self.profile.pads[LEFT].whole(self, 0, 0, LEFT)
			
			# CPAD (touchpad on DS4 controller)
			if controller.flags & ControllerFlags.HAS_CPAD:
				if FE_PAD in fe or self.old_state.cpad_x != state.cpad_x or self.old_state.cpad_y != state.cpad_y:
					self.profile.pads[CPAD].whole(self, state.cpad_x, state.cpad_y, CPAD)
		except Exception:
			# Log error but don't crash here, it breaks too many things at once
			if hasattr(self, "_testing"):
				raise
			log.error("Error while processing controller event")
			log.error(traceback.format_exc())
		
		# TODO: Is it important to run scheduled stuff before generate_events?
		self.scheduler.run()
		self.generate_events()
		self.generate_feedback()
	
	
	def generate_events(self):
		# Generate events - keys
		if len(self.keypress_list):
			self.keyboard.pressEvent(self.keypress_list)
			self.keypress_list = []
		if len(self.keyrelease_list):
			self.keyboard.releaseEvent(self.keyrelease_list)
			self.keyrelease_list = []
		# Generate events - mouse
		mx, my, wx, wy = self.mouse_movements
		if mx != 0 or my != 0:
			self.mouse.moveEvent(mx, my * -1)
			self.syn_list.add(self.mouse)
		if wx != 0 or wy != 0:
			self.mouse.scrollEvent(wx, wy)
			self.syn_list.add(self.mouse)
		self.mouse_movements = [ 0, 0, 0, 0 ]
		self.sync()
	
	
	def generate_feedback(self):
		if self.controller:
			for x in (0, 1):
				if self.feedbacks[x]:
					self.controller.feedback(self.feedbacks[x])
					self.feedbacks[x] = None