Controller Discovery - approxeng.input.controllers¶
New in 2.3, the discovery layer tidies up and abstracts the process of finding a controller or controllers matching a particular set of requirements. In previous versions you had to handle evdev device nodes directly which wasn’t particularly friendly, especially as some controllers used multiple OS devices.
If you are using the resource binding via
ControllerResource the same classes
are used within that binding to specify controllers.
Before you can use a controller, you need to find it:
from approxeng.input.controllers import find_matching_controllers discoveries = find_matching_controllers()
This is all you need to perform the most basic discovery process, specifically one which will attempt to find a single connected controller.
You may not want to just pick the first controller available (although the library does attempt to order controllers
such that the first one will be the most capable). You can use the
ControllerRequirement to specify exactly what you want. At the moment this class
supports two filters:
You can specify an exact controller class with require_class, such as specifying that you only want a DualShock4
You can specify a set of controls on the controller, identified by sname, with ‘require_snames’ that any controller must have to be included in the results. This is great when you know that you need a pair of analogue triggers but don’t care what exact controller type you get as long as it has them.
from approxeng.input.controllers import find_matching_controllers, ControllerRequirement discoveries = find_matching_controllers(ControllerRequirement(require_snames=['lx','ly']))
Specifying multiple controllers¶
Both the above examples return a single controller. This is because they both have a single requirement - when you don’t provide any requirements as in the first example the library treats it as if you’d given it a single requirement with no filters applied.
The result of the
find_matching_controllers() call is a list of
objects, each of which contains both the actual
Controller sub-class and the matching evdev device nodes. In both these
cases this list contains a single item.
To discover multiple controllers, specify multiple requirements when calling:
from approxeng.input.controllers import find_matching_controllers, ControllerRequirement discoveries = find_matching_controllers(ControllerRequirement(require_snames=['lx','ly']), ControllerRequirement())
The above will attempt to find two controllers. The first one must have the specified axes, the second can be any connected device. The result will be a two item list, with the controller discoveries in the same order as the supplied controller requirements.
If the system does not have the controllers you’ve requested, the discovery process will raise a
ControllerNotFoundError, in general you should catch this and wait before trying
to bind again.
ControllerDiscovery(controller, devices, name)¶
Represents a single discovered controller attached to the host. Ordered, with controllers with more axes and buttons being given a higher ordering, then falling back to the assigned name.
__init__(controller, devices, name)¶
Initialize self. See help(type(self)) for accurate signature.
Raised during controller discovery if the specified set of controller requirements cannot be satisfied
Represents a requirement for a single controller, allowing restriction on type. We might add more filtering options later, such as requiring a minimum number of axes, or the presence of a particular control. If you want that now, you can subclass this and pass it into the find_matching_controllers and similar functions.
Create a new requirement
require_class – If specified, this should be a subclass of
approxeng.input.Controller, only controllers which match this class will be accepted. Defaults to None, accepting any available controller class.
require_snames – If specified, this should be a list of strings containing snames of controls (buttons or axes) that must be present in the controller. Use this when you know what controls you need but don’t mind which controller actually implements them.
Returns True if the supplied ControllerDiscovery matches this requirement, False otherwise
find_all_controllers(**kwargs) → List[approxeng.input.controllers.ControllerDiscovery]¶
A list of
ControllerDiscoveryinstances corresponding to controllers attached to this host, ordered by the ordering on ControllerDiscovery. Any controllers found will be constructed with kwargs passed to their constructor function, particularly useful for dead and hot zone parameters.
find_matching_controllers(*requirements, **kwargs) → [<class 'approxeng.input.controllers.ControllerDiscovery'>]¶
Find a sequence of controllers which match the supplied requirements, or raise an error if no such controllers exist.
requirements – Zero or more ControllerRequirement instances defining the requirements for controllers. If no item is passed it will be treated as a single requirement with no filters applied and will therefore match the first controller found.
A sequence of the same length as the supplied requirements array containing ControllerDiscovery instances which match the requirements supplied.
ControllerNotFoundError if no appropriately matching controllers can be located
Pretty-print all controllers found
Simple test function which prints out all devices found by evdev
unique_name(device: evdev.device.InputDevice) → str¶
Construct a unique name for the device based on, in order if available, the uniq ID, the phys ID and finally a concatenation of vendor, product, version and filename.
device – An InputDevice instance to query
A string containing as unique as possible a name for the physical entity represented by the device