add tests for capture and emulation

This commit is contained in:
Ferdinand Schober
2024-04-11 13:53:49 +02:00
parent 141ea2809d
commit f7edfecba9
7 changed files with 120 additions and 4 deletions

View File

@@ -25,7 +25,7 @@ pub mod x11;
/// fallback input capture (does not produce events)
pub mod dummy;
pub async fn create() -> Box<dyn InputCapture> {
pub async fn create() -> Box<dyn InputCapture<Item = io::Result<(ClientHandle, Event)>>> {
#[cfg(target_os = "macos")]
match macos::MacOSInputCapture::new() {
Ok(p) => return Box::new(p),

42
src/capture_test.rs Normal file
View File

@@ -0,0 +1,42 @@
use crate::capture;
use crate::client::{ClientEvent, Position};
use crate::event::{Event, KeyboardEvent};
use anyhow::{anyhow, Result};
use futures::StreamExt;
use tokio::task::LocalSet;
pub fn run() -> Result<()> {
log::info!("running input capture test");
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
.build()?;
runtime.block_on(LocalSet::new().run_until(input_capture_test()))
}
async fn input_capture_test() -> Result<()> {
log::info!("creating input capture");
let mut input_capture = capture::create().await;
log::info!("creating clients");
input_capture.notify(ClientEvent::Create(0, Position::Left))?;
input_capture.notify(ClientEvent::Create(1, Position::Right))?;
input_capture.notify(ClientEvent::Create(2, Position::Top))?;
input_capture.notify(ClientEvent::Create(3, Position::Bottom))?;
loop {
let (client, event) = input_capture
.next()
.await
.ok_or(anyhow!("capture stream closed"))??;
let pos = match client {
0 => Position::Left,
1 => Position::Right,
2 => Position::Top,
_ => Position::Bottom,
};
log::info!("position: {pos}, event: {event}");
if let Event::Keyboard(KeyboardEvent::Key { key: 1, .. }) = event {
input_capture.release()?;
}
}
}

View File

@@ -59,6 +59,14 @@ struct CliArgs {
/// run only the service as a daemon without the frontend
#[arg(short, long)]
daemon: bool,
/// test input capture
#[arg(long)]
test_capture: bool,
/// test input emulation
#[arg(long)]
test_emulation: bool,
}
#[derive(Debug, PartialEq, Eq)]
@@ -74,6 +82,8 @@ pub struct Config {
pub clients: Vec<(TomlClient, Position)>,
pub daemon: bool,
pub release_bind: Vec<scancode::Linux>,
pub test_capture: bool,
pub test_emulation: bool,
}
pub struct ConfigClient {
@@ -169,6 +179,8 @@ impl Config {
}
let daemon = args.daemon;
let test_capture = args.test_capture;
let test_emulation = args.test_emulation;
Ok(Config {
daemon,
@@ -176,6 +188,8 @@ impl Config {
clients,
port,
release_bind,
test_capture,
test_emulation,
})
}

46
src/emulation_test.rs Normal file
View File

@@ -0,0 +1,46 @@
use std::f64::consts::PI;
use std::time::{Duration, Instant};
use anyhow::Result;
use tokio::task::LocalSet;
use crate::client::{ClientEvent, Position};
use crate::emulate;
use crate::event::{Event, PointerEvent};
pub fn run() -> Result<()> {
log::info!("running input emulation test");
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_io()
.enable_time()
.build()?;
runtime.block_on(LocalSet::new().run_until(input_emulation_test()))
}
const FREQUENCY_HZ: f64 = 1.0;
const RADIUS: f64 = 100.0;
async fn input_emulation_test() -> Result<()> {
let mut emulation = emulate::create().await;
emulation.notify(ClientEvent::Create(0, Position::Left)).await;
let start = Instant::now();
let mut offset = (0, 0);
loop {
tokio::select! {
_ = emulation.dispatch() => {}
_ = tokio::time::sleep(Duration::from_millis(1)) => {
let elapsed = start.elapsed();
let elapsed_sec_f64 = elapsed.as_secs_f64();
let second_fraction = elapsed_sec_f64 - elapsed_sec_f64 as u64 as f64;
let radians = second_fraction * 2. * PI * FREQUENCY_HZ;
let new_offset_f = (radians.cos() * RADIUS * 2., (radians * 2.).sin() * RADIUS);
let new_offset = (new_offset_f.0 as i32, new_offset_f.1 as i32);
if new_offset != offset {
let relative_motion = (new_offset.0 - offset.0, new_offset.1 - offset.1);
offset = new_offset;
let (relative_x, relative_y) = (relative_motion.0 as f64, relative_motion.1 as f64);
emulation.consume(Event::Pointer(PointerEvent::Motion {time: 0, relative_x, relative_y }), 0).await;
}
}
}
}
}

View File

@@ -1,3 +1,4 @@
use crate::scancode;
use anyhow::{anyhow, Result};
use std::{
error::Error,
@@ -101,7 +102,14 @@ impl Display for KeyboardEvent {
time: _,
key,
state,
} => write!(f, "key({key}, {state})"),
} => {
let scan = scancode::Linux::try_from(*key);
if let Ok(scan) = scan {
write!(f, "key({scan:?}, {state})")
} else {
write!(f, "key({key}, {state})")
}
}
KeyboardEvent::Modifiers {
mods_depressed,
mods_latched,

View File

@@ -7,5 +7,7 @@ pub mod server;
pub mod capture;
pub mod emulate;
pub mod capture_test;
pub mod emulation_test;
pub mod frontend;
pub mod scancode;

View File

@@ -2,7 +2,7 @@ use anyhow::Result;
use std::process::{self, Child, Command};
use env_logger::Env;
use lan_mouse::{config::Config, frontend, server::Server};
use lan_mouse::{capture_test, config::Config, emulation_test, frontend, server::Server};
use tokio::task::LocalSet;
@@ -31,7 +31,11 @@ pub fn run() -> Result<()> {
log::debug!("{config:?}");
log::info!("release bind: {:?}", config.release_bind);
if config.daemon {
if config.test_capture {
capture_test::run()?;
} else if config.test_emulation {
emulation_test::run()?;
} else if config.daemon {
// if daemon is specified we run the service
run_service(&config)?;
} else {