mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-04-21 00:33:19 +03:00
code cleanup
This commit is contained in:
2
Cargo.lock
generated
2
Cargo.lock
generated
@@ -1242,11 +1242,11 @@ dependencies = [
|
|||||||
name = "input-event"
|
name = "input-event"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"anyhow",
|
|
||||||
"futures-core",
|
"futures-core",
|
||||||
"log",
|
"log",
|
||||||
"num_enum",
|
"num_enum",
|
||||||
"serde",
|
"serde",
|
||||||
|
"thiserror",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -440,8 +440,8 @@ async fn handle_ei_event(
|
|||||||
EiEvent::PointerMotion(motion) => {
|
EiEvent::PointerMotion(motion) => {
|
||||||
let motion_event = PointerEvent::Motion {
|
let motion_event = PointerEvent::Motion {
|
||||||
time: motion.time as u32,
|
time: motion.time as u32,
|
||||||
relative_x: motion.dx as f64,
|
dx: motion.dx as f64,
|
||||||
relative_y: motion.dy as f64,
|
dy: motion.dy as f64,
|
||||||
};
|
};
|
||||||
if let Some(current_client) = current_client {
|
if let Some(current_client) = current_client {
|
||||||
event_tx
|
event_tx
|
||||||
|
|||||||
@@ -849,8 +849,8 @@ impl Dispatch<ZwpRelativePointerV1, ()> for State {
|
|||||||
*client,
|
*client,
|
||||||
Event::Pointer(PointerEvent::Motion {
|
Event::Pointer(PointerEvent::Motion {
|
||||||
time,
|
time,
|
||||||
relative_x: surface_x,
|
dx: surface_x,
|
||||||
relative_y: surface_y,
|
dy: surface_y,
|
||||||
}),
|
}),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::{fmt::Display, io};
|
use reis::tokio::EiConvertEventStreamError;
|
||||||
|
use std::io;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||||
use wayland_client::{
|
use wayland_client::{
|
||||||
backend::WaylandError,
|
backend::WaylandError,
|
||||||
@@ -11,11 +12,29 @@ use wayland_client::{
|
|||||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||||
use reis::tokio::HandshakeError;
|
use reis::tokio::HandshakeError;
|
||||||
|
|
||||||
|
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
#[error("error in libei stream: {inner:?}")]
|
||||||
|
pub struct ReisConvertStreamError {
|
||||||
|
inner: EiConvertEventStreamError,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<EiConvertEventStreamError> for ReisConvertStreamError {
|
||||||
|
fn from(e: EiConvertEventStreamError) -> Self {
|
||||||
|
Self { inner: e }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum EmulationError {
|
pub enum EmulationError {
|
||||||
|
#[error("event stream closed")]
|
||||||
|
EndOfStream,
|
||||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||||
#[error("libei error flushing events: `{0}`")]
|
#[error("libei error flushing events: `{0}`")]
|
||||||
Libei(#[from] reis::event::Error),
|
Libei(#[from] reis::event::Error),
|
||||||
|
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||||
|
#[error("")]
|
||||||
|
LibeiConvertStream(#[from] ReisConvertStreamError),
|
||||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||||
#[error("wayland error: `{0}`")]
|
#[error("wayland error: `{0}`")]
|
||||||
Wayland(#[from] wayland_client::backend::WaylandError),
|
Wayland(#[from] wayland_client::backend::WaylandError),
|
||||||
@@ -33,58 +52,52 @@ pub enum EmulationError {
|
|||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum EmulationCreationError {
|
pub enum EmulationCreationError {
|
||||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||||
|
#[error("wlroots backend: `{0}`")]
|
||||||
Wlroots(#[from] WlrootsEmulationCreationError),
|
Wlroots(#[from] WlrootsEmulationCreationError),
|
||||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||||
|
#[error("libei backend: `{0}`")]
|
||||||
Libei(#[from] LibeiEmulationCreationError),
|
Libei(#[from] LibeiEmulationCreationError),
|
||||||
#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))]
|
||||||
|
#[error("xdg-desktop-portal: `{0}`")]
|
||||||
Xdp(#[from] XdpEmulationCreationError),
|
Xdp(#[from] XdpEmulationCreationError),
|
||||||
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
||||||
|
#[error("x11: `{0}`")]
|
||||||
X11(#[from] X11EmulationCreationError),
|
X11(#[from] X11EmulationCreationError),
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
|
#[error("macos: `{0}`")]
|
||||||
MacOs(#[from] MacOSEmulationCreationError),
|
MacOs(#[from] MacOSEmulationCreationError),
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
#[error("windows: `{0}`")]
|
||||||
Windows(#[from] WindowsEmulationCreationError),
|
Windows(#[from] WindowsEmulationCreationError),
|
||||||
|
#[error("capture error")]
|
||||||
NoAvailableBackend,
|
NoAvailableBackend,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Display for EmulationCreationError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let reason = match self {
|
|
||||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
|
||||||
EmulationCreationError::Wlroots(e) => format!("wlroots backend: {e}"),
|
|
||||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
|
||||||
EmulationCreationError::Libei(e) => format!("libei backend: {e}"),
|
|
||||||
#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))]
|
|
||||||
EmulationCreationError::Xdp(e) => format!("desktop portal backend: {e}"),
|
|
||||||
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
|
||||||
EmulationCreationError::X11(e) => format!("x11 backend: {e}"),
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
EmulationCreationError::MacOs(e) => format!("macos backend: {e}"),
|
|
||||||
#[cfg(windows)]
|
|
||||||
EmulationCreationError::Windows(e) => format!("windows backend: {e}"),
|
|
||||||
EmulationCreationError::NoAvailableBackend => "no backend available".to_string(),
|
|
||||||
};
|
|
||||||
write!(f, "could not create input emulation backend: {reason}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WlrootsEmulationCreationError {
|
pub enum WlrootsEmulationCreationError {
|
||||||
|
#[error(transparent)]
|
||||||
Connect(#[from] ConnectError),
|
Connect(#[from] ConnectError),
|
||||||
|
#[error(transparent)]
|
||||||
Global(#[from] GlobalError),
|
Global(#[from] GlobalError),
|
||||||
|
#[error(transparent)]
|
||||||
Wayland(#[from] WaylandError),
|
Wayland(#[from] WaylandError),
|
||||||
|
#[error(transparent)]
|
||||||
Bind(#[from] WaylandBindError),
|
Bind(#[from] WaylandBindError),
|
||||||
|
#[error(transparent)]
|
||||||
Dispatch(#[from] DispatchError),
|
Dispatch(#[from] DispatchError),
|
||||||
|
#[error(transparent)]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
#[error("wayland protocol \"{protocol}\" not supported: {inner}")]
|
||||||
pub struct WaylandBindError {
|
pub struct WaylandBindError {
|
||||||
inner: BindError,
|
inner: BindError,
|
||||||
protocol: &'static str,
|
protocol: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "wayland", not(target_os = "macos")))]
|
||||||
impl WaylandBindError {
|
impl WaylandBindError {
|
||||||
pub(crate) fn new(inner: BindError, protocol: &'static str) -> Self {
|
pub(crate) fn new(inner: BindError, protocol: &'static str) -> Self {
|
||||||
@@ -92,101 +105,38 @@ impl WaylandBindError {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[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")))]
|
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum LibeiEmulationCreationError {
|
pub enum LibeiEmulationCreationError {
|
||||||
|
#[error(transparent)]
|
||||||
Ashpd(#[from] ashpd::Error),
|
Ashpd(#[from] ashpd::Error),
|
||||||
|
#[error(transparent)]
|
||||||
Io(#[from] std::io::Error),
|
Io(#[from] std::io::Error),
|
||||||
|
#[error(transparent)]
|
||||||
Handshake(#[from] HandshakeError),
|
Handshake(#[from] HandshakeError),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
|
|
||||||
impl Display for LibeiEmulationCreationError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
LibeiEmulationCreationError::Ashpd(e) => write!(f, "xdg-desktop-portal: {e}"),
|
|
||||||
LibeiEmulationCreationError::Io(e) => write!(f, "io error: {e}"),
|
|
||||||
LibeiEmulationCreationError::Handshake(e) => write!(f, "error in libei handshake: {e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum XdpEmulationCreationError {
|
pub enum XdpEmulationCreationError {
|
||||||
|
#[error(transparent)]
|
||||||
Ashpd(#[from] ashpd::Error),
|
Ashpd(#[from] ashpd::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))]
|
|
||||||
impl Display for XdpEmulationCreationError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
XdpEmulationCreationError::Ashpd(e) => write!(f, "portal error: {e}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum X11EmulationCreationError {
|
pub enum X11EmulationCreationError {
|
||||||
|
#[error("could not open display")]
|
||||||
OpenDisplay,
|
OpenDisplay,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(all(unix, feature = "x11", not(target_os = "macos")))]
|
|
||||||
impl Display for X11EmulationCreationError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
X11EmulationCreationError::OpenDisplay => write!(f, "could not open display!"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
#[cfg(target_os = "macos")]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum MacOSEmulationCreationError {
|
pub enum MacOSEmulationCreationError {
|
||||||
|
#[error("could not create event source")]
|
||||||
EventSourceCreation,
|
EventSourceCreation,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(target_os = "macos")]
|
|
||||||
impl Display for MacOSEmulationCreationError {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
match self {
|
|
||||||
MacOSEmulationCreationError::EventSourceCreation => {
|
|
||||||
write!(f, "could not create event source")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
pub enum WindowsEmulationCreationError {}
|
pub enum WindowsEmulationCreationError {}
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ use std::fmt::Display;
|
|||||||
|
|
||||||
use input_event::Event;
|
use input_event::Event;
|
||||||
|
|
||||||
use anyhow::Result;
|
|
||||||
|
|
||||||
use self::error::EmulationCreationError;
|
use self::error::EmulationCreationError;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
|||||||
@@ -1,4 +1,3 @@
|
|||||||
use anyhow::{anyhow, Result};
|
|
||||||
use futures::StreamExt;
|
use futures::StreamExt;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use std::{
|
use std::{
|
||||||
@@ -33,7 +32,7 @@ use reis::{
|
|||||||
|
|
||||||
use input_event::{Event, KeyboardEvent, PointerEvent};
|
use input_event::{Event, KeyboardEvent, PointerEvent};
|
||||||
|
|
||||||
use crate::error::EmulationError;
|
use crate::error::{EmulationError, ReisConvertStreamError};
|
||||||
|
|
||||||
use super::{error::LibeiEmulationCreationError, EmulationHandle, InputEmulation};
|
use super::{error::LibeiEmulationCreationError, EmulationHandle, InputEmulation};
|
||||||
|
|
||||||
@@ -65,7 +64,7 @@ pub struct LibeiEmulation {
|
|||||||
context: ei::Context,
|
context: ei::Context,
|
||||||
devices: Devices,
|
devices: Devices,
|
||||||
serial: AtomicU32,
|
serial: AtomicU32,
|
||||||
ei_task: JoinHandle<Result<()>>,
|
ei_task: JoinHandle<Result<(), EmulationError>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn get_ei_fd() -> Result<OwnedFd, ashpd::Error> {
|
async fn get_ei_fd() -> Result<OwnedFd, ashpd::Error> {
|
||||||
@@ -149,14 +148,10 @@ impl InputEmulation for LibeiEmulation {
|
|||||||
.as_micros() as u64;
|
.as_micros() as u64;
|
||||||
match event {
|
match event {
|
||||||
Event::Pointer(p) => match p {
|
Event::Pointer(p) => match p {
|
||||||
PointerEvent::Motion {
|
PointerEvent::Motion { time: _, dx, dy } => {
|
||||||
time: _,
|
|
||||||
relative_x,
|
|
||||||
relative_y,
|
|
||||||
} => {
|
|
||||||
let pointer_device = self.devices.pointer.read().unwrap();
|
let pointer_device = self.devices.pointer.read().unwrap();
|
||||||
if let Some((d, p)) = pointer_device.as_ref() {
|
if let Some((d, p)) = pointer_device.as_ref() {
|
||||||
p.motion_relative(relative_x as f32, relative_y as f32);
|
p.motion_relative(dx as f32, dy as f32);
|
||||||
d.frame(self.serial.load(Ordering::SeqCst), now);
|
d.frame(self.serial.load(Ordering::SeqCst), now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -239,13 +234,13 @@ async fn ei_event_handler(
|
|||||||
mut events: EiConvertEventStream,
|
mut events: EiConvertEventStream,
|
||||||
context: ei::Context,
|
context: ei::Context,
|
||||||
devices: Devices,
|
devices: Devices,
|
||||||
) -> Result<()> {
|
) -> Result<(), EmulationError> {
|
||||||
loop {
|
loop {
|
||||||
let event = events
|
let event = events
|
||||||
.next()
|
.next()
|
||||||
.await
|
.await
|
||||||
.ok_or(anyhow!("ei stream closed"))?
|
.ok_or(EmulationError::EndOfStream)?
|
||||||
.map_err(|e| anyhow!("libei error: {e:?}"))?;
|
.map_err(ReisConvertStreamError::from)?;
|
||||||
const CAPABILITIES: &[DeviceCapability] = &[
|
const CAPABILITIES: &[DeviceCapability] = &[
|
||||||
DeviceCapability::Pointer,
|
DeviceCapability::Pointer,
|
||||||
DeviceCapability::PointerAbsolute,
|
DeviceCapability::PointerAbsolute,
|
||||||
@@ -330,7 +325,7 @@ async fn ei_event_handler(
|
|||||||
// EiEvent::TouchMotion(_) => { },
|
// EiEvent::TouchMotion(_) => { },
|
||||||
_ => unreachable!("unexpected ei event"),
|
_ => unreachable!("unexpected ei event"),
|
||||||
}
|
}
|
||||||
context.flush()?;
|
context.flush().map_err(|e| io::Error::new(e.kind(), e))?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -114,11 +114,7 @@ impl InputEmulation for MacOSEmulation {
|
|||||||
) -> Result<(), EmulationError> {
|
) -> Result<(), EmulationError> {
|
||||||
match event {
|
match event {
|
||||||
Event::Pointer(pointer_event) => match pointer_event {
|
Event::Pointer(pointer_event) => match pointer_event {
|
||||||
PointerEvent::Motion {
|
PointerEvent::Motion { time: _, dx, dy } => {
|
||||||
time: _,
|
|
||||||
relative_x,
|
|
||||||
relative_y,
|
|
||||||
} => {
|
|
||||||
// FIXME secondary displays?
|
// FIXME secondary displays?
|
||||||
let (min_x, min_y, max_x, max_y) = unsafe {
|
let (min_x, min_y, max_x, max_y) = unsafe {
|
||||||
let display = CGMainDisplayID();
|
let display = CGMainDisplayID();
|
||||||
@@ -137,8 +133,8 @@ impl InputEmulation for MacOSEmulation {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
mouse_location.x = (mouse_location.x + relative_x).clamp(min_x, max_x - 1.);
|
mouse_location.x = (mouse_location.x + dx).clamp(min_x, max_x - 1.);
|
||||||
mouse_location.y = (mouse_location.y + relative_y).clamp(min_y, max_y - 1.);
|
mouse_location.y = (mouse_location.y + dy).clamp(min_y, max_y - 1.);
|
||||||
|
|
||||||
let mut event_type = CGEventType::MouseMoved;
|
let mut event_type = CGEventType::MouseMoved;
|
||||||
if self.button_state.left {
|
if self.button_state.left {
|
||||||
@@ -160,14 +156,8 @@ impl InputEmulation for MacOSEmulation {
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
event.set_integer_value_field(
|
event.set_integer_value_field(EventField::MOUSE_EVENT_DELTA_X, dx as i64);
|
||||||
EventField::MOUSE_EVENT_DELTA_X,
|
event.set_integer_value_field(EventField::MOUSE_EVENT_DELTA_Y, dy as i64);
|
||||||
relative_x as i64,
|
|
||||||
);
|
|
||||||
event.set_integer_value_field(
|
|
||||||
EventField::MOUSE_EVENT_DELTA_Y,
|
|
||||||
relative_y as i64,
|
|
||||||
);
|
|
||||||
event.post(CGEventTapLocation::HID);
|
event.post(CGEventTapLocation::HID);
|
||||||
}
|
}
|
||||||
PointerEvent::Button {
|
PointerEvent::Button {
|
||||||
|
|||||||
@@ -39,12 +39,8 @@ impl InputEmulation for WindowsEmulation {
|
|||||||
async fn consume(&mut self, event: Event, _: EmulationHandle) -> Result<(), EmulationError> {
|
async fn consume(&mut self, event: Event, _: EmulationHandle) -> Result<(), EmulationError> {
|
||||||
match event {
|
match event {
|
||||||
Event::Pointer(pointer_event) => match pointer_event {
|
Event::Pointer(pointer_event) => match pointer_event {
|
||||||
PointerEvent::Motion {
|
PointerEvent::Motion { time: _, dx, dy } => {
|
||||||
time: _,
|
rel_mouse(dx as i32, dy as i32);
|
||||||
relative_x,
|
|
||||||
relative_y,
|
|
||||||
} => {
|
|
||||||
rel_mouse(relative_x as i32, relative_y as i32);
|
|
||||||
}
|
}
|
||||||
PointerEvent::Button {
|
PointerEvent::Button {
|
||||||
time: _,
|
time: _,
|
||||||
|
|||||||
@@ -179,8 +179,8 @@ impl VirtualInput {
|
|||||||
match e {
|
match e {
|
||||||
PointerEvent::Motion {
|
PointerEvent::Motion {
|
||||||
time,
|
time,
|
||||||
relative_x,
|
dx: relative_x,
|
||||||
relative_y,
|
dy: relative_y,
|
||||||
} => self.pointer.motion(time, relative_x, relative_y),
|
} => self.pointer.motion(time, relative_x, relative_y),
|
||||||
PointerEvent::Button {
|
PointerEvent::Button {
|
||||||
time,
|
time,
|
||||||
|
|||||||
@@ -103,12 +103,8 @@ impl InputEmulation for X11Emulation {
|
|||||||
async fn consume(&mut self, event: Event, _: EmulationHandle) -> Result<(), EmulationError> {
|
async fn consume(&mut self, event: Event, _: EmulationHandle) -> Result<(), EmulationError> {
|
||||||
match event {
|
match event {
|
||||||
Event::Pointer(pointer_event) => match pointer_event {
|
Event::Pointer(pointer_event) => match pointer_event {
|
||||||
PointerEvent::Motion {
|
PointerEvent::Motion { time: _, dx, dy } => {
|
||||||
time: _,
|
self.relative_motion(dx as i32, dy as i32);
|
||||||
relative_x,
|
|
||||||
relative_y,
|
|
||||||
} => {
|
|
||||||
self.relative_motion(relative_x as i32, relative_y as i32);
|
|
||||||
}
|
}
|
||||||
PointerEvent::Button {
|
PointerEvent::Button {
|
||||||
time: _,
|
time: _,
|
||||||
|
|||||||
@@ -70,13 +70,9 @@ impl<'a> InputEmulation for DesktopPortalEmulation<'a> {
|
|||||||
) -> Result<(), EmulationError> {
|
) -> Result<(), EmulationError> {
|
||||||
match event {
|
match event {
|
||||||
Pointer(p) => match p {
|
Pointer(p) => match p {
|
||||||
PointerEvent::Motion {
|
PointerEvent::Motion { time: _, dx, dy } => {
|
||||||
time: _,
|
|
||||||
relative_x,
|
|
||||||
relative_y,
|
|
||||||
} => {
|
|
||||||
self.proxy
|
self.proxy
|
||||||
.notify_pointer_motion(&self.session, relative_x, relative_y)
|
.notify_pointer_motion(&self.session, dx, dy)
|
||||||
.await?;
|
.await?;
|
||||||
}
|
}
|
||||||
PointerEvent::Button {
|
PointerEvent::Button {
|
||||||
|
|||||||
@@ -7,8 +7,8 @@ license = "GPL-3.0-or-later"
|
|||||||
repository = "https://github.com/ferdinandschober/lan-mouse"
|
repository = "https://github.com/ferdinandschober/lan-mouse"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
anyhow = "1.0.86"
|
|
||||||
futures-core = "0.3.30"
|
futures-core = "0.3.30"
|
||||||
log = "0.4.22"
|
log = "0.4.22"
|
||||||
num_enum = "0.7.2"
|
num_enum = "0.7.2"
|
||||||
serde = { version = "1.0", features = ["derive"] }
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
thiserror = "1.0.61"
|
||||||
|
|||||||
17
input-event/src/error.rs
Normal file
17
input-event/src/error.rs
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
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),
|
||||||
|
}
|
||||||
@@ -1,9 +1,8 @@
|
|||||||
use anyhow::{anyhow, Result};
|
pub use error::ProtocolError;
|
||||||
use std::{
|
use std::fmt::{self, Display};
|
||||||
error::Error,
|
|
||||||
fmt::{self, Display},
|
|
||||||
};
|
|
||||||
|
|
||||||
|
pub mod error;
|
||||||
|
pub mod proto;
|
||||||
pub mod scancode;
|
pub mod scancode;
|
||||||
|
|
||||||
// FIXME
|
// FIXME
|
||||||
@@ -15,35 +14,23 @@ pub const BTN_FORWARD: u32 = 0x114;
|
|||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum PointerEvent {
|
pub enum PointerEvent {
|
||||||
Motion {
|
/// relative motion event
|
||||||
time: u32,
|
Motion { time: u32, dx: f64, dy: f64 },
|
||||||
relative_x: f64,
|
/// mouse button event
|
||||||
relative_y: f64,
|
Button { time: u32, button: u32, state: u32 },
|
||||||
},
|
/// axis event, scroll event for touchpads
|
||||||
Button {
|
Axis { time: u32, axis: u8, value: f64 },
|
||||||
time: u32,
|
/// discrete axis event, scroll event for mice - 120 = one scroll tick
|
||||||
button: u32,
|
AxisDiscrete120 { axis: u8, value: i32 },
|
||||||
state: u32,
|
/// frame event
|
||||||
},
|
|
||||||
Axis {
|
|
||||||
time: u32,
|
|
||||||
axis: u8,
|
|
||||||
value: f64,
|
|
||||||
},
|
|
||||||
AxisDiscrete120 {
|
|
||||||
axis: u8,
|
|
||||||
value: i32,
|
|
||||||
},
|
|
||||||
Frame {},
|
Frame {},
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, PartialEq, Clone, Copy)]
|
#[derive(Debug, PartialEq, Clone, Copy)]
|
||||||
pub enum KeyboardEvent {
|
pub enum KeyboardEvent {
|
||||||
Key {
|
/// a key press / release event
|
||||||
time: u32,
|
Key { time: u32, key: u32, state: u8 },
|
||||||
key: u32,
|
/// modifiers changed state
|
||||||
state: u8,
|
|
||||||
},
|
|
||||||
Modifiers {
|
Modifiers {
|
||||||
mods_depressed: u32,
|
mods_depressed: u32,
|
||||||
mods_latched: u32,
|
mods_latched: u32,
|
||||||
@@ -82,8 +69,8 @@ impl Display for PointerEvent {
|
|||||||
match self {
|
match self {
|
||||||
PointerEvent::Motion {
|
PointerEvent::Motion {
|
||||||
time: _,
|
time: _,
|
||||||
relative_x,
|
dx: relative_x,
|
||||||
relative_y,
|
dy: relative_y,
|
||||||
} => write!(f, "motion({relative_x},{relative_y})"),
|
} => write!(f, "motion({relative_x},{relative_y})"),
|
||||||
PointerEvent::Button {
|
PointerEvent::Button {
|
||||||
time: _,
|
time: _,
|
||||||
@@ -158,430 +145,3 @@ impl Display for Event {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
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,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
enum PointerEventType {
|
|
||||||
Motion,
|
|
||||||
Button,
|
|
||||||
Axis,
|
|
||||||
AxisDiscrete120,
|
|
||||||
Frame,
|
|
||||||
}
|
|
||||||
enum KeyboardEventType {
|
|
||||||
Key,
|
|
||||||
Modifiers,
|
|
||||||
}
|
|
||||||
enum EventType {
|
|
||||||
Pointer,
|
|
||||||
Keyboard,
|
|
||||||
Enter,
|
|
||||||
Leave,
|
|
||||||
Ping,
|
|
||||||
Pong,
|
|
||||||
Disconnect,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u8> for PointerEventType {
|
|
||||||
type Error = anyhow::Error;
|
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Self> {
|
|
||||||
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(anyhow!(ProtocolError {
|
|
||||||
msg: format!("invalid pointer event type {}", value),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<u8> for KeyboardEventType {
|
|
||||||
type Error = anyhow::Error;
|
|
||||||
|
|
||||||
fn try_from(value: u8) -> Result<Self> {
|
|
||||||
match value {
|
|
||||||
x if x == Self::Key as u8 => Ok(Self::Key),
|
|
||||||
x if x == Self::Modifiers as u8 => Ok(Self::Modifiers),
|
|
||||||
_ => Err(anyhow!(ProtocolError {
|
|
||||||
msg: format!("invalid keyboard event type {}", value),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&Event> for Vec<u8> {
|
|
||||||
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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
struct ProtocolError {
|
|
||||||
msg: String,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for ProtocolError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
write!(f, "Protocol violation: {}", self.msg)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
impl Error for ProtocolError {}
|
|
||||||
|
|
||||||
impl TryFrom<Vec<u8>> for Event {
|
|
||||||
type Error = anyhow::Error;
|
|
||||||
|
|
||||||
fn try_from(value: Vec<u8>) -> Result<Self> {
|
|
||||||
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(anyhow!(ProtocolError {
|
|
||||||
msg: format!("invalid event_id {}", event_id),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&PointerEvent> for Vec<u8> {
|
|
||||||
fn from(event: &PointerEvent) -> Self {
|
|
||||||
let id = vec![event.event_type() as u8];
|
|
||||||
let data = match event {
|
|
||||||
PointerEvent::Motion {
|
|
||||||
time,
|
|
||||||
relative_x,
|
|
||||||
relative_y,
|
|
||||||
} => {
|
|
||||||
let time = time.to_be_bytes();
|
|
||||||
let relative_x = relative_x.to_be_bytes();
|
|
||||||
let relative_y = relative_y.to_be_bytes();
|
|
||||||
[&time[..], &relative_x[..], &relative_y[..]].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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TryFrom<Vec<u8>> for PointerEvent {
|
|
||||||
type Error = anyhow::Error;
|
|
||||||
|
|
||||||
fn try_from(data: Vec<u8>) -> Result<Self> {
|
|
||||||
match data.get(1) {
|
|
||||||
Some(id) => {
|
|
||||||
let event_type = match id.to_owned().try_into() {
|
|
||||||
Ok(event_type) => event_type,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
match event_type {
|
|
||||||
PointerEventType::Motion => {
|
|
||||||
let time = match data.get(2..6) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 2".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let relative_x = match data.get(6..14) {
|
|
||||||
Some(d) => f64::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 8 Bytes at index 6".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let relative_y = match data.get(14..22) {
|
|
||||||
Some(d) => f64::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 8 Bytes at index 14".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Self::Motion {
|
|
||||||
time,
|
|
||||||
relative_x,
|
|
||||||
relative_y,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
PointerEventType::Button => {
|
|
||||||
let time = match data.get(2..6) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 2".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let button = match data.get(6..10) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 10".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let state = match data.get(10..14) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 14".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Self::Button {
|
|
||||||
time,
|
|
||||||
button,
|
|
||||||
state,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
PointerEventType::Axis => {
|
|
||||||
let time = match data.get(2..6) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 2".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let axis = match data.get(6) {
|
|
||||||
Some(d) => *d,
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 1 Byte at index 6".into(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let value = match data.get(7..15) {
|
|
||||||
Some(d) => f64::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 8 Bytes at index 7".into(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Self::Axis { time, axis, value })
|
|
||||||
}
|
|
||||||
PointerEventType::AxisDiscrete120 => {
|
|
||||||
let axis = match data.get(2) {
|
|
||||||
Some(d) => *d,
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 1 Byte at index 2".into(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let value = match data.get(3..7) {
|
|
||||||
Some(d) => i32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 3".into(),
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(Self::AxisDiscrete120 { axis, value })
|
|
||||||
}
|
|
||||||
PointerEventType::Frame => Ok(Self::Frame {}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected an element at index 0".into(),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<&KeyboardEvent> for Vec<u8> {
|
|
||||||
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<Vec<u8>> for KeyboardEvent {
|
|
||||||
type Error = anyhow::Error;
|
|
||||||
|
|
||||||
fn try_from(data: Vec<u8>) -> Result<Self> {
|
|
||||||
match data.get(1) {
|
|
||||||
Some(id) => {
|
|
||||||
let event_type = match id.to_owned().try_into() {
|
|
||||||
Ok(event_type) => event_type,
|
|
||||||
Err(e) => return Err(e),
|
|
||||||
};
|
|
||||||
match event_type {
|
|
||||||
KeyboardEventType::Key => {
|
|
||||||
let time = match data.get(2..6) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 6".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let key = match data.get(6..10) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 10".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let state = match data.get(10) {
|
|
||||||
Some(d) => *d,
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 1 Bytes at index 14".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(KeyboardEvent::Key { time, key, state })
|
|
||||||
}
|
|
||||||
KeyboardEventType::Modifiers => {
|
|
||||||
let mods_depressed = match data.get(2..6) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 6".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mods_latched = match data.get(6..10) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 10".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let mods_locked = match data.get(10..14) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 14".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
let group = match data.get(14..18) {
|
|
||||||
Some(d) => u32::from_be_bytes(d.try_into()?),
|
|
||||||
None => {
|
|
||||||
return Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected 4 Bytes at index 18".into(),
|
|
||||||
}))
|
|
||||||
}
|
|
||||||
};
|
|
||||||
Ok(KeyboardEvent::Modifiers {
|
|
||||||
mods_depressed,
|
|
||||||
mods_latched,
|
|
||||||
mods_locked,
|
|
||||||
group,
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
None => Err(anyhow!(ProtocolError {
|
|
||||||
msg: "Expected an element at index 0".into(),
|
|
||||||
})),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
311
input-event/src/proto.rs
Normal file
311
input-event/src/proto.rs
Normal file
@@ -0,0 +1,311 @@
|
|||||||
|
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<u8> for PointerEventType {
|
||||||
|
type Error = ProtocolError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, ProtocolError> {
|
||||||
|
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<u8> for KeyboardEventType {
|
||||||
|
type Error = ProtocolError;
|
||||||
|
|
||||||
|
fn try_from(value: u8) -> Result<Self, ProtocolError> {
|
||||||
|
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<u8> {
|
||||||
|
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<Vec<u8>> for Event {
|
||||||
|
type Error = ProtocolError;
|
||||||
|
|
||||||
|
fn try_from(value: Vec<u8>) -> Result<Self, ProtocolError> {
|
||||||
|
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<u8> {
|
||||||
|
fn from(event: &PointerEvent) -> Self {
|
||||||
|
let id = vec![event.event_type() as u8];
|
||||||
|
let data = match event {
|
||||||
|
PointerEvent::Motion {
|
||||||
|
time,
|
||||||
|
dx: relative_x,
|
||||||
|
dy: relative_y,
|
||||||
|
} => {
|
||||||
|
let time = time.to_be_bytes();
|
||||||
|
let relative_x = relative_x.to_be_bytes();
|
||||||
|
let relative_y = relative_y.to_be_bytes();
|
||||||
|
[&time[..], &relative_x[..], &relative_y[..]].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<I>(data: &[u8], idx: I) -> Result<u8, ProtocolError>
|
||||||
|
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<I>(data: &[u8], idx: I) -> Result<u32, ProtocolError>
|
||||||
|
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<I>(data: &[u8], idx: I) -> Result<i32, ProtocolError>
|
||||||
|
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<I>(data: &[u8], idx: I) -> Result<f64, ProtocolError>
|
||||||
|
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<Vec<u8>> for PointerEvent {
|
||||||
|
type Error = ProtocolError;
|
||||||
|
|
||||||
|
fn try_from(data: Vec<u8>) -> Result<Self, ProtocolError> {
|
||||||
|
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<u8> {
|
||||||
|
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<Vec<u8>> for KeyboardEvent {
|
||||||
|
type Error = ProtocolError;
|
||||||
|
|
||||||
|
fn try_from(data: Vec<u8>) -> Result<Self, ProtocolError> {
|
||||||
|
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())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -40,8 +40,8 @@ async fn input_emulation_test(config: Config) -> Result<()> {
|
|||||||
let (relative_x, relative_y) = (relative_motion.0 as f64, relative_motion.1 as f64);
|
let (relative_x, relative_y) = (relative_motion.0 as f64, relative_motion.1 as f64);
|
||||||
let event = Event::Pointer(PointerEvent::Motion {
|
let event = Event::Pointer(PointerEvent::Motion {
|
||||||
time: 0,
|
time: 0,
|
||||||
relative_x,
|
dx: relative_x,
|
||||||
relative_y,
|
dy: relative_y,
|
||||||
});
|
});
|
||||||
emulation.consume(event, 0).await?;
|
emulation.consume(event, 0).await?;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -116,7 +116,7 @@ impl Server {
|
|||||||
sender_tx.clone(),
|
sender_tx.clone(),
|
||||||
capture_channel.clone(),
|
capture_channel.clone(),
|
||||||
timer_tx,
|
timer_tx,
|
||||||
)?;
|
);
|
||||||
|
|
||||||
// create dns resolver
|
// create dns resolver
|
||||||
let resolver = dns::DnsResolver::new().await?;
|
let resolver = dns::DnsResolver::new().await?;
|
||||||
|
|||||||
@@ -1,12 +1,16 @@
|
|||||||
use anyhow::{anyhow, Result};
|
|
||||||
use std::net::SocketAddr;
|
use std::net::SocketAddr;
|
||||||
|
|
||||||
|
use thiserror::Error;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
sync::mpsc::{Receiver, Sender},
|
sync::mpsc::{Receiver, Sender},
|
||||||
task::JoinHandle,
|
task::JoinHandle,
|
||||||
};
|
};
|
||||||
|
|
||||||
use crate::{client::ClientHandle, config::EmulationBackend, server::State};
|
use crate::{
|
||||||
|
client::{ClientHandle, ClientManager},
|
||||||
|
config::EmulationBackend,
|
||||||
|
server::State,
|
||||||
|
};
|
||||||
use input_emulation::{
|
use input_emulation::{
|
||||||
self,
|
self,
|
||||||
error::{EmulationCreationError, EmulationError},
|
error::{EmulationCreationError, EmulationError},
|
||||||
@@ -14,7 +18,7 @@ use input_emulation::{
|
|||||||
};
|
};
|
||||||
use input_event::{Event, KeyboardEvent};
|
use input_event::{Event, KeyboardEvent};
|
||||||
|
|
||||||
use super::{CaptureEvent, Server};
|
use super::{network_task::NetworkError, CaptureEvent, Server};
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub enum EmulationEvent {
|
pub enum EmulationEvent {
|
||||||
@@ -31,29 +35,61 @@ pub enum EmulationEvent {
|
|||||||
pub fn new(
|
pub fn new(
|
||||||
backend: Option<EmulationBackend>,
|
backend: Option<EmulationBackend>,
|
||||||
server: Server,
|
server: Server,
|
||||||
mut udp_rx: Receiver<Result<(Event, SocketAddr)>>,
|
udp_rx: Receiver<Result<(Event, SocketAddr), NetworkError>>,
|
||||||
sender_tx: Sender<(Event, SocketAddr)>,
|
sender_tx: Sender<(Event, SocketAddr)>,
|
||||||
capture_tx: Sender<CaptureEvent>,
|
capture_tx: Sender<CaptureEvent>,
|
||||||
timer_tx: Sender<()>,
|
timer_tx: Sender<()>,
|
||||||
) -> Result<(JoinHandle<Result<()>>, Sender<EmulationEvent>), EmulationCreationError> {
|
) -> (
|
||||||
let (tx, mut rx) = tokio::sync::mpsc::channel(32);
|
JoinHandle<Result<(), LanMouseEmulationError>>,
|
||||||
let emulate_task = tokio::task::spawn_local(async move {
|
Sender<EmulationEvent>,
|
||||||
let backend = backend.map(|b| b.into());
|
) {
|
||||||
let mut emulate = input_emulation::create(backend).await?;
|
let (tx, rx) = tokio::sync::mpsc::channel(32);
|
||||||
let mut last_ignored = None;
|
let emulation_task =
|
||||||
|
emulation_task(backend, rx, server, udp_rx, sender_tx, capture_tx, timer_tx);
|
||||||
|
let emulate_task = tokio::task::spawn_local(emulation_task);
|
||||||
|
(emulate_task, tx)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub enum LanMouseEmulationError {
|
||||||
|
#[error("error creating input-emulation: `{0}`")]
|
||||||
|
Create(#[from] EmulationCreationError),
|
||||||
|
#[error("error emulating input: `{0}`")]
|
||||||
|
Emulate(#[from] EmulationError),
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn emulation_task(
|
||||||
|
backend: Option<EmulationBackend>,
|
||||||
|
mut rx: Receiver<EmulationEvent>,
|
||||||
|
server: Server,
|
||||||
|
mut udp_rx: Receiver<Result<(Event, SocketAddr), NetworkError>>,
|
||||||
|
sender_tx: Sender<(Event, SocketAddr)>,
|
||||||
|
capture_tx: Sender<CaptureEvent>,
|
||||||
|
timer_tx: Sender<()>,
|
||||||
|
) -> Result<(), LanMouseEmulationError> {
|
||||||
|
let backend = backend.map(|b| b.into());
|
||||||
|
let mut emulation = input_emulation::create(backend).await?;
|
||||||
|
|
||||||
|
let mut last_ignored = None;
|
||||||
loop {
|
loop {
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
udp_event = udp_rx.recv() => {
|
udp_event = udp_rx.recv() => {
|
||||||
let udp_event = udp_event.ok_or(anyhow!("receiver closed"))??;
|
let udp_event = match udp_event {
|
||||||
handle_udp_rx(&server, &capture_tx, &mut emulate, &sender_tx, &mut last_ignored, udp_event, &timer_tx).await?;
|
Some(Ok(e)) => e,
|
||||||
|
Some(Err(e)) => {
|
||||||
|
log::warn!("network error: {e}");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
None => break,
|
||||||
|
};
|
||||||
|
handle_udp_rx(&server, &capture_tx, &mut emulation, &sender_tx, &mut last_ignored, udp_event, &timer_tx).await?;
|
||||||
}
|
}
|
||||||
emulate_event = rx.recv() => {
|
emulate_event = rx.recv() => {
|
||||||
match emulate_event {
|
match emulate_event {
|
||||||
Some(e) => match e {
|
Some(e) => match e {
|
||||||
EmulationEvent::Create(h) => emulate.create(h).await,
|
EmulationEvent::Create(h) => emulation.create(h).await,
|
||||||
EmulationEvent::Destroy(h) => emulate.destroy(h).await,
|
EmulationEvent::Destroy(h) => emulation.destroy(h).await,
|
||||||
EmulationEvent::ReleaseKeys(c) => release_keys(&server, &mut emulate, c).await?,
|
EmulationEvent::ReleaseKeys(c) => release_keys(&server, &mut emulation, c).await?,
|
||||||
EmulationEvent::Terminate => break,
|
EmulationEvent::Terminate => break,
|
||||||
},
|
},
|
||||||
None => break,
|
None => break,
|
||||||
@@ -63,19 +99,9 @@ pub fn new(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// release potentially still pressed keys
|
// release potentially still pressed keys
|
||||||
let clients = server
|
release_all_keys(&server, &mut emulation).await?;
|
||||||
.client_manager
|
|
||||||
.borrow()
|
|
||||||
.get_client_states()
|
|
||||||
.map(|(h, _)| h)
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
for client in clients {
|
|
||||||
release_keys(&server, &mut emulate, client).await?;
|
|
||||||
}
|
|
||||||
|
|
||||||
anyhow::Ok(())
|
Ok(())
|
||||||
});
|
|
||||||
Ok((emulate_task, tx))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_udp_rx(
|
async fn handle_udp_rx(
|
||||||
@@ -89,38 +115,15 @@ async fn handle_udp_rx(
|
|||||||
) -> Result<(), EmulationError> {
|
) -> Result<(), EmulationError> {
|
||||||
let (event, addr) = event;
|
let (event, addr) = event;
|
||||||
|
|
||||||
// get handle for addr
|
log::trace!("{:20} <-<-<-<------ {addr}", event.to_string());
|
||||||
let handle = match server.client_manager.borrow().get_client(addr) {
|
|
||||||
Some(a) => a,
|
// get client handle for addr
|
||||||
None => {
|
let Some(handle) =
|
||||||
if last_ignored.is_none() || last_ignored.is_some() && last_ignored.unwrap() != addr {
|
activate_client_if_exists(&mut server.client_manager.borrow_mut(), addr, last_ignored)
|
||||||
log::warn!("ignoring events from client {addr}");
|
else {
|
||||||
last_ignored.replace(addr);
|
|
||||||
}
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// next event can be logged as ignored again
|
|
||||||
last_ignored.take();
|
|
||||||
|
|
||||||
log::trace!("{:20} <-<-<-<------ {addr} ({handle})", event.to_string());
|
|
||||||
{
|
|
||||||
let mut client_manager = server.client_manager.borrow_mut();
|
|
||||||
let client_state = match client_manager.get_mut(handle) {
|
|
||||||
Some((_, s)) => s,
|
|
||||||
None => {
|
|
||||||
log::error!("unknown handle");
|
|
||||||
return Ok(());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// reset ttl for client and
|
|
||||||
client_state.alive = true;
|
|
||||||
// set addr as new default for this client
|
|
||||||
client_state.active_addr = Some(addr);
|
|
||||||
}
|
|
||||||
|
|
||||||
match (event, addr) {
|
match (event, addr) {
|
||||||
(Event::Pong(), _) => { /* ignore pong events */ }
|
(Event::Pong(), _) => { /* ignore pong events */ }
|
||||||
(Event::Ping(), addr) => {
|
(Event::Ping(), addr) => {
|
||||||
@@ -148,30 +151,22 @@ async fn handle_udp_rx(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
State::Receiving => {
|
State::Receiving => {
|
||||||
let mut ignore_event = false;
|
let ignore_event =
|
||||||
if let Event::Keyboard(KeyboardEvent::Key {
|
if let Event::Keyboard(KeyboardEvent::Key { key, state, .. }) = event {
|
||||||
time: _,
|
let (ignore_event, restart_timer) = update_client_keys(
|
||||||
|
&mut server.client_manager.borrow_mut(),
|
||||||
|
handle,
|
||||||
key,
|
key,
|
||||||
state,
|
state,
|
||||||
}) = event
|
);
|
||||||
{
|
// restart timer if necessary
|
||||||
let mut client_manager = server.client_manager.borrow_mut();
|
if restart_timer {
|
||||||
let client_state = if let Some((_, s)) = client_manager.get_mut(handle) {
|
|
||||||
s
|
|
||||||
} else {
|
|
||||||
log::error!("unknown handle");
|
|
||||||
return Ok(());
|
|
||||||
};
|
|
||||||
if state == 0 {
|
|
||||||
// ignore release event if key not pressed
|
|
||||||
ignore_event = !client_state.pressed_keys.remove(&key);
|
|
||||||
} else {
|
|
||||||
// ignore press event if key not released
|
|
||||||
ignore_event = !client_state.pressed_keys.insert(key);
|
|
||||||
let _ = timer_tx.try_send(());
|
let _ = timer_tx.try_send(());
|
||||||
}
|
}
|
||||||
}
|
ignore_event
|
||||||
// ignore double press / release events to
|
} else {
|
||||||
|
false
|
||||||
|
};
|
||||||
// workaround buggy rdp backend.
|
// workaround buggy rdp backend.
|
||||||
if !ignore_event {
|
if !ignore_event {
|
||||||
// consume event
|
// consume event
|
||||||
@@ -203,6 +198,22 @@ async fn handle_udp_rx(
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn release_all_keys(
|
||||||
|
server: &Server,
|
||||||
|
emulation: &mut Box<dyn InputEmulation>,
|
||||||
|
) -> Result<(), EmulationError> {
|
||||||
|
let clients = server
|
||||||
|
.client_manager
|
||||||
|
.borrow()
|
||||||
|
.get_client_states()
|
||||||
|
.map(|(h, _)| h)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
for client in clients {
|
||||||
|
release_keys(server, emulation, client).await?;
|
||||||
|
}
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
async fn release_keys(
|
async fn release_keys(
|
||||||
server: &Server,
|
server: &Server,
|
||||||
emulate: &mut Box<dyn InputEmulation>,
|
emulate: &mut Box<dyn InputEmulation>,
|
||||||
@@ -237,3 +248,50 @@ async fn release_keys(
|
|||||||
emulate.consume(event, client).await?;
|
emulate.consume(event, client).await?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn activate_client_if_exists(
|
||||||
|
client_manager: &mut ClientManager,
|
||||||
|
addr: SocketAddr,
|
||||||
|
last_ignored: &mut Option<SocketAddr>,
|
||||||
|
) -> Option<ClientHandle> {
|
||||||
|
let Some(handle) = client_manager.get_client(addr) else {
|
||||||
|
// log ignored if it is the first event from the client in a series
|
||||||
|
if last_ignored.is_none() || last_ignored.is_some() && last_ignored.unwrap() != addr {
|
||||||
|
log::warn!("ignoring events from client {addr}");
|
||||||
|
last_ignored.replace(addr);
|
||||||
|
}
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
// next event can be logged as ignored again
|
||||||
|
last_ignored.take();
|
||||||
|
|
||||||
|
let (_, client_state) = client_manager.get_mut(handle)?;
|
||||||
|
|
||||||
|
// reset ttl for client
|
||||||
|
client_state.alive = true;
|
||||||
|
// set addr as new default for this client
|
||||||
|
client_state.active_addr = Some(addr);
|
||||||
|
Some(handle)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_client_keys(
|
||||||
|
client_manager: &mut ClientManager,
|
||||||
|
handle: ClientHandle,
|
||||||
|
key: u32,
|
||||||
|
state: u8,
|
||||||
|
) -> (bool, bool) {
|
||||||
|
let Some(client_state) = client_manager.get_mut(handle).map(|(_, s)| s) else {
|
||||||
|
return (true, false);
|
||||||
|
};
|
||||||
|
|
||||||
|
// ignore double press / release events
|
||||||
|
let ignore_event = if state == 0 {
|
||||||
|
// ignore release event if key not pressed
|
||||||
|
!client_state.pressed_keys.remove(&key)
|
||||||
|
} else {
|
||||||
|
// ignore press event if key not released
|
||||||
|
!client_state.pressed_keys.insert(key)
|
||||||
|
};
|
||||||
|
let restart_timer = !client_state.pressed_keys.is_empty();
|
||||||
|
(ignore_event, restart_timer)
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
use std::net::SocketAddr;
|
use std::{io, net::SocketAddr};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use thiserror::Error;
|
||||||
use tokio::{
|
use tokio::{
|
||||||
net::UdpSocket,
|
net::UdpSocket,
|
||||||
sync::mpsc::{Receiver, Sender},
|
sync::mpsc::{Receiver, Sender},
|
||||||
@@ -8,7 +9,7 @@ use tokio::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::frontend::FrontendEvent;
|
use crate::frontend::FrontendEvent;
|
||||||
use input_event::Event;
|
use input_event::{Event, ProtocolError};
|
||||||
|
|
||||||
use super::Server;
|
use super::Server;
|
||||||
|
|
||||||
@@ -18,30 +19,24 @@ pub async fn new(
|
|||||||
) -> Result<(
|
) -> Result<(
|
||||||
JoinHandle<()>,
|
JoinHandle<()>,
|
||||||
Sender<(Event, SocketAddr)>,
|
Sender<(Event, SocketAddr)>,
|
||||||
Receiver<Result<(Event, SocketAddr)>>,
|
Receiver<Result<(Event, SocketAddr), NetworkError>>,
|
||||||
Sender<u16>,
|
Sender<u16>,
|
||||||
)> {
|
)> {
|
||||||
// bind the udp socket
|
// bind the udp socket
|
||||||
let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), server.port.get());
|
let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), server.port.get());
|
||||||
let mut socket = UdpSocket::bind(listen_addr).await?;
|
let mut socket = UdpSocket::bind(listen_addr).await?;
|
||||||
let (receiver_tx, receiver_rx) = tokio::sync::mpsc::channel(32);
|
let (receiver_tx, receiver_rx) = tokio::sync::mpsc::channel(32);
|
||||||
let (sender_tx, mut sender_rx) = tokio::sync::mpsc::channel(32);
|
let (sender_tx, sender_rx) = tokio::sync::mpsc::channel(32);
|
||||||
let (port_tx, mut port_rx) = tokio::sync::mpsc::channel(32);
|
let (port_tx, mut port_rx) = tokio::sync::mpsc::channel(32);
|
||||||
|
|
||||||
let udp_task = tokio::task::spawn_local(async move {
|
let udp_task = tokio::task::spawn_local(async move {
|
||||||
|
let mut sender_rx = sender_rx;
|
||||||
loop {
|
loop {
|
||||||
|
let udp_receiver = udp_receiver(&socket, &receiver_tx);
|
||||||
|
let udp_sender = udp_sender(&socket, &mut sender_rx);
|
||||||
tokio::select! {
|
tokio::select! {
|
||||||
event = receive_event(&socket) => {
|
_ = udp_receiver => { }
|
||||||
let _ = receiver_tx.send(event).await;
|
_ = udp_sender => { }
|
||||||
}
|
|
||||||
event = sender_rx.recv() => {
|
|
||||||
let Some((event, addr)) = event else {
|
|
||||||
break;
|
|
||||||
};
|
|
||||||
if let Err(e) = send_event(&socket, event, addr) {
|
|
||||||
log::warn!("udp send failed: {e}");
|
|
||||||
};
|
|
||||||
}
|
|
||||||
port = port_rx.recv() => {
|
port = port_rx.recv() => {
|
||||||
let Some(port) = port else {
|
let Some(port) = port else {
|
||||||
break;
|
break;
|
||||||
@@ -67,7 +62,6 @@ pub async fn new(
|
|||||||
)).await;
|
)).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -75,7 +69,37 @@ pub async fn new(
|
|||||||
Ok((udp_task, sender_tx, receiver_rx, port_tx))
|
Ok((udp_task, sender_tx, receiver_rx, port_tx))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn receive_event(socket: &UdpSocket) -> Result<(Event, SocketAddr)> {
|
async fn udp_receiver(
|
||||||
|
socket: &UdpSocket,
|
||||||
|
receiver_tx: &Sender<Result<(Event, SocketAddr), NetworkError>>,
|
||||||
|
) {
|
||||||
|
loop {
|
||||||
|
let event = receive_event(&socket).await;
|
||||||
|
let _ = receiver_tx.send(event).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn udp_sender(socket: &UdpSocket, rx: &mut Receiver<(Event, SocketAddr)>) {
|
||||||
|
loop {
|
||||||
|
let (event, addr) = match rx.recv().await {
|
||||||
|
Some(e) => e,
|
||||||
|
None => return,
|
||||||
|
};
|
||||||
|
if let Err(e) = send_event(&socket, event, addr) {
|
||||||
|
log::warn!("udp send failed: {e}");
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
pub(crate) enum NetworkError {
|
||||||
|
#[error(transparent)]
|
||||||
|
Protocol(#[from] ProtocolError),
|
||||||
|
#[error("network error: `{0}`")]
|
||||||
|
Io(#[from] io::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn receive_event(socket: &UdpSocket) -> Result<(Event, SocketAddr), NetworkError> {
|
||||||
let mut buf = vec![0u8; 22];
|
let mut buf = vec![0u8; 22];
|
||||||
let (_amt, src) = socket.recv_from(&mut buf).await?;
|
let (_amt, src) = socket.recv_from(&mut buf).await?;
|
||||||
Ok((Event::try_from(buf)?, src))
|
Ok((Event::try_from(buf)?, src))
|
||||||
|
|||||||
Reference in New Issue
Block a user