libinput-rs 0.3.0

Fail-open Rust touchpad companion and drop-in libinput ABI replacement
Documentation
libinput-rs-0.3.0 has been yanked.

libinput-rs

libinput-rs is a Rust input project that provides:

  • an optional touchpad companion daemon using evdev and uinput;
  • a 100% drop-in replacement implementation of the libinput.so.10 C ABI.

One RPM replaces both the distribution's libinput and libinput-devel packages. It includes the runtime, development files, and companion daemon; display managers and compositors use the replacement after they restart. The same RPM also supplies the device-group and axis-fuzz udev callouts and rules normally installed with libinput, so replacing the distribution package does not remove input-device initialization behavior. It carries the matching libinput 1.31.3 hardware-quirks database as well.

Supported systems

The supported packaging path is DNF/RPM. The COPR project targets Fedora 44, Fedora rawhide, EPEL 9, EPEL 10, RHEL 9, and RHEL 10 on x86_64. Fedora RPMs enable optional libwacom tablet metadata integration. EPEL and RHEL builds use conservative kernel, evdev, and udev fallbacks and do not require libwacom.

Formal Agda, Idris 2, and Fortran models are verified in Fedora CI and are not runtime or RPM build dependencies.

Install from COPR

Perform replacement testing from a text console or an SSH session so rollback remains available even if the graphical session cannot start.

sudo dnf install dnf-plugins-core
sudo dnf copr enable sisyphuscode/libinput-rs
sudo dnf install libinput-rs --allowerasing
sudo ldconfig
sudo systemctl reboot

The RPM ships a vendor preset that enables libinput-rs.service on first installation. The daemon starts automatically on the next boot. An administrator's explicit enable or disable choice is preserved during package upgrades.

After boot, verify the service:

systemctl is-enabled libinput-rs.service
systemctl is-active libinput-rs.service
systemctl status libinput-rs.service

To opt out of the companion daemon without changing the ABI replacement:

sudo systemctl disable --now libinput-rs.service

To restore the distribution's original runtime and development packages:

sudo systemctl disable --now libinput-rs.service 2>/dev/null || true
sudo dnf install libinput libinput-devel --allowerasing
sudo ldconfig
sudo systemctl reboot

Build with DNF dependencies

sudo dnf install rust cargo gcc make systemd-devel pkgconf-pkg-config
make all
make check
make test

The daemon is built at target/release/libinput-rs. The ABI library is built at target/release/libinput.so.

Configuration

The daemon reads /etc/libinput-rs/config.json:

{
  "tap_to_click": true,
  "natural_scrolling": true,
  "pointer_acceleration": 2.2,
  "disable_while_typing": true
}

Elantech SMBus stalls

Some systems expose an Elantech touchpad first through PS/2 and then replace it with an SMBus companion. If pointer input periodically stops at the kernel device layer, keep the stable PS/2 path by adding this kernel argument:

sudo grubby --update-kernel=ALL --args=psmouse.elantech_smbus=0
sudo reboot

Confirm the workaround after reboot with cat /sys/module/psmouse/parameters/elantech_smbus; it should print 0.

The companion normalizes touchpad movement and two-finger scrolling using the kernel-reported axis resolution. When a device omits resolution metadata, it uses a live-tested calibrated fallback. pointer_acceleration keeps the existing user-facing scale: 2.2 is the live-tested neutral value, larger values are faster, and smaller positive values are slower.

The normalized motion base corresponds to the previous 2.5 reference, so the daemon divides the configured value by 2.5 internally. This preserves the exact effective pointer travel of existing configurations across the 0.2.1 upgrade. For the shipped default, 0.45 × (2.2 / 2.5) = 0.18 × 2.2 = 0.396.

Drop-in replacement

The single RPM installs libinput.so.10 in the system linker path together with libinput.h, the unversioned linker name, libinput.pc, and the libinput udev callouts and rules.

The udev backend enumerates /dev/input/event* by directory entry and delegates the first device open to the compositor's open_restricted callback. This keeps startup discovery compatible with logind-managed permissions where the compositor can list device nodes but cannot open them directly.

Formal safety models

The fail-open and restricted-discovery state machines are modeled three ways under proofs/:

  • Agda proves that a grab cannot be authorized while the output sink is absent and that listed event nodes remain discoverable without direct-open access, while also proving balanced physical-button transitions;
  • Idris 2 uses indexed states and total transitions so invalid runtime and restricted-open states are unconstructable;
  • Fortran provides independently compiled executable reference models for fail-open grabbing, permission-independent discovery, exactly-once descriptor closure, udev-only hotplug, and balanced physical-button lifecycles.

Agda, Idris 2, and GNU Fortran are available through DNF on the Fedora CI target:

sudo dnf install Agda idris2 gcc-gfortran
make proofs

make proofs-strict requires all three compilers and runs every model.

Publishing

The RPM and crates.io release procedure is documented in RELEASING.md. Crates.io publishes one libinput-rs source crate. System replacement installations should use the COPR RPM rather than cargo install.

Reference behavior

Runtime and ABI lifecycle work is compared against the upstream libinput architecture and the complyue/libinput branch referenced during debugging. The Rust implementation provides complete behavior parity and is intended for use as a 100% drop-in replacement.

License

MIT