# encoding: utf-8
import os
import stat
import time
from collections import defaultdict
from evdev import _uinput
from evdev import ecodes, util, device
from evdev.events import InputEvent
import evdev.ff as ff
import ctypes
try:
from evdev.eventio_async import EventIO
except ImportError:
from evdev.eventio import EventIO
class UInputError(Exception):
pass
class UInput(EventIO):
'''
A userland input device and that can inject input events into the
linux input subsystem.
'''
__slots__ = (
'name', 'vendor', 'product', 'version', 'bustype',
'events', 'devnode', 'fd', 'device',
)
@classmethod
def from_device(cls, *devices, filtered_types=(ecodes.EV_SYN, ecodes.EV_FF), **kwargs):
'''
Create an UInput device with the capabilities of one or more input
devices.
Arguments
---------
devices : InputDevice|str
Varargs of InputDevice instances or paths to input devices.
filtered_types : Tuple[event type codes]
Event types to exclude from the capabilities of the uinput device.
**kwargs
Keyword arguments to UInput constructor (i.e. name, vendor etc.).
'''
device_instances = []
for dev in devices:
if not isinstance(dev, device.InputDevice):
dev = device.InputDevice(str(dev))
device_instances.append(dev)
all_capabilities = defaultdict(set)
# Merge the capabilities of all devices into one dictionary.
for dev in device_instances:
for ev_type, ev_codes in dev.capabilities().items():
all_capabilities[ev_type].update(ev_codes)
for evtype in filtered_types:
if evtype in all_capabilities:
del all_capabilities[evtype]
return cls(events=all_capabilities, **kwargs)
def __init__(self,
events=None,
name='py-evdev-uinput',
vendor=0x1, product=0x1, version=0x1, bustype=0x3,
devnode='/dev/uinput', phys='py-evdev-uinput', input_props=None):
'''
Arguments
---------
events : dict
Dictionary of event types mapping to lists of event codes. The
event types and codes that the uinput device will be able to
inject - defaults to all key codes.
name
The name of the input device.
vendor
Vendor identifier.
product
Product identifier.
version
Version identifier.
bustype
Bustype identifier.
phys
Physical path.
input_props
Input properties and quirks.
Note
----
If you do not specify any events, the uinput device will be able
to inject only ``KEY_*`` and ``BTN_*`` event codes.
'''
self.name = name #: Uinput device name.
self.vendor = vendor #: Device vendor identifier.
self.product = product #: Device product identifier.
self.version = version #: Device version identifier.
self.bustype = bustype #: Device bustype - e.g. ``BUS_USB``.
self.phys = phys #: Uinput device physical path.
self.devnode = devnode #: Uinput device node - e.g. ``/dev/uinput/``.
if not events:
events = {ecodes.EV_KEY: ecodes.keys.keys()}
self._verify()
#: Write-only, non-blocking file descriptor to the uinput device node.
self.fd = _uinput.open(devnode)
# Prepare the list of events for passing to _uinput.enable and _uinput.setup.
absinfo, prepared_events = self._prepare_events(events)
# Set phys name
_uinput.set_phys(self.fd, phys)
# Set properties
input_props = input_props or []
for prop in input_props:
_uinput.set_prop(self.fd, prop)
for etype, code in prepared_events:
_uinput.enable(self.fd, etype, code)
_uinput.setup(self.fd, name, vendor, product, version, bustype, absinfo)
# Create the uinput device.
_uinput.create(self.fd)
self.dll = ctypes.CDLL(_uinput.__file__)
self.dll._uinput_begin_upload.restype = ctypes.c_int
self.dll._uinput_end_upload.restype = ctypes.c_int
#: An :class:`InputDevice