diff --git a/input-capture/src/dummy.rs b/input-capture/src/dummy.rs index 8bd2f65..2296572 100644 --- a/input-capture/src/dummy.rs +++ b/input-capture/src/dummy.rs @@ -8,7 +8,7 @@ use input_event::Event; use crate::CaptureError; -use super::{CaptureHandle, InputCapture, Position}; +use super::{Capture, CaptureHandle, Position}; pub struct DummyInputCapture {} @@ -25,7 +25,7 @@ impl Default for DummyInputCapture { } #[async_trait] -impl InputCapture for DummyInputCapture { +impl Capture for DummyInputCapture { async fn create(&mut self, _handle: CaptureHandle, _pos: Position) -> Result<(), CaptureError> { Ok(()) } diff --git a/input-capture/src/lib.rs b/input-capture/src/lib.rs index 53505aa..273f6f2 100644 --- a/input-capture/src/lib.rs +++ b/input-capture/src/lib.rs @@ -1,31 +1,32 @@ -use std::fmt::Display; +use std::{collections::HashSet, fmt::Display, task::Poll}; use async_trait::async_trait; +use futures::StreamExt; use futures_core::Stream; -use input_event::Event; +use input_event::{scancode, Event, KeyboardEvent}; pub use error::{CaptureCreationError, CaptureError, InputCaptureError}; pub mod error; #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] -pub mod libei; +mod libei; #[cfg(target_os = "macos")] -pub mod macos; +mod macos; #[cfg(all(unix, feature = "wayland", not(target_os = "macos")))] -pub mod wayland; +mod wayland; #[cfg(windows)] -pub mod windows; +mod windows; #[cfg(all(unix, feature = "x11", not(target_os = "macos")))] -pub mod x11; +mod x11; /// fallback input capture (does not produce events) -pub mod dummy; +mod dummy; pub type CaptureHandle = u64; @@ -93,10 +94,79 @@ impl Display for Backend { } } +pub struct InputCapture { + capture: Box, + pressed_keys: HashSet, +} + +impl InputCapture { + /// create a new client with the given id + pub async fn create(&mut self, id: CaptureHandle, pos: Position) -> Result<(), CaptureError> { + self.capture.create(id, pos).await + } + + /// destroy the client with the given id, if it exists + pub async fn destroy(&mut self, id: CaptureHandle) -> Result<(), CaptureError> { + self.capture.destroy(id).await + } + + /// release mouse + pub async fn release(&mut self) -> Result<(), CaptureError> { + self.pressed_keys.clear(); + self.capture.release().await + } + + /// destroy the input capture + pub async fn terminate(&mut self) -> Result<(), CaptureError> { + self.capture.terminate().await + } + + /// creates a new [`InputCapture`] + pub async fn new(backend: Option) -> Result { + let capture = create(backend).await?; + Ok(Self { + capture, + pressed_keys: HashSet::new(), + }) + } + + /// check whether the given keys are pressed + pub fn keys_pressed(&self, keys: &[scancode::Linux]) -> bool { + keys.iter().all(|k| self.pressed_keys.contains(k)) + } + + fn update_pressed_keys(&mut self, key: u32, state: u8) { + if let Ok(scancode) = scancode::Linux::try_from(key) { + log::debug!("key: {key}, state: {state}, scancode: {scancode:?}"); + match state { + 1 => self.pressed_keys.insert(scancode), + _ => self.pressed_keys.remove(&scancode), + }; + } + } +} + +impl Stream for InputCapture { + type Item = Result<(CaptureHandle, Event), CaptureError>; + + fn poll_next( + mut self: std::pin::Pin<&mut Self>, + cx: &mut std::task::Context<'_>, + ) -> Poll> { + match self.capture.poll_next_unpin(cx) { + Poll::Ready(e) => { + if let Some(Ok((_, Event::Keyboard(KeyboardEvent::Key { key, state, .. })))) = e { + self.update_pressed_keys(key, state); + } + Poll::Ready(e) + } + Poll::Pending => Poll::Pending, + } + } +} + #[async_trait] -pub trait InputCapture: - Stream> + Unpin -{ +trait Capture: Stream> + Unpin { /// create a new client with the given id async fn create(&mut self, id: CaptureHandle, pos: Position) -> Result<(), CaptureError>; @@ -110,10 +180,10 @@ pub trait InputCapture: async fn terminate(&mut self) -> Result<(), CaptureError>; } -pub async fn create_backend( +async fn create_backend( backend: Backend, ) -> Result< - Box>>, + Box>>, CaptureCreationError, > { match backend { @@ -131,10 +201,10 @@ pub async fn create_backend( } } -pub async fn create( +async fn create( backend: Option, ) -> Result< - Box>>, + Box>>, CaptureCreationError, > { if let Some(backend) = backend { diff --git a/input-capture/src/libei.rs b/input-capture/src/libei.rs index f37e626..5941848 100644 --- a/input-capture/src/libei.rs +++ b/input-capture/src/libei.rs @@ -38,7 +38,7 @@ use input_event::Event; use super::{ error::{CaptureError, LibeiCaptureCreationError, ReisConvertEventStreamError}, - CaptureHandle, InputCapture as LanMouseInputCapture, Position, + Capture as LanMouseInputCapture, CaptureHandle, Position, }; /* there is a bug in xdg-remote-desktop-portal-gnome / mutter that diff --git a/input-capture/src/macos.rs b/input-capture/src/macos.rs index fb899a2..22e6eed 100644 --- a/input-capture/src/macos.rs +++ b/input-capture/src/macos.rs @@ -1,5 +1,5 @@ use crate::{ - error::MacOSInputCaptureCreationError, CaptureError, CaptureHandle, InputCapture, Position, + error::MacOSInputCaptureCreationError, Capture, CaptureError, CaptureHandle, Position, }; use async_trait::async_trait; use futures_core::Stream; @@ -24,7 +24,7 @@ impl Stream for MacOSInputCapture { } #[async_trait] -impl InputCapture for MacOSInputCapture { +impl Capture for MacOSInputCapture { async fn create(&mut self, _id: CaptureHandle, _pos: Position) -> Result<(), CaptureError> { Ok(()) } diff --git a/input-capture/src/wayland.rs b/input-capture/src/wayland.rs index a667afc..66fc1cc 100644 --- a/input-capture/src/wayland.rs +++ b/input-capture/src/wayland.rs @@ -58,15 +58,13 @@ use wayland_client::{ Connection, Dispatch, DispatchError, EventQueue, QueueHandle, WEnum, }; -use tempfile; - use input_event::{Event, KeyboardEvent, PointerEvent}; use crate::CaptureError; use super::{ error::{LayerShellCaptureCreationError, WaylandBindError}, - CaptureHandle, InputCapture, Position, + Capture, CaptureHandle, Position, }; struct Globals { @@ -561,7 +559,7 @@ impl Inner { } #[async_trait] -impl InputCapture for WaylandInputCapture { +impl Capture for WaylandInputCapture { async fn create(&mut self, handle: CaptureHandle, pos: Position) -> Result<(), CaptureError> { self.add_client(handle, pos); let inner = self.0.get_mut(); diff --git a/input-capture/src/windows.rs b/input-capture/src/windows.rs index d2edd50..15750cb 100644 --- a/input-capture/src/windows.rs +++ b/input-capture/src/windows.rs @@ -37,7 +37,7 @@ use input_event::{ Event, KeyboardEvent, PointerEvent, BTN_BACK, BTN_FORWARD, BTN_LEFT, BTN_MIDDLE, BTN_RIGHT, }; -use super::{CaptureError, CaptureHandle, InputCapture, Position}; +use super::{Capture, CaptureError, CaptureHandle, Position}; enum Request { Create(CaptureHandle, Position), @@ -64,7 +64,7 @@ unsafe fn signal_message_thread(event_type: EventType) { } #[async_trait] -impl InputCapture for WindowsInputCapture { +impl Capture for WindowsInputCapture { async fn create(&mut self, handle: CaptureHandle, pos: Position) -> Result<(), CaptureError> { unsafe { { diff --git a/input-capture/src/x11.rs b/input-capture/src/x11.rs index 1473d0f..89a1da7 100644 --- a/input-capture/src/x11.rs +++ b/input-capture/src/x11.rs @@ -5,7 +5,7 @@ use futures_core::Stream; use crate::CaptureError; -use super::InputCapture; +use super::Capture; use input_event::Event; use super::error::X11InputCaptureCreationError; @@ -20,7 +20,7 @@ impl X11InputCapture { } #[async_trait] -impl InputCapture for X11InputCapture { +impl Capture for X11InputCapture { async fn create(&mut self, _id: CaptureHandle, _pos: Position) -> Result<(), CaptureError> { Ok(()) } diff --git a/src/capture_test.rs b/src/capture_test.rs index 4eafc05..c96c2c7 100644 --- a/src/capture_test.rs +++ b/src/capture_test.rs @@ -20,7 +20,7 @@ async fn input_capture_test(config: Config) -> Result<(), InputCaptureError> { log::info!("creating input capture"); let backend = config.capture_backend.map(|b| b.into()); loop { - let mut input_capture = input_capture::create(backend).await?; + let mut input_capture = InputCapture::new(backend).await?; log::info!("creating clients"); input_capture.create(0, Position::Left).await?; input_capture.create(1, Position::Right).await?; @@ -33,7 +33,7 @@ async fn input_capture_test(config: Config) -> Result<(), InputCaptureError> { } } -async fn do_capture(input_capture: &mut Box) -> Result<(), CaptureError> { +async fn do_capture(input_capture: &mut InputCapture) -> Result<(), CaptureError> { loop { let (client, event) = input_capture .next() diff --git a/src/server/capture_task.rs b/src/server/capture_task.rs index 616016b..ec52632 100644 --- a/src/server/capture_task.rs +++ b/src/server/capture_task.rs @@ -1,5 +1,5 @@ use futures::StreamExt; -use std::{collections::HashSet, net::SocketAddr}; +use std::net::SocketAddr; use tokio::{ process::Command, @@ -9,7 +9,7 @@ use tokio::{ use input_capture::{self, CaptureError, CaptureHandle, InputCapture, InputCaptureError, Position}; -use input_event::{scancode, Event, KeyboardEvent}; +use input_event::Event; use crate::{client::ClientHandle, frontend::Status, server::State}; @@ -68,36 +68,34 @@ async fn do_capture( ) -> Result<(), InputCaptureError> { /* allow cancelling capture request */ let mut capture = tokio::select! { - r = input_capture::create(backend) => { - r? - }, + r = InputCapture::new(backend) => r?, _ = server.cancelled() => return Ok(()), }; server.set_capture_status(Status::Enabled); - // FIXME DUPLICATES - let clients = server - .client_manager - .borrow() - .get_client_states() - .map(|(h, s)| (h, s.clone())) - .collect::>(); - log::info!("{clients:?}"); - for (handle, (config, _state)) in clients { - capture.create(handle, config.pos.into()).await?; + let clients = server.active_clients(); + let clients = clients.iter().copied().map(|handle| { + ( + handle, + server + .client_manager + .borrow() + .get(handle) + .map(|(c, _)| c.pos) + .expect("no such client"), + ) + }); + for (handle, pos) in clients { + capture.create(handle, pos.into()).await?; } - let mut pressed_keys = HashSet::new(); loop { tokio::select! { - event = capture.next() => { - match event { - Some(Ok(event)) => handle_capture_event(server, &mut capture, sender_tx, event, &mut pressed_keys).await?, - Some(Err(e)) => return Err(e.into()), - None => return Ok(()), - } - } + event = capture.next() => match event { + Some(event) => handle_capture_event(server, &mut capture, sender_tx, event?).await?, + None => return Ok(()), + }, e = notify_rx.recv() => { log::debug!("input capture notify rx: {e:?}"); match e { @@ -119,38 +117,20 @@ async fn do_capture( Ok(()) } -fn update_pressed_keys(pressed_keys: &mut HashSet, key: u32, state: u8) { - if let Ok(scancode) = scancode::Linux::try_from(key) { - log::debug!("key: {key}, state: {state}, scancode: {scancode:?}"); - match state { - 1 => pressed_keys.insert(scancode), - _ => pressed_keys.remove(&scancode), - }; - } -} - async fn handle_capture_event( server: &Server, - capture: &mut Box, + capture: &mut InputCapture, sender_tx: &Sender<(Event, SocketAddr)>, event: (CaptureHandle, Event), - pressed_keys: &mut HashSet, ) -> Result<(), CaptureError> { let (handle, mut e) = event; log::trace!("({handle}) {e:?}"); - if let Event::Keyboard(KeyboardEvent::Key { key, state, .. }) = e { - update_pressed_keys(pressed_keys, key, state); - log::debug!("{pressed_keys:?}"); - if server.release_bind.iter().all(|k| pressed_keys.contains(k)) { - pressed_keys.clear(); - log::info!("releasing pointer"); - capture.release().await?; - server.state.replace(State::Receiving); - log::trace!("STATE ===> Receiving"); - // send an event to release all the modifiers - e = Event::Disconnect(); - } + // check release bind + if capture.keys_pressed(&server.release_bind) { + capture.release().await?; + server.state.replace(State::Receiving); + e = Event::Disconnect(); } let info = {