Selkies
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
= label
attributefdOptional[int]
= None
attributedevice_nodeslist
= []

Functions

func__init__(self, label) -> None
Source Code
def __init__(self, label: str) -> None:
    self.label = label
    self.fd: Optional[int] = None
    self.device_nodes: list = []
paramself
paramlabelstr

Returns

None
funccreate(self) -> list

Register 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_nodes
paramself

Returns

list
func_resolve_device_nodes(self) -> list

The /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"))
    )
paramself

Returns

list
funcemit(self, ev_type, ev_code, ev_value) -> None
Source 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))
paramself
paramev_typeint
paramev_codeint
paramev_valuefloat

Returns

None
funcdestroy(self) -> None
Source 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 = []
paramself

Returns

None

On this page

Edit on GitHub