mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-04-20 08:53:19 +03:00
add leave event to make entering a client more reliable (#50)
Instead of relying on release events not getting lost, every event now signals the opponent to release its pointer grab. There is one case that requires a Leave event: Consider a Sending client A and receiving Client B. If B enters the dead-zone of client A, it will send an enter event towards A but before A receives the Release event, it may still send additional events towards B that should not cause B to immediately revert to Receiving state again. Therefore B puts itself into AwaitingLeave state until it receives a Leave event coming from A. A responds to the Enter event coming from B with a leave event, to signify that it will no longer send any events and releases it's pointer. To guard against packet loss of the leave events, B sends additional enter events while it is in AwaitingLeave mode until it receives a Leave event at some point. This is still not resilient against possible packet reordering in UDP but in the (rare) case where a leave event arrives before some other event coming from A, the user would simply need to move the pointer into the dead-zone again.
This commit is contained in:
committed by
GitHub
parent
02d1b33e45
commit
735434438f
@@ -209,9 +209,7 @@ impl EventConsumer for MacOSConsumer {
|
|||||||
}
|
}
|
||||||
KeyboardEvent::Modifiers { .. } => {}
|
KeyboardEvent::Modifiers { .. } => {}
|
||||||
},
|
},
|
||||||
Event::Release() => {}
|
_ => ()
|
||||||
Event::Ping() => {}
|
|
||||||
Event::Pong() => {}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -662,7 +662,7 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
|
|||||||
.iter()
|
.iter()
|
||||||
.find(|(w, _c)| w.surface == surface)
|
.find(|(w, _c)| w.surface == surface)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
app.pending_events.push_back((*client, Event::Release()));
|
app.pending_events.push_back((*client, Event::Enter()));
|
||||||
}
|
}
|
||||||
wl_pointer::Event::Leave { .. } => {
|
wl_pointer::Event::Leave { .. } => {
|
||||||
app.ungrab();
|
app.ungrab();
|
||||||
|
|||||||
30
src/event.rs
30
src/event.rs
@@ -47,10 +47,23 @@ pub enum KeyboardEvent {
|
|||||||
|
|
||||||
#[derive(Debug, Clone, Copy)]
|
#[derive(Debug, Clone, Copy)]
|
||||||
pub enum Event {
|
pub enum Event {
|
||||||
|
/// pointer event (motion / button / axis)
|
||||||
Pointer(PointerEvent),
|
Pointer(PointerEvent),
|
||||||
|
/// keyboard events (key / modifiers)
|
||||||
Keyboard(KeyboardEvent),
|
Keyboard(KeyboardEvent),
|
||||||
Release(),
|
/// enter event: request to enter a client.
|
||||||
|
/// The client must release the pointer if it is grabbed
|
||||||
|
/// and reply with a leave event, as soon as its ready to
|
||||||
|
/// receive events
|
||||||
|
Enter(),
|
||||||
|
/// leave event: this client is now ready to receive events and will
|
||||||
|
/// not send any events after until it sends an enter event
|
||||||
|
Leave(),
|
||||||
|
/// ping a client, to see if it is still alive. A client that does
|
||||||
|
/// not respond with a pong event will be assumed to be offline.
|
||||||
Ping(),
|
Ping(),
|
||||||
|
/// response to a ping event: this event signals that a client
|
||||||
|
/// is still alive but must otherwise be ignored
|
||||||
Pong(),
|
Pong(),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -103,7 +116,8 @@ impl Display for Event {
|
|||||||
match self {
|
match self {
|
||||||
Event::Pointer(p) => write!(f, "{}", p),
|
Event::Pointer(p) => write!(f, "{}", p),
|
||||||
Event::Keyboard(k) => write!(f, "{}", k),
|
Event::Keyboard(k) => write!(f, "{}", k),
|
||||||
Event::Release() => write!(f, "release"),
|
Event::Enter() => write!(f, "enter"),
|
||||||
|
Event::Leave() => write!(f, "leave"),
|
||||||
Event::Ping() => write!(f, "ping"),
|
Event::Ping() => write!(f, "ping"),
|
||||||
Event::Pong() => write!(f, "pong"),
|
Event::Pong() => write!(f, "pong"),
|
||||||
}
|
}
|
||||||
@@ -115,7 +129,8 @@ impl Event {
|
|||||||
match self {
|
match self {
|
||||||
Self::Pointer(_) => EventType::Pointer,
|
Self::Pointer(_) => EventType::Pointer,
|
||||||
Self::Keyboard(_) => EventType::Keyboard,
|
Self::Keyboard(_) => EventType::Keyboard,
|
||||||
Self::Release() => EventType::Release,
|
Self::Enter() => EventType::Enter,
|
||||||
|
Self::Leave() => EventType::Leave,
|
||||||
Self::Ping() => EventType::Ping,
|
Self::Ping() => EventType::Ping,
|
||||||
Self::Pong() => EventType::Pong,
|
Self::Pong() => EventType::Pong,
|
||||||
}
|
}
|
||||||
@@ -155,7 +170,8 @@ enum KeyboardEventType {
|
|||||||
enum EventType {
|
enum EventType {
|
||||||
Pointer,
|
Pointer,
|
||||||
Keyboard,
|
Keyboard,
|
||||||
Release,
|
Enter,
|
||||||
|
Leave,
|
||||||
Ping,
|
Ping,
|
||||||
Pong,
|
Pong,
|
||||||
}
|
}
|
||||||
@@ -196,7 +212,8 @@ impl From<&Event> for Vec<u8> {
|
|||||||
let event_data = match event {
|
let event_data = match event {
|
||||||
Event::Pointer(p) => p.into(),
|
Event::Pointer(p) => p.into(),
|
||||||
Event::Keyboard(k) => k.into(),
|
Event::Keyboard(k) => k.into(),
|
||||||
Event::Release() => vec![],
|
Event::Enter() => vec![],
|
||||||
|
Event::Leave() => vec![],
|
||||||
Event::Ping() => vec![],
|
Event::Ping() => vec![],
|
||||||
Event::Pong() => vec![],
|
Event::Pong() => vec![],
|
||||||
};
|
};
|
||||||
@@ -224,7 +241,8 @@ impl TryFrom<Vec<u8>> for Event {
|
|||||||
match event_id {
|
match event_id {
|
||||||
i if i == (EventType::Pointer as u8) => Ok(Event::Pointer(value.try_into()?)),
|
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::Keyboard as u8) => Ok(Event::Keyboard(value.try_into()?)),
|
||||||
i if i == (EventType::Release as u8) => Ok(Event::Release()),
|
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::Ping as u8) => Ok(Event::Ping()),
|
||||||
i if i == (EventType::Pong as u8) => Ok(Event::Pong()),
|
i if i == (EventType::Pong as u8) => Ok(Event::Pong()),
|
||||||
_ => Err(Box::new(ProtocolError {
|
_ => Err(Box::new(ProtocolError {
|
||||||
|
|||||||
@@ -36,6 +36,7 @@ use crate::{
|
|||||||
enum State {
|
enum State {
|
||||||
Sending,
|
Sending,
|
||||||
Receiving,
|
Receiving,
|
||||||
|
AwaitingLeave,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Server {
|
pub struct Server {
|
||||||
@@ -308,63 +309,91 @@ impl Server {
|
|||||||
state.client.active_addr = Some(addr);
|
state.client.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) => {
|
||||||
if let Err(e) = send_event(&self.socket, Event::Pong(), addr).await {
|
if let Err(e) = send_event(&self.socket, Event::Pong(), addr).await {
|
||||||
log::error!("udp send: {}", e);
|
log::error!("udp send: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(event, addr) => {
|
(event, addr) => {
|
||||||
// device is sending events => release pointer if captured
|
// tell clients that we are ready to receive events
|
||||||
if self.state == State::Sending {
|
if let Event::Enter() = event {
|
||||||
// Even in sending state, we can still receive events
|
if let Err(e) = send_event(&self.socket, Event::Leave(), addr).await {
|
||||||
// from the client we entered until (our) release event
|
log::error!("udp send: {}", e);
|
||||||
// arrives there.
|
}
|
||||||
//
|
}
|
||||||
// Therefore we must wait until we receive
|
match self.state {
|
||||||
// another release event to actually release the pointer.
|
State::Sending => {
|
||||||
if let Event::Release() = event {
|
if let Event::Leave() = event {
|
||||||
log::debug!("releasing pointer ...");
|
// ignore additional leave events that may
|
||||||
|
// have been sent for redundancy
|
||||||
|
} else {
|
||||||
|
// upon receiving any event, we go back to receiving mode
|
||||||
self.producer.release();
|
self.producer.release();
|
||||||
self.state = State::Receiving;
|
self.state = State::Receiving;
|
||||||
}
|
}
|
||||||
return;
|
},
|
||||||
}
|
State::Receiving => {
|
||||||
|
|
||||||
// consume event
|
// consume event
|
||||||
self.consumer.consume(event, handle).await;
|
self.consumer.consume(event, handle).await;
|
||||||
log::trace!("{event:?} => consumer");
|
log::trace!("{event:?} => consumer");
|
||||||
|
},
|
||||||
|
State::AwaitingLeave => {
|
||||||
|
// we just entered the deadzone of a client, so
|
||||||
|
// we need to ignore events that may still
|
||||||
|
// be on the way until a leave event occurs
|
||||||
|
// telling us the client registered the enter
|
||||||
|
if let Event::Leave() = event {
|
||||||
|
self.state = State::Sending;
|
||||||
|
}
|
||||||
|
|
||||||
|
// entering a client that is waiting for a leave
|
||||||
|
// event should still be possible
|
||||||
|
if let Event::Enter() = event {
|
||||||
|
self.state = State::Receiving;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
// let the server know we are still alive once every second
|
// let the server know we are still alive once every second
|
||||||
let last_replied = state.last_replied;
|
if state.last_replied.is_none()
|
||||||
if last_replied.is_none()
|
|| state.last_replied.is_some()
|
||||||
|| last_replied.is_some()
|
&& state.last_replied.unwrap().elapsed() > Duration::from_secs(1)
|
||||||
&& last_replied.unwrap().elapsed() > Duration::from_secs(1)
|
|
||||||
{
|
{
|
||||||
state.last_replied = Some(Instant::now());
|
state.last_replied = Some(Instant::now());
|
||||||
if let Err(e) = send_event(&self.socket, Event::Pong(), addr).await {
|
if let Err(e) = send_event(&self.socket, Event::Pong(), addr).await {
|
||||||
log::error!("udp send: {}", e);
|
log::error!("udp send: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn handle_producer_event(&mut self, c: ClientHandle, e: Event) {
|
async fn handle_producer_event(&mut self, c: ClientHandle, e: Event) {
|
||||||
log::trace!("producer: ({c}) {e:?}");
|
log::trace!("producer: ({c}) {e:?}");
|
||||||
|
|
||||||
// we are sending events
|
|
||||||
self.state = State::Sending;
|
|
||||||
|
|
||||||
// get client state for handle
|
// get client state for handle
|
||||||
let state = match self.client_manager.get_mut(c) {
|
let state = match self.client_manager.get_mut(c) {
|
||||||
Some(state) => state,
|
Some(state) => state,
|
||||||
None => {
|
None => {
|
||||||
|
// should not happen
|
||||||
log::warn!("unknown client!");
|
log::warn!("unknown client!");
|
||||||
|
self.producer.release();
|
||||||
|
self.state = State::Receiving;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// if we just entered the client we want to send additional enter events until
|
||||||
|
// we get a leave event
|
||||||
|
if let State::Receiving | State::AwaitingLeave = self.state {
|
||||||
|
self.state = State::AwaitingLeave;
|
||||||
|
if let Some(addr) = state.client.active_addr {
|
||||||
|
if let Err(e) = send_event(&self.socket, Event::Enter(), addr).await {
|
||||||
|
log::error!("udp send: {}", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// otherwise we should have an address to
|
// otherwise we should have an address to
|
||||||
// transmit events to the corrensponding client
|
// transmit events to the corrensponding client
|
||||||
if let Some(addr) = state.client.active_addr {
|
if let Some(addr) = state.client.active_addr {
|
||||||
@@ -414,16 +443,6 @@ impl Server {
|
|||||||
log::error!("udp send: {}", e);
|
log::error!("udp send: {}", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// we can not assume the client is in receiving mode because a
|
|
||||||
// client can always change mode from receiving to sending
|
|
||||||
// by restarting.
|
|
||||||
// To prevent both clients from being in sending mode,
|
|
||||||
// we send a release event.
|
|
||||||
if let Err(e) = send_event(&self.socket, Event::Release(), *addr).await {
|
|
||||||
if e.kind() != ErrorKind::WouldBlock {
|
|
||||||
log::error!("udp send: {}", e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user