Skip to content

Conversation

@samvv
Copy link

@samvv samvv commented May 29, 2025

This pull request adds another input emulation backend that uses evdev to create a virtual mouse/keyboard, bypassing Wayland restrictions. It is meant to be a fallback for the other Linux backends.

This backend successfully fixes input emulation issues on COSMIC and potentially other platforms that lack a proper remote desktop portal.

Limitations

Currently this feature requires lan-mouse to be run as root, e.g. with sudo -E lan-mouse. This is a temporary limitation that I hope to alleviate by creating a separate daemon and authentication mechanism.

To Do

  • Discrete scrolling needs to be tested. I just put a formula I thought might work. If I'm correct this is a Mac feature, which I don't have.
  • A daemon that allows unprivileged execution of lan-mouse, as described above. We are going to use an udev rule.
  • Natural scrolling doesn't work because presumably the WM is responsible for the conversion. We'd need to emulate it. (optional?)

@samvv
Copy link
Author

samvv commented May 29, 2025

Potentially somewhat related: https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/2664

@feschber feschber marked this pull request as ready for review May 30, 2025 05:44
@feschber
Copy link
Owner

feschber commented Jun 1, 2025

@samvv I'm not sure running the daemon as root is going to work. The input capture backends need to be run as the current user to access xdg-desktop portal or the wayland socket.
But you can change the permissions on /dev/uinput to allow access to your user. (Steam also does this afaik for controller input)

@feschber
Copy link
Owner

feschber commented Jun 1, 2025

Btw: For the cli backend override to work, you have to add the backend to the config struct as well:

diff --git a/src/config.rs b/src/config.rs
index 41f442d..361bb5e 100644
--- a/src/config.rs
+++ b/src/config.rs
@@ -172,6 +172,9 @@ impl From<CaptureBackend> for input_capture::Backend {
 
 #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, ValueEnum)]
 pub enum EmulationBackend {
+    #[cfg(all(target_os = "linux", feature = "evdev_emulation"))]
+    #[serde(rename = "evdev")]
+    Evdev,
     #[cfg(all(unix, feature = "wlroots_emulation", not(target_os = "macos")))]
     #[serde(rename = "wlroots")]
     Wlroots,
@@ -197,6 +200,8 @@ pub enum EmulationBackend {
 impl From<EmulationBackend> for input_emulation::Backend {
     fn from(backend: EmulationBackend) -> Self {
         match backend {
+            #[cfg(all(target_os = "linux", feature = "evdev_emulation"))]
+            EmulationBackend::Evdev => Self::Evdev,
             #[cfg(all(unix, feature = "wlroots_emulation", not(target_os = "macos")))]
             EmulationBackend::Wlroots => Self::Wlroots,
             #[cfg(all(unix, feature = "libei_emulation", not(target_os = "macos")))]
@@ -217,6 +222,8 @@ impl From<EmulationBackend> for input_emulation::Backend {
 impl Display for EmulationBackend {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         match self {
+            #[cfg(all(target_os = "linux", feature = "evdev_emulation"))]
+            EmulationBackend::Evdev => write!(f, "evdev"),
             #[cfg(all(unix, feature = "wlroots_emulation", not(target_os = "macos")))]
             EmulationBackend::Wlroots => write!(f, "wlroots"),
             #[cfg(all(unix, feature = "libei_emulation", not(target_os = "macos")))]

I think I might want to remove this duplication at some point

@samvv
Copy link
Author

samvv commented Jun 1, 2025

Thanks for the information. That steam 'hack' might actually work. At least on Arch it could be as simple as usermod -aG input username.

The daemon I was talking about isn't a lan-mouse daemon, it's this one I just wrote:
https://github.com/samvv/input-daemon. It uses polkit to authenticate whatever process connects to it. If I'm correct it should in theory be more secure than the steam hack, where every user process has access (no questions asked), at the price of way more complexity.

What solution would you prefer?

I'll update this pull request with the CLI logic.

Co-authored-by: Ferdinand Schober <[email protected]>
@samvv
Copy link
Author

samvv commented Jun 1, 2025

I just tested and can confirm that adding the group input to the user works!

@feschber
Copy link
Owner

feschber commented Jun 2, 2025

I just tested and can confirm that adding the group input to the user works!

Adding the user to input is not necessary and a much bigger security risk than giving the user access to /dev/uinput via ACLs

@samvv
Copy link
Author

samvv commented Jun 2, 2025

I'm a bit hesitant to chown the /dev/uinput file. Do you mean that adding the input group is less secure because it allows access to all devices?

If so, what about:

sudo groupadd --system lan-mouse
sudo usermod -aG lan-mouse <username>
echo 'KERNEL=="uinput", GROUP="lan-mouse"' | sudo tee /lib/udev/rules.d/05-lan-mouse.rules

I've just tested this and it works.

@nbolton
Copy link
Contributor

nbolton commented Jun 2, 2025

@sithlord48 May be of interest.

@feschber
Copy link
Owner

feschber commented Jun 3, 2025

I'm a bit hesitant to chown the /dev/uinput file. Do you mean that adding the input group is less secure because it allows access to all devices?

Yes, adding the user to input allows arbitrary processes to also read input, which is a much bigger risk.

If so, what about:

sudo groupadd --system lan-mouse
sudo usermod -aG lan-mouse <username>
echo 'KERNEL=="uinput", GROUP="lan-mouse"' | sudo tee /lib/udev/rules.d/05-lan-mouse.rules

I've just tested this and it works.

Sounds like a good solution, if it works!

The Linux kernel on REL_WHEEL and REL_HWEEL:

> These event codes are legacy codes and REL_WHEEL_HI_RES and REL_HWHEEL_HI_RES should be preferred where available.

This commit fixes the mouse wheel on my setup. The new constant
`WHEEL_SENSITIVITY` might need to become a configuration variable.
@samvv
Copy link
Author

samvv commented Jun 4, 2025

@feschber I've fixed the mouse wheel, at the very least on my setup. We might need to make WHEEL_SENSITIVITY a configuration variable for other setups, but that can happen later.

Is there anything else that needs to be done before this can be merged?

@feschber
Copy link
Owner

As far as I'm concerned, it's looking good! I might even consider moving this backend up in priority for input emulation on systems that have access to uinput. And we might look into a way of automatically setting permissions somehow. But thats something for the future :).

If you fix that formatting error, I would be ready to merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants