Developer Referenceinput_handler
UInputGamepad
One slot's kernel gamepad, created through /dev/uinput.
Applications discover it as an ordinary controller, so neither the Joystick Interposer nor fake-udev is involved. It carries the evdev event stream the interposer socket carries, presented as the same Xbox pad.
Attributes
attributelabel= labelattributefdOptional[int]= Noneattributedevice_nodeslist= []Functions
func__init__(self, label) -> NoneSource Code
def __init__(self, label: str) -> None:
self.label = label
self.fd: Optional[int] = None
self.device_nodes: list = []paramselfparamlabelstrReturns
Nonefunccreate(self) -> listRegister the kernel device and return its /dev/input node paths.
Source Code
def create(self) -> list:
"""Register the kernel device and return its /dev/input node paths.
Raises:
OSError: The uinput setup ioctls failed; the fd is closed first.
"""
fd = os.open(UINPUT_PATH, os.O_WRONLY | os.O_NONBLOCK)
try:
fcntl.ioctl(fd, UI_SET_EVBIT, EV_KEY)
fcntl.ioctl(fd, UI_SET_EVBIT, EV_ABS)
for code in STANDARD_XPAD_CONFIG["btn_map"]:
fcntl.ioctl(fd, UI_SET_KEYBIT, code)
for code in STANDARD_XPAD_CONFIG["axes_map"]:
fcntl.ioctl(fd, UI_SET_ABSBIT, code)
minimum, maximum, fuzz, flat, resolution = UINPUT_ABS_INFO.get(
code, UINPUT_ABS_INFO_DEFAULT
)
fcntl.ioctl(fd, UI_ABS_SETUP, struct.pack(
UINPUT_ABS_SETUP_FMT, code, 0, minimum, maximum, fuzz, flat, resolution
))
fcntl.ioctl(fd, UI_DEV_SETUP, struct.pack(
UINPUT_SETUP_FMT,
BUS_USB,
STANDARD_XPAD_CONFIG["vendor_id"],
STANDARD_XPAD_CONFIG["product_id"],
STANDARD_XPAD_CONFIG["version"],
STANDARD_XPAD_CONFIG["name"].encode("utf-8")[:UINPUT_MAX_NAME_SIZE - 1],
0,
))
fcntl.ioctl(fd, UI_DEV_CREATE)
except OSError:
os.close(fd)
raise
self.fd = fd
self.device_nodes = self._resolve_device_nodes()
return self.device_nodesparamselfReturns
listfunc_resolve_device_nodes(self) -> listThe /dev/input nodes the kernel registered for this device: event* always, js* as well when joydev is loaded.
Source Code
def _resolve_device_nodes(self) -> list:
"""The /dev/input nodes the kernel registered for this device: event*
always, js* as well when joydev is loaded."""
buffer = bytearray(UINPUT_SYSNAME_LEN)
try:
fcntl.ioctl(self.fd, UI_GET_SYSNAME, buffer, True)
except OSError:
return []
sysname = bytes(buffer).split(b"\0", 1)[0].decode("utf-8", "replace")
if not sysname:
return []
sysdir = os.path.join(UINPUT_SYSFS_BASE, sysname)
try:
entries = os.listdir(sysdir)
except OSError:
return []
return sorted(
os.path.join("/dev/input", entry)
for entry in entries
if entry.startswith(("event", "js"))
)paramselfReturns
listfuncemit(self, ev_type, ev_code, ev_value) -> NoneSource Code
def emit(self, ev_type: int, ev_code: int, ev_value: float) -> None:
os.write(self.fd, get_evdev_events_packed(ev_type, ev_code, ev_value, LOCAL_ARCH_BITS))paramselfparamev_typeintparamev_codeintparamev_valuefloatReturns
Nonefuncdestroy(self) -> NoneSource Code
def destroy(self) -> None:
if self.fd is None:
return
try:
fcntl.ioctl(self.fd, UI_DEV_DESTROY)
except OSError as e:
logger_selkies_gamepad.warning(f"Gamepad {self.label}: could not destroy the kernel device: {e}")
try:
os.close(self.fd)
except OSError:
pass
self.fd = None
self.device_nodes = []paramselfReturns
None