From e9de3671a8e6122c9765b9f0e252841bf802c832 Mon Sep 17 00:00:00 2001 From: Ferdinand Schober Date: Tue, 6 Aug 2024 15:48:33 +0200 Subject: [PATCH] move refcounting of key presses to input-emulation extract proto into its own crate asdf asdf asdf --- Cargo.lock | 17 ++ Cargo.toml | 3 +- input-capture/src/dummy.rs | 8 +- input-capture/src/lib.rs | 31 ++- input-capture/src/libei.rs | 18 +- input-capture/src/wayland.rs | 36 +-- input-capture/src/x11.rs | 13 +- input-emulation/src/lib.rs | 6 +- input-emulation/src/libei.rs | 2 - input-emulation/src/wlroots.rs | 8 +- input-emulation/src/x11.rs | 1 - input-emulation/src/xdg_desktop_portal.rs | 2 - input-event/src/error.rs | 16 -- input-event/src/lib.rs | 39 +-- input-event/src/libei.rs | 6 +- input-event/src/proto.rs | 307 ---------------------- lan-mouse-proto/Cargo.toml | 13 + lan-mouse-proto/src/lib.rs | 248 +++++++++++++++++ src/capture_test.rs | 4 +- src/server.rs | 11 +- src/server/capture_task.rs | 36 ++- src/server/emulation_task.rs | 107 +++----- src/server/network_task.rs | 26 +- src/server/ping_task.rs | 9 +- 24 files changed, 437 insertions(+), 530 deletions(-) delete mode 100644 input-event/src/proto.rs create mode 100644 lan-mouse-proto/Cargo.toml create mode 100644 lan-mouse-proto/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 328e2e22..1f0a67ad 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1321,6 +1321,7 @@ dependencies = [ "input-capture", "input-emulation", "input-event", + "lan-mouse-proto", "libadwaita", "libc", "log", @@ -1333,6 +1334,16 @@ dependencies = [ "toml", ] +[[package]] +name = "lan-mouse-proto" +version = "0.1.0" +dependencies = [ + "input-event", + "num_enum", + "paste", + "thiserror", +] + [[package]] name = "libadwaita" version = "0.7.0" @@ -1596,6 +1607,12 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + [[package]] name = "percent-encoding" version = "2.3.1" diff --git a/Cargo.toml b/Cargo.toml index 4e527fea..efde54f5 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,5 +1,5 @@ [workspace] -members = ["input-capture", "input-emulation", "input-event"] +members = ["input-capture", "input-emulation", "input-event", "lan-mouse-proto"] [package] name = "lan-mouse" @@ -17,6 +17,7 @@ lto = "fat" input-event = { path = "input-event", version = "0.2.1" } input-emulation = { path = "input-emulation", version = "0.2.1", default-features = false } input-capture = { path = "input-capture", version = "0.2.0", default-features = false } +lan-mouse-proto = { path = "lan-mouse-proto", version = "0.1.0" } hickory-resolver = "0.24.1" toml = "0.8" diff --git a/input-capture/src/dummy.rs b/input-capture/src/dummy.rs index 22965723..54b0c1ae 100644 --- a/input-capture/src/dummy.rs +++ b/input-capture/src/dummy.rs @@ -4,11 +4,7 @@ use std::task::{Context, Poll}; use async_trait::async_trait; use futures_core::Stream; -use input_event::Event; - -use crate::CaptureError; - -use super::{Capture, CaptureHandle, Position}; +use super::{Capture, CaptureError, CaptureEvent, CaptureHandle, Position}; pub struct DummyInputCapture {} @@ -44,7 +40,7 @@ impl Capture for DummyInputCapture { } impl Stream for DummyInputCapture { - type Item = Result<(CaptureHandle, Event), CaptureError>; + type Item = Result<(CaptureHandle, CaptureEvent), CaptureError>; fn poll_next(self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll> { Poll::Pending diff --git a/input-capture/src/lib.rs b/input-capture/src/lib.rs index 273f6f28..49838384 100644 --- a/input-capture/src/lib.rs +++ b/input-capture/src/lib.rs @@ -30,6 +30,23 @@ mod dummy; pub type CaptureHandle = u64; +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum CaptureEvent { + /// capture on this capture handle is now active + Begin, + /// input event coming from capture handle + Input(Event), +} + +impl Display for CaptureEvent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + CaptureEvent::Begin => write!(f, "begin capture"), + CaptureEvent::Input(e) => write!(f, "{e}"), + } + } +} + #[derive(Debug, Clone, Copy, Eq, Hash, PartialEq)] pub enum Position { Left, @@ -147,7 +164,7 @@ impl InputCapture { } impl Stream for InputCapture { - type Item = Result<(CaptureHandle, Event), CaptureError>; + type Item = Result<(CaptureHandle, CaptureEvent), CaptureError>; fn poll_next( mut self: std::pin::Pin<&mut Self>, @@ -155,7 +172,11 @@ impl Stream for InputCapture { ) -> Poll> { match self.capture.poll_next_unpin(cx) { Poll::Ready(e) => { - if let Some(Ok((_, Event::Keyboard(KeyboardEvent::Key { key, state, .. })))) = e { + if let Some(Ok(( + _, + CaptureEvent::Input(Event::Keyboard(KeyboardEvent::Key { key, state, .. })), + ))) = e + { self.update_pressed_keys(key, state); } Poll::Ready(e) @@ -166,7 +187,7 @@ impl Stream for InputCapture { } #[async_trait] -trait Capture: 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>; @@ -183,7 +204,7 @@ trait Capture: Stream> + Unp async fn create_backend( backend: Backend, ) -> Result< - Box>>, + Box>>, CaptureCreationError, > { match backend { @@ -204,7 +225,7 @@ async fn create_backend( 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 5941848c..b169ee4d 100644 --- a/input-capture/src/libei.rs +++ b/input-capture/src/libei.rs @@ -36,6 +36,8 @@ use once_cell::sync::Lazy; use input_event::Event; +use crate::CaptureEvent; + use super::{ error::{CaptureError, LibeiCaptureCreationError, ReisConvertEventStreamError}, Capture as LanMouseInputCapture, CaptureHandle, Position, @@ -56,7 +58,7 @@ enum LibeiNotifyEvent { pub struct LibeiInputCapture<'a> { input_capture: Pin>>, capture_task: JoinHandle>, - event_rx: Receiver<(CaptureHandle, Event)>, + event_rx: Receiver<(CaptureHandle, CaptureEvent)>, notify_capture: Sender, notify_release: Arc, cancellation_token: CancellationToken, @@ -201,7 +203,7 @@ async fn connect_to_eis( async fn libei_event_handler( mut ei_event_stream: EiConvertEventStream, context: ei::Context, - event_tx: Sender<(CaptureHandle, Event)>, + event_tx: Sender<(CaptureHandle, CaptureEvent)>, release_session: Arc, current_client: Rc>>, ) -> Result<(), CaptureError> { @@ -258,7 +260,7 @@ async fn do_capture( mut capture_event: Receiver, notify_release: Arc, session: Option<(Session<'_, InputCapture<'_>>, BitFlags)>, - event_tx: Sender<(CaptureHandle, Event)>, + event_tx: Sender<(CaptureHandle, CaptureEvent)>, cancellation_token: CancellationToken, ) -> Result<(), CaptureError> { let mut session = session.map(|s| s.0); @@ -354,7 +356,7 @@ async fn do_capture( async fn do_capture_session( input_capture: &InputCapture<'_>, session: &mut Session<'_, InputCapture<'_>>, - event_tx: &Sender<(CaptureHandle, Event)>, + event_tx: &Sender<(CaptureHandle, CaptureEvent)>, active_clients: &[(CaptureHandle, Position)], next_barrier_id: &mut u32, notify_release: &Notify, @@ -423,7 +425,7 @@ async fn do_capture_session( current_client.replace(Some(client)); // client entered => send event - event_tx.send((client, Event::Enter())).await.expect("no channel"); + event_tx.send((client, CaptureEvent::Begin)).await.expect("no channel"); tokio::select! { _ = notify_release.notified() => { /* capture release */ @@ -554,7 +556,7 @@ async fn handle_ei_event( ei_event: EiEvent, current_client: Option, context: &ei::Context, - event_tx: &Sender<(CaptureHandle, Event)>, + event_tx: &Sender<(CaptureHandle, CaptureEvent)>, release_session: &Notify, ) -> Result<(), CaptureError> { match ei_event { @@ -575,7 +577,7 @@ async fn handle_ei_event( _ => { if let Some(handle) = current_client { for event in Event::from_ei_event(ei_event) { - event_tx.send((handle, event)).await.expect("no channel"); + event_tx.send((handle, CaptureEvent::Input(event))).await.expect("no channel"); } } } @@ -627,7 +629,7 @@ impl<'a> Drop for LibeiInputCapture<'a> { } impl<'a> Stream for LibeiInputCapture<'a> { - type Item = Result<(CaptureHandle, Event), CaptureError>; + type Item = Result<(CaptureHandle, CaptureEvent), CaptureError>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { match self.capture_task.poll_unpin(cx) { diff --git a/input-capture/src/wayland.rs b/input-capture/src/wayland.rs index 66fc1cc4..2975e357 100644 --- a/input-capture/src/wayland.rs +++ b/input-capture/src/wayland.rs @@ -60,7 +60,7 @@ use wayland_client::{ use input_event::{Event, KeyboardEvent, PointerEvent}; -use crate::CaptureError; +use crate::{CaptureError, CaptureEvent}; use super::{ error::{LayerShellCaptureCreationError, WaylandBindError}, @@ -108,7 +108,7 @@ struct State { wayland_fd: RawFd, read_guard: Option, qh: QueueHandle, - pending_events: VecDeque<(CaptureHandle, Event)>, + pending_events: VecDeque<(CaptureHandle, CaptureEvent)>, output_info: Vec<(WlOutput, OutputInfo)>, scroll_discrete_pending: bool, } @@ -585,7 +585,7 @@ impl Capture for WaylandInputCapture { } impl Stream for WaylandInputCapture { - type Item = Result<(CaptureHandle, Event), CaptureError>; + type Item = Result<(CaptureHandle, CaptureEvent), CaptureError>; fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll> { if let Some(event) = self.0.get_mut().state.pending_events.pop_front() { @@ -694,7 +694,7 @@ impl Dispatch for State { .iter() .find(|(w, _c)| w.surface == surface) .unwrap(); - app.pending_events.push_back((*client, Event::Enter())); + app.pending_events.push_back((*client, CaptureEvent::Begin)); } wl_pointer::Event::Leave { .. } => { /* There are rare cases, where when a window is opened in @@ -718,11 +718,11 @@ impl Dispatch for State { let (_, client) = app.focused.as_ref().unwrap(); app.pending_events.push_back(( *client, - Event::Pointer(PointerEvent::Button { + CaptureEvent::Input(Event::Pointer(PointerEvent::Button { time, button, state: u32::from(state), - }), + })), )); } wl_pointer::Event::Axis { time, axis, value } => { @@ -735,11 +735,11 @@ impl Dispatch for State { } else { app.pending_events.push_back(( *client, - Event::Pointer(PointerEvent::Axis { + CaptureEvent::Input(Event::Pointer(PointerEvent::Axis { time, axis: u32::from(axis) as u8, value, - }), + })), )); } } @@ -748,10 +748,10 @@ impl Dispatch for State { app.scroll_discrete_pending = true; app.pending_events.push_back(( *client, - Event::Pointer(PointerEvent::AxisDiscrete120 { + CaptureEvent::Input(Event::Pointer(PointerEvent::AxisDiscrete120 { axis: u32::from(axis) as u8, value: value120, - }), + })), )); } wl_pointer::Event::Frame {} => { @@ -787,11 +787,11 @@ impl Dispatch for State { if let Some(client) = client { app.pending_events.push_back(( *client, - Event::Keyboard(KeyboardEvent::Key { + CaptureEvent::Input(Event::Keyboard(KeyboardEvent::Key { time, key, state: u32::from(state) as u8, - }), + })), )); } } @@ -805,12 +805,12 @@ impl Dispatch for State { if let Some(client) = client { app.pending_events.push_back(( *client, - Event::Keyboard(KeyboardEvent::Modifiers { - mods_depressed, - mods_latched, - mods_locked, + CaptureEvent::Input(Event::Keyboard(KeyboardEvent::Modifiers { + depressed: mods_depressed, + latched: mods_latched, + locked: mods_locked, group, - }), + })), )); } } @@ -840,7 +840,7 @@ impl Dispatch for State { let time = (((utime_hi as u64) << 32 | utime_lo as u64) / 1000) as u32; app.pending_events.push_back(( *client, - Event::Pointer(PointerEvent::Motion { time, dx, dy }), + CaptureEvent::Input(Event::Pointer(PointerEvent::Motion { time, dx, dy })), )); } } diff --git a/input-capture/src/x11.rs b/input-capture/src/x11.rs index 89a1da76..8bcff94b 100644 --- a/input-capture/src/x11.rs +++ b/input-capture/src/x11.rs @@ -3,13 +3,10 @@ use std::task::Poll; use async_trait::async_trait; use futures_core::Stream; -use crate::CaptureError; - -use super::Capture; -use input_event::Event; - -use super::error::X11InputCaptureCreationError; -use super::{CaptureHandle, Position}; +use super::{ + error::X11InputCaptureCreationError, Capture, CaptureError, CaptureEvent, CaptureHandle, + Position, +}; pub struct X11InputCapture {} @@ -39,7 +36,7 @@ impl Capture for X11InputCapture { } impl Stream for X11InputCapture { - type Item = Result<(CaptureHandle, Event), CaptureError>; + type Item = Result<(CaptureHandle, CaptureEvent), CaptureError>; fn poll_next( self: std::pin::Pin<&mut Self>, diff --git a/input-emulation/src/lib.rs b/input-emulation/src/lib.rs index 68b26add..81699ab9 100644 --- a/input-emulation/src/lib.rs +++ b/input-emulation/src/lib.rs @@ -195,9 +195,9 @@ impl InputEmulation { } let event = Event::Keyboard(KeyboardEvent::Modifiers { - mods_depressed: 0, - mods_latched: 0, - mods_locked: 0, + depressed: 0, + latched: 0, + locked: 0, group: 0, }); self.emulation.consume(event, handle).await?; diff --git a/input-emulation/src/libei.rs b/input-emulation/src/libei.rs index f1f4a2da..4967c83a 100644 --- a/input-emulation/src/libei.rs +++ b/input-emulation/src/libei.rs @@ -213,7 +213,6 @@ impl<'a> Emulation for LibeiEmulation<'a> { d.frame(self.serial.load(Ordering::SeqCst), now); } } - PointerEvent::Frame {} => {} }, Event::Keyboard(k) => match k { KeyboardEvent::Key { @@ -235,7 +234,6 @@ impl<'a> Emulation for LibeiEmulation<'a> { } KeyboardEvent::Modifiers { .. } => {} }, - _ => {} } self.context .flush() diff --git a/input-emulation/src/wlroots.rs b/input-emulation/src/wlroots.rs index f840e3c4..6049c1d0 100644 --- a/input-emulation/src/wlroots.rs +++ b/input-emulation/src/wlroots.rs @@ -200,7 +200,6 @@ impl VirtualInput { .axis_discrete(0, axis, value as f64 / 6., value / 120); self.pointer.frame(); } - PointerEvent::Frame {} => self.pointer.frame(), } self.pointer.frame(); } @@ -209,16 +208,15 @@ impl VirtualInput { self.keyboard.key(time, key, state as u32); } KeyboardEvent::Modifiers { - mods_depressed, - mods_latched, - mods_locked, + depressed: mods_depressed, + latched: mods_latched, + locked: mods_locked, group, } => { self.keyboard .modifiers(mods_depressed, mods_latched, mods_locked, group); } }, - _ => {} } Ok(()) } diff --git a/input-emulation/src/x11.rs b/input-emulation/src/x11.rs index 7825e820..b7e1c739 100644 --- a/input-emulation/src/x11.rs +++ b/input-emulation/src/x11.rs @@ -123,7 +123,6 @@ impl Emulation for X11Emulation { PointerEvent::AxisDiscrete120 { axis, value } => { self.emulate_scroll(axis, value as f64); } - PointerEvent::Frame {} => {} }, Event::Keyboard(KeyboardEvent::Key { time: _, diff --git a/input-emulation/src/xdg_desktop_portal.rs b/input-emulation/src/xdg_desktop_portal.rs index 97c4c165..24b547e9 100644 --- a/input-emulation/src/xdg_desktop_portal.rs +++ b/input-emulation/src/xdg_desktop_portal.rs @@ -108,7 +108,6 @@ impl<'a> Emulation for DesktopPortalEmulation<'a> { .notify_pointer_axis(&self.session, dx, dy, true) .await?; } - PointerEvent::Frame {} => {} }, Keyboard(k) => { match k { @@ -130,7 +129,6 @@ impl<'a> Emulation for DesktopPortalEmulation<'a> { } } } - _ => {} } Ok(()) } diff --git a/input-event/src/error.rs b/input-event/src/error.rs index 8700adf2..8b137891 100644 --- a/input-event/src/error.rs +++ b/input-event/src/error.rs @@ -1,17 +1 @@ -use std::array::TryFromSliceError; -use thiserror::Error; - -#[derive(Debug, Error)] -pub enum ProtocolError { - #[error(transparent)] - MissingData(#[from] TryFromSliceError), - #[error("invalid event id: `{0}`")] - InvalidEventId(u8), - #[error("invalid pointer event type: `{0}`")] - InvalidPointerEventId(u8), - #[error("invalid keyboard event type: `{0}`")] - InvalidKeyboardEventId(u8), - #[error("expected data at idx `{0:?}`")] - Data(String), -} diff --git a/input-event/src/lib.rs b/input-event/src/lib.rs index c5c5bf6e..713c8409 100644 --- a/input-event/src/lib.rs +++ b/input-event/src/lib.rs @@ -1,8 +1,6 @@ -pub use error::ProtocolError; use std::fmt::{self, Display}; pub mod error; -pub mod proto; pub mod scancode; #[cfg(all(unix, feature = "libei", not(target_os = "macos")))] @@ -25,8 +23,6 @@ pub enum PointerEvent { Axis { time: u32, axis: u8, value: f64 }, /// discrete axis event, scroll event for mice - 120 = one scroll tick AxisDiscrete120 { axis: u8, value: i32 }, - /// frame event - Frame {}, } #[derive(Debug, PartialEq, Clone, Copy)] @@ -35,9 +31,9 @@ pub enum KeyboardEvent { Key { time: u32, key: u32, state: u8 }, /// modifiers changed state Modifiers { - mods_depressed: u32, - mods_latched: u32, - mods_locked: u32, + depressed: u32, + latched: u32, + locked: u32, group: u32, }, } @@ -48,23 +44,6 @@ pub enum Event { Pointer(PointerEvent), /// keyboard events (key / modifiers) Keyboard(KeyboardEvent), - /// enter event: request to enter a client. - /// The client must release the pointer if it is grabbed - /// and reply with a leave event, as soon as its ready to - /// receive events - Enter(), - /// leave event: this client is now ready to receive events and will - /// not send any events after until it sends an enter event - Leave(), - /// ping a client, to see if it is still alive. A client that does - /// not respond with a pong event will be assumed to be offline. - Ping(), - /// response to a ping event: this event signals that a client - /// is still alive but must otherwise be ignored - Pong(), - /// explicit disconnect request. The client will no longer - /// send events until the next Enter event. All of its keys should be released. - Disconnect(), } impl Display for PointerEvent { @@ -98,7 +77,6 @@ impl Display for PointerEvent { PointerEvent::AxisDiscrete120 { axis, value } => { write!(f, "scroll-120 ({axis}, {value})") } - PointerEvent::Frame {} => write!(f, "frame()"), } } } @@ -119,9 +97,9 @@ impl Display for KeyboardEvent { } } KeyboardEvent::Modifiers { - mods_depressed, - mods_latched, - mods_locked, + depressed: mods_depressed, + latched: mods_latched, + locked: mods_locked, group, } => write!( f, @@ -136,11 +114,6 @@ impl Display for Event { match self { Event::Pointer(p) => write!(f, "{}", p), Event::Keyboard(k) => write!(f, "{}", k), - Event::Enter() => write!(f, "enter"), - Event::Leave() => write!(f, "leave"), - Event::Ping() => write!(f, "ping"), - Event::Pong() => write!(f, "pong"), - Event::Disconnect() => write!(f, "disconnect"), } } } diff --git a/input-event/src/libei.rs b/input-event/src/libei.rs index 51e63687..f7904898 100644 --- a/input-event/src/libei.rs +++ b/input-event/src/libei.rs @@ -57,9 +57,9 @@ fn to_input_events(ei_event: EiEvent) -> Events { match ei_event { EiEvent::KeyboardModifiers(mods) => { let modifier_event = KeyboardEvent::Modifiers { - mods_depressed: mods.depressed, - mods_latched: mods.latched, - mods_locked: mods.locked, + depressed: mods.depressed, + latched: mods.latched, + locked: mods.locked, group: mods.group, }; Events::One(Event::Keyboard(modifier_event)) diff --git a/input-event/src/proto.rs b/input-event/src/proto.rs deleted file mode 100644 index 73975692..00000000 --- a/input-event/src/proto.rs +++ /dev/null @@ -1,307 +0,0 @@ -use std::{fmt::Debug, slice::SliceIndex}; - -use crate::ProtocolError; - -use super::{Event, KeyboardEvent, PointerEvent}; - -enum PointerEventType { - Motion, - Button, - Axis, - AxisDiscrete120, - Frame, -} - -enum KeyboardEventType { - Key, - Modifiers, -} - -enum EventType { - Pointer, - Keyboard, - Enter, - Leave, - Ping, - Pong, - Disconnect, -} - -impl Event { - fn event_type(&self) -> EventType { - match self { - Self::Pointer(_) => EventType::Pointer, - Self::Keyboard(_) => EventType::Keyboard, - Self::Enter() => EventType::Enter, - Self::Leave() => EventType::Leave, - Self::Ping() => EventType::Ping, - Self::Pong() => EventType::Pong, - Self::Disconnect() => EventType::Disconnect, - } - } -} - -impl PointerEvent { - fn event_type(&self) -> PointerEventType { - match self { - Self::Motion { .. } => PointerEventType::Motion, - Self::Button { .. } => PointerEventType::Button, - Self::Axis { .. } => PointerEventType::Axis, - Self::AxisDiscrete120 { .. } => PointerEventType::AxisDiscrete120, - Self::Frame { .. } => PointerEventType::Frame, - } - } -} - -impl KeyboardEvent { - fn event_type(&self) -> KeyboardEventType { - match self { - KeyboardEvent::Key { .. } => KeyboardEventType::Key, - KeyboardEvent::Modifiers { .. } => KeyboardEventType::Modifiers, - } - } -} - -impl TryFrom for PointerEventType { - type Error = ProtocolError; - - fn try_from(value: u8) -> Result { - match value { - x if x == Self::Motion as u8 => Ok(Self::Motion), - x if x == Self::Button as u8 => Ok(Self::Button), - x if x == Self::Axis as u8 => Ok(Self::Axis), - x if x == Self::AxisDiscrete120 as u8 => Ok(Self::AxisDiscrete120), - x if x == Self::Frame as u8 => Ok(Self::Frame), - _ => Err(ProtocolError::InvalidPointerEventId(value)), - } - } -} - -impl TryFrom for KeyboardEventType { - type Error = ProtocolError; - - fn try_from(value: u8) -> Result { - match value { - x if x == Self::Key as u8 => Ok(Self::Key), - x if x == Self::Modifiers as u8 => Ok(Self::Modifiers), - _ => Err(ProtocolError::InvalidKeyboardEventId(value)), - } - } -} - -impl From<&Event> for Vec { - fn from(event: &Event) -> Self { - let event_id = vec![event.event_type() as u8]; - let event_data = match event { - Event::Pointer(p) => p.into(), - Event::Keyboard(k) => k.into(), - Event::Enter() => vec![], - Event::Leave() => vec![], - Event::Ping() => vec![], - Event::Pong() => vec![], - Event::Disconnect() => vec![], - }; - [event_id, event_data].concat() - } -} - -impl TryFrom> for Event { - type Error = ProtocolError; - - fn try_from(value: Vec) -> Result { - let event_id = u8::from_be_bytes(value[..1].try_into()?); - match event_id { - i if i == (EventType::Pointer as u8) => Ok(Event::Pointer(value.try_into()?)), - i if i == (EventType::Keyboard as u8) => Ok(Event::Keyboard(value.try_into()?)), - i if i == (EventType::Enter as u8) => Ok(Event::Enter()), - i if i == (EventType::Leave as u8) => Ok(Event::Leave()), - i if i == (EventType::Ping as u8) => Ok(Event::Ping()), - i if i == (EventType::Pong as u8) => Ok(Event::Pong()), - i if i == (EventType::Disconnect as u8) => Ok(Event::Disconnect()), - _ => Err(ProtocolError::InvalidEventId(event_id)), - } - } -} - -impl From<&PointerEvent> for Vec { - fn from(event: &PointerEvent) -> Self { - let id = vec![event.event_type() as u8]; - let data = match event { - PointerEvent::Motion { time, dx, dy } => { - let time = time.to_be_bytes(); - let dx = dx.to_be_bytes(); - let dy = dy.to_be_bytes(); - [&time[..], &dx[..], &dy[..]].concat() - } - PointerEvent::Button { - time, - button, - state, - } => { - let time = time.to_be_bytes(); - let button = button.to_be_bytes(); - let state = state.to_be_bytes(); - [&time[..], &button[..], &state[..]].concat() - } - PointerEvent::Axis { time, axis, value } => { - let time = time.to_be_bytes(); - let axis = axis.to_be_bytes(); - let value = value.to_be_bytes(); - [&time[..], &axis[..], &value[..]].concat() - } - PointerEvent::AxisDiscrete120 { axis, value } => { - let axis = axis.to_be_bytes(); - let value = value.to_be_bytes(); - [&axis[..], &value[..]].concat() - } - PointerEvent::Frame {} => { - vec![] - } - }; - [id, data].concat() - } -} - -fn decode_u8(data: &[u8], idx: I) -> Result -where - I: SliceIndex<[u8], Output = [u8]> + Debug + Clone, -{ - let data = data - .get(idx.clone()) - .ok_or(ProtocolError::Data(format!("{:?}", idx)))?; - Ok(u8::from_be_bytes(data.try_into()?)) -} - -fn decode_u32(data: &[u8], idx: I) -> Result -where - I: SliceIndex<[u8], Output = [u8]> + Debug + Clone, -{ - let data = data - .get(idx.clone()) - .ok_or(ProtocolError::Data(format!("{:?}", idx)))?; - Ok(u32::from_be_bytes(data.try_into()?)) -} - -fn decode_i32(data: &[u8], idx: I) -> Result -where - I: SliceIndex<[u8], Output = [u8]> + Debug + Clone, -{ - let data = data - .get(idx.clone()) - .ok_or(ProtocolError::Data(format!("{:?}", idx)))?; - Ok(i32::from_be_bytes(data.try_into()?)) -} -fn decode_f64(data: &[u8], idx: I) -> Result -where - I: SliceIndex<[u8], Output = [u8]> + Debug + Clone, -{ - let data = data - .get(idx.clone()) - .ok_or(ProtocolError::Data(format!("{:?}", idx)))?; - Ok(f64::from_be_bytes(data.try_into()?)) -} - -impl TryFrom> for PointerEvent { - type Error = ProtocolError; - - fn try_from(data: Vec) -> Result { - match data.get(1) { - Some(id) => match id.to_owned().try_into()? { - PointerEventType::Motion => { - let time = decode_u32(&data, 2..6)?; - let dx = decode_f64(&data, 6..14)?; - let dy = decode_f64(&data, 14..22)?; - - Ok(Self::Motion { time, dx, dy }) - } - PointerEventType::Button => { - let time = decode_u32(&data, 2..6)?; - let button = decode_u32(&data, 6..10)?; - let state = decode_u32(&data, 10..14)?; - - Ok(Self::Button { - time, - button, - state, - }) - } - PointerEventType::Axis => { - let time = decode_u32(&data, 2..6)?; - let axis = decode_u8(&data, 6..7)?; - let value = decode_f64(&data, 7..15)?; - Ok(Self::Axis { time, axis, value }) - } - PointerEventType::AxisDiscrete120 => { - let axis = decode_u8(&data, 2..3)?; - let value = decode_i32(&data, 3..7)?; - Ok(Self::AxisDiscrete120 { axis, value }) - } - PointerEventType::Frame => Ok(Self::Frame {}), - }, - None => Err(ProtocolError::Data("0".to_string())), - } - } -} - -impl From<&KeyboardEvent> for Vec { - fn from(event: &KeyboardEvent) -> Self { - let id = vec![event.event_type() as u8]; - let data = match event { - KeyboardEvent::Key { time, key, state } => { - let time = time.to_be_bytes(); - let key = key.to_be_bytes(); - let state = state.to_be_bytes(); - [&time[..], &key[..], &state[..]].concat() - } - KeyboardEvent::Modifiers { - mods_depressed, - mods_latched, - mods_locked, - group, - } => { - let mods_depressed = mods_depressed.to_be_bytes(); - let mods_latched = mods_latched.to_be_bytes(); - let mods_locked = mods_locked.to_be_bytes(); - let group = group.to_be_bytes(); - [ - &mods_depressed[..], - &mods_latched[..], - &mods_locked[..], - &group[..], - ] - .concat() - } - }; - [id, data].concat() - } -} - -impl TryFrom> for KeyboardEvent { - type Error = ProtocolError; - - fn try_from(data: Vec) -> Result { - match data.get(1) { - Some(id) => match id.to_owned().try_into()? { - KeyboardEventType::Key => { - let time = decode_u32(&data, 2..6)?; - let key = decode_u32(&data, 6..10)?; - let state = decode_u8(&data, 10..11)?; - Ok(KeyboardEvent::Key { time, key, state }) - } - KeyboardEventType::Modifiers => { - let mods_depressed = decode_u32(&data, 2..6)?; - let mods_latched = decode_u32(&data, 6..10)?; - let mods_locked = decode_u32(&data, 10..14)?; - let group = decode_u32(&data, 14..18)?; - Ok(KeyboardEvent::Modifiers { - mods_depressed, - mods_latched, - mods_locked, - group, - }) - } - }, - None => Err(ProtocolError::Data("0".to_string())), - } - } -} diff --git a/lan-mouse-proto/Cargo.toml b/lan-mouse-proto/Cargo.toml new file mode 100644 index 00000000..00e2f561 --- /dev/null +++ b/lan-mouse-proto/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "lan-mouse-proto" +description = "network protocol for lan-mouse" +version = "0.1.0" +edition = "2021" +license = "GPL-3.0-or-later" +repository = "https://github.com/feschber/lan-mouse" + +[dependencies] +num_enum = "0.7.2" +thiserror = "1.0.61" +input-event = { path = "../input-event", version = "0.2.1" } +paste = "1.0" diff --git a/lan-mouse-proto/src/lib.rs b/lan-mouse-proto/src/lib.rs new file mode 100644 index 00000000..f6f265ed --- /dev/null +++ b/lan-mouse-proto/src/lib.rs @@ -0,0 +1,248 @@ +use input_event::{Event as InputEvent, KeyboardEvent, PointerEvent}; +use num_enum::{IntoPrimitive, TryFromPrimitive, TryFromPrimitiveError}; +use paste::paste; +use std::fmt::{Debug, Display}; +use thiserror::Error; + +/// defines the maximum size an encoded event can take up +/// this is currently the pointer motion event +/// type: u8, time: u32, dx: f64, dy: f64 +pub const MAX_EVENT_SIZE: usize = size_of::() + size_of::() + 2 * size_of::(); + +/// error type for protocol violations +#[derive(Debug, Error)] +pub enum ProtocolError { + /// event type does not exist + #[error("invalid event id: `{0}`")] + InvalidEventId(#[from] TryFromPrimitiveError), +} + +/// main lan-mouse protocol event type +#[derive(Clone, Copy, Debug)] +pub enum ProtoEvent { + /// notify a client that the cursor entered its region + /// [`ProtoEvent::Ack`] with the same serial is used for synchronization between devices + Enter(u32), + /// notify a client that the cursor left its region + /// [`ProtoEvent::Ack`] with the same serial is used for synchronization between devices + Leave(u32), + /// acknowledge of an [`ProtoEvent::Enter`] or [`ProtoEvent::Leave`] event + Ack(u32), + /// Input event + Input(InputEvent), + /// Ping event for tracking unresponsive clients. + /// A client has to respond with [`ProtoEvent::Pong`]. + Ping, + /// Response to [`ProtoEvent::Ping`] + Pong, +} + +impl Display for ProtoEvent { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + ProtoEvent::Enter(s) => write!(f, "Enter({s})"), + ProtoEvent::Leave(s) => write!(f, "Leave({s})"), + ProtoEvent::Ack(s) => write!(f, "Ack({s})"), + ProtoEvent::Input(e) => write!(f, "{e}"), + ProtoEvent::Ping => write!(f, "ping"), + ProtoEvent::Pong => write!(f, "pong"), + } + } +} + +#[derive(TryFromPrimitive, IntoPrimitive)] +#[repr(u8)] +pub enum EventType { + PointerMotion, + PointerButton, + PointerAxis, + PointerAxisValue120, + KeyboardKey, + KeyboardModifiers, + Ping, + Pong, + Enter, + Leave, + Ack, +} + +impl ProtoEvent { + fn event_type(&self) -> EventType { + match self { + ProtoEvent::Input(e) => match e { + InputEvent::Pointer(p) => match p { + PointerEvent::Motion { .. } => EventType::PointerMotion, + PointerEvent::Button { .. } => EventType::PointerButton, + PointerEvent::Axis { .. } => EventType::PointerAxis, + PointerEvent::AxisDiscrete120 { .. } => EventType::PointerAxisValue120, + }, + InputEvent::Keyboard(k) => match k { + KeyboardEvent::Key { .. } => EventType::KeyboardKey, + KeyboardEvent::Modifiers { .. } => EventType::KeyboardModifiers, + }, + }, + ProtoEvent::Ping => EventType::Ping, + ProtoEvent::Pong => EventType::Pong, + ProtoEvent::Enter(_) => EventType::Enter, + ProtoEvent::Leave(_) => EventType::Leave, + ProtoEvent::Ack(_) => EventType::Ack, + } + } +} + +impl TryFrom<[u8; MAX_EVENT_SIZE]> for ProtoEvent { + type Error = ProtocolError; + + fn try_from(buf: [u8; MAX_EVENT_SIZE]) -> Result { + let mut buf = &buf[..]; + let event_type = decode_u8(&mut buf)?; + match EventType::try_from(event_type)? { + EventType::PointerMotion => { + Ok(Self::Input(InputEvent::Pointer(PointerEvent::Motion { + time: decode_u32(&mut buf)?, + dx: decode_f64(&mut buf)?, + dy: decode_f64(&mut buf)?, + }))) + } + EventType::PointerButton => { + Ok(Self::Input(InputEvent::Pointer(PointerEvent::Button { + time: decode_u32(&mut buf)?, + button: decode_u32(&mut buf)?, + state: decode_u32(&mut buf)?, + }))) + } + EventType::PointerAxis => Ok(Self::Input(InputEvent::Pointer(PointerEvent::Axis { + time: decode_u32(&mut buf)?, + axis: decode_u8(&mut buf)?, + value: decode_f64(&mut buf)?, + }))), + EventType::PointerAxisValue120 => Ok(Self::Input(InputEvent::Pointer( + PointerEvent::AxisDiscrete120 { + axis: decode_u8(&mut buf)?, + value: decode_i32(&mut buf)?, + }, + ))), + EventType::KeyboardKey => Ok(Self::Input(InputEvent::Keyboard(KeyboardEvent::Key { + time: decode_u32(&mut buf)?, + key: decode_u32(&mut buf)?, + state: decode_u8(&mut buf)?, + }))), + EventType::KeyboardModifiers => Ok(Self::Input(InputEvent::Keyboard( + KeyboardEvent::Modifiers { + depressed: decode_u32(&mut buf)?, + latched: decode_u32(&mut buf)?, + locked: decode_u32(&mut buf)?, + group: decode_u32(&mut buf)?, + }, + ))), + EventType::Ping => Ok(Self::Ping), + EventType::Pong => Ok(Self::Pong), + EventType::Enter => Ok(Self::Enter(decode_u32(&mut buf)?)), + EventType::Leave => Ok(Self::Leave(decode_u32(&mut buf)?)), + EventType::Ack => Ok(Self::Ack(decode_u32(&mut buf)?)), + } + } +} + +impl From for ([u8; MAX_EVENT_SIZE], usize) { + fn from(event: ProtoEvent) -> Self { + let mut buf = [0u8; MAX_EVENT_SIZE]; + let mut len = 0usize; + { + let mut buf = &mut buf[..]; + let buf = &mut buf; + let len = &mut len; + encode_u8(buf, len, event.event_type() as u8); + match event { + ProtoEvent::Input(event) => match event { + InputEvent::Pointer(p) => match p { + PointerEvent::Motion { time, dx, dy } => { + encode_u32(buf, len, time); + encode_f64(buf, len, dx); + encode_f64(buf, len, dy); + } + PointerEvent::Button { + time, + button, + state, + } => { + encode_u32(buf, len, time); + encode_u32(buf, len, button); + encode_u32(buf, len, state); + } + PointerEvent::Axis { time, axis, value } => { + encode_u32(buf, len, time); + encode_u8(buf, len, axis); + encode_f64(buf, len, value); + } + PointerEvent::AxisDiscrete120 { axis, value } => { + encode_u8(buf, len, axis); + encode_i32(buf, len, value); + } + }, + InputEvent::Keyboard(k) => match k { + KeyboardEvent::Key { time, key, state } => { + encode_u32(buf, len, time); + encode_u32(buf, len, key); + encode_u8(buf, len, state); + } + KeyboardEvent::Modifiers { + depressed, + latched, + locked, + group, + } => { + encode_u32(buf, len, depressed); + encode_u32(buf, len, latched); + encode_u32(buf, len, locked); + encode_u32(buf, len, group); + } + }, + }, + ProtoEvent::Ping => {} + ProtoEvent::Pong => {} + ProtoEvent::Enter(serial) => encode_u32(buf, len, serial), + ProtoEvent::Leave(serial) => encode_u32(buf, len, serial), + ProtoEvent::Ack(serial) => encode_u32(buf, len, serial), + } + } + (buf, len) + } +} + +macro_rules! decode_impl { + ($t:ty) => { + paste! { + fn [](data: &mut &[u8]) -> Result<$t, ProtocolError> { + let (int_bytes, rest) = data.split_at(size_of::<$t>()); + *data = rest; + Ok($t::from_be_bytes(int_bytes.try_into().unwrap())) + } + } + }; +} + +decode_impl!(u8); +decode_impl!(u32); +decode_impl!(i32); +decode_impl!(f64); + +macro_rules! encode_impl { + ($t:ty) => { + paste! { + fn [](buf: &mut &mut [u8], amt: &mut usize, n: $t) { + let src = n.to_be_bytes(); + let data = std::mem::take(buf); + let (int_bytes, rest) = data.split_at_mut(size_of::<$t>()); + int_bytes.copy_from_slice(&src); + *amt += size_of::<$t>(); + *buf = rest + } + } + }; +} + +encode_impl!(u8); +encode_impl!(u32); +encode_impl!(i32); +encode_impl!(f64); diff --git a/src/capture_test.rs b/src/capture_test.rs index c96c2c72..42aa0d87 100644 --- a/src/capture_test.rs +++ b/src/capture_test.rs @@ -1,6 +1,6 @@ use crate::config::Config; use futures::StreamExt; -use input_capture::{self, CaptureError, InputCapture, InputCaptureError, Position}; +use input_capture::{self, CaptureError, CaptureEvent, InputCapture, InputCaptureError, Position}; use input_event::{Event, KeyboardEvent}; use tokio::task::LocalSet; @@ -46,7 +46,7 @@ async fn do_capture(input_capture: &mut InputCapture) -> Result<(), CaptureError _ => Position::Bottom, }; log::info!("position: {pos}, event: {event}"); - if let Event::Keyboard(KeyboardEvent::Key { key: 1, .. }) = event { + if let CaptureEvent::Input(Event::Keyboard(KeyboardEvent::Key { key: 1, .. })) = event { input_capture.release().await?; break Ok(()); } diff --git a/src/server.rs b/src/server.rs index e67ec8bc..b36f9337 100644 --- a/src/server.rs +++ b/src/server.rs @@ -45,7 +45,7 @@ enum State { Receiving, /// Entered the deadzone of another device but waiting /// for acknowledgement (Leave event) from the device - AwaitingLeave, + AwaitAck, } #[derive(Clone)] @@ -144,13 +144,8 @@ impl Server { let capture = capture_task::new(self.clone(), capture_rx, udp_send_tx.clone()); // input emulation - let emulation = emulation_task::new( - self.clone(), - emulation_rx, - udp_recv_rx, - udp_send_tx.clone(), - capture_tx.clone(), - ); + let emulation = + emulation_task::new(self.clone(), emulation_rx, udp_recv_rx, udp_send_tx.clone()); // create dns resolver let resolver = DnsResolver::new(dns_rx)?; diff --git a/src/server/capture_task.rs b/src/server/capture_task.rs index 85ce4cab..1700dd00 100644 --- a/src/server/capture_task.rs +++ b/src/server/capture_task.rs @@ -1,4 +1,5 @@ use futures::StreamExt; +use lan_mouse_proto::ProtoEvent; use std::net::SocketAddr; use tokio::{ @@ -7,9 +8,9 @@ use tokio::{ task::JoinHandle, }; -use input_capture::{self, CaptureError, CaptureHandle, InputCapture, InputCaptureError, Position}; - -use input_event::Event; +use input_capture::{ + self, CaptureError, CaptureEvent, CaptureHandle, InputCapture, InputCaptureError, Position, +}; use crate::{client::ClientHandle, frontend::Status, server::State}; @@ -28,7 +29,7 @@ pub(crate) enum CaptureRequest { pub(crate) fn new( server: Server, capture_rx: Receiver, - udp_send: Sender<(Event, SocketAddr)>, + udp_send: Sender<(ProtoEvent, SocketAddr)>, ) -> JoinHandle<()> { let backend = server.config.capture_backend.map(|b| b.into()); tokio::task::spawn_local(capture_task(server, backend, udp_send, capture_rx)) @@ -37,7 +38,7 @@ pub(crate) fn new( async fn capture_task( server: Server, backend: Option, - sender_tx: Sender<(Event, SocketAddr)>, + sender_tx: Sender<(ProtoEvent, SocketAddr)>, mut notify_rx: Receiver, ) { loop { @@ -63,7 +64,7 @@ async fn capture_task( async fn do_capture( backend: Option, server: &Server, - sender_tx: &Sender<(Event, SocketAddr)>, + sender_tx: &Sender<(ProtoEvent, SocketAddr)>, notify_rx: &mut Receiver, ) -> Result<(), InputCaptureError> { /* allow cancelling capture request */ @@ -120,17 +121,20 @@ async fn do_capture( async fn handle_capture_event( server: &Server, capture: &mut InputCapture, - sender_tx: &Sender<(Event, SocketAddr)>, - event: (CaptureHandle, Event), + sender_tx: &Sender<(ProtoEvent, SocketAddr)>, + event: (CaptureHandle, CaptureEvent), ) -> Result<(), CaptureError> { let (handle, event) = event; log::trace!("({handle}) {event:?}"); // capture started - if event == Event::Enter() { - server.set_state(State::AwaitingLeave); + if event == CaptureEvent::Begin { + // wait for remote to acknowlegde enter + server.set_state(State::AwaitAck); server.set_active(Some(handle)); + // restart ping timer to release capture if unreachable server.restart_ping_timer(); + // spawn enter hook cmd spawn_hook_command(server, handle); } @@ -148,14 +152,18 @@ async fn handle_capture_event( if let Some(addr) = server.active_addr(handle) { let event = match server.get_state() { - State::Sending => event, + State::Sending => match event { + CaptureEvent::Begin => ProtoEvent::Enter(0), + CaptureEvent::Input(e) => ProtoEvent::Input(e), + }, /* send additional enter events until acknowleged */ - State::AwaitingLeave => Event::Enter(), + State::AwaitAck => ProtoEvent::Enter(0), /* released capture */ - State::Receiving => Event::Disconnect(), + State::Receiving => ProtoEvent::Leave(0), }; sender_tx.send((event, addr)).await.expect("sender closed"); - } + }; + Ok(()) } diff --git a/src/server/emulation_task.rs b/src/server/emulation_task.rs index 311c9f8a..78af81f7 100644 --- a/src/server/emulation_task.rs +++ b/src/server/emulation_task.rs @@ -1,5 +1,6 @@ use std::net::SocketAddr; +use lan_mouse_proto::ProtoEvent; use tokio::{ sync::mpsc::{Receiver, Sender}, task::JoinHandle, @@ -11,9 +12,8 @@ use crate::{ server::State, }; use input_emulation::{self, EmulationError, EmulationHandle, InputEmulation, InputEmulationError}; -use input_event::Event; -use super::{network_task::NetworkError, CaptureRequest, Server}; +use super::{network_task::NetworkError, Server}; #[derive(Clone, Debug)] pub(crate) enum EmulationRequest { @@ -28,23 +28,21 @@ pub(crate) enum EmulationRequest { pub(crate) fn new( server: Server, emulation_rx: Receiver, - udp_rx: Receiver>, - sender_tx: Sender<(Event, SocketAddr)>, - capture_tx: Sender, + udp_rx: Receiver>, + sender_tx: Sender<(ProtoEvent, SocketAddr)>, ) -> JoinHandle<()> { - let emulation_task = emulation_task(server, emulation_rx, udp_rx, sender_tx, capture_tx); + let emulation_task = emulation_task(server, emulation_rx, udp_rx, sender_tx); tokio::task::spawn_local(emulation_task) } async fn emulation_task( server: Server, mut rx: Receiver, - mut udp_rx: Receiver>, - sender_tx: Sender<(Event, SocketAddr)>, - capture_tx: Sender, + mut udp_rx: Receiver>, + sender_tx: Sender<(ProtoEvent, SocketAddr)>, ) { loop { - if let Err(e) = do_emulation(&server, &mut rx, &mut udp_rx, &sender_tx, &capture_tx).await { + if let Err(e) = do_emulation(&server, &mut rx, &mut udp_rx, &sender_tx).await { log::warn!("input emulation exited: {e}"); } server.set_emulation_status(Status::Disabled); @@ -66,9 +64,8 @@ async fn emulation_task( async fn do_emulation( server: &Server, rx: &mut Receiver, - udp_rx: &mut Receiver>, - sender_tx: &Sender<(Event, SocketAddr)>, - capture_tx: &Sender, + udp_rx: &mut Receiver>, + sender_tx: &Sender<(ProtoEvent, SocketAddr)>, ) -> Result<(), InputEmulationError> { let backend = server.config.emulation_backend.map(|b| b.into()); log::info!("creating input emulation..."); @@ -84,7 +81,7 @@ async fn do_emulation( emulation.create(handle).await; } - let res = do_emulation_session(server, &mut emulation, rx, udp_rx, sender_tx, capture_tx).await; + let res = do_emulation_session(server, &mut emulation, rx, udp_rx, sender_tx).await; emulation.terminate().await; // manual drop res } @@ -93,9 +90,8 @@ async fn do_emulation_session( server: &Server, emulation: &mut InputEmulation, rx: &mut Receiver, - udp_rx: &mut Receiver>, - sender_tx: &Sender<(Event, SocketAddr)>, - capture_tx: &Sender, + udp_rx: &mut Receiver>, + sender_tx: &Sender<(ProtoEvent, SocketAddr)>, ) -> Result<(), InputEmulationError> { let mut last_ignored = None; @@ -109,7 +105,7 @@ async fn do_emulation_session( continue; } }; - handle_udp_rx(server, capture_tx, emulation, sender_tx, &mut last_ignored, udp_event).await?; + handle_incoming_event(server, emulation, sender_tx, &mut last_ignored, udp_event).await?; } emulate_event = rx.recv() => { match emulate_event.expect("channel closed") { @@ -123,13 +119,12 @@ async fn do_emulation_session( } } -async fn handle_udp_rx( +async fn handle_incoming_event( server: &Server, - capture_tx: &Sender, emulate: &mut InputEmulation, - sender_tx: &Sender<(Event, SocketAddr)>, + sender_tx: &Sender<(ProtoEvent, SocketAddr)>, last_ignored: &mut Option, - event: (Event, SocketAddr), + event: (ProtoEvent, SocketAddr), ) -> Result<(), EmulationError> { let (event, addr) = event; @@ -143,55 +138,27 @@ async fn handle_udp_rx( }; match (event, addr) { - (Event::Pong(), _) => { /* ignore pong events */ } - (Event::Ping(), addr) => { - let _ = sender_tx.send((Event::Pong(), addr)).await; + (ProtoEvent::Pong, _) => { /* ignore pong events */ } + (ProtoEvent::Ping, addr) => { + let _ = sender_tx.send((ProtoEvent::Pong, addr)).await; } - (Event::Disconnect(), _) => emulate.release_keys(handle).await?, - (event, addr) => { - // tell clients that we are ready to receive events - if let Event::Enter() = event { - let _ = sender_tx.send((Event::Leave(), addr)).await; - } - - match server.state.get() { - State::Sending => { - if let Event::Leave() = event { - // ignore additional leave events that may - // have been sent for redundancy - } else { - // upon receiving any event, we go back to receiving mode - server.state.replace(State::Receiving); - let _ = capture_tx.send(CaptureRequest::Release).await; - log::trace!("STATE ===> Receiving"); - } - } - State::Receiving => { - log::trace!("{event} => emulate"); - emulate.consume(event, handle).await?; - let has_pressed_keys = emulate.has_pressed_keys(handle); - server.update_pressed_keys(handle, has_pressed_keys); - if has_pressed_keys { - server.restart_ping_timer(); - } - } - State::AwaitingLeave => { - // we just entered the deadzone of a client, so - // we need to ignore events that may still - // be on the way until a leave event occurs - // telling us the client registered the enter - if let Event::Leave() = event { - server.state.replace(State::Sending); - log::trace!("STATE ===> Sending"); - } - - // entering a client that is waiting for a leave - // event should still be possible - if let Event::Enter() = event { - server.state.replace(State::Receiving); - let _ = capture_tx.send(CaptureRequest::Release).await; - log::trace!("STATE ===> Receiving"); - } + (ProtoEvent::Leave(_), _) => emulate.release_keys(handle).await?, + (ProtoEvent::Ack(_), _) => server.set_state(State::Sending), + (ProtoEvent::Enter(_), _) => { + server.set_state(State::Receiving); + sender_tx + .send((ProtoEvent::Ack(0), addr)) + .await + .expect("no channel") + } + (ProtoEvent::Input(e), _) => { + if let State::Receiving = server.get_state() { + log::trace!("{event} => emulate"); + emulate.consume(e, handle).await?; + let has_pressed_keys = emulate.has_pressed_keys(handle); + server.update_pressed_keys(handle, has_pressed_keys); + if has_pressed_keys { + server.restart_ping_timer(); } } } diff --git a/src/server/network_task.rs b/src/server/network_task.rs index 20e2c3b0..09a48d36 100644 --- a/src/server/network_task.rs +++ b/src/server/network_task.rs @@ -7,14 +7,13 @@ use tokio::{ task::JoinHandle, }; -use input_event::{Event, ProtocolError}; - use super::Server; +use lan_mouse_proto::{ProtoEvent, ProtocolError}; pub(crate) async fn new( server: Server, - udp_recv_tx: Sender>, - udp_send_rx: Receiver<(Event, SocketAddr)>, + udp_recv_tx: Sender>, + udp_send_rx: Receiver<(ProtoEvent, SocketAddr)>, ) -> io::Result> { // bind the udp socket let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), server.port.get()); @@ -62,7 +61,7 @@ async fn update_port(server: &Server, socket: &mut UdpSocket) { async fn udp_receiver( socket: &UdpSocket, - receiver_tx: &Sender>, + receiver_tx: &Sender>, ) { loop { let event = receive_event(socket).await; @@ -70,7 +69,7 @@ async fn udp_receiver( } } -async fn udp_sender(socket: &UdpSocket, rx: &mut Receiver<(Event, SocketAddr)>) { +async fn udp_sender(socket: &UdpSocket, rx: &mut Receiver<(ProtoEvent, SocketAddr)>) { loop { let (event, addr) = rx.recv().await.expect("channel closed"); if let Err(e) = send_event(socket, event, addr) { @@ -87,16 +86,17 @@ pub(crate) enum NetworkError { Io(#[from] io::Error), } -async fn receive_event(socket: &UdpSocket) -> Result<(Event, SocketAddr), NetworkError> { - let mut buf = vec![0u8; 22]; - let (_amt, src) = socket.recv_from(&mut buf).await?; - Ok((Event::try_from(buf)?, src)) +async fn receive_event(socket: &UdpSocket) -> Result<(ProtoEvent, SocketAddr), NetworkError> { + let mut buf = [0u8; lan_mouse_proto::MAX_EVENT_SIZE]; + let (_len, src) = socket.recv_from(&mut buf).await?; + let event = ProtoEvent::try_from(buf)?; + Ok((event, src)) } -fn send_event(sock: &UdpSocket, e: Event, addr: SocketAddr) -> Result { +fn send_event(sock: &UdpSocket, e: ProtoEvent, addr: SocketAddr) -> Result { log::trace!("{:20} ------>->->-> {addr}", e.to_string()); - let data: Vec = (&e).into(); + let (data, len): ([u8; lan_mouse_proto::MAX_EVENT_SIZE], usize) = e.into(); // When udp blocks, we dont want to block the event loop. // Dropping events is better than potentially crashing the input capture. - Ok(sock.try_send_to(&data, addr)?) + Ok(sock.try_send_to(&data[..len], addr)?) } diff --git a/src/server/ping_task.rs b/src/server/ping_task.rs index 3a89fe62..ad6534d6 100644 --- a/src/server/ping_task.rs +++ b/src/server/ping_task.rs @@ -1,9 +1,8 @@ use std::{net::SocketAddr, time::Duration}; +use lan_mouse_proto::ProtoEvent; use tokio::{sync::mpsc::Sender, task::JoinHandle}; -use input_event::Event; - use crate::client::ClientHandle; use super::{capture_task::CaptureRequest, emulation_task::EmulationRequest, Server, State}; @@ -12,7 +11,7 @@ const MAX_RESPONSE_TIME: Duration = Duration::from_millis(500); pub(crate) fn new( server: Server, - sender_ch: Sender<(Event, SocketAddr)>, + sender_ch: Sender<(ProtoEvent, SocketAddr)>, emulate_notify: Sender, capture_notify: Sender, ) -> JoinHandle<()> { @@ -27,7 +26,7 @@ pub(crate) fn new( async fn ping_task( server: &Server, - sender_ch: Sender<(Event, SocketAddr)>, + sender_ch: Sender<(ProtoEvent, SocketAddr)>, emulate_notify: Sender, capture_notify: Sender, ) { @@ -86,7 +85,7 @@ async fn ping_task( // ping clients for addr in ping_addrs { - if sender_ch.send((Event::Ping(), addr)).await.is_err() { + if sender_ch.send((ProtoEvent::Ping, addr)).await.is_err() { break; } }