Merge pull request #1 from ferdinandschober/conditional-compilation-of-backends

enable conditional compilation for all backends
This commit is contained in:
Ferdinand Schober
2023-02-17 14:14:52 +01:00
committed by GitHub
22 changed files with 310 additions and 197 deletions

View File

@@ -15,12 +15,25 @@ serde_derive = "1.0"
threadpool = "1.8"
[target.'cfg(unix)'.dependencies]
wayland-client = { version="0.30.0" }
wayland-protocols = { version="0.30.0", features=["client", "staging", "unstable"] }
wayland-protocols-wlr = { version="0.1.0", features=["client"] }
wayland-protocols-misc = { version="0.1.0", features=["client"] }
wayland-protocols-plasma = { version="0.1.0", features=["client"] }
x11 = { version = "2.21.0", features = ["xlib", "xtest"] }
wayland-client = { version="0.30.0", optional = true }
wayland-protocols = { version="0.30.0", features=["client", "staging", "unstable"], optional = true }
wayland-protocols-wlr = { version="0.1.0", features=["client"], optional = true }
wayland-protocols-misc = { version="0.1.0", features=["client"], optional = true }
wayland-protocols-plasma = { version="0.1.0", features=["client"], optional = true }
x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true }
[target.'cfg(windows)'.dependencies]
winapi = { version = "0.3.9", features = ["winuser"] }
[features]
default = [ "wayland", "x11", "xdg_desktop_portal", "libei" ]
wayland = [
"dep:wayland-client",
"dep:wayland-protocols",
"dep:wayland-protocols-wlr",
"dep:wayland-protocols-misc",
"dep:wayland-protocols-plasma" ]
x11 = [ "dep:x11" ]
xdg_desktop_portal = []
libei = []

View File

@@ -1,4 +1,5 @@
port = 42069
backend = "wlroots"
# [client.right]
# host_name = "localhost"

View File

@@ -1,14 +1,2 @@
#[cfg(windows)]
pub mod windows;
#[cfg(unix)]
pub mod wayland;
#[cfg(unix)]
pub mod x11;
#[derive(Clone, Copy, Debug)]
pub enum Backend {
X11,
WAYLAND,
}
pub mod consumer;
pub mod producer;

14
src/backend/consumer.rs Normal file
View File

@@ -0,0 +1,14 @@
#[cfg(windows)]
pub mod windows;
#[cfg(all(unix, feature="x11"))]
pub mod x11;
#[cfg(all(unix, feature = "wayland"))]
pub mod wlroots;
#[cfg(all(unix, feature = "xdg_desktop_portal"))]
pub mod xdg_desktop_portal;
#[cfg(all(unix, feature = "libei"))]
pub mod libei;

View File

@@ -0,0 +1,9 @@
use std::sync::mpsc::Receiver;
use crate::{event::Event, client::{ClientHandle, Client}};
pub(crate) fn run(_consume_rx: Receiver<(Event, ClientHandle)>, _clients: Vec<Client>) {
todo!()
}

View File

@@ -35,13 +35,8 @@ use tempfile;
use crate::event::{Event, KeyboardEvent, PointerEvent};
enum VirtualInputManager {
Wlroots {
vpm: VpManager,
vkm: VkManager,
},
Kde {
fake_input: OrgKdeKwinFakeInput,
}
Wlroots { vpm: VpManager, vkm: VkManager },
Kde { fake_input: OrgKdeKwinFakeInput },
}
// App State, implements Dispatch event handlers
@@ -72,16 +67,21 @@ impl App {
let virtual_input_manager = match (vpm, vkm, fake_input) {
(Ok(vpm), Ok(vkm), _) => VirtualInputManager::Wlroots { vpm, vkm },
(_, _, Ok(fake_input)) => {
fake_input.authenticate("lan-mouse".into(), "Allow remote clients to control this devices".into());
fake_input.authenticate(
"lan-mouse".into(),
"Allow remote clients to control this devices".into(),
);
VirtualInputManager::Kde { fake_input }
},
}
(Err(e1), Err(e2), Err(e3)) => {
eprintln!("zwlr_virtual_pointer_v1: {e1}");
eprintln!("zwp_virtual_keyboard_v1: {e2}");
eprintln!("org_kde_kwin_fake_input: {e3}");
panic!("neither wlroots nor kde input emulation protocol supported!")
},
_ => { panic!() }
}
_ => {
panic!()
}
};
let input_for_client: HashMap<ClientHandle, VirtualInput> = HashMap::new();
@@ -152,28 +152,22 @@ impl App {
buf.flush().unwrap();
keyboard.keymap(1, f.as_raw_fd(), data.len() as u32);
let vinput = VirtualInput::Wlroots{ pointer, keyboard };
let vinput = VirtualInput::Wlroots { pointer, keyboard };
self.input_for_client.insert(client.handle, vinput);
},
}
VirtualInputManager::Kde { fake_input } => {
let fake_input = fake_input.clone();
let vinput = VirtualInput::Kde { fake_input };
self.input_for_client.insert(client.handle, vinput);
},
}
}
}
}
enum VirtualInput {
Wlroots {
pointer: Vp,
keyboard: Vk,
},
Kde {
fake_input: OrgKdeKwinFakeInput,
}
Wlroots { pointer: Vp, keyboard: Vk },
Kde { fake_input: OrgKdeKwinFakeInput },
}
impl VirtualInput {
@@ -185,17 +179,18 @@ impl VirtualInput {
time,
relative_x,
relative_y,
} => {
match self {
VirtualInput::Wlroots { pointer, keyboard:_ } => {
pointer.motion(time, relative_x, relative_y);
pointer.frame();
},
VirtualInput::Kde { fake_input } => {
fake_input.pointer_motion(relative_y, relative_y);
},
} => match self {
VirtualInput::Wlroots {
pointer,
keyboard: _,
} => {
pointer.motion(time, relative_x, relative_y);
pointer.frame();
}
}
VirtualInput::Kde { fake_input } => {
fake_input.pointer_motion(relative_y, relative_y);
}
},
PointerEvent::Button {
time,
button,
@@ -203,70 +198,80 @@ impl VirtualInput {
} => {
let state: ButtonState = state.try_into().unwrap();
match self {
VirtualInput::Wlroots { pointer, keyboard:_ } => {
VirtualInput::Wlroots {
pointer,
keyboard: _,
} => {
pointer.button(time, button, state);
pointer.frame();
},
}
VirtualInput::Kde { fake_input } => {
fake_input.button(button, state as u32);
},
}
}
}
PointerEvent::Axis { time, axis, value } => {
let axis: Axis = (axis as u32).try_into().unwrap();
match self {
VirtualInput::Wlroots { pointer, keyboard:_ } => {
VirtualInput::Wlroots {
pointer,
keyboard: _,
} => {
pointer.axis(time, axis, value);
pointer.frame();
},
}
VirtualInput::Kde { fake_input } => {
fake_input.axis(axis as u32, value);
},
}
}
}
PointerEvent::Frame {} => {
match self {
VirtualInput::Wlroots { pointer, keyboard:_ } => {
pointer.frame();
},
VirtualInput::Kde { fake_input:_ } => { },
PointerEvent::Frame {} => match self {
VirtualInput::Wlroots {
pointer,
keyboard: _,
} => {
pointer.frame();
}
}
VirtualInput::Kde { fake_input: _ } => {}
},
},
Event::Keyboard(e) => match e {
KeyboardEvent::Key { time, key, state } => {
match self {
VirtualInput::Wlroots { pointer:_, keyboard } => {
keyboard.key(time, key, state as u32);
},
VirtualInput::Kde { fake_input } => {
fake_input.keyboard_key(key, state as u32);
},
KeyboardEvent::Key { time, key, state } => match self {
VirtualInput::Wlroots {
pointer: _,
keyboard,
} => {
keyboard.key(time, key, state as u32);
}
}
VirtualInput::Kde { fake_input } => {
fake_input.keyboard_key(key, state as u32);
}
},
KeyboardEvent::Modifiers {
mods_depressed,
mods_latched,
mods_locked,
group,
} => {
match self {
VirtualInput::Wlroots { pointer:_, keyboard } => {
keyboard.modifiers(mods_depressed, mods_latched, mods_locked, group);
},
VirtualInput::Kde { fake_input:_ } => { },
} => match self {
VirtualInput::Wlroots {
pointer: _,
keyboard,
} => {
keyboard.modifiers(mods_depressed, mods_latched, mods_locked, group);
}
}
VirtualInput::Kde { fake_input: _ } => {}
},
},
Event::Release() => {
match self {
VirtualInput::Wlroots { pointer:_, keyboard } => {
keyboard.modifiers(77, 0, 0, 0);
keyboard.modifiers(0, 0, 0, 0);
},
VirtualInput::Kde { fake_input:_ } => {},
Event::Release() => match self {
VirtualInput::Wlroots {
pointer: _,
keyboard,
} => {
keyboard.modifiers(77, 0, 0, 0);
keyboard.modifiers(0, 0, 0, 0);
}
}
VirtualInput::Kde { fake_input: _ } => {}
},
}
Ok(())
}

View File

@@ -0,0 +1,9 @@
use std::sync::mpsc::Receiver;
use crate::{event::Event, client::{ClientHandle, Client}};
pub(crate) fn run(_consume_rx: Receiver<(Event, ClientHandle)>, _clients: Vec<Client>) {
todo!()
}

6
src/backend/producer.rs Normal file
View File

@@ -0,0 +1,6 @@
#[cfg(all(unix, feature = "wayland"))]
pub mod wayland;
#[cfg(windows)]
pub mod windows;
#[cfg(all(unix, feature = "x11"))]
pub mod x11;

View File

@@ -1,2 +0,0 @@
pub mod consumer;
pub mod producer;

View File

@@ -1,2 +0,0 @@
pub mod consumer;
pub mod producer;

View File

@@ -1,2 +0,0 @@
pub mod consumer;
pub mod producer;

View File

@@ -1,5 +1,7 @@
use std::net::SocketAddr;
use crate::{config, dns};
#[derive(Eq, Hash, PartialEq, Clone, Copy)]
pub enum Position {
Left,
@@ -34,19 +36,56 @@ pub struct ClientManager {
pub type ClientHandle = u32;
impl ClientManager {
fn add_client(&mut self, client: &config::Client, pos: Position) {
let ip = match client.ip {
Some(ip) => ip,
None => match &client.host_name {
Some(host_name) => match dns::resolve(host_name) {
Ok(ip) => ip,
Err(e) => panic!("{}", e),
},
None => panic!("neither ip nor hostname specified"),
},
};
let addr = SocketAddr::new(ip, client.port.unwrap_or(42069));
self.register_client(addr, pos);
}
fn new_id(&mut self) -> ClientHandle {
self.next_id += 1;
self.next_id
}
pub fn new() -> Self {
ClientManager {
pub fn new(config: &config::Config) -> Self {
let mut client_manager = ClientManager {
next_id: 0,
clients: Vec::new(),
};
// add clients from config
for client in vec![
&config.client.left,
&config.client.right,
&config.client.top,
&config.client.bottom,
] {
if let Some(client) = client {
let pos = match client {
client if Some(client) == config.client.left.as_ref() => Position::Left,
client if Some(client) == config.client.right.as_ref() => Position::Right,
client if Some(client) == config.client.top.as_ref() => Position::Top,
client if Some(client) == config.client.bottom.as_ref() => Position::Bottom,
_ => panic!(),
};
client_manager.add_client(client, pos);
}
}
client_manager
}
pub fn add_client(&mut self, addr: SocketAddr, pos: Position) {
pub fn register_client(&mut self, addr: SocketAddr, pos: Position) {
let handle = self.new_id();
let client = Client { addr, pos, handle };
self.clients.push(client);

View File

@@ -7,6 +7,7 @@ use toml;
pub struct Config {
pub client: Clients,
pub port: Option<u16>,
pub backend: Option<String>,
}
#[derive(Serialize, Deserialize, Debug)]

70
src/consumer.rs Normal file
View File

@@ -0,0 +1,70 @@
use std::{thread::{JoinHandle, self}, env, sync::mpsc::Receiver};
use crate::{backend::consumer, client::{Client, ClientHandle}, event::Event};
#[derive(Debug)]
enum Backend {
Wlroots,
X11,
RemoteDesktopPortal,
Libei,
}
pub fn start(consume_rx: Receiver<(Event, ClientHandle)>, clients: Vec<Client>, backend: Option<String>) -> JoinHandle<()> {
thread::Builder::new()
.name("event consumer".into())
.spawn(move || {
#[cfg(windows)]
consumer::windows::run(consume_rx, clients);
#[cfg(unix)]
let backend = match env::var("XDG_SESSION_TYPE") {
Ok(session_type) => match session_type.as_str() {
"x11" => Backend::X11,
"wayland" => {
match backend {
Some(backend) => match backend.as_str() {
"wlroots" => Backend::Wlroots,
"libei" => Backend::Libei,
"xdg_desktop_portal" => Backend::RemoteDesktopPortal,
backend => panic!("invalid backend: {}", backend)
}
// default to wlroots backend for now
_ => Backend::Wlroots,
}
}
_ => panic!("unknown XDG_SESSION_TYPE"),
},
Err(_) => panic!("could not detect session type: XDG_SESSION_TYPE environment variable not set!"),
};
#[cfg(unix)]
match backend {
Backend::Libei => {
#[cfg(not(feature = "libei"))]
panic!("feature libei not enabled");
#[cfg(feature = "libei")]
consumer::libei::run(consume_rx, clients);
},
Backend::RemoteDesktopPortal => {
#[cfg(not(feature = "xdg_desktop_portal"))]
panic!("feature xdg_desktop_portal not enabled");
#[cfg(feature = "xdg_desktop_portal")]
consumer::xdg_desktop_portal::run(consume_rx, clients);
},
Backend::Wlroots => {
#[cfg(not(feature = "wayland"))]
panic!("feature wayland not enabled");
#[cfg(feature = "wayland")]
consumer::wlroots::run(consume_rx, clients);
},
Backend::X11 => {
#[cfg(not(feature = "x11"))]
panic!("feature x11 not enabled");
#[cfg(feature = "x11")]
consumer::x11::run(consume_rx, clients);
},
}
})
.unwrap()
}

View File

@@ -4,4 +4,7 @@ pub mod dns;
pub mod event;
pub mod request;
pub mod consumer;
pub mod producer;
pub mod backend;

View File

@@ -1,34 +1,11 @@
use std::{net::SocketAddr, sync::mpsc, thread};
#[cfg(unix)]
use std::env;
use std::sync::mpsc;
use lan_mouse::{
client::{ClientManager, Position},
config, dns, event, request,
client::ClientManager,
consumer, producer,
config, event, request,
};
#[cfg(windows)]
use lan_mouse::backend::windows;
#[cfg(unix)]
use lan_mouse::backend::{wayland, x11, Backend};
fn add_client(client_manager: &mut ClientManager, client: &config::Client, pos: Position) {
let ip = match client.ip {
Some(ip) => ip,
None => match &client.host_name {
Some(host_name) => match dns::resolve(host_name) {
Ok(ip) => ip,
Err(e) => panic!("{}", e),
},
None => panic!("neither ip nor hostname specified"),
},
};
let addr = SocketAddr::new(ip, client.port.unwrap_or(42069));
client_manager.add_client(addr, pos);
}
pub fn main() {
// parse config file
let config = config::Config::new("config.toml").unwrap();
@@ -42,83 +19,15 @@ pub fn main() {
// event channel for consuming events
let (consume_tx, consume_rx) = mpsc::sync_channel(128);
let mut client_manager = ClientManager::new();
// add clients from config
for client in vec![
&config.client.left,
&config.client.right,
&config.client.top,
&config.client.bottom,
] {
if let Some(client) = client {
let pos = match client {
client if Some(client) == config.client.left.as_ref() => Position::Left,
client if Some(client) == config.client.right.as_ref() => Position::Right,
client if Some(client) == config.client.top.as_ref() => Position::Top,
client if Some(client) == config.client.bottom.as_ref() => Position::Bottom,
_ => panic!(),
};
add_client(&mut client_manager, client, pos);
}
}
// create client manager
let mut client_manager = ClientManager::new(&config);
// start receiving client connection requests
let (request_server, request_thread) = request::Server::listen(port).unwrap();
let clients = client_manager.get_clients();
#[cfg(unix)]
let backend = match env::var("XDG_SESSION_TYPE") {
Ok(session_type) => match session_type.as_str() {
"x11" => Backend::X11,
"wayland" => Backend::WAYLAND,
_ => panic!("unknown XDG_SESSION_TYPE"),
},
Err(_) => panic!("could not detect session type"),
};
#[cfg(windows)]
println!("using backend: windows");
#[cfg(unix)]
println!(
"using backend: {}",
match backend {
Backend::X11 => "x11",
Backend::WAYLAND => "wayland",
}
);
// start producing and consuming events
let event_producer = thread::Builder::new()
.name("event producer".into())
.spawn(move || {
#[cfg(windows)]
windows::producer::run(produce_tx, request_server, clients);
#[cfg(unix)]
match backend {
Backend::X11 => x11::producer::run(produce_tx, request_server, clients),
Backend::WAYLAND => wayland::producer::run(produce_tx, request_server, clients),
}
})
.unwrap();
let clients = client_manager.get_clients();
let event_consumer = thread::Builder::new()
.name("event consumer".into())
.spawn(move || {
#[cfg(windows)]
windows::consumer::run(consume_rx, clients);
#[cfg(unix)]
match backend {
Backend::X11 => x11::consumer::run(consume_rx, clients),
Backend::WAYLAND => wayland::consumer::run(consume_rx, clients),
}
})
.unwrap();
let event_producer = producer::start(produce_tx, client_manager.get_clients(), request_server);
let event_consumer = consumer::start(consume_rx, client_manager.get_clients(), config.backend);
// start sending and receiving events
let event_server = event::server::Server::new(port);

52
src/producer.rs Normal file
View File

@@ -0,0 +1,52 @@
#[cfg(unix)]
use std::env;
use std::{thread::{JoinHandle, self}, sync::mpsc::SyncSender};
use crate::{client::{Client, ClientHandle}, event::Event, request::Server};
use crate::backend::producer;
enum Backend {
Wayland,
X11,
}
pub fn start(
produce_tx: SyncSender<(Event, ClientHandle)>,
clients: Vec<Client>,
request_server: Server,
) -> JoinHandle<()> {
thread::Builder::new()
.name("event producer".into())
.spawn(move || {
#[cfg(windows)]
producer::windows::run(produce_tx, request_server, clients);
#[cfg(unix)]
let backend = match env::var("XDG_SESSION_TYPE") {
Ok(session_type) => match session_type.as_str() {
"x11" => Backend::X11,
"wayland" => Backend::Wayland,
_ => panic!("unknown XDG_SESSION_TYPE"),
},
Err(_) => panic!("could not detect session type: XDG_SESSION_TYPE environment variable not set!"),
};
#[cfg(unix)]
match backend {
Backend::X11 => {
#[cfg(not(feature = "x11"))]
panic!("feature x11 not enabled");
#[cfg(feature = "x11")]
producer::x11::run(produce_tx, request_server, clients);
}
Backend::Wayland => {
#[cfg(not(feature = "wayland"))]
panic!("feature wayland not enabled");
#[cfg(feature = "wayland")]
producer::wayland::run(produce_tx, request_server, clients);
}
}
})
.unwrap()
}