mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-12 07:40:55 +03:00
Configurable capture backend (#150)
capture backend can now be configured via the `capture_backend` cli argument / config entry
This commit is contained in:
committed by
GitHub
parent
232c048c19
commit
3528ef4fae
140
src/capture/error.rs
Normal file
140
src/capture/error.rs
Normal file
@@ -0,0 +1,140 @@
|
||||
use std::fmt::Display;
|
||||
use thiserror::Error;
|
||||
|
||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||
use std::io;
|
||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||
use wayland_client::{
|
||||
backend::WaylandError,
|
||||
globals::{BindError, GlobalError},
|
||||
ConnectError, DispatchError,
|
||||
};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum CaptureCreationError {
|
||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||
Libei(#[from] LibeiCaptureCreationError),
|
||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||
LayerShell(#[from] LayerShellCaptureCreationError),
|
||||
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
||||
X11(#[from] X11InputCaptureCreationError),
|
||||
#[cfg(target_os = "macos")]
|
||||
Macos(#[from] MacOSInputCaptureCreationError),
|
||||
#[cfg(windows)]
|
||||
Windows,
|
||||
}
|
||||
|
||||
impl Display for CaptureCreationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
let reason = match self {
|
||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||
CaptureCreationError::Libei(reason) => {
|
||||
format!("error creating portal backend: {reason}")
|
||||
}
|
||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||
CaptureCreationError::LayerShell(reason) => {
|
||||
format!("error creating layer-shell backend: {reason}")
|
||||
}
|
||||
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
||||
CaptureCreationError::X11(e) => format!("{e}"),
|
||||
#[cfg(target_os = "macos")]
|
||||
CaptureCreationError::Macos(e) => format!("{e}"),
|
||||
#[cfg(windows)]
|
||||
CaptureCreationError::Windows => String::from(""),
|
||||
};
|
||||
write!(f, "could not create input capture: {reason}")
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum LibeiCaptureCreationError {
|
||||
Ashpd(#[from] ashpd::Error),
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||
impl Display for LibeiCaptureCreationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
LibeiCaptureCreationError::Ashpd(portal_error) => write!(f, "{portal_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")))]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum LayerShellCaptureCreationError {
|
||||
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")))]
|
||||
impl Display for LayerShellCaptureCreationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match self {
|
||||
LayerShellCaptureCreationError::Bind(e) => write!(f, "{e}"),
|
||||
LayerShellCaptureCreationError::Connect(e) => {
|
||||
write!(f, "could not connect to wayland compositor: {e}")
|
||||
}
|
||||
LayerShellCaptureCreationError::Global(e) => write!(f, "wayland error: {e}"),
|
||||
LayerShellCaptureCreationError::Wayland(e) => write!(f, "wayland error: {e}"),
|
||||
LayerShellCaptureCreationError::Dispatch(e) => {
|
||||
write!(f, "error dispatching wayland events: {e}")
|
||||
}
|
||||
LayerShellCaptureCreationError::Io(e) => write!(f, "io error: {e}"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum X11InputCaptureCreationError {
|
||||
NotImplemented,
|
||||
}
|
||||
|
||||
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
||||
impl Display for X11InputCaptureCreationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "X11 input capture is not yet implemented :(")
|
||||
}
|
||||
}
|
||||
#[cfg(target_os = "macos")]
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MacOSInputCaptureCreationError {
|
||||
NotImplemented,
|
||||
}
|
||||
|
||||
#[cfg(target_os = "macos")]
|
||||
impl Display for MacOSInputCaptureCreationError {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
write!(f, "macos input capture is not yet implemented :(")
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,8 @@ use crate::{
|
||||
event::{Event, KeyboardEvent, PointerEvent},
|
||||
};
|
||||
|
||||
use super::error::LibeiCaptureCreationError;
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ProducerEvent {
|
||||
Release,
|
||||
@@ -131,7 +133,7 @@ impl<'a> Drop for LibeiInputCapture<'a> {
|
||||
|
||||
async fn create_session<'a>(
|
||||
input_capture: &'a InputCapture<'a>,
|
||||
) -> Result<(Session<'a>, BitFlags<Capabilities>)> {
|
||||
) -> std::result::Result<(Session<'a>, BitFlags<Capabilities>), ashpd::Error> {
|
||||
log::debug!("creating input capture session");
|
||||
let (session, capabilities) = loop {
|
||||
match input_capture
|
||||
@@ -213,7 +215,7 @@ async fn wait_for_active_client(
|
||||
}
|
||||
|
||||
impl<'a> LibeiInputCapture<'a> {
|
||||
pub async fn new() -> Result<Self> {
|
||||
pub async fn new() -> std::result::Result<Self, LibeiCaptureCreationError> {
|
||||
let input_capture = Box::pin(InputCapture::new().await?);
|
||||
let input_capture_ptr = input_capture.as_ref().get_ref() as *const InputCapture<'static>;
|
||||
let mut first_session = Some(create_session(unsafe { &*input_capture_ptr }).await?);
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::capture::error::MacOSInputCaptureCreationError;
|
||||
use crate::capture::InputCapture;
|
||||
use crate::client::{ClientEvent, ClientHandle};
|
||||
use crate::event::Event;
|
||||
use anyhow::{anyhow, Result};
|
||||
use futures_core::Stream;
|
||||
use std::task::{Context, Poll};
|
||||
use std::{io, pin::Pin};
|
||||
@@ -9,8 +9,8 @@ use std::{io, pin::Pin};
|
||||
pub struct MacOSInputCapture;
|
||||
|
||||
impl MacOSInputCapture {
|
||||
pub fn new() -> Result<Self> {
|
||||
Err(anyhow!("not yet implemented"))
|
||||
pub fn new() -> std::result::Result<Self, MacOSInputCaptureCreationError> {
|
||||
Err(MacOSInputCaptureCreationError::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
use crate::{
|
||||
capture::InputCapture,
|
||||
capture::{error::WaylandBindError, InputCapture},
|
||||
client::{ClientEvent, ClientHandle, Position},
|
||||
};
|
||||
|
||||
use anyhow::{anyhow, Result};
|
||||
use futures_core::Stream;
|
||||
use memmap::MmapOptions;
|
||||
use std::{
|
||||
@@ -68,6 +67,8 @@ use tempfile;
|
||||
|
||||
use crate::event::{Event, KeyboardEvent, PointerEvent};
|
||||
|
||||
use super::error::LayerShellCaptureCreationError;
|
||||
|
||||
struct Globals {
|
||||
compositor: wl_compositor::WlCompositor,
|
||||
pointer_constraints: ZwpPointerConstraintsV1,
|
||||
@@ -258,64 +259,37 @@ fn draw(f: &mut File, (width, height): (u32, u32)) {
|
||||
}
|
||||
|
||||
impl WaylandInputCapture {
|
||||
pub fn new() -> Result<Self> {
|
||||
let conn = match Connection::connect_to_env() {
|
||||
Ok(c) => c,
|
||||
Err(e) => return Err(anyhow!("could not connect to wayland compositor: {e:?}")),
|
||||
};
|
||||
|
||||
let (g, mut queue) = match registry_queue_init::<State>(&conn) {
|
||||
Ok(q) => q,
|
||||
Err(e) => return Err(anyhow!("failed to initialize wl_registry: {e:?}")),
|
||||
};
|
||||
pub fn new() -> std::result::Result<Self, LayerShellCaptureCreationError> {
|
||||
let conn = Connection::connect_to_env()?;
|
||||
let (g, mut queue) = registry_queue_init::<State>(&conn)?;
|
||||
|
||||
let qh = queue.handle();
|
||||
|
||||
let compositor: wl_compositor::WlCompositor = match g.bind(&qh, 4..=5, ()) {
|
||||
Ok(compositor) => compositor,
|
||||
Err(_) => return Err(anyhow!("wl_compositor >= v4 not supported")),
|
||||
};
|
||||
|
||||
let xdg_output_manager: ZxdgOutputManagerV1 = match g.bind(&qh, 1..=3, ()) {
|
||||
Ok(xdg_output_manager) => xdg_output_manager,
|
||||
Err(_) => return Err(anyhow!("xdg_output not supported!")),
|
||||
};
|
||||
|
||||
let shm: wl_shm::WlShm = match g.bind(&qh, 1..=1, ()) {
|
||||
Ok(wl_shm) => wl_shm,
|
||||
Err(_) => return Err(anyhow!("wl_shm v1 not supported")),
|
||||
};
|
||||
|
||||
let layer_shell: ZwlrLayerShellV1 = match g.bind(&qh, 3..=4, ()) {
|
||||
Ok(layer_shell) => layer_shell,
|
||||
Err(_) => return Err(anyhow!("zwlr_layer_shell_v1 >= v3 not supported - required to display a surface at the edge of the screen")),
|
||||
};
|
||||
|
||||
let seat: wl_seat::WlSeat = match g.bind(&qh, 7..=8, ()) {
|
||||
Ok(wl_seat) => wl_seat,
|
||||
Err(_) => return Err(anyhow!("wl_seat >= v7 not supported")),
|
||||
};
|
||||
|
||||
let pointer_constraints: ZwpPointerConstraintsV1 = match g.bind(&qh, 1..=1, ()) {
|
||||
Ok(pointer_constraints) => pointer_constraints,
|
||||
Err(_) => return Err(anyhow!("zwp_pointer_constraints_v1 not supported")),
|
||||
};
|
||||
|
||||
let relative_pointer_manager: ZwpRelativePointerManagerV1 = match g.bind(&qh, 1..=1, ()) {
|
||||
Ok(relative_pointer_manager) => relative_pointer_manager,
|
||||
Err(_) => return Err(anyhow!("zwp_relative_pointer_manager_v1 not supported")),
|
||||
};
|
||||
|
||||
let shortcut_inhibit_manager: ZwpKeyboardShortcutsInhibitManagerV1 =
|
||||
match g.bind(&qh, 1..=1, ()) {
|
||||
Ok(shortcut_inhibit_manager) => shortcut_inhibit_manager,
|
||||
Err(_) => {
|
||||
return Err(anyhow!(
|
||||
"zwp_keyboard_shortcuts_inhibit_manager_v1 not supported"
|
||||
))
|
||||
}
|
||||
};
|
||||
let compositor: wl_compositor::WlCompositor = g
|
||||
.bind(&qh, 4..=5, ())
|
||||
.map_err(|e| WaylandBindError::new(e, "wl_compositor 4..=5"))?;
|
||||
let xdg_output_manager: ZxdgOutputManagerV1 = g
|
||||
.bind(&qh, 1..=3, ())
|
||||
.map_err(|e| WaylandBindError::new(e, "xdg_output_manager 1..=3"))?;
|
||||
let shm: wl_shm::WlShm = g
|
||||
.bind(&qh, 1..=1, ())
|
||||
.map_err(|e| WaylandBindError::new(e, "wl_shm"))?;
|
||||
let layer_shell: ZwlrLayerShellV1 = g
|
||||
.bind(&qh, 3..=4, ())
|
||||
.map_err(|e| WaylandBindError::new(e, "wlr_layer_shell 3..=4"))?;
|
||||
let seat: wl_seat::WlSeat = g
|
||||
.bind(&qh, 7..=8, ())
|
||||
.map_err(|e| WaylandBindError::new(e, "wl_seat 7..=8"))?;
|
||||
|
||||
let pointer_constraints: ZwpPointerConstraintsV1 = g
|
||||
.bind(&qh, 1..=1, ())
|
||||
.map_err(|e| WaylandBindError::new(e, "zwp_pointer_constraints_v1"))?;
|
||||
let relative_pointer_manager: ZwpRelativePointerManagerV1 = g
|
||||
.bind(&qh, 1..=1, ())
|
||||
.map_err(|e| WaylandBindError::new(e, "zwp_relative_pointer_manager_v1"))?;
|
||||
let shortcut_inhibit_manager: ZwpKeyboardShortcutsInhibitManagerV1 = g
|
||||
.bind(&qh, 1..=1, ())
|
||||
.map_err(|e| WaylandBindError::new(e, "zwp_keyboard_shortcuts_inhibit_manager_v1"))?;
|
||||
let outputs = vec![];
|
||||
|
||||
let g = Globals {
|
||||
|
||||
@@ -575,7 +575,7 @@ fn update_clients(client_event: ClientEvent) {
|
||||
}
|
||||
|
||||
impl WindowsInputCapture {
|
||||
pub(crate) fn new() -> Result<Self> {
|
||||
pub(crate) fn new() -> Self {
|
||||
unsafe {
|
||||
let (tx, rx) = channel(10);
|
||||
EVENT_TX.replace(tx);
|
||||
@@ -583,10 +583,10 @@ impl WindowsInputCapture {
|
||||
let msg_thread = Some(thread::spawn(|| message_thread(ready_tx)));
|
||||
/* wait for thread to set its id */
|
||||
ready_rx.recv().expect("channel closed");
|
||||
Ok(Self {
|
||||
Self {
|
||||
msg_thread,
|
||||
event_rx: rx,
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::io;
|
||||
use std::task::Poll;
|
||||
|
||||
@@ -9,11 +8,13 @@ use crate::event::Event;
|
||||
|
||||
use crate::client::{ClientEvent, ClientHandle};
|
||||
|
||||
use super::error::X11InputCaptureCreationError;
|
||||
|
||||
pub struct X11InputCapture {}
|
||||
|
||||
impl X11InputCapture {
|
||||
pub fn new() -> Result<Self> {
|
||||
Err(anyhow!("not implemented"))
|
||||
pub fn new() -> std::result::Result<Self, X11InputCaptureCreationError> {
|
||||
Err(X11InputCaptureCreationError::NotImplemented)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user