Compare commits

..

13 Commits

Author SHA1 Message Date
Ferdinand Schober
6c99f9bea3 chore: Release lan-mouse version 0.5.1 2024-01-12 13:46:56 +01:00
Ferdinand Schober
d54b3a08e1 ignore double press / release events (#71)
This should fix most of the remaining issues with stuck keys in KDE
2024-01-12 13:13:23 +01:00
Ferdinand Schober
767fc8bd6b comment about pointer relase in sending state
Figured out, why it sometimes happened that the pointer is released in
sending state. However nothing we can do about it.

(not a real issue)
2024-01-08 16:54:14 +01:00
Ferdinand Schober
fa15048ad8 ignore every event except Enter in receiving mode (#65)
Modifier or other key events are still sent by some compositors after leaving the window which causes them to be pressed on both devices.
Now an Enter event must be produced before any further events are sent out (except disconnect)
2024-01-05 18:00:30 +01:00
Ferdinand Schober
eb366bcd34 Update README.md
fix typos
2024-01-05 17:23:36 +01:00
Ferdinand Schober
91176b1267 Update README.md
see #64
2024-01-05 17:14:03 +01:00
Ferdinand Schober
a6f386ea83 windows: impl key repeating (#63)
closes #47
2024-01-05 13:19:41 +01:00
Ferdinand Schober
40b0cdd52e Add security disclaimer 2024-01-03 16:52:56 +01:00
Ferdinand Schober
1553ed4212 Update README.md 2024-01-02 22:46:27 +01:00
Ferdinand Schober
4561c20610 layer-shell: recreate windows, when output is removed / added (#62)
Previously, when an output was removed (e.g. laptop lid closed and opened) the windows used for input capture would not appear anymore until toggling the client off and on
2024-01-01 22:48:44 +01:00
Ferdinand Schober
6cdb607b11 Fix Error handling in layershell producer (#61)
previous error handling resulted in a softlock when the connection
to the compositor was lost
2024-01-01 22:07:21 +01:00
Ferdinand Schober
f5827bb31c fix port changing 2024-01-01 14:55:29 +01:00
Ferdinand Schober
64e3bf3ff4 release stuck keys (#53)
Keys are now released when
- A client disconnects and still has pressed keys
- A client disconnects through CTLR+ALT+SHIFT+WIN
- Lan Mouse terminates with keys still being pressed through a remote client

This is also fixes an issue caused by KDE's implementation of the remote desktop portal backend:
Keys are not correctly released when a remote desktop session is closed while keys are still pressed,
causing them to be permanently stuck until kwin is restarted.

This workaround remembers all pressed keys and releases them when lan-mouse exits or a device disconnects.

closes #15
2023-12-31 15:42:29 +01:00
17 changed files with 624 additions and 350 deletions

2
Cargo.lock generated
View File

@@ -1226,7 +1226,7 @@ checksum = "b1a46d1a171d865aa5f83f92695765caa047a9b4cbae2cbf37dbd613a793fd4c"
[[package]]
name = "lan-mouse"
version = "0.5.0"
version = "0.5.1"
dependencies = [
"anyhow",
"ashpd",

View File

@@ -1,7 +1,7 @@
[package]
name = "lan-mouse"
description = "Software KVM Switch / mouse & keyboard sharing software for Local Area Networks"
version = "0.5.0"
version = "0.5.1"
edition = "2021"
license = "GPL-3.0-or-later"
repository = "https://github.com/ferdinandschober/lan-mouse"

View File

@@ -14,7 +14,7 @@ The primary target is Wayland on Linux but Windows and MacOS and Linux on Xorg h
</picture>
Goal of this project is to be an open-source replacement for proprietary tools like [Synergy](https://symless.com/synergy), [Share Mouse](https://www.sharemouse.com/de/).
Goal of this project is to be an open-source replacement for proprietary tools like [Synergy 2/3](https://symless.com/synergy), [Share Mouse](https://www.sharemouse.com/de/).
Focus lies on performance and a clean, manageable implementation that can easily be expanded to support additional backends like e.g. Android, iOS, ... .
@@ -22,6 +22,18 @@ Focus lies on performance and a clean, manageable implementation that can easily
For an alternative (with slightly different goals) you may check out [Input Leap](https://github.com/input-leap).
> [!WARNING]
> Since this tool has gained a bit of popularity over the past couple of days:
>
> All network traffic is currently **unencrypted** and sent in **plaintext**.
>
> A malicious actor with access to the network could read input data or send input events with spoofed IPs to take control over a device.
>
> Therefore you should only use this tool in your local network with trusted devices for now
> and I take no responsibility for any leakage of data!
## OS Support
The following table shows support for input emulation (to emulate events received from other clients) and
@@ -38,6 +50,10 @@ input capture (to send events *to* other clients) on different operating systems
Keycode translation is not yet implemented so on MacOS only mouse emulation works as of right now.
> [!Important]
> If you are using [Wayfire](https://github.com/WayfireWM/wayfire), make sure to use a recent version (must be newer than October 23rd) and **add `shortcuts-inhibit` to the list of plugins in your wayfire config!**
> Otherwise input capture will not work.
## Build and Run
### Install Dependencies
@@ -210,11 +226,12 @@ Where `left` can be either `left`, `right`, `top` or `bottom`.
- [x] respect xdg-config-home for config file location.
- [x] IP Address switching
- [x] Liveness tracking Automatically ungrab mouse when client unreachable
- [ ] Liveness tracking: Automatically release keys, when server offline
- [x] Liveness tracking: Automatically release keys, when server offline
- [ ] Libei Input Capture
- [ ] X11 Input Capture
- [ ] Windows Input Capture
- [ ] MacOS Input Capture
- [ ] MaxOS KeyCode Translation
- [ ] MacOS KeyCode Translation
- [ ] Latency measurement and visualization
- [ ] Bandwidth usage measurement and visualization
- [ ] Clipboard support

View File

@@ -10,4 +10,4 @@ Name=Lan Mouse
StartupNotify=true
Terminal=false
Type=Application
Version=0.5.0
Version=0.5.1

View File

@@ -5,6 +5,8 @@ use crate::{
};
use anyhow::Result;
use async_trait::async_trait;
use std::time::Duration;
use tokio::task::AbortHandle;
use winapi::um::winuser::{SendInput, KEYEVENTF_EXTENDEDKEY};
use winapi::{
self,
@@ -21,11 +23,16 @@ use crate::{
event::Event,
};
pub struct WindowsConsumer {}
const DEFAULT_REPEAT_DELAY: Duration = Duration::from_millis(500);
const DEFAULT_REPEAT_INTERVAL: Duration = Duration::from_millis(32);
pub struct WindowsConsumer {
repeat_task: Option<AbortHandle>,
}
impl WindowsConsumer {
pub fn new() -> Result<Self> {
Ok(Self {})
Ok(Self { repeat_task: None })
}
}
@@ -58,7 +65,15 @@ impl EventConsumer for WindowsConsumer {
time: _,
key,
state,
} => key_event(key, state),
} => {
match state {
// pressed
0 => self.kill_repeat_task(),
1 => self.spawn_repeat_task(key).await,
_ => {}
}
key_event(key, state)
}
KeyboardEvent::Modifiers { .. } => {}
},
_ => {}
@@ -72,6 +87,27 @@ impl EventConsumer for WindowsConsumer {
async fn destroy(&mut self) {}
}
impl WindowsConsumer {
async fn spawn_repeat_task(&mut self, key: u32) {
// there can only be one repeating key and it's
// always the last to be pressed
self.kill_repeat_task();
let repeat_task = tokio::task::spawn_local(async move {
tokio::time::sleep(DEFAULT_REPEAT_DELAY).await;
loop {
key_event(key, 1);
tokio::time::sleep(DEFAULT_REPEAT_INTERVAL).await;
}
});
self.repeat_task = Some(repeat_task.abort_handle());
}
fn kill_repeat_task(&mut self) {
if let Some(task) = self.repeat_task.take() {
task.abort();
}
}
}
fn send_mouse_input(mi: MOUSEINPUT) {
unsafe {
let mut input = INPUT {

View File

@@ -24,9 +24,13 @@ impl Default for DummyProducer {
}
impl EventProducer for DummyProducer {
fn notify(&mut self, _: ClientEvent) {}
fn notify(&mut self, _event: ClientEvent) -> io::Result<()> {
Ok(())
}
fn release(&mut self) {}
fn release(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Stream for DummyProducer {

View File

@@ -3,7 +3,11 @@ use std::{io, task::Poll};
use futures_core::Stream;
use crate::{client::ClientHandle, event::Event, producer::EventProducer};
use crate::{
client::{ClientEvent, ClientHandle},
event::Event,
producer::EventProducer,
};
pub struct LibeiProducer {}
@@ -14,9 +18,13 @@ impl LibeiProducer {
}
impl EventProducer for LibeiProducer {
fn notify(&mut self, _event: crate::client::ClientEvent) {}
fn notify(&mut self, _event: ClientEvent) -> io::Result<()> {
Ok(())
}
fn release(&mut self) {}
fn release(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Stream for LibeiProducer {

View File

@@ -23,7 +23,11 @@ impl Stream for MacOSProducer {
}
impl EventProducer for MacOSProducer {
fn notify(&mut self, _event: ClientEvent) {}
fn notify(&mut self, _event: ClientEvent) -> io::Result<()> {
Ok(())
}
fn release(&mut self) {}
fn release(&mut self) -> io::Result<()> {
Ok(())
}
}

View File

@@ -125,6 +125,7 @@ struct Window {
buffer: wl_buffer::WlBuffer,
surface: wl_surface::WlSurface,
layer_surface: ZwlrLayerSurfaceV1,
pos: Position,
}
impl Window {
@@ -179,6 +180,7 @@ impl Window {
surface.set_input_region(None);
surface.commit();
Window {
pos,
buffer,
surface,
layer_surface,
@@ -381,6 +383,24 @@ impl WaylandEventProducer {
Ok(WaylandEventProducer(inner))
}
fn add_client(&mut self, handle: ClientHandle, pos: Position) {
self.0.get_mut().state.add_client(handle, pos);
}
fn delete_client(&mut self, handle: ClientHandle) {
let inner = self.0.get_mut();
// remove all windows corresponding to this client
while let Some(i) = inner
.state
.client_for_window
.iter()
.position(|(_, c)| *c == handle)
{
inner.state.client_for_window.remove(i);
inner.state.focused = None;
}
}
}
impl State {
@@ -475,6 +495,19 @@ impl State {
self.client_for_window.push((window, client));
});
}
fn update_windows(&mut self) {
log::debug!("updating windows");
log::debug!("output info: {:?}", self.output_info);
let clients: Vec<_> = self
.client_for_window
.drain(..)
.map(|(w, c)| (c, w.pos))
.collect();
for (client, pos) in clients {
self.add_client(client, pos);
}
}
}
impl Inner {
@@ -527,50 +560,42 @@ impl Inner {
}
}
fn flush_events(&mut self) {
fn flush_events(&mut self) -> io::Result<()> {
// flush outgoing events
match self.queue.flush() {
Ok(_) => (),
Err(e) => match e {
WaylandError::Io(e) => {
log::error!("error writing to wayland socket: {e}")
return Err(e);
}
WaylandError::Protocol(e) => {
panic!("wayland protocol violation: {e}")
}
},
}
Ok(())
}
}
impl EventProducer for WaylandEventProducer {
fn notify(&mut self, client_event: ClientEvent) {
fn notify(&mut self, client_event: ClientEvent) -> io::Result<()> {
match client_event {
ClientEvent::Create(handle, pos) => {
self.0.get_mut().state.add_client(handle, pos);
self.add_client(handle, pos);
}
ClientEvent::Destroy(handle) => {
let inner = self.0.get_mut();
// remove all windows corresponding to this client
while let Some(i) = inner
.state
.client_for_window
.iter()
.position(|(_, c)| *c == handle)
{
inner.state.client_for_window.remove(i);
inner.state.focused = None;
}
self.delete_client(handle);
}
}
let inner = self.0.get_mut();
inner.flush_events();
inner.flush_events()
}
fn release(&mut self) {
fn release(&mut self) -> io::Result<()> {
log::debug!("releasing pointer");
let inner = self.0.get_mut();
inner.state.ungrab();
inner.flush_events();
inner.flush_events()
}
}
@@ -601,7 +626,11 @@ impl Stream for WaylandEventProducer {
inner.dispatch_events();
// flush outgoing events
inner.flush_events();
if let Err(e) = inner.flush_events() {
if e.kind() != ErrorKind::WouldBlock {
return Poll::Ready(Some(Err(e)));
}
}
// prepare for the next read
match inner.prepare_read() {
@@ -683,6 +712,13 @@ impl Dispatch<wl_pointer::WlPointer, ()> for State {
app.pending_events.push_back((*client, Event::Enter()));
}
wl_pointer::Event::Leave { .. } => {
/* There are rare cases, where when a window is opened in
* just the wrong moment, the pointer is released, while
* still grabbed.
* In that case, the pointer must be ungrabbed, otherwise
* it is impossible to grab it again (since the pointer
* lock, relative pointer,... objects are still in place)
*/
app.ungrab();
}
wl_pointer::Event::Button {
@@ -923,6 +959,21 @@ impl Dispatch<ZxdgOutputV1, WlOutput> for State {
}
}
impl Dispatch<wl_output::WlOutput, ()> for State {
fn event(
state: &mut Self,
_proxy: &wl_output::WlOutput,
event: <wl_output::WlOutput as wayland_client::Proxy>::Event,
_data: &(),
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {
if let wl_output::Event::Done = event {
state.update_windows();
}
}
}
// don't emit any events
delegate_noop!(State: wl_region::WlRegion);
delegate_noop!(State: wl_shm_pool::WlShmPool);
@@ -933,7 +984,6 @@ delegate_noop!(State: ZwpKeyboardShortcutsInhibitManagerV1);
delegate_noop!(State: ZwpPointerConstraintsV1);
// ignore events
delegate_noop!(State: ignore wl_output::WlOutput);
delegate_noop!(State: ignore ZxdgOutputManagerV1);
delegate_noop!(State: ignore wl_shm::WlShm);
delegate_noop!(State: ignore wl_buffer::WlBuffer);

View File

@@ -12,9 +12,13 @@ use crate::{
pub struct WindowsProducer {}
impl EventProducer for WindowsProducer {
fn notify(&mut self, _: ClientEvent) {}
fn notify(&mut self, _event: ClientEvent) -> io::Result<()> {
Ok(())
}
fn release(&mut self) {}
fn release(&mut self) -> io::Result<()> {
Ok(())
}
}
impl WindowsProducer {

View File

@@ -18,9 +18,13 @@ impl X11Producer {
}
impl EventProducer for X11Producer {
fn notify(&mut self, _: ClientEvent) {}
fn notify(&mut self, _event: ClientEvent) -> io::Result<()> {
Ok(())
}
fn release(&mut self) {}
fn release(&mut self) -> io::Result<()> {
Ok(())
}
}
impl Stream for X11Producer {

View File

@@ -2,7 +2,6 @@ use std::{
collections::HashSet,
fmt::Display,
net::{IpAddr, SocketAddr},
time::Instant,
};
use serde::{Deserialize, Serialize};
@@ -57,10 +56,6 @@ pub struct Client {
/// This way any event consumer / producer backend does not
/// need to know anything about a client other than its handle.
pub handle: ClientHandle,
/// `active` address of the client, used to send data to.
/// This should generally be the socket address where data
/// was last received from.
pub active_addr: Option<SocketAddr>,
/// all socket addresses associated with a particular client
/// e.g. Laptops usually have at least an ethernet and a wifi port
/// which have different ip addresses
@@ -71,7 +66,7 @@ pub struct Client {
pub pos: Position,
}
#[derive(Debug)]
#[derive(Clone, Copy, Debug)]
pub enum ClientEvent {
Create(ClientHandle, Position),
Destroy(ClientHandle),
@@ -81,11 +76,18 @@ pub type ClientHandle = u32;
#[derive(Debug, Clone)]
pub struct ClientState {
/// information about the client
pub client: Client,
/// events should be sent to and received from the client
pub active: bool,
pub last_ping: Option<Instant>,
pub last_seen: Option<Instant>,
pub last_replied: Option<Instant>,
/// `active` address of the client, used to send data to.
/// This should generally be the socket address where data
/// was last received from.
pub active_addr: Option<SocketAddr>,
/// tracks whether or not the client is responding to pings
pub alive: bool,
/// keys currently pressed by this client
pub pressed_keys: HashSet<u32>,
}
pub struct ClientManager {
@@ -114,9 +116,6 @@ impl ClientManager {
// get a new client_handle
let handle = self.free_id();
// we dont know, which IP is initially active
let active_addr = None;
// store fix ip addresses
let fix_ips = ips.iter().cloned().collect();
@@ -128,7 +127,6 @@ impl ClientManager {
hostname,
fix_ips,
handle,
active_addr,
addrs,
port,
pos,
@@ -137,10 +135,10 @@ impl ClientManager {
// client was never seen, nor pinged
let client_state = ClientState {
client,
last_ping: None,
last_seen: None,
last_replied: None,
active: false,
active_addr: None,
alive: false,
pressed_keys: HashSet::new(),
};
if handle as usize >= self.clients.len() {

View File

@@ -1,3 +1,4 @@
use anyhow::{anyhow, Result};
use std::{
error::Error,
fmt::{self, Display},
@@ -10,7 +11,7 @@ pub const BTN_MIDDLE: u32 = 0x112;
pub const BTN_BACK: u32 = 0x113;
pub const BTN_FORWARD: u32 = 0x114;
#[derive(Debug, Clone, Copy)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum PointerEvent {
Motion {
time: u32,
@@ -30,7 +31,7 @@ pub enum PointerEvent {
Frame {},
}
#[derive(Debug, Clone, Copy)]
#[derive(Debug, PartialEq, Clone, Copy)]
pub enum KeyboardEvent {
Key {
time: u32,
@@ -45,7 +46,7 @@ pub enum KeyboardEvent {
},
}
#[derive(Debug, Clone, Copy)]
#[derive(PartialEq, Debug, Clone, Copy)]
pub enum Event {
/// pointer event (motion / button / axis)
Pointer(PointerEvent),
@@ -65,6 +66,9 @@ pub enum Event {
/// response to a ping event: this event signals that a client
/// is still alive but must otherwise be ignored
Pong(),
/// explicit disconnect request. The client will no longer
/// send events until the next Enter event. All of its keys should be released.
Disconnect(),
}
impl Display for PointerEvent {
@@ -120,6 +124,7 @@ impl Display for Event {
Event::Leave() => write!(f, "leave"),
Event::Ping() => write!(f, "ping"),
Event::Pong() => write!(f, "pong"),
Event::Disconnect() => write!(f, "disconnect"),
}
}
}
@@ -133,6 +138,7 @@ impl Event {
Self::Leave() => EventType::Leave,
Self::Ping() => EventType::Ping,
Self::Pong() => EventType::Pong,
Self::Disconnect() => EventType::Disconnect,
}
}
}
@@ -174,18 +180,19 @@ enum EventType {
Leave,
Ping,
Pong,
Disconnect,
}
impl TryFrom<u8> for PointerEventType {
type Error = Box<dyn Error>;
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::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::Frame as u8 => Ok(Self::Frame),
_ => Err(Box::new(ProtocolError {
_ => Err(anyhow!(ProtocolError {
msg: format!("invalid pointer event type {}", value),
})),
}
@@ -193,13 +200,13 @@ impl TryFrom<u8> for PointerEventType {
}
impl TryFrom<u8> for KeyboardEventType {
type Error = Box<dyn Error>;
type Error = anyhow::Error;
fn try_from(value: u8) -> Result<Self, Self::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(Box::new(ProtocolError {
_ => Err(anyhow!(ProtocolError {
msg: format!("invalid keyboard event type {}", value),
})),
}
@@ -216,6 +223,7 @@ impl From<&Event> for Vec<u8> {
Event::Leave() => vec![],
Event::Ping() => vec![],
Event::Pong() => vec![],
Event::Disconnect() => vec![],
};
[event_id, event_data].concat()
}
@@ -234,9 +242,9 @@ impl fmt::Display for ProtocolError {
impl Error for ProtocolError {}
impl TryFrom<Vec<u8>> for Event {
type Error = Box<dyn Error>;
type Error = anyhow::Error;
fn try_from(value: Vec<u8>) -> Result<Self, Self::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()?)),
@@ -245,7 +253,8 @@ impl TryFrom<Vec<u8>> for Event {
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()),
_ => Err(Box::new(ProtocolError {
i if i == (EventType::Disconnect as u8) => Ok(Event::Disconnect()),
_ => Err(anyhow!(ProtocolError {
msg: format!("invalid event_id {}", event_id),
})),
}
@@ -291,9 +300,9 @@ impl From<&PointerEvent> for Vec<u8> {
}
impl TryFrom<Vec<u8>> for PointerEvent {
type Error = Box<dyn Error>;
type Error = anyhow::Error;
fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
fn try_from(data: Vec<u8>) -> Result<Self> {
match data.get(1) {
Some(id) => {
let event_type = match id.to_owned().try_into() {
@@ -305,7 +314,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let time = match data.get(2..6) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 2".into(),
}))
}
@@ -313,7 +322,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let relative_x = match data.get(6..14) {
Some(d) => f64::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 8 Bytes at index 6".into(),
}))
}
@@ -321,7 +330,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let relative_y = match data.get(14..22) {
Some(d) => f64::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 8 Bytes at index 14".into(),
}))
}
@@ -336,7 +345,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let time = match data.get(2..6) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 2".into(),
}))
}
@@ -344,7 +353,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let button = match data.get(6..10) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 10".into(),
}))
}
@@ -352,7 +361,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let state = match data.get(10..14) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 14".into(),
}))
}
@@ -367,7 +376,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let time = match data.get(2..6) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 2".into(),
}))
}
@@ -375,7 +384,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let axis = match data.get(6) {
Some(d) => *d,
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 1 Byte at index 6".into(),
}));
}
@@ -383,7 +392,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
let value = match data.get(7..15) {
Some(d) => f64::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 8 Bytes at index 7".into(),
}));
}
@@ -393,7 +402,7 @@ impl TryFrom<Vec<u8>> for PointerEvent {
PointerEventType::Frame => Ok(Self::Frame {}),
}
}
None => Err(Box::new(ProtocolError {
None => Err(anyhow!(ProtocolError {
msg: "Expected an element at index 0".into(),
})),
}
@@ -434,9 +443,9 @@ impl From<&KeyboardEvent> for Vec<u8> {
}
impl TryFrom<Vec<u8>> for KeyboardEvent {
type Error = Box<dyn Error>;
type Error = anyhow::Error;
fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
fn try_from(data: Vec<u8>) -> Result<Self> {
match data.get(1) {
Some(id) => {
let event_type = match id.to_owned().try_into() {
@@ -448,7 +457,7 @@ impl TryFrom<Vec<u8>> for KeyboardEvent {
let time = match data.get(2..6) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 6".into(),
}))
}
@@ -456,7 +465,7 @@ impl TryFrom<Vec<u8>> for KeyboardEvent {
let key = match data.get(6..10) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 10".into(),
}))
}
@@ -464,7 +473,7 @@ impl TryFrom<Vec<u8>> for KeyboardEvent {
let state = match data.get(10) {
Some(d) => *d,
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 1 Bytes at index 14".into(),
}))
}
@@ -475,7 +484,7 @@ impl TryFrom<Vec<u8>> for KeyboardEvent {
let mods_depressed = match data.get(2..6) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 6".into(),
}))
}
@@ -483,7 +492,7 @@ impl TryFrom<Vec<u8>> for KeyboardEvent {
let mods_latched = match data.get(6..10) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 10".into(),
}))
}
@@ -491,7 +500,7 @@ impl TryFrom<Vec<u8>> for KeyboardEvent {
let mods_locked = match data.get(10..14) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 14".into(),
}))
}
@@ -499,7 +508,7 @@ impl TryFrom<Vec<u8>> for KeyboardEvent {
let group = match data.get(14..18) {
Some(d) => u32::from_be_bytes(d.try_into()?),
None => {
return Err(Box::new(ProtocolError {
return Err(anyhow!(ProtocolError {
msg: "Expected 4 Bytes at index 18".into(),
}))
}
@@ -513,7 +522,7 @@ impl TryFrom<Vec<u8>> for KeyboardEvent {
}
}
}
None => Err(Box::new(ProtocolError {
None => Err(anyhow!(ProtocolError {
msg: "Expected an element at index 0".into(),
})),
}

View File

@@ -108,6 +108,7 @@ pub enum FrontendNotify {
NotifyClientDelete(ClientHandle),
/// new port, reason of failure (if failed)
NotifyPortChange(u16, Option<String>),
/// Client State, active
Enumerate(Vec<(Client, bool)>),
NotifyError(String),
}

View File

@@ -65,7 +65,9 @@ fn run_service(config: &Config) -> Result<()> {
runtime.block_on(LocalSet::new().run_until(async {
// run main loop
log::info!("Press Ctrl+Alt+Shift+Super to release the mouse");
Server::run(config).await?;
let server = Server::new(config);
server.run().await?;
log::debug!("service exiting");
anyhow::Ok(())

View File

@@ -54,8 +54,8 @@ pub async fn create() -> Box<dyn EventProducer> {
pub trait EventProducer: Stream<Item = io::Result<(ClientHandle, Event)>> + Unpin {
/// notify event producer of configuration changes
fn notify(&mut self, event: ClientEvent);
fn notify(&mut self, event: ClientEvent) -> io::Result<()>;
/// release mouse
fn release(&mut self);
fn release(&mut self) -> io::Result<()>;
}

File diff suppressed because it is too large Load Diff