Compare commits

...

6 Commits

Author SHA1 Message Date
Ferdinand Schober
281cb406dd chore: Release 2024-07-30 11:06:04 +02:00
Ferdinand Schober
06ac390dbf chore: Release 2024-07-30 11:05:03 +02:00
Ferdinand Schober
dcc9250b6d fix repository url 2024-07-30 11:04:21 +02:00
Ferdinand Schober
376ae50b45 chore: Release 2024-07-30 11:03:08 +02:00
Ferdinand Schober
0e2c749b29 fix conditional compilation 2024-07-30 10:52:56 +02:00
Ferdinand Schober
127c3366bf derive barrier_id from cursor position (#162)
this should fix #140
2024-07-19 15:23:04 +02:00
7 changed files with 97 additions and 33 deletions

4
Cargo.lock generated
View File

@@ -1192,7 +1192,7 @@ dependencies = [
[[package]]
name = "input-capture"
version = "0.1.0"
version = "0.2.0"
dependencies = [
"ashpd",
"async-trait",
@@ -1240,7 +1240,7 @@ dependencies = [
[[package]]
name = "input-event"
version = "0.1.0"
version = "0.2.1"
dependencies = [
"futures-core",
"log",

View File

@@ -7,16 +7,16 @@ description = "Software KVM Switch / mouse & keyboard sharing software for Local
version = "0.8.0"
edition = "2021"
license = "GPL-3.0-or-later"
repository = "https://github.com/ferdinandschober/lan-mouse"
repository = "https://github.com/feschber/lan-mouse"
[profile.release]
strip = true
lto = "fat"
[dependencies]
input-event = { path = "input-event", version = "0.1.0" }
input-event = { path = "input-event", version = "0.2.1" }
input-emulation = { path = "input-emulation", version = "0.1.0", default-features = false }
input-capture = { path = "input-capture", version = "0.1.0", default-features = false }
input-capture = { path = "input-capture", version = "0.2.0", default-features = false }
hickory-resolver = "0.24.1"
toml = "0.8"

View File

@@ -1,16 +1,16 @@
[package]
name = "input-capture"
description = "cross-platform input-capture library used by lan-mouse"
version = "0.1.0"
version = "0.2.0"
edition = "2021"
license = "GPL-3.0-or-later"
repository = "https://github.com/ferdinandschober/lan-mouse"
repository = "https://github.com/feschber/lan-mouse"
[dependencies]
futures = "0.3.28"
futures-core = "0.3.30"
log = "0.4.22"
input-event = { path = "../input-event", version = "0.1.0" }
input-event = { path = "../input-event", version = "0.2.1" }
memmap = "0.7"
tempfile = "3.8"
thiserror = "1.0.61"

View File

@@ -91,13 +91,35 @@ fn pos_to_barrier(r: &Region, pos: Position) -> (i32, i32, i32, i32) {
}
}
/// Ashpd does not expose fields
#[derive(Clone, Copy, Debug)]
struct ICBarrier {
barrier_id: BarrierID,
position: (i32, i32, i32, i32),
}
impl ICBarrier {
fn new(barrier_id: BarrierID, position: (i32, i32, i32, i32)) -> Self {
Self {
barrier_id,
position,
}
}
}
impl From<ICBarrier> for Barrier {
fn from(barrier: ICBarrier) -> Self {
Barrier::new(barrier.barrier_id, barrier.position)
}
}
fn select_barriers(
zones: &Zones,
clients: &Vec<(CaptureHandle, Position)>,
clients: &[(CaptureHandle, Position)],
next_barrier_id: &mut u32,
) -> (Vec<Barrier>, HashMap<BarrierID, CaptureHandle>) {
) -> (Vec<ICBarrier>, HashMap<BarrierID, CaptureHandle>) {
let mut client_for_barrier = HashMap::new();
let mut barriers: Vec<Barrier> = vec![];
let mut barriers: Vec<ICBarrier> = vec![];
for (handle, pos) in clients {
let mut client_barriers = zones
@@ -108,7 +130,7 @@ fn select_barriers(
*next_barrier_id = id + 1;
let position = pos_to_barrier(r, *pos);
client_for_barrier.insert(id, *handle);
Barrier::new(id, position)
ICBarrier::new(id, position)
})
.collect();
barriers.append(&mut client_barriers);
@@ -119,9 +141,9 @@ fn select_barriers(
async fn update_barriers(
input_capture: &InputCapture<'_>,
session: &Session<'_, InputCapture<'_>>,
active_clients: &Vec<(CaptureHandle, Position)>,
active_clients: &[(CaptureHandle, Position)],
next_barrier_id: &mut u32,
) -> Result<HashMap<BarrierID, CaptureHandle>, ashpd::Error> {
) -> Result<(Vec<ICBarrier>, HashMap<BarrierID, CaptureHandle>), ashpd::Error> {
let zones = input_capture.zones(session).await?.response()?;
log::debug!("zones: {zones:?}");
@@ -129,12 +151,13 @@ async fn update_barriers(
log::debug!("barriers: {barriers:?}");
log::debug!("client for barrier id: {id_map:?}");
let ashpd_barriers: Vec<Barrier> = barriers.iter().copied().map(|b| b.into()).collect();
let response = input_capture
.set_pointer_barriers(session, &barriers, zones.zone_set())
.set_pointer_barriers(session, &ashpd_barriers, zones.zone_set())
.await?;
let response = response.response()?;
log::debug!("{response:?}");
Ok(id_map)
Ok((barriers, id_map))
}
async fn create_session<'a>(
@@ -289,7 +312,7 @@ async fn do_capture(
input_capture,
&mut session,
&event_tx,
&mut active_clients,
&active_clients,
&mut next_barrier_id,
&notify_release,
(cancel_session.clone(), cancel_update.clone()),
@@ -332,7 +355,7 @@ async fn do_capture_session(
input_capture: &InputCapture<'_>,
session: &mut Session<'_, InputCapture<'_>>,
event_tx: &Sender<(CaptureHandle, Event)>,
active_clients: &mut Vec<(CaptureHandle, Position)>,
active_clients: &[(CaptureHandle, Position)],
next_barrier_id: &mut u32,
notify_release: &Notify,
cancel: (CancellationToken, CancellationToken),
@@ -345,7 +368,7 @@ async fn do_capture_session(
let (context, ei_event_stream) = connect_to_eis(input_capture, session).await?;
// set barriers
let client_for_barrier_id =
let (barriers, client_for_barrier_id) =
update_barriers(input_capture, session, active_clients, next_barrier_id).await?;
log::debug!("enabling session");
@@ -388,9 +411,15 @@ async fn do_capture_session(
let activated = activated.ok_or(CaptureError::ActivationClosed)?;
log::debug!("activated: {activated:?}");
let client = *client_for_barrier_id
.get(&activated.barrier_id().expect("no barrier id reported by compositor!"))
.expect("invalid barrier id");
// get barrier id from activation
let barrier_id = match activated.barrier_id() {
Some(bid) => bid,
// workaround for KDE plasma not reporting barrier ids
None => find_corresponding_client(&barriers, activated.cursor_position().expect("no cursor position reported by compositor")),
};
// find client corresponding to barrier
let client = *client_for_barrier_id.get(&barrier_id).expect("invalid barrier id");
current_client.replace(Some(client));
// client entered => send event
@@ -462,6 +491,7 @@ async fn release_capture<'a>(
let (x, y) = activated
.cursor_position()
.expect("compositor did not report cursor position!");
log::debug!("client entered @ ({x}, {y})");
let pos = active_clients
.iter()
.filter(|(c, _)| *c == current_client)
@@ -483,6 +513,34 @@ async fn release_capture<'a>(
Ok(())
}
fn find_corresponding_client(barriers: &[ICBarrier], pos: (f32, f32)) -> BarrierID {
barriers
.iter()
.copied()
.min_by_key(|b| {
let (x1, y1, x2, y2) = b.position;
let (x1, y1, x2, y2) = (x1 as f32, y1 as f32, x2 as f32, y2 as f32);
distance_to_line(((x1, y1), (x2, y2)), pos) as i32
})
.expect("could not find barrier corresponding to client")
.barrier_id
}
fn distance_to_line(line: ((f32, f32), (f32, f32)), p: (f32, f32)) -> f32 {
let ((x1, y1), (x2, y2)) = line;
let (x0, y0) = p;
/*
* we use the fact that for the triangle spanned by the line and p,
* the height of the triangle is the desired distance and can be calculated by
* h = 2A / b with b being the line_length and
*/
let double_triangle_area = ((y2 - y1) * x0 - (x2 - x1) * y0 + x2 * y1 - y2 * x1).abs();
let line_length = ((y2 - y1).powf(2.0) + (x2 - x1).powf(2.0)).sqrt();
let distance = double_triangle_area / line_length;
log::debug!("distance to line({line:?}, {p:?}) = {distance}");
distance
}
static ALL_CAPABILITIES: &[DeviceCapability] = &[
DeviceCapability::Pointer,
DeviceCapability::PointerAbsolute,

View File

@@ -4,13 +4,13 @@ description = "cross-platform input emulation library used by lan-mouse"
version = "0.1.0"
edition = "2021"
license = "GPL-3.0-or-later"
repository = "https://github.com/ferdinandschober/lan-mouse"
repository = "https://github.com/feschber/lan-mouse"
[dependencies]
async-trait = "0.1.80"
futures = "0.3.28"
log = "0.4.22"
input-event = { path = "../input-event", version = "0.1.0" }
input-event = { path = "../input-event", version = "0.2.1" }
thiserror = "1.0.61"
tokio = { version = "1.32.0", features = [
"io-util",

View File

@@ -87,19 +87,25 @@ pub enum EmulationCreationError {
impl EmulationCreationError {
/// request was intentionally denied by the user
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
pub(crate) fn cancelled_by_user(&self) -> bool {
matches!(
#[cfg(feature = "libei")]
if matches!(
self,
EmulationCreationError::Libei(LibeiEmulationCreationError::Ashpd(Response(
ResponseError::Cancelled,
))) | EmulationCreationError::Xdp(XdpEmulationCreationError::Ashpd(Response(
)))
) {
return true;
}
#[cfg(feature = "xdg_desktop_portal")]
if matches!(
self,
EmulationCreationError::Xdp(XdpEmulationCreationError::Ashpd(Response(
ResponseError::Cancelled,
)))
)
}
#[cfg(not(all(unix, feature = "libei", not(target_os = "macos"))))]
pub(crate) fn cancelled_by_user(&self) -> bool {
) {
return true;
}
false
}
}

View File

@@ -1,10 +1,10 @@
[package]
name = "input-event"
description = "cross-platform input-event types for input-capture / input-emulation"
version = "0.1.0"
version = "0.2.1"
edition = "2021"
license = "GPL-3.0-or-later"
repository = "https://github.com/ferdinandschober/lan-mouse"
repository = "https://github.com/feschber/lan-mouse"
[dependencies]
futures-core = "0.3.30"