Binding - approxeng.input.selectbinder

Note

This has been re-written almost entirely in version 2.3. The simplest usage of the controller resource remains compatible, but all more sophisticated use will have changed. In general the binder now only handles the binding between controllers and the evdev events, leaving all forms of discovery to Controller Discovery - approxeng.input.controllers

A significant change is that you can now bind to and use multiple controllers by simply specifying multiple requirements for discovery.

The binder provides a bridge between the low level operating system representation of your connected controller and the high level python classes such as approxeng.input.dualshock3.DualShock3 which your code uses. The binder starts a new thread to pull events out of the operating system and update your controller object, this is the bit that means you don’t have to continuously poll the controller, it just updates in the background. It’s also the thread which calls any functions you’ve bound to buttons as event handlers. You can either manually bind the controller yourself (in which case you’re also responsible for un-binding it after you’re done!) or you can use the python ‘with’ functionality.

To bind a controller manually you’ll need to have already discovered it using the discovery layer. Once you have one or more instances of approxeng.input.controllers.ControllerDiscovery you can bind them manually as follows:

from approxeng.input.controllers import find_matching_controllers, ControllerRequirement
from approxeng.input.selectbinder import bind_controllers

discoveries = find_matching_controllers(ControllerRequirement(require_snames=['lx','ly']))

unbind_function = bind_controllers(*discoveries)
# At this point the joystick object is bound to the device and will receive updates. You can get the controller
# object itself, used to read axes and buttons etc, from the discovery - in this case the discoveries value is a
# single item list because we only asked for a single controller:
controller = discoveries[0].controller
# .... do stuff ....
# When we're finished, call the unbind function to free up the resources used by the binder
unbind_function()

Binding a controller manually works, but there’s a simpler way to handle the process (and one which avoids ever having to worry about explicitly unbinding the controller!):

from approxeng.input.selectbinder import ControllerResource
from approxeng.input.dualshock3 import DualShock3

with ControllerResource(ControllerRequirement(require_class=DualShock3)) as joystick:
    # .... do stuff, the controller is bound to 'joystick' which is a DualShock3 instance....

On exit from the ‘with’ block the binder is automatically unbound, this includes cases where we break out of the block because of exceptions or other error conditions. It’s a simpler and more robust way to handle the binding and I suggest you use it instead of explicitly binding it yourself.

Either form can be used to bind multiple controllers as well. Either by calling bind_controllers with more than one controller discovery, or by specifying multiple controller requirements to the ControllerResource:

from approxeng.input.selectbinder import ControllerResource
from approxeng.input.dualshock3 import DualShock3

with ControllerResource(ControllerRequirement(require_class=DualShock3),
                        ControllerRequirement(require_snames=['lx','ly'])) as ds3, joystick:
    # Do stuff, if we didn't raise an error, two controllers are now bound and receiving events.
    # The first controller is a DualShock3, the second is any connected controller with lx and ly
    # controls.
class approxeng.input.selectbinder.ControllerResource(*requirements, print_events=False, **kwargs)[source]

General resource which binds one or more controllers on entry and unbinds the event listening thread on exit.

__init__(*requirements, print_events=False, **kwargs)[source]

Create a new resource to bind and access one or more controllers. If no additional arguments are supplied this will find the first controller of any kind enabled by the library. Otherwise the requirements must be provided as a list of ControllerRequirement

Parameters:
  • requirements (ControllerRequirement) – ControllerRequirement instances used, in order, to find and bind controllers. If empty this will be equivalent to supplying a single unfiltered requirement and will match the first specified controller.

  • print_events (bool) – Defaults to False, if set to True then all events picked up by the binder will be printed to stdout. Use this when you’re trying to figure out what events correspond to what axes and buttons!

  • kwargs – Any addition keyword arguments are passed to the constructors for the controller classes. This is useful particularly to specify e.g. dead and hot zone ranges on discovery.

Raises:

ControllerNotFoundError – If the requirement can’t be satisfied, or no requirements are specified but there aren’t any controllers.

approxeng.input.selectbinder.bind_controllers(*discoveries, print_events=False)[source]

Bind a controller or controllers to a set of evdev InputDevice instances, starting a thread to keep those controllers in sync with the state of the hardware.

Parameters:
  • discoveries (ControllerDiscovery) – ControllerDiscovery instances specifying the controllers and their associated input devices

  • print_events (bool) – Defaults to False, if set to True then all events picked up by this binder will be printed to stdout

Returns:

A function which can be used to stop the event reading thread and unbind from the device