From 4db2d37f32dca0fe3e3e051d73c518be809f8a26 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Tue, 2 Jul 2024 20:16:52 +0200 Subject: [PATCH] split into input-{event,capture,emulation} --- Cargo.lock | 94 ++++++++++++++----- Cargo.toml | 51 ++++------ input-capture/Cargo.toml | 49 ++++++++++ {src/capture => input-capture/src}/dummy.rs | 2 +- {src/capture => input-capture/src}/error.rs | 0 src/capture.rs => input-capture/src/lib.rs | 49 +++++++--- {src/capture => input-capture/src}/libei.rs | 2 +- {src/capture => input-capture/src}/macos.rs | 5 +- {src/capture => input-capture/src}/wayland.rs | 2 +- {src/capture => input-capture/src}/windows.rs | 6 +- {src/capture => input-capture/src}/x11.rs | 2 +- input-emulation/Cargo.toml | 47 ++++++++++ {src/emulate => input-emulation/src}/dummy.rs | 2 +- {src/emulate => input-emulation/src}/error.rs | 0 src/emulate.rs => input-emulation/src/lib.rs | 72 ++++++++++---- {src/emulate => input-emulation/src}/libei.rs | 16 ++-- {src/emulate => input-emulation/src}/macos.rs | 14 +-- .../src}/windows.rs | 8 +- .../src}/wlroots.rs | 4 +- {src/emulate => input-emulation/src}/x11.rs | 2 +- .../src}/xdg_desktop_portal.rs | 4 +- input-event/Cargo.toml | 14 +++ src/event.rs => input-event/src/lib.rs | 3 +- {src => input-event/src}/scancode.rs | 0 src/capture_test.rs | 7 +- src/client.rs | 15 +-- src/config.rs | 45 ++++++++- src/emulation_test.rs | 6 +- src/lib.rs | 5 - src/server.rs | 2 +- src/server/capture_task.rs | 16 ++-- src/server/emulation_task.rs | 16 ++-- src/server/network_task.rs | 3 +- src/server/ping_task.rs | 4 +- 34 files changed, 400 insertions(+), 167 deletions(-) create mode 100644 input-capture/Cargo.toml rename {src/capture => input-capture/src}/dummy.rs (97%) rename {src/capture => input-capture/src}/error.rs (100%) rename src/capture.rs => input-capture/src/lib.rs (69%) rename {src/capture => input-capture/src}/libei.rs (99%) rename {src/capture => input-capture/src}/macos.rs (84%) rename {src/capture => input-capture/src}/wayland.rs (99%) rename {src/capture => input-capture/src}/windows.rs (99%) rename {src/capture => input-capture/src}/x11.rs (97%) create mode 100644 input-emulation/Cargo.toml rename {src/emulate => input-emulation/src}/dummy.rs (95%) rename {src/emulate => input-emulation/src}/error.rs (100%) rename src/emulate.rs => input-emulation/src/lib.rs (54%) rename {src/emulate => input-emulation/src}/libei.rs (97%) rename {src/emulate => input-emulation/src}/macos.rs (96%) rename {src/emulate => input-emulation/src}/windows.rs (97%) rename {src/emulate => input-emulation/src}/wlroots.rs (98%) rename {src/emulate => input-emulation/src}/x11.rs (99%) rename {src/emulate => input-emulation/src}/xdg_desktop_portal.rs (98%) create mode 100644 input-event/Cargo.toml rename src/event.rs => input-event/src/lib.rs (99%) rename {src => input-event/src}/scancode.rs (100%) diff --git a/Cargo.lock b/Cargo.lock index 81c6524..1609673 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -76,9 +76,9 @@ dependencies = [ [[package]] name = "anyhow" -version = "1.0.81" +version = "1.0.86" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0952808a6c2afd1aa8947271f3a60f1a6763c7b912d210184c5149b5cf147247" +checksum = "b3d1d046238990b9cf5bcde22a3fb3584ee5cf65fb2765f454ed428c7a0063da" [[package]] name = "arraydeque" @@ -231,9 +231,9 @@ checksum = "fbb36e985947064623dbd357f727af08ffd077f93d696782f3c56365fa2e2799" [[package]] name = "async-trait" -version = "0.1.78" +version = "0.1.80" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "461abc97219de0eaaf81fe3ef974a540158f3d079c2ab200f891f1a2ef201e85" +checksum = "c6fa2087f2753a7da8cc1c0dbfcf89579dd57458e36769de5ac750b4671737ca" dependencies = [ "proc-macro2", "quote", @@ -1234,6 +1234,65 @@ dependencies = [ "hashbrown", ] +[[package]] +name = "input-capture" +version = "0.1.0" +dependencies = [ + "anyhow", + "ashpd", + "core-graphics", + "futures", + "futures-core", + "input-event", + "log", + "memmap", + "once_cell", + "reis", + "tempfile", + "thiserror", + "tokio", + "wayland-client", + "wayland-protocols", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "windows 0.54.0", + "x11", +] + +[[package]] +name = "input-emulation" +version = "0.1.0" +dependencies = [ + "anyhow", + "ashpd", + "async-trait", + "core-graphics", + "futures", + "input-event", + "keycode", + "log", + "reis", + "thiserror", + "tokio", + "wayland-client", + "wayland-protocols", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "windows 0.54.0", + "x11", +] + +[[package]] +name = "input-event" +version = "0.1.0" +dependencies = [ + "anyhow", + "futures-core", + "log", + "num_enum", + "serde", +] + [[package]] name = "ipconfig" version = "0.3.2" @@ -1287,11 +1346,9 @@ name = "lan-mouse" version = "0.8.0" dependencies = [ "anyhow", - "ashpd", "async-channel", "async-trait", "clap", - "core-graphics", "endi", "env_logger", "futures", @@ -1300,27 +1357,20 @@ dependencies = [ "gtk4", "hickory-resolver", "hostname 0.4.0", - "keycode", + "input-capture", + "input-emulation", + "input-event", "libadwaita", "libc", "log", - "memmap", "num_enum", "once_cell", - "reis", "serde", "serde_json", "slab", - "tempfile", "thiserror", "tokio", "toml", - "wayland-client", - "wayland-protocols", - "wayland-protocols-misc", - "wayland-protocols-wlr", - "windows 0.54.0", - "x11", ] [[package]] @@ -1395,9 +1445,9 @@ dependencies = [ [[package]] name = "log" -version = "0.4.21" +version = "0.4.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "a7a70ba024b9dc04c27ea2f0c0548feb474ec5c54bba33a7f72f873a39d07b24" [[package]] name = "lru-cache" @@ -1851,18 +1901,18 @@ checksum = "92d43fe69e652f3df9bdc2b85b2854a0825b86e4fb76bc44d945137d053639ca" [[package]] name = "serde" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" +checksum = "7253ab4de971e72fb7be983802300c30b5a7f0c2e56fab8abfc6a214307c0094" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.197" +version = "1.0.203" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" +checksum = "500cbc0ebeb6f46627f50f3f5811ccf6bf00643be300b4c3eabc0ef55dc5b5ba" dependencies = [ "proc-macro2", "quote", diff --git a/Cargo.toml b/Cargo.toml index 059bd1d..1ab76e8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,3 +1,10 @@ +[workspace] +members = [ + "input-capture", + "input-emulation", + "input-event", +] + [package] name = "lan-mouse" description = "Software KVM Switch / mouse & keyboard sharing software for Local Area Networks" @@ -6,16 +13,16 @@ edition = "2021" license = "GPL-3.0-or-later" repository = "https://github.com/ferdinandschober/lan-mouse" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [profile.release] strip = true lto = "fat" [dependencies] -tempfile = "3.8" +input-emulation = { path = "input-emulation" } +input-event = { path = "input-event" } +input-capture = { path = "input-capture" } + hickory-resolver = "0.24.1" -memmap = "0.7" toml = "0.8" serde = { version = "1.0", features = ["derive"] } anyhow = "1.0.71" @@ -24,13 +31,12 @@ env_logger = "0.11.3" serde_json = "1.0.107" tokio = {version = "1.32.0", features = ["io-util", "io-std", "macros", "net", "process", "rt", "sync", "signal"] } async-trait = "0.1.73" -futures-core = "0.3.28" futures = "0.3.28" +futures-core = "0.3.28" clap = { version="4.4.11", features = ["derive"] } gtk = { package = "gtk4", version = "0.8.1", features = ["v4_2"], optional = true } adw = { package = "libadwaita", version = "0.6.0", features = ["v1_1"], optional = true } async-channel = { version = "2.1.1", optional = true } -keycode = "0.4.0" once_cell = "1.19.0" num_enum = "0.7.2" hostname = "0.4.0" @@ -41,36 +47,13 @@ thiserror = "1.0.61" [target.'cfg(unix)'.dependencies] libc = "0.2.148" -[target.'cfg(all(unix, not(target_os="macos")))'.dependencies] -wayland-client = { version="0.31.1", optional = true } -wayland-protocols = { version="0.31.0", features=["client", "staging", "unstable"], optional = true } -wayland-protocols-wlr = { version="0.2.0", features=["client"], optional = true } -wayland-protocols-misc = { version="0.2.0", features=["client"], optional = true } -x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true } -ashpd = { version = "0.8", default-features = false, features = ["tokio"], optional = true } -reis = { version = "0.2", features = [ "tokio" ], optional = true } - -[target.'cfg(target_os="macos")'.dependencies] -core-graphics = { version = "0.23", features = ["highsierra"] } - -[target.'cfg(windows)'.dependencies] -windows = { version = "0.54.0", features = [ - "Win32_System_LibraryLoader", - "Win32_System_Threading", - "Win32_Foundation", - "Win32_Graphics", - "Win32_Graphics_Gdi", - "Win32_UI_Input_KeyboardAndMouse", - "Win32_UI_WindowsAndMessaging", -] } - [build-dependencies] glib-build-tools = { version = "0.19.0", optional = true } [features] -default = ["wayland", "x11", "xdg_desktop_portal", "libei", "gtk"] -wayland = ["dep:wayland-client", "dep:wayland-protocols", "dep:wayland-protocols-wlr", "dep:wayland-protocols-misc" ] -x11 = ["dep:x11"] -xdg_desktop_portal = ["dep:ashpd"] -libei = ["dep:reis", "dep:ashpd"] +default = [ "wayland", "x11", "xdg_desktop_portal", "libei", "gtk" ] +wayland = [ "input-capture/wayland", "input-emulation/wayland" ] +x11 = [ "input-capture/x11", "input-emulation/x11" ] +xdg_desktop_portal = [ "input-emulation/xdg_desktop_portal" ] +libei = [ "input-capture/libei", "input-emulation/libei" ] gtk = ["dep:gtk", "dep:adw", "dep:async-channel", "dep:glib-build-tools"] diff --git a/input-capture/Cargo.toml b/input-capture/Cargo.toml new file mode 100644 index 0000000..fca68ed --- /dev/null +++ b/input-capture/Cargo.toml @@ -0,0 +1,49 @@ +[package] +name = "input-capture" +description = "cross-platform input-capture library used by lan-mouse" +version = "0.1.0" +edition = "2021" +license = "GPL-3.0-or-later" +repository = "https://github.com/ferdinandschober/lan-mouse" + +[dependencies] +anyhow = "1.0.86" +futures = "0.3.28" +futures-core = "0.3.30" +log = "0.4.22" +input-event = { path = "../input-event" } +memmap = "0.7" +tempfile = "3.8" +thiserror = "1.0.61" +tokio = { version = "1.32.0", features = ["io-util", "io-std", "macros", "net", "process", "rt", "sync", "signal"] } +once_cell = "1.19.0" + + +[target.'cfg(all(unix, not(target_os="macos")))'.dependencies] +wayland-client = { version="0.31.1", optional = true } +wayland-protocols = { version="0.31.0", features=["client", "staging", "unstable"], optional = true } +wayland-protocols-wlr = { version="0.2.0", features=["client"], optional = true } +wayland-protocols-misc = { version="0.2.0", features=["client"], optional = true } +x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true } +ashpd = { version = "0.8", default-features = false, features = ["tokio"], optional = true } +reis = { version = "0.2", features = [ "tokio" ], optional = true } + +[target.'cfg(target_os="macos")'.dependencies] +core-graphics = { version = "0.23", features = ["highsierra"] } + +[target.'cfg(windows)'.dependencies] +windows = { version = "0.54.0", features = [ + "Win32_System_LibraryLoader", + "Win32_System_Threading", + "Win32_Foundation", + "Win32_Graphics", + "Win32_Graphics_Gdi", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_WindowsAndMessaging", +] } + +[features] +default = ["wayland", "x11", "libei"] +wayland = ["dep:wayland-client", "dep:wayland-protocols", "dep:wayland-protocols-wlr", "dep:wayland-protocols-misc" ] +x11 = ["dep:x11"] +libei = ["dep:reis", "dep:ashpd"] diff --git a/src/capture/dummy.rs b/input-capture/src/dummy.rs similarity index 97% rename from src/capture/dummy.rs rename to input-capture/src/dummy.rs index 9ef549c..21808db 100644 --- a/src/capture/dummy.rs +++ b/input-capture/src/dummy.rs @@ -4,7 +4,7 @@ use std::task::{Context, Poll}; use futures_core::Stream; -use crate::event::Event; +use input_event::Event; use super::{CaptureHandle, InputCapture, Position}; diff --git a/src/capture/error.rs b/input-capture/src/error.rs similarity index 100% rename from src/capture/error.rs rename to input-capture/src/error.rs diff --git a/src/capture.rs b/input-capture/src/lib.rs similarity index 69% rename from src/capture.rs rename to input-capture/src/lib.rs index 65e671b..f24f166 100644 --- a/src/capture.rs +++ b/input-capture/src/lib.rs @@ -2,7 +2,7 @@ use std::{fmt::Display, io}; use futures_core::Stream; -use crate::{config::CaptureBackend, event::Event}; +use input_event::Event; use self::error::CaptureCreationError; @@ -59,6 +59,7 @@ impl Display for Position { } } +#[derive(Clone, Copy, Debug, Eq, PartialEq)] pub enum Backend { #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] InputCapturePortal, @@ -73,6 +74,24 @@ pub enum Backend { Dummy, } +impl Display for Backend { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] + Backend::InputCapturePortal => write!(f, "input-capture-portal"), + #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] + Backend::LayerShell => write!(f, "layer-shell"), + #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] + Backend::X11 => write!(f, "X11"), + #[cfg(windows)] + Backend::Windows => write!(f, "windows"), + #[cfg(target_os = "macos")] + Backend::MacOs => write!(f, "MacOS"), + Backend::Dummy => write!(f, "dummy"), + } + } +} + pub trait InputCapture: Stream> + Unpin { /// create a new client with the given id fn create(&mut self, id: CaptureHandle, pos: Position) -> io::Result<()>; @@ -85,26 +104,26 @@ pub trait InputCapture: Stream> + Unpi } pub async fn create_backend( - backend: CaptureBackend, + backend: Backend, ) -> Result>>, CaptureCreationError> { match backend { #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] - CaptureBackend::InputCapturePortal => Ok(Box::new(libei::LibeiInputCapture::new().await?)), + Backend::InputCapturePortal => Ok(Box::new(libei::LibeiInputCapture::new().await?)), #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] - CaptureBackend::LayerShell => Ok(Box::new(wayland::WaylandInputCapture::new()?)), + Backend::LayerShell => Ok(Box::new(wayland::WaylandInputCapture::new()?)), #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] - CaptureBackend::X11 => Ok(Box::new(x11::X11InputCapture::new()?)), + Backend::X11 => Ok(Box::new(x11::X11InputCapture::new()?)), #[cfg(windows)] - CaptureBackend::Windows => Ok(Box::new(windows::WindowsInputCapture::new())), + Backend::Windows => Ok(Box::new(windows::WindowsInputCapture::new())), #[cfg(target_os = "macos")] - CaptureBackend::MacOs => Ok(Box::new(macos::MacOSInputCapture::new()?)), - CaptureBackend::Dummy => Ok(Box::new(dummy::DummyInputCapture::new())), + Backend::MacOs => Ok(Box::new(macos::MacOSInputCapture::new()?)), + Backend::Dummy => Ok(Box::new(dummy::DummyInputCapture::new())), } } pub async fn create( - backend: Option, + backend: Option, ) -> Result>>, CaptureCreationError> { if let Some(backend) = backend { @@ -117,16 +136,16 @@ pub async fn create( for backend in [ #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] - CaptureBackend::InputCapturePortal, + Backend::InputCapturePortal, #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] - CaptureBackend::LayerShell, + Backend::LayerShell, #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] - CaptureBackend::X11, + Backend::X11, #[cfg(windows)] - CaptureBackend::Windows, + Backend::Windows, #[cfg(target_os = "macos")] - CaptureBackend::MacOs, - CaptureBackend::Dummy, + Backend::MacOs, + Backend::Dummy, ] { match create_backend(backend).await { Ok(b) => { diff --git a/src/capture/libei.rs b/input-capture/src/libei.rs similarity index 99% rename from src/capture/libei.rs rename to input-capture/src/libei.rs index f845926..84b9099 100644 --- a/src/capture/libei.rs +++ b/input-capture/src/libei.rs @@ -30,7 +30,7 @@ use tokio::{ use futures_core::Stream; use once_cell::sync::Lazy; -use crate::event::{Event, KeyboardEvent, PointerEvent}; +use input_event::{Event, KeyboardEvent, PointerEvent}; use super::{ error::LibeiCaptureCreationError, CaptureHandle, InputCapture as LanMouseInputCapture, Position, diff --git a/src/capture/macos.rs b/input-capture/src/macos.rs similarity index 84% rename from src/capture/macos.rs rename to input-capture/src/macos.rs index fb0efb7..a2383e1 100644 --- a/src/capture/macos.rs +++ b/input-capture/src/macos.rs @@ -1,7 +1,6 @@ -use crate::capture::error::MacOSInputCaptureCreationError; -use crate::capture::{CaptureHandle, InputCapture, Position}; -use crate::event::Event; +use crate::{error::MacOSInputCaptureCreationError, CaptureHandle, InputCapture, Position}; use futures_core::Stream; +use input_event::Event; use std::task::{Context, Poll}; use std::{io, pin::Pin}; diff --git a/src/capture/wayland.rs b/input-capture/src/wayland.rs similarity index 99% rename from src/capture/wayland.rs rename to input-capture/src/wayland.rs index ecfaa2b..d11030c 100644 --- a/src/capture/wayland.rs +++ b/input-capture/src/wayland.rs @@ -60,7 +60,7 @@ use wayland_client::{ use tempfile; -use crate::event::{Event, KeyboardEvent, PointerEvent}; +use input_event::{Event, KeyboardEvent, PointerEvent}; use super::{ error::{LayerShellCaptureCreationError, WaylandBindError}, diff --git a/src/capture/windows.rs b/input-capture/src/windows.rs similarity index 99% rename from src/capture/windows.rs rename to input-capture/src/windows.rs index 7faee75..28c7826 100644 --- a/src/capture/windows.rs +++ b/input-capture/src/windows.rs @@ -32,10 +32,10 @@ use windows::Win32::UI::WindowsAndMessaging::{ WNDPROC, }; -use crate::event::{ - KeyboardEvent, PointerEvent, BTN_BACK, BTN_FORWARD, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, +use input_event::{ + scancode::{self, Linux}, + Event, KeyboardEvent, PointerEvent, BTN_BACK, BTN_FORWARD, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, }; -use crate::{event::Event, scancode, scancode::Linux}; use super::{CaptureHandle, InputCapture, Position}; diff --git a/src/capture/x11.rs b/input-capture/src/x11.rs similarity index 97% rename from src/capture/x11.rs rename to input-capture/src/x11.rs index b4cd2a8..2378c85 100644 --- a/src/capture/x11.rs +++ b/input-capture/src/x11.rs @@ -4,7 +4,7 @@ use std::task::Poll; use futures_core::Stream; use super::InputCapture; -use crate::event::Event; +use input_event::Event; use super::error::X11InputCaptureCreationError; use super::{CaptureHandle, Position}; diff --git a/input-emulation/Cargo.toml b/input-emulation/Cargo.toml new file mode 100644 index 0000000..449058e --- /dev/null +++ b/input-emulation/Cargo.toml @@ -0,0 +1,47 @@ +[package] +name = "input-emulation" +description = "cross-platform input emulation library used by lan-mouse" +version = "0.1.0" +edition = "2021" +license = "GPL-3.0-or-later" +repository = "https://github.com/ferdinandschober/lan-mouse" + +[dependencies] +anyhow = "1.0.86" +async-trait = "0.1.80" +futures = "0.3.28" +log = "0.4.22" +input-event = { path = "../input-event" } +thiserror = "1.0.61" +tokio = { version = "1.32.0", features = ["io-util", "io-std", "macros", "net", "process", "rt", "sync", "signal"] } + +[target.'cfg(all(unix, not(target_os="macos")))'.dependencies] +wayland-client = { version="0.31.1", optional = true } +wayland-protocols = { version="0.31.0", features=["client", "staging", "unstable"], optional = true } +wayland-protocols-wlr = { version="0.2.0", features=["client"], optional = true } +wayland-protocols-misc = { version="0.2.0", features=["client"], optional = true } +x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true } +ashpd = { version = "0.8", default-features = false, features = ["tokio"], optional = true } +reis = { version = "0.2", features = [ "tokio" ], optional = true } + +[target.'cfg(target_os="macos")'.dependencies] +core-graphics = { version = "0.23", features = ["highsierra"] } +keycode = "0.4.0" + +[target.'cfg(windows)'.dependencies] +windows = { version = "0.54.0", features = [ + "Win32_System_LibraryLoader", + "Win32_System_Threading", + "Win32_Foundation", + "Win32_Graphics", + "Win32_Graphics_Gdi", + "Win32_UI_Input_KeyboardAndMouse", + "Win32_UI_WindowsAndMessaging", +] } + +[features] +default = ["wayland", "x11", "xdg_desktop_portal", "libei"] +wayland = ["dep:wayland-client", "dep:wayland-protocols", "dep:wayland-protocols-wlr", "dep:wayland-protocols-misc" ] +x11 = ["dep:x11"] +xdg_desktop_portal = ["dep:ashpd"] +libei = ["dep:reis", "dep:ashpd"] diff --git a/src/emulate/dummy.rs b/input-emulation/src/dummy.rs similarity index 95% rename from src/emulate/dummy.rs rename to input-emulation/src/dummy.rs index 6b1de3d..f077639 100644 --- a/src/emulate/dummy.rs +++ b/input-emulation/src/dummy.rs @@ -1,5 +1,5 @@ -use crate::event::Event; use async_trait::async_trait; +use input_event::Event; use super::{EmulationHandle, InputEmulation}; diff --git a/src/emulate/error.rs b/input-emulation/src/error.rs similarity index 100% rename from src/emulate/error.rs rename to input-emulation/src/error.rs diff --git a/src/emulate.rs b/input-emulation/src/lib.rs similarity index 54% rename from src/emulate.rs rename to input-emulation/src/lib.rs index 759365a..869f1f5 100644 --- a/src/emulate.rs +++ b/input-emulation/src/lib.rs @@ -1,7 +1,8 @@ use async_trait::async_trait; -use std::future; +use std::{fmt::Display, future}; + +use input_event::Event; -use crate::{config::EmulationBackend, event::Event}; use anyhow::Result; use self::error::EmulationCreationError; @@ -30,6 +31,43 @@ pub mod error; pub type EmulationHandle = u64; +#[derive(Clone, Copy, Debug, Eq, PartialEq)] +pub enum Backend { + #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] + Wlroots, + #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] + Libei, + #[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))] + Xdp, + #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] + X11, + #[cfg(windows)] + Windows, + #[cfg(target_os = "macos")] + MacOs, + Dummy, +} + +impl Display for Backend { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] + Backend::Wlroots => write!(f, "wlroots"), + #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] + Backend::Libei => write!(f, "libei"), + #[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))] + Backend::Xdp => write!(f, "xdg-desktop-portal"), + #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] + Backend::X11 => write!(f, "X11"), + #[cfg(windows)] + Backend::Windows => write!(f, "windows"), + #[cfg(target_os = "macos")] + Backend::MacOs => write!(f, "macos"), + Backend::Dummy => write!(f, "dummy"), + } + } +} + #[async_trait] pub trait InputEmulation: Send { async fn consume(&mut self, event: Event, handle: EmulationHandle); @@ -43,29 +81,29 @@ pub trait InputEmulation: Send { } pub async fn create_backend( - backend: EmulationBackend, + backend: Backend, ) -> Result, EmulationCreationError> { match backend { #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] - EmulationBackend::Wlroots => Ok(Box::new(wlroots::WlrootsEmulation::new()?)), + Backend::Wlroots => Ok(Box::new(wlroots::WlrootsEmulation::new()?)), #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] - EmulationBackend::Libei => Ok(Box::new(libei::LibeiEmulation::new().await?)), + Backend::Libei => Ok(Box::new(libei::LibeiEmulation::new().await?)), #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] - EmulationBackend::X11 => Ok(Box::new(x11::X11Emulation::new()?)), + Backend::X11 => Ok(Box::new(x11::X11Emulation::new()?)), #[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))] - EmulationBackend::Xdp => Ok(Box::new( + Backend::Xdp => Ok(Box::new( xdg_desktop_portal::DesktopPortalEmulation::new().await?, )), #[cfg(windows)] - EmulationBackend::Windows => Ok(Box::new(windows::WindowsEmulation::new()?)), + Backend::Windows => Ok(Box::new(windows::WindowsEmulation::new()?)), #[cfg(target_os = "macos")] - EmulationBackend::MacOs => Ok(Box::new(macos::MacOSEmulation::new()?)), - EmulationBackend::Dummy => Ok(Box::new(dummy::DummyEmulation::new())), + Backend::MacOs => Ok(Box::new(macos::MacOSEmulation::new()?)), + Backend::Dummy => Ok(Box::new(dummy::DummyEmulation::new())), } } pub async fn create( - backend: Option, + backend: Option, ) -> Result, EmulationCreationError> { if let Some(backend) = backend { let b = create_backend(backend).await; @@ -77,16 +115,16 @@ pub async fn create( for backend in [ #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] - EmulationBackend::Wlroots, + Backend::Wlroots, #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] - EmulationBackend::Libei, + Backend::Libei, #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] - EmulationBackend::X11, + Backend::X11, #[cfg(windows)] - EmulationBackend::Windows, + Backend::Windows, #[cfg(target_os = "macos")] - EmulationBackend::MacOs, - EmulationBackend::Dummy, + Backend::MacOs, + Backend::Dummy, ] { match create_backend(backend).await { Ok(b) => { diff --git a/src/emulate/libei.rs b/input-emulation/src/libei.rs similarity index 97% rename from src/emulate/libei.rs rename to input-emulation/src/libei.rs index c18b166..679a7bd 100644 --- a/src/emulate/libei.rs +++ b/input-emulation/src/libei.rs @@ -22,7 +22,7 @@ use reis::{ PendingRequestResult, }; -use crate::event::Event; +use input_event::{Event, KeyboardEvent, PointerEvent}; use super::{error::LibeiEmulationCreationError, EmulationHandle, InputEmulation}; @@ -114,7 +114,7 @@ impl InputEmulation for LibeiEmulation { .as_micros() as u64; match event { Event::Pointer(p) => match p { - crate::event::PointerEvent::Motion { + PointerEvent::Motion { time: _, relative_x, relative_y, @@ -127,7 +127,7 @@ impl InputEmulation for LibeiEmulation { d.frame(self.serial, now); } } - crate::event::PointerEvent::Button { + PointerEvent::Button { time: _, button, state, @@ -146,7 +146,7 @@ impl InputEmulation for LibeiEmulation { d.frame(self.serial, now); } } - crate::event::PointerEvent::Axis { + PointerEvent::Axis { time: _, axis, value, @@ -162,7 +162,7 @@ impl InputEmulation for LibeiEmulation { d.frame(self.serial, now); } } - crate::event::PointerEvent::AxisDiscrete120 { axis, value } => { + PointerEvent::AxisDiscrete120 { axis, value } => { if !self.has_scroll { return; } @@ -174,10 +174,10 @@ impl InputEmulation for LibeiEmulation { d.frame(self.serial, now); } } - crate::event::PointerEvent::Frame {} => {} + PointerEvent::Frame {} => {} }, Event::Keyboard(k) => match k { - crate::event::KeyboardEvent::Key { + KeyboardEvent::Key { time: _, key, state, @@ -196,7 +196,7 @@ impl InputEmulation for LibeiEmulation { d.frame(self.serial, now); } } - crate::event::KeyboardEvent::Modifiers { .. } => {} + KeyboardEvent::Modifiers { .. } => {} }, _ => {} } diff --git a/src/emulate/macos.rs b/input-emulation/src/macos.rs similarity index 96% rename from src/emulate/macos.rs rename to input-emulation/src/macos.rs index bc80c2c..8054cce 100644 --- a/src/emulate/macos.rs +++ b/input-emulation/src/macos.rs @@ -1,11 +1,11 @@ use super::{EmulationHandle, InputEmulation}; -use crate::event::{Event, KeyboardEvent, PointerEvent}; use async_trait::async_trait; use core_graphics::display::{CGDisplayBounds, CGMainDisplayID, CGPoint}; use core_graphics::event::{ CGEvent, CGEventTapLocation, CGEventType, CGKeyCode, CGMouseButton, EventField, ScrollEventUnit, }; use core_graphics::event_source::{CGEventSource, CGEventSourceStateID}; +use input_event::{Event, KeyboardEvent, PointerEvent}; use keycode::{KeyMap, KeyMapping}; use std::ops::{Index, IndexMut}; use std::time::Duration; @@ -172,22 +172,22 @@ impl InputEmulation for MacOSEmulation { state, } => { let (event_type, mouse_button) = match (button, state) { - (b, 1) if b == crate::event::BTN_LEFT => { + (b, 1) if b == input_event::BTN_LEFT => { (CGEventType::LeftMouseDown, CGMouseButton::Left) } - (b, 0) if b == crate::event::BTN_LEFT => { + (b, 0) if b == input_event::BTN_LEFT => { (CGEventType::LeftMouseUp, CGMouseButton::Left) } - (b, 1) if b == crate::event::BTN_RIGHT => { + (b, 1) if b == input_event::BTN_RIGHT => { (CGEventType::RightMouseDown, CGMouseButton::Right) } - (b, 0) if b == crate::event::BTN_RIGHT => { + (b, 0) if b == input_event::BTN_RIGHT => { (CGEventType::RightMouseUp, CGMouseButton::Right) } - (b, 1) if b == crate::event::BTN_MIDDLE => { + (b, 1) if b == input_event::BTN_MIDDLE => { (CGEventType::OtherMouseDown, CGMouseButton::Center) } - (b, 0) if b == crate::event::BTN_MIDDLE => { + (b, 0) if b == input_event::BTN_MIDDLE => { (CGEventType::OtherMouseUp, CGMouseButton::Center) } _ => { diff --git a/src/emulate/windows.rs b/input-emulation/src/windows.rs similarity index 97% rename from src/emulate/windows.rs rename to input-emulation/src/windows.rs index 96860f9..c9a699a 100644 --- a/src/emulate/windows.rs +++ b/input-emulation/src/windows.rs @@ -1,9 +1,7 @@ use super::error::WindowsEmulationCreationError; -use crate::{ - event::{ - Event, KeyboardEvent, PointerEvent, BTN_BACK, BTN_FORWARD, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, - }, - scancode, +use input_event::{ + scancode, Event, KeyboardEvent, PointerEvent, BTN_BACK, BTN_FORWARD, BTN_LEFT, BTN_MIDDLE, + BTN_RIGHT, }; use async_trait::async_trait; diff --git a/src/emulate/wlroots.rs b/input-emulation/src/wlroots.rs similarity index 98% rename from src/emulate/wlroots.rs rename to input-emulation/src/wlroots.rs index 0da3347..d0ff994 100644 --- a/src/emulate/wlroots.rs +++ b/input-emulation/src/wlroots.rs @@ -1,4 +1,4 @@ -use crate::emulate::{error::WlrootsEmulationCreationError, InputEmulation}; +use super::{error::WlrootsEmulationCreationError, InputEmulation}; use async_trait::async_trait; use std::collections::HashMap; use std::io; @@ -26,7 +26,7 @@ use wayland_client::{ Connection, Dispatch, EventQueue, QueueHandle, }; -use crate::event::{Event, KeyboardEvent, PointerEvent}; +use input_event::{Event, KeyboardEvent, PointerEvent}; use super::error::WaylandBindError; use super::EmulationHandle; diff --git a/src/emulate/x11.rs b/input-emulation/src/x11.rs similarity index 99% rename from src/emulate/x11.rs rename to input-emulation/src/x11.rs index 36f4043..5b9911d 100644 --- a/src/emulate/x11.rs +++ b/input-emulation/src/x11.rs @@ -5,7 +5,7 @@ use x11::{ xtest, }; -use crate::event::{ +use input_event::{ Event, KeyboardEvent, PointerEvent, BTN_BACK, BTN_FORWARD, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, }; diff --git a/src/emulate/xdg_desktop_portal.rs b/input-emulation/src/xdg_desktop_portal.rs similarity index 98% rename from src/emulate/xdg_desktop_portal.rs rename to input-emulation/src/xdg_desktop_portal.rs index 75f974e..eb7edfc 100644 --- a/src/emulate/xdg_desktop_portal.rs +++ b/input-emulation/src/xdg_desktop_portal.rs @@ -8,7 +8,7 @@ use ashpd::{ }; use async_trait::async_trait; -use crate::event::{ +use input_event::{ Event::{Keyboard, Pointer}, KeyboardEvent, PointerEvent, }; @@ -59,7 +59,7 @@ impl<'a> DesktopPortalEmulation<'a> { #[async_trait] impl<'a> InputEmulation for DesktopPortalEmulation<'a> { - async fn consume(&mut self, event: crate::event::Event, _client: crate::client::ClientHandle) { + async fn consume(&mut self, event: input_event::Event, _client: EmulationHandle) { match event { Pointer(p) => match p { PointerEvent::Motion { diff --git a/input-event/Cargo.toml b/input-event/Cargo.toml new file mode 100644 index 0000000..94ed13c --- /dev/null +++ b/input-event/Cargo.toml @@ -0,0 +1,14 @@ +[package] +name = "input-event" +description = "cross-platform input-event types for input-capture / input-emulation" +version = "0.1.0" +edition = "2021" +license = "GPL-3.0-or-later" +repository = "https://github.com/ferdinandschober/lan-mouse" + +[dependencies] +anyhow = "1.0.86" +futures-core = "0.3.30" +log = "0.4.22" +num_enum = "0.7.2" +serde = "1.0.203" diff --git a/src/event.rs b/input-event/src/lib.rs similarity index 99% rename from src/event.rs rename to input-event/src/lib.rs index f8d512d..db31a25 100644 --- a/src/event.rs +++ b/input-event/src/lib.rs @@ -1,10 +1,11 @@ -use crate::scancode; use anyhow::{anyhow, Result}; use std::{ error::Error, fmt::{self, Display}, }; +pub mod scancode; + // FIXME pub const BTN_LEFT: u32 = 0x110; pub const BTN_RIGHT: u32 = 0x111; diff --git a/src/scancode.rs b/input-event/src/scancode.rs similarity index 100% rename from src/scancode.rs rename to input-event/src/scancode.rs diff --git a/src/capture_test.rs b/src/capture_test.rs index e6be9b3..68b94c5 100644 --- a/src/capture_test.rs +++ b/src/capture_test.rs @@ -1,8 +1,8 @@ -use crate::capture::{self, Position}; use crate::config::Config; -use crate::event::{Event, KeyboardEvent}; use anyhow::{anyhow, Result}; use futures::StreamExt; +use input_capture::{self, Position}; +use input_event::{Event, KeyboardEvent}; use tokio::task::LocalSet; pub fn run() -> Result<()> { @@ -19,7 +19,8 @@ pub fn run() -> Result<()> { async fn input_capture_test(config: Config) -> Result<()> { log::info!("creating input capture"); - let mut input_capture = capture::create(config.capture_backend).await?; + let backend = config.capture_backend.map(|b| b.into()); + let mut input_capture = input_capture::create(backend).await?; log::info!("creating clients"); input_capture.create(0, Position::Left)?; input_capture.create(1, Position::Right)?; diff --git a/src/client.rs b/src/client.rs index c6c533b..2753e24 100644 --- a/src/client.rs +++ b/src/client.rs @@ -9,7 +9,8 @@ use std::{ use serde::{Deserialize, Serialize}; use slab::Slab; -use crate::{capture, config::DEFAULT_PORT}; +use crate::config::DEFAULT_PORT; +use input_capture; #[derive(Debug, Eq, Hash, PartialEq, Clone, Copy, Serialize, Deserialize)] pub enum Position { @@ -25,13 +26,13 @@ impl Default for Position { } } -impl From for capture::Position { - fn from(position: Position) -> capture::Position { +impl From for input_capture::Position { + fn from(position: Position) -> input_capture::Position { match position { - Position::Left => capture::Position::Left, - Position::Right => capture::Position::Right, - Position::Top => capture::Position::Top, - Position::Bottom => capture::Position::Bottom, + Position::Left => input_capture::Position::Left, + Position::Right => input_capture::Position::Right, + Position::Top => input_capture::Position::Top, + Position::Bottom => input_capture::Position::Bottom, } } } diff --git a/src/config.rs b/src/config.rs index ecbffe3..1c2e499 100644 --- a/src/config.rs +++ b/src/config.rs @@ -9,8 +9,11 @@ use std::{error::Error, fs}; use toml; use crate::client::Position; -use crate::scancode; -use crate::scancode::Linux::{KeyLeftAlt, KeyLeftCtrl, KeyLeftMeta, KeyLeftShift}; + +use input_event::scancode::{ + self, + Linux::{KeyLeftAlt, KeyLeftCtrl, KeyLeftMeta, KeyLeftShift}, +}; pub const DEFAULT_PORT: u16 = 4242; @@ -115,6 +118,24 @@ impl Display for CaptureBackend { } } +impl From for input_capture::Backend { + fn from(backend: CaptureBackend) -> Self { + match backend { + #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] + CaptureBackend::InputCapturePortal => Self::InputCapturePortal, + #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] + CaptureBackend::LayerShell => Self::LayerShell, + #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] + CaptureBackend::X11 => Self::X11, + #[cfg(windows)] + CaptureBackend::Windows => Self::Windows, + #[cfg(target_os = "macos")] + CaptureBackend::MacOs => Self::MacOs, + CaptureBackend::Dummy => Self::Dummy, + } + } +} + #[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq, Serialize, ValueEnum)] pub enum EmulationBackend { #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] @@ -132,6 +153,26 @@ pub enum EmulationBackend { Dummy, } +impl From for input_emulation::Backend { + fn from(backend: EmulationBackend) -> Self { + match backend { + #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] + EmulationBackend::Wlroots => Self::Wlroots, + #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] + EmulationBackend::Libei => Self::Libei, + #[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))] + EmulationBackend::Xdp => Self::Xdp, + #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] + EmulationBackend::X11 => Self::X11, + #[cfg(windows)] + EmulationBackend::Windows => Self::Windows, + #[cfg(target_os = "macos")] + EmulationBackend::MacOs => Self::MacOs, + EmulationBackend::Dummy => Self::Dummy, + } + } +} + impl Display for EmulationBackend { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { diff --git a/src/emulation_test.rs b/src/emulation_test.rs index b6fd3d8..1bc2a10 100644 --- a/src/emulation_test.rs +++ b/src/emulation_test.rs @@ -1,7 +1,6 @@ use crate::config::Config; -use crate::emulate; -use crate::event::{Event, PointerEvent}; use anyhow::Result; +use input_event::{Event, PointerEvent}; use std::f64::consts::PI; use std::time::{Duration, Instant}; use tokio::task::LocalSet; @@ -22,7 +21,8 @@ const FREQUENCY_HZ: f64 = 1.0; const RADIUS: f64 = 100.0; async fn input_emulation_test(config: Config) -> Result<()> { - let mut emulation = emulate::create(config.emulation_backend).await?; + let backend = config.emulation_backend.map(|b| b.into()); + let mut emulation = input_emulation::create(backend).await?; emulation.create(0).await; let start = Instant::now(); let mut offset = (0, 0); diff --git a/src/lib.rs b/src/lib.rs index 7e756ed..148681c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,8 @@ pub mod client; pub mod config; pub mod dns; -pub mod event; pub mod server; -pub mod capture; -pub mod emulate; - pub mod capture_test; pub mod emulation_test; pub mod frontend; -pub mod scancode; diff --git a/src/server.rs b/src/server.rs index 596b125..ca61ca2 100644 --- a/src/server.rs +++ b/src/server.rs @@ -40,7 +40,7 @@ pub struct Server { client_manager: Rc>, port: Rc>, state: Rc>, - release_bind: Vec, + release_bind: Vec, } impl Server { diff --git a/src/server/capture_task.rs b/src/server/capture_task.rs index cc85b30..84158d0 100644 --- a/src/server/capture_task.rs +++ b/src/server/capture_task.rs @@ -4,14 +4,11 @@ use std::{collections::HashSet, net::SocketAddr}; use tokio::{process::Command, sync::mpsc::Sender, task::JoinHandle}; -use crate::{ - capture::{self, error::CaptureCreationError, CaptureHandle, InputCapture, Position}, - client::ClientHandle, - config::CaptureBackend, - event::{Event, KeyboardEvent}, - scancode, - server::State, -}; +use input_capture::{self, error::CaptureCreationError, CaptureHandle, InputCapture, Position}; + +use input_event::{scancode, Event, KeyboardEvent}; + +use crate::{client::ClientHandle, config::CaptureBackend, server::State}; use super::Server; @@ -35,8 +32,9 @@ pub fn new( release_bind: Vec, ) -> Result<(JoinHandle>, Sender), CaptureCreationError> { let (tx, mut rx) = tokio::sync::mpsc::channel(32); + let backend = backend.map(|b| b.into()); let task = tokio::task::spawn_local(async move { - let mut capture = capture::create(backend).await?; + let mut capture = input_capture::create(backend).await?; let mut pressed_keys = HashSet::new(); loop { tokio::select! { diff --git a/src/server/emulation_task.rs b/src/server/emulation_task.rs index cd18d0f..be46d91 100644 --- a/src/server/emulation_task.rs +++ b/src/server/emulation_task.rs @@ -6,14 +6,9 @@ use tokio::{ task::JoinHandle, }; -use crate::{ - client::ClientHandle, - config::EmulationBackend, - emulate::{self, error::EmulationCreationError, EmulationHandle, InputEmulation}, - event::{Event, KeyboardEvent}, - scancode, - server::State, -}; +use crate::{client::ClientHandle, config::EmulationBackend, server::State}; +use input_emulation::{self, error::EmulationCreationError, EmulationHandle, InputEmulation}; +use input_event::{Event, KeyboardEvent}; use super::{CaptureEvent, Server}; @@ -39,7 +34,8 @@ pub fn new( ) -> Result<(JoinHandle>, Sender), EmulationCreationError> { let (tx, mut rx) = tokio::sync::mpsc::channel(32); let emulate_task = tokio::task::spawn_local(async move { - let mut emulate = emulate::create(backend).await?; + let backend = backend.map(|b| b.into()); + let mut emulate = input_emulation::create(backend).await?; let mut last_ignored = None; loop { @@ -225,7 +221,7 @@ async fn release_keys( state: 0, }); emulate.consume(event, client).await; - if let Ok(key) = scancode::Linux::try_from(key) { + if let Ok(key) = input_event::scancode::Linux::try_from(key) { log::warn!("releasing stuck key: {key:?}"); } } diff --git a/src/server/network_task.rs b/src/server/network_task.rs index 1b85ee6..cdc9c2a 100644 --- a/src/server/network_task.rs +++ b/src/server/network_task.rs @@ -7,7 +7,8 @@ use tokio::{ task::JoinHandle, }; -use crate::{event::Event, frontend::FrontendEvent}; +use crate::frontend::FrontendEvent; +use input_event::Event; use super::Server; diff --git a/src/server/ping_task.rs b/src/server/ping_task.rs index 5ae55b6..2177671 100644 --- a/src/server/ping_task.rs +++ b/src/server/ping_task.rs @@ -5,7 +5,9 @@ use tokio::{ task::JoinHandle, }; -use crate::{client::ClientHandle, event::Event}; +use input_event::Event; + +use crate::client::ClientHandle; use super::{capture_task::CaptureEvent, emulation_task::EmulationEvent, Server, State};