upgrade ashpd + reis (#226)

This commit is contained in:
Ferdinand Schober
2024-11-07 00:38:26 +01:00
committed by GitHub
parent 9d28fe6c7b
commit 1d25dfbe50
9 changed files with 84 additions and 246 deletions

117
Cargo.lock generated
View File

@@ -98,9 +98,9 @@ dependencies = [
[[package]] [[package]]
name = "ashpd" name = "ashpd"
version = "0.9.2" version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d43c03d9e36dd40cab48435be0b09646da362c278223ca535493877b2c1dee9" checksum = "e9c39d707614dbcc6bed00015539f488d8e3fe3e66ed60961efc0c90f4b380b3"
dependencies = [ dependencies = [
"enumflags2", "enumflags2",
"futures-channel", "futures-channel",
@@ -271,15 +271,6 @@ version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de" checksum = "b048fb63fd8b5923fc5aa7b340d8e156aec7ec02f0c78fa8a6ddc2613f6f71de"
[[package]]
name = "block-buffer"
version = "0.10.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71"
dependencies = [
"generic-array",
]
[[package]] [[package]]
name = "blocking" name = "blocking"
version = "1.6.1" version = "1.6.1"
@@ -454,47 +445,18 @@ dependencies = [
"libc", "libc",
] ]
[[package]]
name = "cpufeatures"
version = "0.2.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "608697df725056feaccfa42cffdaeeec3fccc4ffc38358ecd19b243e716a78e0"
dependencies = [
"libc",
]
[[package]] [[package]]
name = "crossbeam-utils" name = "crossbeam-utils"
version = "0.8.20" version = "0.8.20"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80" checksum = "22ec99545bb0ed0ea7bb9b8e1e9122ea386ff8a48c0922e43f36d45ab09e0e80"
[[package]]
name = "crypto-common"
version = "0.1.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3"
dependencies = [
"generic-array",
"typenum",
]
[[package]] [[package]]
name = "data-encoding" name = "data-encoding"
version = "2.6.0" version = "2.6.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2" checksum = "e8566979429cf69b49a5c740c60791108e86440e8be149bbea4fe54d2c32d6e2"
[[package]]
name = "digest"
version = "0.10.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292"
dependencies = [
"block-buffer",
"crypto-common",
]
[[package]] [[package]]
name = "displaydoc" name = "displaydoc"
version = "0.2.5" version = "0.2.5"
@@ -831,16 +793,6 @@ dependencies = [
"system-deps", "system-deps",
] ]
[[package]]
name = "generic-array"
version = "0.14.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a"
dependencies = [
"typenum",
"version_check",
]
[[package]] [[package]]
name = "getrandom" name = "getrandom"
version = "0.2.15" version = "0.2.15"
@@ -1975,9 +1927,9 @@ checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "reis" name = "reis"
version = "0.2.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "635de3608f72e8d067f8972f9401619ac7a3f34a0a17340fa0e3f9db57e067a3" checksum = "827073dbe443c57fd72ae05491c6b94213218627ac6ac169850673b0cb7034f1"
dependencies = [ dependencies = [
"futures", "futures",
"rustix", "rustix",
@@ -2098,17 +2050,6 @@ dependencies = [
"serde", "serde",
] ]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "1.3.0"
@@ -2404,12 +2345,6 @@ dependencies = [
"once_cell", "once_cell",
] ]
[[package]]
name = "typenum"
version = "1.17.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825"
[[package]] [[package]]
name = "uds_windows" name = "uds_windows"
version = "1.1.0" version = "1.1.0"
@@ -2484,12 +2419,6 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b" checksum = "852e951cb7832cb45cb1169900d19760cfa39b82bc0ea9c0e5a14ae88411c98b"
[[package]]
name = "version_check"
version = "0.9.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "wasi" name = "wasi"
version = "0.11.0+wasi-snapshot-preview1" version = "0.11.0+wasi-snapshot-preview1"
@@ -2918,9 +2847,9 @@ dependencies = [
[[package]] [[package]]
name = "zbus" name = "zbus"
version = "4.4.0" version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" checksum = "4e0c8d6fdd4c4ac401fd298fd169d538a386e9df3c32ff136e8745dfa443dbd8"
dependencies = [ dependencies = [
"async-broadcast", "async-broadcast",
"async-process", "async-process",
@@ -2929,20 +2858,18 @@ dependencies = [
"enumflags2", "enumflags2",
"event-listener", "event-listener",
"futures-core", "futures-core",
"futures-sink",
"futures-util", "futures-util",
"hex", "hex",
"nix", "nix",
"ordered-stream", "ordered-stream",
"rand",
"serde", "serde",
"serde_repr", "serde_repr",
"sha1",
"static_assertions", "static_assertions",
"tokio", "tokio",
"tracing", "tracing",
"uds_windows", "uds_windows",
"windows-sys 0.52.0", "windows-sys 0.59.0",
"winnow",
"xdg-home", "xdg-home",
"zbus_macros", "zbus_macros",
"zbus_names", "zbus_names",
@@ -2951,25 +2878,28 @@ dependencies = [
[[package]] [[package]]
name = "zbus_macros" name = "zbus_macros"
version = "4.4.0" version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" checksum = "ed1f3cc6313cbefd539b4eee6de36a990897ab6cc2c30a82b3ac29ef9099e6c0"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
"quote", "quote",
"syn", "syn",
"zbus_names",
"zvariant",
"zvariant_utils", "zvariant_utils",
] ]
[[package]] [[package]]
name = "zbus_names" name = "zbus_names"
version = "3.0.0" version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" checksum = "856b7a38811f71846fd47856ceee8bccaec8399ff53fb370247e66081ace647b"
dependencies = [ dependencies = [
"serde", "serde",
"static_assertions", "static_assertions",
"winnow",
"zvariant", "zvariant",
] ]
@@ -3039,23 +2969,25 @@ dependencies = [
[[package]] [[package]]
name = "zvariant" name = "zvariant"
version = "4.2.0" version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" checksum = "a1200ee6ac32f1e5a312e455a949a4794855515d34f9909f4a3e082d14e1a56f"
dependencies = [ dependencies = [
"endi", "endi",
"enumflags2", "enumflags2",
"serde", "serde",
"static_assertions", "static_assertions",
"url", "url",
"winnow",
"zvariant_derive", "zvariant_derive",
"zvariant_utils",
] ]
[[package]] [[package]]
name = "zvariant_derive" name = "zvariant_derive"
version = "4.2.0" version = "5.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" checksum = "687e3b97fae6c9104fbbd36c73d27d149abf04fb874e2efbd84838763daa8916"
dependencies = [ dependencies = [
"proc-macro-crate", "proc-macro-crate",
"proc-macro2", "proc-macro2",
@@ -3066,11 +2998,14 @@ dependencies = [
[[package]] [[package]]
name = "zvariant_utils" name = "zvariant_utils"
version = "2.1.0" version = "3.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" checksum = "20d1d011a38f12360e5fcccceeff5e2c42a8eb7f27f0dcba97a0862ede05c9c6"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"serde",
"static_assertions",
"syn", "syn",
"winnow",
] ]

View File

@@ -40,10 +40,10 @@ wayland-protocols-wlr = { version = "0.3.1", features = [
"client", "client",
], optional = true } ], optional = true }
x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true } x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true }
ashpd = { version = "0.9", default-features = false, features = [ ashpd = { version = "0.10", default-features = false, features = [
"tokio", "tokio",
], optional = true } ], optional = true }
reis = { version = "0.2", features = ["tokio"], optional = true } reis = { version = "0.4", features = ["tokio"], optional = true }
[target.'cfg(target_os="macos")'.dependencies] [target.'cfg(target_os="macos")'.dependencies]
core-graphics = { version = "0.23", features = ["highsierra"] } core-graphics = { version = "0.23", features = ["highsierra"] }

View File

@@ -19,26 +19,10 @@ use wayland_client::{
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))] #[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
use ashpd::desktop::ResponseError; use ashpd::desktop::ResponseError;
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
use reis::tokio::{EiConvertEventStreamError, HandshakeError};
#[cfg(target_os = "macos")] #[cfg(target_os = "macos")]
use core_graphics::base::CGError; use core_graphics::base::CGError;
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
#[derive(Debug, Error)]
#[error("error in libei stream: {inner:?}")]
pub struct ReisConvertEventStreamError {
inner: EiConvertEventStreamError,
}
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
impl From<EiConvertEventStreamError> for ReisConvertEventStreamError {
fn from(e: EiConvertEventStreamError) -> Self {
Self { inner: e }
}
}
#[derive(Debug, Error)] #[derive(Debug, Error)]
pub enum CaptureError { pub enum CaptureError {
#[error("activation stream closed unexpectedly")] #[error("activation stream closed unexpectedly")]
@@ -48,11 +32,8 @@ pub enum CaptureError {
#[error("io error: `{0}`")] #[error("io error: `{0}`")]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))] #[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
#[error("error in libei stream: `{0}`")] #[error("libei error: `{0}`")]
Reis(#[from] ReisConvertEventStreamError), Reis(#[from] reis::Error),
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
#[error("libei handshake failed: `{0}`")]
Handshake(#[from] HandshakeError),
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))] #[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
#[error(transparent)] #[error(transparent)]
Portal(#[from] ashpd::Error), Portal(#[from] ashpd::Error),

View File

@@ -1,6 +1,9 @@
use ashpd::{ use ashpd::{
desktop::{ desktop::{
input_capture::{Activated, Barrier, BarrierID, Capabilities, InputCapture, Region, Zones}, input_capture::{
Activated, ActivatedBarrier, Barrier, BarrierID, Capabilities, InputCapture, Region,
Zones,
},
Session, Session,
}, },
enumflags2::BitFlags, enumflags2::BitFlags,
@@ -8,14 +11,15 @@ use ashpd::{
use async_trait::async_trait; use async_trait::async_trait;
use futures::{FutureExt, StreamExt}; use futures::{FutureExt, StreamExt};
use reis::{ use reis::{
ei, ei::{self, handshake::ContextType},
event::{DeviceCapability, EiEvent}, event::{Connection, DeviceCapability, EiEvent},
tokio::{EiConvertEventStream, EiEventStream}, tokio::EiConvertEventStream,
}; };
use std::{ use std::{
cell::Cell, cell::Cell,
collections::HashMap, collections::HashMap,
io, io,
num::NonZeroU32,
os::unix::net::UnixStream, os::unix::net::UnixStream,
pin::Pin, pin::Pin,
rc::Rc, rc::Rc,
@@ -32,14 +36,13 @@ use tokio::{
use tokio_util::sync::CancellationToken; use tokio_util::sync::CancellationToken;
use futures_core::Stream; use futures_core::Stream;
use once_cell::sync::Lazy;
use input_event::Event; use input_event::Event;
use crate::CaptureEvent; use crate::CaptureEvent;
use super::{ use super::{
error::{CaptureError, LibeiCaptureCreationError, ReisConvertEventStreamError}, error::{CaptureError, LibeiCaptureCreationError},
Capture as LanMouseInputCapture, Position, Capture as LanMouseInputCapture, Position,
}; };
@@ -65,22 +68,6 @@ pub struct LibeiInputCapture<'a> {
terminated: bool, terminated: bool,
} }
static INTERFACES: Lazy<HashMap<&'static str, u32>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert("ei_connection", 1);
m.insert("ei_callback", 1);
m.insert("ei_pingpong", 1);
m.insert("ei_seat", 1);
m.insert("ei_device", 2);
m.insert("ei_pointer", 1);
m.insert("ei_pointer_absolute", 1);
m.insert("ei_scroll", 1);
m.insert("ei_button", 1);
m.insert("ei_keyboard", 1);
m.insert("ei_touchscreen", 1);
m
});
/// returns (start pos, end pos), inclusive /// returns (start pos, end pos), inclusive
fn pos_to_barrier(r: &Region, pos: Position) -> (i32, i32, i32, i32) { fn pos_to_barrier(r: &Region, pos: Position) -> (i32, i32, i32, i32) {
let (x, y) = (r.x_offset(), r.y_offset()); let (x, y) = (r.x_offset(), r.y_offset());
@@ -118,7 +105,7 @@ impl From<ICBarrier> for Barrier {
fn select_barriers( fn select_barriers(
zones: &Zones, zones: &Zones,
clients: &[Position], clients: &[Position],
next_barrier_id: &mut u32, next_barrier_id: &mut NonZeroU32,
) -> (Vec<ICBarrier>, HashMap<BarrierID, Position>) { ) -> (Vec<ICBarrier>, HashMap<BarrierID, Position>) {
let mut pos_for_barrier = HashMap::new(); let mut pos_for_barrier = HashMap::new();
let mut barriers: Vec<ICBarrier> = vec![]; let mut barriers: Vec<ICBarrier> = vec![];
@@ -129,7 +116,9 @@ fn select_barriers(
.iter() .iter()
.map(|r| { .map(|r| {
let id = *next_barrier_id; let id = *next_barrier_id;
*next_barrier_id = id + 1; *next_barrier_id = next_barrier_id
.checked_add(1)
.expect("barrier id out of range");
let position = pos_to_barrier(r, *pos); let position = pos_to_barrier(r, *pos);
pos_for_barrier.insert(id, *pos); pos_for_barrier.insert(id, *pos);
ICBarrier::new(id, position) ICBarrier::new(id, position)
@@ -144,7 +133,7 @@ async fn update_barriers(
input_capture: &InputCapture<'_>, input_capture: &InputCapture<'_>,
session: &Session<'_, InputCapture<'_>>, session: &Session<'_, InputCapture<'_>>,
active_clients: &[Position], active_clients: &[Position],
next_barrier_id: &mut u32, next_barrier_id: &mut NonZeroU32,
) -> Result<(Vec<ICBarrier>, HashMap<BarrierID, Position>), ashpd::Error> { ) -> Result<(Vec<ICBarrier>, HashMap<BarrierID, Position>), ashpd::Error> {
let zones = input_capture.zones(session).await?.response()?; let zones = input_capture.zones(session).await?.response()?;
log::debug!("zones: {zones:?}"); log::debug!("zones: {zones:?}");
@@ -168,7 +157,7 @@ async fn create_session<'a>(
log::debug!("creating input capture session"); log::debug!("creating input capture session");
input_capture input_capture
.create_session( .create_session(
&ashpd::WindowIdentifier::default(), None,
Capabilities::Keyboard | Capabilities::Pointer | Capabilities::Touchscreen, Capabilities::Keyboard | Capabilities::Pointer | Capabilities::Touchscreen,
) )
.await .await
@@ -177,7 +166,7 @@ async fn create_session<'a>(
async fn connect_to_eis( async fn connect_to_eis(
input_capture: &InputCapture<'_>, input_capture: &InputCapture<'_>,
session: &Session<'_, InputCapture<'_>>, session: &Session<'_, InputCapture<'_>>,
) -> Result<(ei::Context, EiConvertEventStream), CaptureError> { ) -> Result<(ei::Context, Connection, EiConvertEventStream), CaptureError> {
log::debug!("connect_to_eis"); log::debug!("connect_to_eis");
let fd = input_capture.connect_to_eis(session).await?; let fd = input_capture.connect_to_eis(session).await?;
@@ -187,17 +176,11 @@ async fn connect_to_eis(
// create ei context // create ei context
let context = ei::Context::new(stream)?; let context = ei::Context::new(stream)?;
let mut event_stream = EiEventStream::new(context.clone())?; let (conn, event_stream) = context
let response = reis::tokio::ei_handshake( .handshake_tokio("de.feschber.LanMouse", ContextType::Receiver)
&mut event_stream, .await?;
"de.feschber.LanMouse",
ei::handshake::ContextType::Receiver,
&INTERFACES,
)
.await?;
let event_stream = EiConvertEventStream::new(event_stream, response.serial);
Ok((context, event_stream)) Ok((context, conn, event_stream))
} }
async fn libei_event_handler( async fn libei_event_handler(
@@ -211,8 +194,7 @@ async fn libei_event_handler(
let ei_event = ei_event_stream let ei_event = ei_event_stream
.next() .next()
.await .await
.ok_or(CaptureError::EndOfStream)? .ok_or(CaptureError::EndOfStream)??;
.map_err(ReisConvertEventStreamError::from)?;
log::trace!("from ei: {ei_event:?}"); log::trace!("from ei: {ei_event:?}");
let client = current_pos.get(); let client = current_pos.get();
handle_ei_event(ei_event, client, &context, &event_tx, &release_session).await?; handle_ei_event(ei_event, client, &context, &event_tx, &release_session).await?;
@@ -268,7 +250,7 @@ async fn do_capture(
/* safety: libei_task does not outlive Self */ /* safety: libei_task does not outlive Self */
let input_capture = unsafe { &*input_capture }; let input_capture = unsafe { &*input_capture };
let mut active_clients: Vec<Position> = vec![]; let mut active_clients: Vec<Position> = vec![];
let mut next_barrier_id = 1u32; let mut next_barrier_id = NonZeroU32::new(1).expect("id must be non-zero");
let mut zones_changed = input_capture.receive_zones_changed().await?; let mut zones_changed = input_capture.receive_zones_changed().await?;
@@ -358,7 +340,7 @@ async fn do_capture_session(
session: &mut Session<'_, InputCapture<'_>>, session: &mut Session<'_, InputCapture<'_>>,
event_tx: &Sender<(Position, CaptureEvent)>, event_tx: &Sender<(Position, CaptureEvent)>,
active_clients: &[Position], active_clients: &[Position],
next_barrier_id: &mut u32, next_barrier_id: &mut NonZeroU32,
notify_release: &Notify, notify_release: &Notify,
cancel: (CancellationToken, CancellationToken), cancel: (CancellationToken, CancellationToken),
) -> Result<(), CaptureError> { ) -> Result<(), CaptureError> {
@@ -367,7 +349,7 @@ async fn do_capture_session(
let current_pos = Rc::new(Cell::new(None)); let current_pos = Rc::new(Cell::new(None));
// connect to eis server // connect to eis server
let (context, ei_event_stream) = connect_to_eis(input_capture, session).await?; let (context, _conn, ei_event_stream) = connect_to_eis(input_capture, session).await?;
// set barriers // set barriers
let (barriers, pos_for_barrier_id) = let (barriers, pos_for_barrier_id) =
@@ -415,9 +397,9 @@ async fn do_capture_session(
// get barrier id from activation // get barrier id from activation
let barrier_id = match activated.barrier_id() { let barrier_id = match activated.barrier_id() {
Some(bid) => bid, Some(ActivatedBarrier::Barrier(id)) => id,
// workaround for KDE plasma not reporting barrier ids // workaround for KDE plasma not reporting barrier ids
None => find_corresponding_client(&barriers, activated.cursor_position().expect("no cursor position reported by compositor")), Some(ActivatedBarrier::UnknownBarrier) | None => find_corresponding_client(&barriers, activated.cursor_position().expect("no cursor position reported by compositor")),
}; };
// find client corresponding to barrier // find client corresponding to barrier

View File

@@ -38,10 +38,10 @@ wayland-protocols-misc = { version = "0.3.1", features = [
"client", "client",
], optional = true } ], optional = true }
x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true } x11 = { version = "2.21.0", features = ["xlib", "xtest"], optional = true }
ashpd = { version = "0.9", default-features = false, features = [ ashpd = { version = "0.10", default-features = false, features = [
"tokio", "tokio",
], optional = true } ], optional = true }
reis = { version = "0.2", features = ["tokio"], optional = true } reis = { version = "0.4", features = ["tokio"], optional = true }
[target.'cfg(target_os="macos")'.dependencies] [target.'cfg(target_os="macos")'.dependencies]
bitflags = "2.5.0" bitflags = "2.5.0"

View File

@@ -8,8 +8,6 @@ pub enum InputEmulationError {
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))] #[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
use ashpd::{desktop::ResponseError, Error::Response}; use ashpd::{desktop::ResponseError, Error::Response};
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
use reis::tokio::EiConvertEventStreamError;
use std::io; use std::io;
use thiserror::Error; use thiserror::Error;
@@ -20,33 +18,13 @@ use wayland_client::{
ConnectError, DispatchError, ConnectError, DispatchError,
}; };
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
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,
}
#[cfg(all(unix, feature = "libei", not(target_os = "macos")))]
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")] #[error("event stream closed")]
EndOfStream, 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: `{0}`")]
Libei(#[from] reis::event::Error), Libei(#[from] reis::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),
@@ -150,7 +128,7 @@ pub enum LibeiEmulationCreationError {
#[error(transparent)] #[error(transparent)]
Io(#[from] std::io::Error), Io(#[from] std::io::Error),
#[error(transparent)] #[error(transparent)]
Handshake(#[from] HandshakeError), Reis(#[from] reis::Error),
} }
#[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))] #[cfg(all(unix, feature = "xdg_desktop_portal", not(target_os = "macos")))]

View File

@@ -1,23 +1,18 @@
use futures::{future, StreamExt}; use futures::{future, StreamExt};
use once_cell::sync::Lazy;
use std::{ use std::{
collections::HashMap,
io, io,
os::{fd::OwnedFd, unix::net::UnixStream}, os::{fd::OwnedFd, unix::net::UnixStream},
sync::{ sync::{
atomic::{AtomicBool, AtomicU32, Ordering}, atomic::{AtomicBool, Ordering},
Arc, Mutex, RwLock, Arc, Mutex, RwLock,
}, },
time::{SystemTime, UNIX_EPOCH}, time::{SystemTime, UNIX_EPOCH},
}; };
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use ashpd::{ use ashpd::desktop::{
desktop::{ remote_desktop::{DeviceType, RemoteDesktop},
remote_desktop::{DeviceType, RemoteDesktop}, PersistMode, Session,
PersistMode, Session,
},
WindowIdentifier,
}; };
use async_trait::async_trait; use async_trait::async_trait;
@@ -26,32 +21,16 @@ use reis::{
self, button::ButtonState, handshake::ContextType, keyboard::KeyState, Button, Keyboard, self, button::ButtonState, handshake::ContextType, keyboard::KeyState, Button, Keyboard,
Pointer, Scroll, Pointer, Scroll,
}, },
event::{DeviceCapability, DeviceEvent, EiEvent, SeatEvent}, event::{self, Connection, DeviceCapability, DeviceEvent, EiEvent, SeatEvent},
tokio::{ei_handshake, EiConvertEventStream, EiEventStream}, tokio::EiConvertEventStream,
}; };
use input_event::{Event, KeyboardEvent, PointerEvent}; use input_event::{Event, KeyboardEvent, PointerEvent};
use crate::error::{EmulationError, ReisConvertStreamError}; use crate::error::EmulationError;
use super::{error::LibeiEmulationCreationError, Emulation, EmulationHandle}; use super::{error::LibeiEmulationCreationError, Emulation, EmulationHandle};
static INTERFACES: Lazy<HashMap<&'static str, u32>> = Lazy::new(|| {
let mut m = HashMap::new();
m.insert("ei_connection", 1);
m.insert("ei_callback", 1);
m.insert("ei_pingpong", 1);
m.insert("ei_seat", 1);
m.insert("ei_device", 2);
m.insert("ei_pointer", 1);
m.insert("ei_pointer_absolute", 1);
m.insert("ei_scroll", 1);
m.insert("ei_button", 1);
m.insert("ei_keyboard", 1);
m.insert("ei_touchscreen", 1);
m
});
#[derive(Clone, Default)] #[derive(Clone, Default)]
struct Devices { struct Devices {
pointer: Arc<RwLock<Option<(ei::Device, ei::Pointer)>>>, pointer: Arc<RwLock<Option<(ei::Device, ei::Pointer)>>>,
@@ -62,11 +41,11 @@ struct Devices {
pub(crate) struct LibeiEmulation<'a> { pub(crate) struct LibeiEmulation<'a> {
context: ei::Context, context: ei::Context,
conn: event::Connection,
devices: Devices, devices: Devices,
ei_task: JoinHandle<()>, ei_task: JoinHandle<()>,
error: Arc<Mutex<Option<EmulationError>>>, error: Arc<Mutex<Option<EmulationError>>>,
libei_error: Arc<AtomicBool>, libei_error: Arc<AtomicBool>,
serial: AtomicU32,
_remote_desktop: RemoteDesktop<'a>, _remote_desktop: RemoteDesktop<'a>,
session: Session<'a, RemoteDesktop<'a>>, session: Session<'a, RemoteDesktop<'a>>,
} }
@@ -89,10 +68,7 @@ async fn get_ei_fd<'a>(
.await?; .await?;
log::info!("requesting permission for input emulation"); log::info!("requesting permission for input emulation");
let _devices = remote_desktop let _devices = remote_desktop.start(&session, None).await?.response()?;
.start(&session, &WindowIdentifier::default())
.await?
.response()?;
let fd = remote_desktop.connect_to_eis(&session).await?; let fd = remote_desktop.connect_to_eis(&session).await?;
Ok((remote_desktop, session, fd)) Ok((remote_desktop, session, fd))
@@ -104,20 +80,15 @@ impl<'a> LibeiEmulation<'a> {
let stream = UnixStream::from(eifd); let stream = UnixStream::from(eifd);
stream.set_nonblocking(true)?; stream.set_nonblocking(true)?;
let context = ei::Context::new(stream)?; let context = ei::Context::new(stream)?;
let mut events = EiEventStream::new(context.clone())?; let (conn, events) = context
let handshake = ei_handshake( .handshake_tokio("de.feschber.LanMouse", ContextType::Sender)
&mut events, .await?;
"de.feschber.LanMouse",
ContextType::Sender,
&INTERFACES,
)
.await?;
let events = EiConvertEventStream::new(events, handshake.serial);
let devices = Devices::default(); let devices = Devices::default();
let libei_error = Arc::new(AtomicBool::default()); let libei_error = Arc::new(AtomicBool::default());
let error = Arc::new(Mutex::new(None)); let error = Arc::new(Mutex::new(None));
let ei_handler = ei_task( let ei_handler = ei_task(
events, events,
conn.clone(),
context.clone(), context.clone(),
devices.clone(), devices.clone(),
libei_error.clone(), libei_error.clone(),
@@ -125,15 +96,13 @@ impl<'a> LibeiEmulation<'a> {
); );
let ei_task = tokio::task::spawn_local(ei_handler); let ei_task = tokio::task::spawn_local(ei_handler);
let serial = AtomicU32::new(handshake.serial);
Ok(Self { Ok(Self {
context, context,
conn,
devices, devices,
ei_task, ei_task,
error, error,
libei_error, libei_error,
serial,
_remote_desktop, _remote_desktop,
session, session,
}) })
@@ -169,7 +138,7 @@ impl<'a> Emulation for LibeiEmulation<'a> {
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(dx as f32, dy as f32); p.motion_relative(dx as f32, dy as f32);
d.frame(self.serial.load(Ordering::SeqCst), now); d.frame(self.conn.serial(), now);
} }
} }
PointerEvent::Button { PointerEvent::Button {
@@ -186,7 +155,7 @@ impl<'a> Emulation for LibeiEmulation<'a> {
_ => ButtonState::Press, _ => ButtonState::Press,
}, },
); );
d.frame(self.serial.load(Ordering::SeqCst), now); d.frame(self.conn.serial(), now);
} }
} }
PointerEvent::Axis { PointerEvent::Axis {
@@ -200,7 +169,7 @@ impl<'a> Emulation for LibeiEmulation<'a> {
0 => s.scroll(0., value as f32), 0 => s.scroll(0., value as f32),
_ => s.scroll(value as f32, 0.), _ => s.scroll(value as f32, 0.),
} }
d.frame(self.serial.load(Ordering::SeqCst), now); d.frame(self.conn.serial(), now);
} }
} }
PointerEvent::AxisDiscrete120 { axis, value } => { PointerEvent::AxisDiscrete120 { axis, value } => {
@@ -210,7 +179,7 @@ impl<'a> Emulation for LibeiEmulation<'a> {
0 => s.scroll_discrete(0, value), 0 => s.scroll_discrete(0, value),
_ => s.scroll_discrete(value, 0), _ => s.scroll_discrete(value, 0),
} }
d.frame(self.serial.load(Ordering::SeqCst), now); d.frame(self.conn.serial(), now);
} }
} }
}, },
@@ -229,7 +198,7 @@ impl<'a> Emulation for LibeiEmulation<'a> {
_ => KeyState::Press, _ => KeyState::Press,
}, },
); );
d.frame(self.serial.load(Ordering::SeqCst), now); d.frame(self.conn.serial(), now);
} }
} }
KeyboardEvent::Modifiers { .. } => {} KeyboardEvent::Modifiers { .. } => {}
@@ -252,6 +221,7 @@ impl<'a> Emulation for LibeiEmulation<'a> {
async fn ei_task( async fn ei_task(
mut events: EiConvertEventStream, mut events: EiConvertEventStream,
_conn: Connection,
context: ei::Context, context: ei::Context,
devices: Devices, devices: Devices,
libei_error: Arc<AtomicBool>, libei_error: Arc<AtomicBool>,
@@ -276,11 +246,7 @@ async fn ei_event_handler(
devices: &Devices, devices: &Devices,
) -> Result<(), EmulationError> { ) -> Result<(), EmulationError> {
loop { loop {
let event = events let event = events.next().await.ok_or(EmulationError::EndOfStream)??;
.next()
.await
.ok_or(EmulationError::EndOfStream)?
.map_err(ReisConvertStreamError::from)?;
const CAPABILITIES: &[DeviceCapability] = &[ const CAPABILITIES: &[DeviceCapability] = &[
DeviceCapability::Pointer, DeviceCapability::Pointer,
DeviceCapability::PointerAbsolute, DeviceCapability::PointerAbsolute,

View File

@@ -4,7 +4,6 @@ use ashpd::{
PersistMode, Session, PersistMode, Session,
}, },
zbus::AsyncDrop, zbus::AsyncDrop,
WindowIdentifier,
}; };
use async_trait::async_trait; use async_trait::async_trait;
@@ -43,10 +42,7 @@ impl<'a> DesktopPortalEmulation<'a> {
.await?; .await?;
log::info!("requesting permission for input emulation"); log::info!("requesting permission for input emulation");
let _devices = proxy let _devices = proxy.start(&session, None).await?.response()?;
.start(&session, &WindowIdentifier::default())
.await?
.response()?;
log::debug!("started session"); log::debug!("started session");
let session = session; let session = session;

View File

@@ -14,7 +14,7 @@ serde = { version = "1.0", features = ["derive"] }
thiserror = "2.0.0" thiserror = "2.0.0"
[target.'cfg(all(unix, not(target_os="macos")))'.dependencies] [target.'cfg(all(unix, not(target_os="macos")))'.dependencies]
reis = { version = "0.2.0", optional = true } reis = { version = "0.4", optional = true }
[features] [features]
default = ["libei"] default = ["libei"]