diff --git a/src/emulate.rs b/src/emulate.rs index 2ffe7a7..368939f 100644 --- a/src/emulate.rs +++ b/src/emulate.rs @@ -2,11 +2,12 @@ use async_trait::async_trait; use std::future; use crate::{ - client::{ClientEvent, ClientHandle}, - event::Event, + client::{ClientEvent, ClientHandle}, config::EmulationBackend, event::Event }; use anyhow::Result; +use self::error::EmulationCreationError; + #[cfg(windows)] pub mod windows; @@ -42,10 +43,10 @@ pub trait InputEmulation: Send { async fn destroy(&mut self); } -pub async fn create(backend: Option) -> Box { +pub async fn create(backend: Option) -> Result, EmulationCreationError> { #[cfg(windows)] match windows::WindowsEmulation::new() { - Ok(c) => return Box::new(c), + Ok(c) => return Ok(Box::new(c)), Err(e) => log::warn!("windows input emulation unavailable: {e}"), } @@ -53,7 +54,7 @@ pub async fn create(backend: Option) -> Box { log::info!("using macos input emulation"); - return Box::new(c); + return Ok(Box::new(c)); } Err(e) => log::error!("macos input emulatino not available: {e}"), } @@ -62,7 +63,7 @@ pub async fn create(backend: Option) -> Box { log::info!("using wlroots input emulation"); - return Box::new(c); + return Ok(Box::new(c)); } Err(e) => log::info!("wayland backend not available: {e}"), } @@ -71,7 +72,7 @@ pub async fn create(backend: Option) -> Box { log::info!("using libei input emulation"); - return Box::new(c); + return Ok(Box::new(c)); } Err(e) => log::info!("libei not available: {e}"), } @@ -80,7 +81,7 @@ pub async fn create(backend: Option) -> Box { log::info!("using xdg-remote-desktop-portal input emulation"); - return Box::new(c); + return Ok(Box::new(c)); } Err(e) => log::info!("remote desktop portal not available: {e}"), } @@ -89,11 +90,11 @@ pub async fn create(backend: Option) -> Box { log::info!("using x11 input emulation"); - return Box::new(c); + return Ok(Box::new(c)); } Err(e) => log::info!("x11 input emulation not available: {e}"), } log::error!("falling back to dummy input emulation"); - Box::new(dummy::DummyEmulation::new()) + Ok(Box::new(dummy::DummyEmulation::new())) } diff --git a/src/emulate/error.rs b/src/emulate/error.rs new file mode 100644 index 0000000..03e7dba --- /dev/null +++ b/src/emulate/error.rs @@ -0,0 +1,98 @@ +use std::{fmt::Display, io}; + +use thiserror::Error; +use wayland_client::{backend::WaylandError, globals::{BindError, GlobalError}, ConnectError, DispatchError}; + + +#[derive(Debug, Error)] +pub enum EmulationCreationError { + #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] + Wlroots(#[from] WlrootsEmulationCreationError), + #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] + Libei(#[from] LibeiEmulationCreationError), + #[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))] + Xdp(#[from] XdpEmulationCreationError), + #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] + X11(#[from] X11EmulationCreationError), +} + +impl Display for EmulationCreationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let reason = match self { + EmulationCreationError::Wlroots(e) => format!("wlroots backend: {e}"), + EmulationCreationError::Libei(e) => todo!("libei backend: {e}"), + EmulationCreationError::Xdp(e) => todo!("desktop portal backend: {e}"), + EmulationCreationError::X11(e) => todo!("x11 backend: {e}"), + }; + write!(f, "could not create input emulation backend: {reason}") + } +} + +#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] +#[derive(Debug, Error)] +pub enum WlrootsEmulationCreationError { + Connect(#[from] ConnectError), + Global(#[from] GlobalError), + Wayland(#[from] WaylandError), + Bind(#[from] WaylandBindError), + Dispatch(#[from] DispatchError), + Io(#[from] io::Error), +} + +#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] +#[derive(Debug, Error)] +pub struct WaylandBindError { + inner: BindError, + protocol: &'static str, +} +#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] +impl WaylandBindError { + pub(crate) fn new(inner: BindError, protocol: &'static str) -> Self { + Self { inner, protocol } + } +} + + +#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] +impl Display for WaylandBindError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!( + f, + "{} protocol not supported: {}", + self.protocol, self.inner + ) + } +} + +#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] +impl Display for WlrootsEmulationCreationError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + WlrootsEmulationCreationError::Bind(e) => write!(f, "{e}"), + WlrootsEmulationCreationError::Connect(e) => { + write!(f, "could not connect to wayland compositor: {e}") + } + WlrootsEmulationCreationError::Global(e) => write!(f, "wayland error: {e}"), + WlrootsEmulationCreationError::Wayland(e) => write!(f, "wayland error: {e}"), + WlrootsEmulationCreationError::Dispatch(e) => { + write!(f, "error dispatching wayland events: {e}") + } + WlrootsEmulationCreationError::Io(e) => write!(f, "io error: {e}"), + } + } +} + +#[cfg(all(unix, feature = "libei", not(target_os = "macos")))] +#[derive(Debug, Error)] +pub enum LibeiEmulationCreationError {} + + +#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))] +#[derive(Debug, Error)] +pub enum XdpEmulationCreationError {} + + + +#[cfg(all(unix, feature = "x11", not(target_os = "macos")))] +#[derive(Debug, Error)] +pub enum X11EmulationCreationError {} diff --git a/src/emulate/libei.rs b/src/emulate/libei.rs index 226cd0e..1ee7645 100644 --- a/src/emulate/libei.rs +++ b/src/emulate/libei.rs @@ -1,3 +1,4 @@ +use anyhow::{anyhow, Result}; use std::{ collections::HashMap, os::{fd::OwnedFd, unix::net::UnixStream}, diff --git a/src/emulation_test.rs b/src/emulation_test.rs index 3104328..f5fde9a 100644 --- a/src/emulation_test.rs +++ b/src/emulation_test.rs @@ -1,4 +1,5 @@ use crate::client::{ClientEvent, Position}; +use crate::config::Config; use crate::emulate; use crate::event::{Event, PointerEvent}; use anyhow::Result; @@ -13,14 +14,16 @@ pub fn run() -> Result<()> { .enable_time() .build()?; - runtime.block_on(LocalSet::new().run_until(input_emulation_test())) + let config = Config::new()?; + + runtime.block_on(LocalSet::new().run_until(input_emulation_test(config))) } const FREQUENCY_HZ: f64 = 1.0; const RADIUS: f64 = 100.0; -async fn input_emulation_test() -> Result<()> { - let mut emulation = emulate::create().await; +async fn input_emulation_test(config: Config) -> Result<()> { + let mut emulation = emulate::create(config.emulation_backend).await?; emulation .notify(ClientEvent::Create(0, Position::Left)) .await; diff --git a/src/server/emulation_task.rs b/src/server/emulation_task.rs index 7e3f21a..3055b9c 100644 --- a/src/server/emulation_task.rs +++ b/src/server/emulation_task.rs @@ -72,7 +72,7 @@ pub fn new( emulate.destroy().await; anyhow::Ok(()) }); - (emulate_task, tx) + Ok((emulate_task, tx)) } async fn handle_udp_rx(