mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-23 13:10:56 +03:00
Compare commits
7 Commits
v0.5.0
...
x11-event-
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2594a83e6a | ||
|
|
b81e5806ab | ||
|
|
a129e27a26 | ||
|
|
4561c20610 | ||
|
|
6cdb607b11 | ||
|
|
f5827bb31c | ||
|
|
64e3bf3ff4 |
@@ -2,7 +2,7 @@ use anyhow::{anyhow, Result};
|
||||
use async_trait::async_trait;
|
||||
use std::ptr;
|
||||
use x11::{
|
||||
xlib::{self, XCloseDisplay},
|
||||
xlib::{self, XCloseDisplay, XOpenDisplay},
|
||||
xtest,
|
||||
};
|
||||
|
||||
@@ -23,7 +23,7 @@ unsafe impl Send for X11Consumer {}
|
||||
impl X11Consumer {
|
||||
pub fn new() -> Result<Self> {
|
||||
let display = unsafe {
|
||||
match xlib::XOpenDisplay(ptr::null()) {
|
||||
match XOpenDisplay(ptr::null()) {
|
||||
d if d == ptr::null::<xlib::Display>() as *mut xlib::Display => {
|
||||
Err(anyhow!("could not open display"))
|
||||
}
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
@@ -923,6 +952,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 +977,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);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -1,35 +1,255 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::io;
|
||||
use std::task::Poll;
|
||||
use x11::xinput::XGrabDevice;
|
||||
use x11::xinput2::XIAllDevices;
|
||||
use std::collections::VecDeque;
|
||||
use std::os::fd::{AsRawFd, RawFd};
|
||||
use std::task::{ready, Poll};
|
||||
use std::{io, ptr};
|
||||
|
||||
use futures_core::Stream;
|
||||
|
||||
use crate::event::Event;
|
||||
use crate::event::{Event, PointerEvent};
|
||||
use crate::producer::EventProducer;
|
||||
|
||||
use crate::client::{ClientEvent, ClientHandle};
|
||||
use tokio::io::unix::AsyncFd;
|
||||
|
||||
pub struct X11Producer {}
|
||||
use x11::xlib::{
|
||||
self, ButtonPress, ButtonPressMask, ButtonRelease, ButtonReleaseMask, CWBackPixel, CWEventMask,
|
||||
CWOverrideRedirect, CopyFromParent, CurrentTime, EnterNotify, EnterWindowMask, ExposureMask,
|
||||
GrabModeAsync, KeyPress, KeyPressMask, KeyRelease, KeyReleaseMask, LeaveWindowMask,
|
||||
MotionNotify, PointerMotionMask, VisibilityChangeMask, XClassHint, XCloseDisplay,
|
||||
XCreateWindow, XDefaultScreen, XFlush, XGetInputFocus, XGrabKeyboard,
|
||||
XGrabPointer, XMapRaised, XNextEvent, XOpenDisplay, XPending, XRootWindow, XSetClassHint,
|
||||
XSetWindowAttributes, XWhitePixel, XDefaultRootWindow,
|
||||
};
|
||||
|
||||
pub struct X11Producer(AsyncFd<Inner>);
|
||||
|
||||
struct Inner {
|
||||
connection_fd: RawFd,
|
||||
display: *mut xlib::Display,
|
||||
pending_events: VecDeque<(ClientHandle, Event)>,
|
||||
window: u64,
|
||||
}
|
||||
|
||||
impl AsRawFd for Inner {
|
||||
fn as_raw_fd(&self) -> std::os::unix::prelude::RawFd {
|
||||
self.connection_fd
|
||||
}
|
||||
}
|
||||
|
||||
impl X11Producer {
|
||||
pub fn new() -> Result<Self> {
|
||||
Err(anyhow!("not implemented"))
|
||||
let display = unsafe {
|
||||
match XOpenDisplay(ptr::null()) {
|
||||
d if d == ptr::null::<xlib::Display>() as *mut xlib::Display => {
|
||||
Err(anyhow!("could not open display"))
|
||||
}
|
||||
display => Ok(display),
|
||||
}
|
||||
}?;
|
||||
let screen = unsafe { XDefaultScreen(display) };
|
||||
log::warn!("screen: {screen}");
|
||||
|
||||
let root_window = unsafe { XRootWindow(display, screen) };
|
||||
log::warn!("root: {root_window}");
|
||||
let mut attr: XSetWindowAttributes = unsafe { std::mem::zeroed() };
|
||||
attr.override_redirect = true as i32;
|
||||
attr.background_pixel = unsafe { XWhitePixel(display, screen) };
|
||||
attr.event_mask = ExposureMask
|
||||
| VisibilityChangeMask
|
||||
| KeyPressMask
|
||||
| KeyReleaseMask
|
||||
| PointerMotionMask
|
||||
| ButtonPressMask
|
||||
| ButtonReleaseMask
|
||||
| EnterWindowMask
|
||||
| LeaveWindowMask;
|
||||
let window = unsafe {
|
||||
XCreateWindow(
|
||||
display,
|
||||
root_window,
|
||||
0, /* x */
|
||||
0, /* y */
|
||||
2560, /* min width */
|
||||
10, /* min height */
|
||||
0, /* border width */
|
||||
CopyFromParent, /* depth */
|
||||
CopyFromParent as u32, /* class */
|
||||
ptr::null_mut(), /* Visual *visual */
|
||||
CWOverrideRedirect | CWBackPixel | CWEventMask,
|
||||
&mut attr as *mut _,
|
||||
)
|
||||
};
|
||||
let mut name: String = "lan-mouse".into();
|
||||
let name = name.as_mut_ptr();
|
||||
|
||||
let mut class_hint = XClassHint {
|
||||
res_name: name as *mut i8,
|
||||
res_class: name as *mut i8,
|
||||
};
|
||||
unsafe { XSetClassHint(display, window, &mut class_hint as *mut _) };
|
||||
log::warn!("window: {window}");
|
||||
// unsafe { XSelectInput(display, window, event_mask as i64) };
|
||||
unsafe { XMapRaised(display, window) };
|
||||
unsafe { XFlush(display) };
|
||||
|
||||
/* can not fail */
|
||||
let connection_fd = unsafe { xlib::XConnectionNumber(display) };
|
||||
let pending_events = VecDeque::new();
|
||||
let inner = Inner {
|
||||
connection_fd,
|
||||
display,
|
||||
window,
|
||||
pending_events,
|
||||
};
|
||||
let async_fd = AsyncFd::new(inner)?;
|
||||
Ok(X11Producer(async_fd))
|
||||
}
|
||||
}
|
||||
|
||||
impl Inner {
|
||||
fn decode(&mut self, xevent: xlib::XEvent) -> Option<(u32, Event)> {
|
||||
log::info!("decoding {xevent:?}");
|
||||
match xevent.get_type() {
|
||||
t if t == KeyPress || t == KeyRelease => {
|
||||
let key_event: xlib::XKeyEvent = unsafe { xevent.key };
|
||||
let code = key_event.keycode;
|
||||
let linux_code = code - 8;
|
||||
let state = (xevent.get_type() == KeyPress) as u8;
|
||||
return Some((
|
||||
0,
|
||||
Event::Keyboard(crate::event::KeyboardEvent::Key {
|
||||
time: 0,
|
||||
key: linux_code,
|
||||
state,
|
||||
}),
|
||||
));
|
||||
}
|
||||
t if t == EnterNotify => {
|
||||
let mut prev_win = 0;
|
||||
unsafe {
|
||||
XGetInputFocus(
|
||||
self.display,
|
||||
&mut self.window as *mut _,
|
||||
&mut prev_win as *mut _,
|
||||
);
|
||||
XGrabKeyboard(
|
||||
self.display,
|
||||
XDefaultRootWindow(self.display),
|
||||
true as i32,
|
||||
GrabModeAsync,
|
||||
GrabModeAsync,
|
||||
CurrentTime,
|
||||
);
|
||||
XGrabPointer(
|
||||
self.display,
|
||||
self.window, /* window to grab */
|
||||
true as i32, /* owner_events */
|
||||
(PointerMotionMask | ButtonPressMask | ButtonReleaseMask) as u32, /* event mask */
|
||||
GrabModeAsync, /* pointer_mode */
|
||||
GrabModeAsync, /* keyboard_mode */
|
||||
self.window, /* confine_to */
|
||||
0, /* cursor */
|
||||
CurrentTime,
|
||||
);
|
||||
};
|
||||
|
||||
Some((0, Event::Enter()))
|
||||
}
|
||||
t if t == MotionNotify => {
|
||||
let pointer_event = unsafe { xevent.motion };
|
||||
let (abs_x, abs_y) = (pointer_event.x, pointer_event.y);
|
||||
let event = Event::Pointer(PointerEvent::Motion {
|
||||
time: 0,
|
||||
relative_x: abs_x as f64,
|
||||
relative_y: abs_y as f64,
|
||||
});
|
||||
Some((0, event))
|
||||
}
|
||||
t if t == ButtonPress || t == ButtonRelease => {
|
||||
let button_event = unsafe { xevent.button };
|
||||
log::info!("{:?}", xevent);
|
||||
Some((0, Event::Pointer(PointerEvent::Button {
|
||||
time: 0,
|
||||
button: button_event.button,
|
||||
state: button_event.state,
|
||||
})))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
fn dispatch(&mut self) -> io::Result<bool> {
|
||||
unsafe {
|
||||
if XPending(self.display) > 0 {
|
||||
let mut xevent: xlib::XEvent = std::mem::zeroed();
|
||||
XNextEvent(self.display, &mut xevent as *mut _);
|
||||
if let Some(event) = self.decode(xevent) {
|
||||
self.pending_events.push_back(event);
|
||||
}
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Drop for Inner {
|
||||
fn drop(&mut self) {
|
||||
unsafe {
|
||||
XCloseDisplay(self.display);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 {
|
||||
type Item = io::Result<(ClientHandle, Event)>;
|
||||
|
||||
fn poll_next(
|
||||
self: std::pin::Pin<&mut Self>,
|
||||
_cx: &mut std::task::Context<'_>,
|
||||
) -> std::task::Poll<Option<Self::Item>> {
|
||||
Poll::Pending
|
||||
mut self: std::pin::Pin<&mut Self>,
|
||||
cx: &mut std::task::Context<'_>,
|
||||
) -> Poll<Option<Self::Item>> {
|
||||
if let Some(event) = self.0.get_mut().pending_events.pop_front() {
|
||||
return Poll::Ready(Some(Ok(event)));
|
||||
}
|
||||
loop {
|
||||
let mut guard = ready!(self.0.poll_read_ready_mut(cx))?;
|
||||
{
|
||||
let inner = guard.get_inner_mut();
|
||||
loop {
|
||||
if match inner.dispatch() {
|
||||
Ok(event) => event,
|
||||
Err(e) => {
|
||||
guard.clear_ready();
|
||||
return Poll::Ready(Some(Err(e)));
|
||||
}
|
||||
} == false
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
guard.clear_ready();
|
||||
|
||||
match guard.get_inner_mut().pending_events.pop_front() {
|
||||
Some(event) => {
|
||||
return Poll::Ready(Some(Ok(event)));
|
||||
}
|
||||
None => continue,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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() {
|
||||
|
||||
71
src/event.rs
71
src/event.rs
@@ -1,3 +1,4 @@
|
||||
use anyhow::{anyhow, Result};
|
||||
use std::{
|
||||
error::Error,
|
||||
fmt::{self, Display},
|
||||
@@ -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(),
|
||||
})),
|
||||
}
|
||||
|
||||
@@ -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),
|
||||
}
|
||||
|
||||
@@ -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(())
|
||||
|
||||
@@ -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<()>;
|
||||
}
|
||||
|
||||
636
src/server.rs
636
src/server.rs
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user