major refactor

every instance of lan-mouse can now simultaneously send and receive
events
This commit is contained in:
Ferdinand Schober
2023-01-30 19:15:58 +01:00
parent 5c60e2eb58
commit 5222f54eee
15 changed files with 923 additions and 528 deletions

30
DOC.md
View File

@@ -51,3 +51,33 @@ sequenceDiagram
Bob-->>-Alice: Ack (Keyboard Layout)
```
## Problems
The general Idea is to have a bidirectional connection by default, meaning
any connected device can not only receive events but also send events back.
This way when connecting e.g. a PC to a Laptop, either device can be used
to control the other.
It needs to be ensured, that whenever a device is controlled the controlled
device does not transmit the events back to the original sender.
Otherwise events are multiplied and either one of the instances crashes.
To keep the implementation of input backends simple this needs to be handled
on the server level.
## Device State - Active and Inactive
To solve this problem, each device can be in exactly two states:
Events can only be sent to active clients.
Events can only be received from inactive clients.
Active denotes that a particular device is controlled by the local pc.
Any event received from an active device is ignored unless it is a state change request.
In this case the device is marked as inactive and no further events are sent to the device.
The received events are then processed until a further state change to active
is requested (when the corresponding layer surface is entered).
**In short:** The invariance "each client either sends or receives events" must
always be true.

2
TODO Normal file
View File

@@ -0,0 +1,2 @@
remove handle_to_addr / addr_to_handle functions from client_manager
instead mirror state in event server

View File

@@ -1,10 +1,13 @@
port = 42069
[client.left]
host_name = "rubinium"
ip = "192.168.2.182"
port = 42069
[client.right]
host_name = "rubinium"
ip = "192.168.2.182"
# [client.right]
# host_name = "localhost"
# port = 42068
[client.left]
host_name = "Osmium"
port = 42069
# [client.right]
# host_name = "Osmium"
# port = 42069

View File

@@ -1,147 +0,0 @@
use lan_mouse::{
config::Config,
protocol::{self, DataRequest},
};
use std::{
io::{BufWriter, Write},
os::unix::prelude::AsRawFd,
};
use wayland_protocols_wlr::virtual_pointer::v1::client::{
zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1 as VpManager,
zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1 as Vp,
};
use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{
zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1 as VkManager,
zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1 as Vk,
};
use wayland_client::{
delegate_noop,
globals::{registry_queue_init, GlobalListContents},
protocol::{wl_keyboard, wl_pointer, wl_registry, wl_seat},
Connection, Dispatch, EventQueue, QueueHandle,
};
use tempfile;
// App State, implements Dispatch event handlers
struct App;
fn main() {
let config = Config::new("config.toml").unwrap();
let conn = Connection::connect_to_env().unwrap();
let (globals, queue) = registry_queue_init::<App>(&conn).unwrap();
let qh = queue.handle();
let vpm: VpManager = globals.bind(&qh, 1..=1, ()).unwrap();
let vkm: VkManager = globals.bind(&qh, 1..=1, ()).unwrap();
let seat: wl_seat::WlSeat = globals.bind(&qh, 7..=8, ()).unwrap();
let pointer: Vp = vpm.create_virtual_pointer(None, &qh, ());
let keyboard: Vk = vkm.create_virtual_keyboard(&seat, &qh, ());
let connection = protocol::Connection::new(config);
let data = loop {
match connection.receive_data(DataRequest::KeyMap) {
Some(data) => break data,
None => {}
}
};
// TODO use shm_open
let f = tempfile::tempfile().unwrap();
let mut buf = BufWriter::new(&f);
buf.write_all(&data[..]).unwrap();
buf.flush().unwrap();
keyboard.keymap(1, f.as_raw_fd(), data.len() as u32);
loop {
receive_event(&connection, &pointer, &keyboard, &queue).unwrap();
}
}
/// main loop handling udp packets
fn receive_event(
connection: &protocol::Connection,
pointer: &Vp,
keyboard: &Vk,
q: &EventQueue<App>,
) -> std::io::Result<()> {
let event = if let Some(event) = connection.receive_event() {
event
} else {
return Ok(());
};
match event {
protocol::Event::Pointer(e) => match e {
wl_pointer::Event::Motion {
time,
surface_x,
surface_y,
} => {
pointer.motion(time, surface_x, surface_y);
pointer.frame();
}
wl_pointer::Event::Button {
serial: _,
time: t,
button: b,
state: s,
} => {
pointer.button(t, b, s.into_result().unwrap());
pointer.frame();
}
wl_pointer::Event::Axis {
time: t,
axis: a,
value: v,
} => {
pointer.axis(t, a.into_result().unwrap(), v);
pointer.frame();
}
wl_pointer::Event::Frame => {
pointer.frame();
}
_ => todo!(),
},
protocol::Event::Keyboard(e) => match e {
wl_keyboard::Event::Key {
serial: _,
time: t,
key: k,
state: s,
} => {
keyboard.key(t, k, u32::from(s));
}
wl_keyboard::Event::Modifiers {
serial: _,
mods_depressed,
mods_latched,
mods_locked,
group,
} => {
keyboard.modifiers(mods_depressed, mods_latched, mods_locked, group);
}
_ => todo!(),
},
}
q.flush().unwrap();
Ok(())
}
delegate_noop!(App: Vp);
delegate_noop!(App: Vk);
delegate_noop!(App: VpManager);
delegate_noop!(App: VkManager);
delegate_noop!(App: wl_seat::WlSeat);
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for App {
fn event(
_: &mut App,
_: &wl_registry::WlRegistry,
_: wl_registry::Event,
_: &GlobalListContents,
_: &Connection,
_: &QueueHandle<App>,
) {
}
}

57
src/client.rs Normal file
View File

@@ -0,0 +1,57 @@
use std::net::SocketAddr;
#[derive(Eq, Hash, PartialEq, Clone, Copy)]
pub enum Position {
Left, Right, Top, Bottom,
}
#[derive(Clone, Copy)]
pub struct Client {
pub addr: SocketAddr,
pub pos: Position,
pub handle: ClientHandle,
}
impl Client {
pub fn handle(&self) -> ClientHandle {
return self.handle;
}
}
pub enum ClientEvent {
Create(Client),
Destroy(Client),
}
pub struct ClientManager {
next_id: u32,
clients: Vec<Client>,
}
pub type ClientHandle = u32;
impl ClientManager {
fn new_id(&mut self) -> ClientHandle {
self.next_id += 1;
self.next_id
}
pub fn new() -> Self {
ClientManager {
next_id: 0,
clients: Vec::new(),
}
}
pub fn add_client(&mut self, addr: SocketAddr, pos: Position) {
let handle = self.new_id();
let client = Client { addr, pos, handle };
self.clients.push(client);
}
pub fn get_clients(&self) -> Vec<Client> {
self.clients.clone()
}
}

View File

@@ -17,7 +17,7 @@ pub struct Clients {
pub bottom: Option<Client>,
}
#[derive(Serialize, Deserialize, Debug)]
#[derive(Serialize, Deserialize, Debug, Eq, PartialEq)]
pub struct Client {
pub host_name: Option<String>,
pub ip: Option<IpAddr>,

View File

@@ -10,14 +10,6 @@ struct DnsError {
host: String,
}
impl Error for InvalidConfigError {}
impl Display for InvalidConfigError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "No hostname specified!")
}
}
impl Error for DnsError {}
impl Display for DnsError {
@@ -26,11 +18,7 @@ impl Display for DnsError {
}
}
pub fn resolve(host: &Option<String>) -> Result<IpAddr, Box<dyn Error>> {
let host = match host {
Some(host) => host,
None => return Err(InvalidConfigError.into()),
};
pub fn resolve(host: &String) -> Result<IpAddr, Box<dyn Error>> {
let response = Resolver::from_system_conf()?.lookup_ip(host)?;
match response.iter().next() {
Some(ip) => Ok(ip),

154
src/event.rs Normal file
View File

@@ -0,0 +1,154 @@
pub mod producer;
pub mod consumer;
pub mod server;
/*
* TODO: currently the wayland events are encoded
* directly with no generalized event format
*/
use wayland_client::{protocol::{wl_pointer, wl_keyboard}, WEnum};
pub trait Encode {
fn encode(&self) -> Vec<u8>;
}
pub trait Decode {
fn decode(buf: Vec<u8>) -> Self;
}
impl Encode for wl_pointer::Event {
fn encode(&self) -> Vec<u8> {
let mut buf = Vec::new();
match *self {
Self::Motion {
time: t,
surface_x: x,
surface_y: y,
} => {
buf.push(0u8);
buf.extend_from_slice(t.to_ne_bytes().as_ref());
buf.extend_from_slice(x.to_ne_bytes().as_ref());
buf.extend_from_slice(y.to_ne_bytes().as_ref());
}
Self::Button {
serial: _,
time: t,
button: b,
state: s,
} => {
buf.push(1u8);
buf.extend_from_slice(t.to_ne_bytes().as_ref());
buf.extend_from_slice(b.to_ne_bytes().as_ref());
buf.push(u32::from(s) as u8);
}
Self::Axis {
time: t,
axis: a,
value: v,
} => {
buf.push(2u8);
buf.extend_from_slice(t.to_ne_bytes().as_ref());
buf.push(u32::from(a) as u8);
buf.extend_from_slice(v.to_ne_bytes().as_ref());
}
Self::Frame {} => {
buf.push(3u8);
}
_ => todo!(),
}
buf
}
}
impl Encode for wl_keyboard::Event {
fn encode(&self) -> Vec<u8> {
let mut buf = Vec::new();
match self {
Self::Key {
serial: _,
time: t,
key: k,
state: s,
} => {
buf.push(4u8);
buf.extend_from_slice(t.to_ne_bytes().as_ref());
buf.extend_from_slice(k.to_ne_bytes().as_ref());
buf.push(u32::from(*s) as u8);
}
Self::Modifiers {
serial: _,
mods_depressed,
mods_latched,
mods_locked,
group,
} => {
buf.push(5u8);
buf.extend_from_slice(mods_depressed.to_ne_bytes().as_ref());
buf.extend_from_slice(mods_latched.to_ne_bytes().as_ref());
buf.extend_from_slice(mods_locked.to_ne_bytes().as_ref());
buf.extend_from_slice(group.to_ne_bytes().as_ref());
}
_ => todo!(),
}
buf
}
}
pub enum Event {
Pointer(wl_pointer::Event),
Keyboard(wl_keyboard::Event),
Release(),
}
impl Encode for Event {
fn encode(&self) -> Vec<u8> {
match self {
Event::Pointer(p) => p.encode(),
Event::Keyboard(k) => k.encode(),
Event::Release() => vec![6u8],
}
}
}
unsafe impl Send for Event {}
unsafe impl Sync for Event {}
impl Decode for Event {
fn decode(buf: Vec<u8>) -> Self {
match buf[0] {
0 => Self::Pointer(wl_pointer::Event::Motion {
time: u32::from_ne_bytes(buf[1..5].try_into().unwrap()),
surface_x: f64::from_ne_bytes(buf[5..13].try_into().unwrap()),
surface_y: f64::from_ne_bytes(buf[13..21].try_into().unwrap()),
}),
1 => Self::Pointer(wl_pointer::Event::Button {
serial: 0,
time: (u32::from_ne_bytes(buf[1..5].try_into().unwrap())),
button: (u32::from_ne_bytes(buf[5..9].try_into().unwrap())),
state: (WEnum::Value(wl_pointer::ButtonState::try_from(buf[9] as u32).unwrap())),
}),
2 => Self::Pointer(wl_pointer::Event::Axis {
time: (u32::from_ne_bytes(buf[1..5].try_into().unwrap())),
axis: (WEnum::Value(wl_pointer::Axis::try_from(buf[5] as u32).unwrap())),
value: (f64::from_ne_bytes(buf[6..14].try_into().unwrap())),
}),
3 => Self::Pointer(wl_pointer::Event::Frame {}),
4 => Self::Keyboard(wl_keyboard::Event::Key {
serial: 0,
time: u32::from_ne_bytes(buf[1..5].try_into().unwrap()),
key: u32::from_ne_bytes(buf[5..9].try_into().unwrap()),
state: WEnum::Value(wl_keyboard::KeyState::try_from(buf[9] as u32).unwrap()),
}),
5 => Self::Keyboard(wl_keyboard::Event::Modifiers {
serial: 0,
mods_depressed: u32::from_ne_bytes(buf[1..5].try_into().unwrap()),
mods_latched: u32::from_ne_bytes(buf[5..9].try_into().unwrap()),
mods_locked: u32::from_ne_bytes(buf[9..13].try_into().unwrap()),
group: u32::from_ne_bytes(buf[13..17].try_into().unwrap()),
}),
6 => Self::Release(),
_ => panic!("protocol violation"),
}
}
}

197
src/event/consumer.rs Normal file
View File

@@ -0,0 +1,197 @@
use crate::client::{Client, ClientHandle};
use crate::request::{self, Request};
use std::collections::HashMap;
use std::time::Duration;
use std::{io, thread};
use std::sync::mpsc::Receiver;
use std::{
io::{BufWriter, Write},
os::unix::prelude::AsRawFd,
};
use wayland_protocols_wlr::virtual_pointer::v1::client::{
zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1 as VpManager,
zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1 as Vp,
};
use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{
zwp_virtual_keyboard_manager_v1::ZwpVirtualKeyboardManagerV1 as VkManager,
zwp_virtual_keyboard_v1::ZwpVirtualKeyboardV1 as Vk,
};
use wayland_client::{
delegate_noop,
globals::{registry_queue_init, GlobalListContents},
protocol::{wl_keyboard, wl_pointer, wl_registry, wl_seat},
Connection, Dispatch, EventQueue, QueueHandle,
};
use tempfile;
use super::Event;
// App State, implements Dispatch event handlers
struct App {
input_for_client: HashMap<ClientHandle, VirtualInput>,
seat: wl_seat::WlSeat,
event_rx: Receiver<(Event, ClientHandle)>,
vpm: VpManager,
vkm: VkManager,
queue: EventQueue<Self>,
qh: QueueHandle<Self>,
}
pub fn run(event_rx: Receiver<(Event, ClientHandle)>, clients: Vec<Client>) {
let mut app = App::new(event_rx, clients);
app.run();
}
impl App {
pub fn new(event_rx: Receiver<(Event, ClientHandle)>, clients: Vec<Client>) -> Self {
let conn = Connection::connect_to_env().unwrap();
let (globals, queue) = registry_queue_init::<App>(&conn).unwrap();
let qh = queue.handle();
let vpm: VpManager = globals.bind(&qh, 1..=1, ()).expect("zwlr_virtual_pointer_manager_v1 protocol is required to emulate mouse input");
let vkm: VkManager = globals.bind(&qh, 1..=1, ()).expect("zwp_virtual_keyboard_manager_v1 protocol is required to emulate keyboard input");
let input_for_client: HashMap<ClientHandle, VirtualInput> = HashMap::new();
let seat: wl_seat::WlSeat = globals.bind(&qh, 7..=8, ()).unwrap();
let mut app = App { input_for_client, seat, event_rx, vpm, vkm, queue, qh };
for client in clients {
app.add_client(client);
}
app
}
pub fn run(&mut self) {
loop {
let (event, client) = self.event_rx.recv().unwrap();
if let Some(virtual_input) = self.input_for_client.get(&client) {
virtual_input.consume_event(event).unwrap();
if let Err(e) = self.queue.flush() {
eprintln!("{}", e);
}
}
}
}
fn add_client(&mut self, client: Client) {
// create virtual input devices
let pointer: Vp = self.vpm.create_virtual_pointer(None, &self.qh, ());
let keyboard: Vk = self.vkm.create_virtual_keyboard(&self.seat, &self.qh, ());
// receive keymap from device
eprintln!("connecting to {}", client.addr);
let data = loop {
match request::request_data(client.addr, Request::KeyMap) {
Some(data) => break data,
None => {
eprint!(".");
io::stderr().flush().unwrap();
thread::sleep(Duration::from_millis(500));
}
}
};
// TODO use shm_open
let f = tempfile::tempfile().unwrap();
let mut buf = BufWriter::new(&f);
buf.write_all(&data[..]).unwrap();
buf.flush().unwrap();
keyboard.keymap(1, f.as_raw_fd(), data.len() as u32);
let vinput = VirtualInput { pointer, keyboard };
self.input_for_client.insert(client.handle, vinput);
}
}
struct VirtualInput {
pointer: Vp,
keyboard: Vk,
}
impl VirtualInput {
/// main loop handling udp packets
fn consume_event(&self, event: Event) -> std::io::Result<()> {
match event {
Event::Pointer(e) => match e {
wl_pointer::Event::Motion {
time,
surface_x,
surface_y,
} => {
self.pointer.motion(time, surface_x, surface_y);
self.pointer.frame();
}
wl_pointer::Event::Button {
serial: _,
time: t,
button: b,
state: s,
} => {
self.pointer.button(t, b, s.into_result().unwrap());
self.pointer.frame();
}
wl_pointer::Event::Axis {
time: t,
axis: a,
value: v,
} => {
self.pointer.axis(t, a.into_result().unwrap(), v);
self.pointer.frame();
}
wl_pointer::Event::Frame => {
self.pointer.frame();
}
_ => todo!(),
},
Event::Keyboard(e) => match e {
wl_keyboard::Event::Key {
serial: _,
time: t,
key: k,
state: s,
} => {
self.keyboard.key(t, k, u32::from(s));
}
wl_keyboard::Event::Modifiers {
serial: _,
mods_depressed,
mods_latched,
mods_locked,
group,
} => {
self.keyboard.modifiers(mods_depressed, mods_latched, mods_locked, group);
}
_ => todo!(),
},
Event::Release() => {
self.keyboard.modifiers(77, 0, 0, 0);
self.keyboard.modifiers(0, 0, 0, 0);
}
}
Ok(())
}
}
delegate_noop!(App: Vp);
delegate_noop!(App: Vk);
delegate_noop!(App: VpManager);
delegate_noop!(App: VkManager);
delegate_noop!(App: wl_seat::WlSeat);
impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for App {
fn event(
_: &mut App,
_: &wl_registry::WlRegistry,
_: wl_registry::Event,
_: &GlobalListContents,
_: &Connection,
_: &QueueHandle<App>,
) {
}
}

View File

@@ -1,10 +1,11 @@
use lan_mouse::protocol;
use crate::{request, client::{ClientHandle, Position, Client}};
use memmap::Mmap;
use std::{
fs::File,
io::{BufWriter, Write},
os::unix::prelude::{AsRawFd, FromRawFd},
os::unix::prelude::{AsRawFd, FromRawFd}, sync::mpsc::SyncSender, rc::Rc,
};
use wayland_protocols::wp::{
@@ -39,6 +40,8 @@ use wayland_client::{
use tempfile;
use super::Event;
struct Globals {
compositor: wl_compositor::WlCompositor,
pointer_constraints: ZwpPointerConstraintsV1,
@@ -51,19 +54,15 @@ struct Globals {
struct App {
running: bool,
windows: Windows,
pointer_lock: Option<ZwpLockedPointerV1>,
rel_pointer: Option<ZwpRelativePointerV1>,
shortcut_inhibitor: Option<ZwpKeyboardShortcutsInhibitorV1>,
connection: protocol::Connection,
client_for_window: Vec<(Rc<Window>, ClientHandle)>,
focused: Option<(Rc<Window>, ClientHandle)>,
g: Globals,
}
struct Windows {
_left: Option<Window>,
right: Option<Window>,
_top: Option<Window>,
_bottom: Option<Window>,
tx: SyncSender<(Event, ClientHandle)>,
server: request::Server,
qh: QueueHandle<Self>,
}
struct Window {
@@ -73,34 +72,40 @@ struct Window {
}
impl Window {
fn new(g: &Globals, qh: QueueHandle<App>) -> Window {
fn new(g: &Globals, qh: &QueueHandle<App>, pos: Position) -> Window {
let (width, height) = (1, 1440);
let mut file = tempfile::tempfile().unwrap();
draw(&mut file, (width, height));
let pool = g
.shm
.create_pool(file.as_raw_fd(), (width * height * 4) as i32, &qh, ());
.create_pool(file.as_raw_fd(), (width * height * 4) as i32, qh, ());
let buffer = pool.create_buffer(
0,
width as i32,
height as i32,
(width * 4) as i32,
wl_shm::Format::Argb8888,
&qh,
qh,
(),
);
let surface = g.compositor.create_surface(&qh, ());
let surface = g.compositor.create_surface(qh, ());
let layer_surface = g.layer_shell.get_layer_surface(
&surface,
None,
Layer::Top,
"LAN Mouse Sharing".into(),
&qh,
qh,
(),
);
let anchor = match pos {
Position::Left => Anchor::Left,
Position::Right => Anchor::Right,
Position::Top => Anchor::Top,
Position::Bottom => Anchor::Bottom,
};
layer_surface.set_anchor(Anchor::Right);
layer_surface.set_anchor(anchor);
layer_surface.set_size(1, 1440);
layer_surface.set_exclusive_zone(0);
layer_surface.set_margin(0, 0, 0, 0);
@@ -114,9 +119,11 @@ impl Window {
}
}
fn main() {
let config = lan_mouse::config::Config::new("config.toml").unwrap();
let connection = protocol::Connection::new(config);
pub fn run(
tx: SyncSender<(Event, ClientHandle)>,
server: request::Server,
clients: Vec<Client>,
) {
let conn = Connection::connect_to_env().expect("could not connect to wayland compositor");
let (g, mut queue) = registry_queue_init::<App>(&conn).expect("failed to initialize wl_registry");
let qh = queue.handle();
@@ -129,7 +136,7 @@ fn main() {
.expect("wl_shm v1 not supported");
let layer_shell: ZwlrLayerShellV1 = g
.bind(&qh, 3..=4, ())
.expect("zwlr_layer_shell_v1 >= v3 not supported");
.expect("zwlr_layer_shell_v1 >= v3 not supported - required to display a surface at the edge of the screen");
let seat: wl_seat::WlSeat = g
.bind(&qh, 7..=8, ())
.expect("wl_seat >= v7 not supported");
@@ -153,23 +160,25 @@ fn main() {
shortcut_inhibit_manager,
};
let windows: Windows = Windows {
_left: None,
right: Some(Window::new(&g, qh)),
_top: None,
_bottom: None,
};
let client_for_window = Vec::new();
let mut app = App {
running: true,
g,
windows,
pointer_lock: None,
rel_pointer: None,
shortcut_inhibitor: None,
connection,
client_for_window,
focused: None,
tx,
server,
qh,
};
for client in clients {
app.add_client(client.handle, client.pos);
}
while app.running {
queue.blocking_dispatch(&mut app).unwrap();
}
@@ -185,15 +194,27 @@ fn draw(f: &mut File, (width, height): (u32, u32)) {
}
impl App {
fn grab(&mut self, pointer: &wl_pointer::WlPointer, serial: u32, qh: &QueueHandle<App>) {
fn grab(
&mut self,
surface: &wl_surface::WlSurface,
pointer: &wl_pointer::WlPointer,
serial: u32,
qh: &QueueHandle<App>
) {
let (window, _) = self.focused.as_ref().unwrap();
// hide the cursor
pointer.set_cursor(serial, None, 0, 0);
let layer_surface = &self.windows.right.as_ref().unwrap().layer_surface;
layer_surface.set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
let surface = &self.windows.right.as_ref().unwrap().surface;
surface.commit();
// capture input
window.layer_surface.set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
window.surface.commit();
// lock pointer
if self.pointer_lock.is_none() {
self.pointer_lock = Some(self.g.pointer_constraints.lock_pointer(
&surface,
surface,
pointer,
None,
Lifetime::Oneshot,
@@ -201,6 +222,8 @@ impl App {
(),
));
}
// request relative input
if self.rel_pointer.is_none() {
self.rel_pointer = Some(self.g.relative_pointer_manager.get_relative_pointer(
pointer,
@@ -208,9 +231,11 @@ impl App {
(),
));
}
// capture modifier keys
if self.shortcut_inhibitor.is_none() {
self.shortcut_inhibitor = Some(self.g.shortcut_inhibit_manager.inhibit_shortcuts(
&surface,
surface,
&self.g.seat,
qh,
(),
@@ -219,23 +244,36 @@ impl App {
}
fn ungrab(&mut self) {
let layer_surface = &self.windows.right.as_ref().unwrap().layer_surface;
layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None);
let surface = &self.windows.right.as_ref().unwrap().surface;
surface.commit();
// get focused client
let (window, _client) = self.focused.as_ref().unwrap();
// ungrab surface
window.layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None);
window.surface.commit();
// release pointer
if let Some(pointer_lock) = &self.pointer_lock {
pointer_lock.destroy();
self.pointer_lock = None;
}
// destroy relative input
if let Some(rel_pointer) = &self.rel_pointer {
rel_pointer.destroy();
self.rel_pointer = None;
}
// release shortcut inhibitor
if let Some(shortcut_inhibitor) = &self.shortcut_inhibitor {
shortcut_inhibitor.destroy();
self.shortcut_inhibitor = None;
}
}
fn add_client(&mut self, client: ClientHandle, pos: Position) {
let window = Rc::new(Window::new(&self.g, &self.qh, pos));
self.client_for_window.push((window, client));
}
}
impl Dispatch<wl_seat::WlSeat, ()> for App {
@@ -273,23 +311,40 @@ impl Dispatch<wl_pointer::WlPointer, ()> for App {
match event {
wl_pointer::Event::Enter {
serial,
surface: _,
surface,
surface_x: _,
surface_y: _,
} => {
app.grab(pointer, serial, qh);
// get client corresponding to the focused surface
{
let (window, client) = app.client_for_window
.iter()
.find(|(w,_c)| w.surface == surface)
.unwrap();
app.focused = Some((window.clone(), *client));
app.grab(&surface, pointer, serial.clone(), qh);
}
let (_, client) = app.client_for_window
.iter()
.find(|(w,_c)| w.surface == surface)
.unwrap();
app.tx.send((Event::Release(), *client)).unwrap();
}
wl_pointer::Event::Leave { .. } => {
app.ungrab();
}
wl_pointer::Event::Button { .. } => {
app.connection.send_event(event);
let (_, client) = app.focused.as_ref().unwrap();
app.tx.send((Event::Pointer(event), *client)).unwrap();
}
wl_pointer::Event::Axis { .. } => {
app.connection.send_event(event);
let (_, client) = app.focused.as_ref().unwrap();
app.tx.send((Event::Pointer(event), *client)).unwrap();
}
wl_pointer::Event::Frame { .. } => {
app.connection.send_event(event);
let (_, client) = app.focused.as_ref().unwrap();
app.tx.send((Event::Pointer(event), *client)).unwrap();
}
_ => {}
}
@@ -305,12 +360,20 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for App {
_: &Connection,
_: &QueueHandle<Self>,
) {
let (_window, client) = match &app.focused {
Some(focused) => (Some(&focused.0), Some(&focused.1)),
None => (None, None),
};
match event {
wl_keyboard::Event::Key { .. } => {
app.connection.send_event(event);
if let Some(client) = client {
app.tx.send((Event::Keyboard(event), *client)).unwrap();
}
}
wl_keyboard::Event::Modifiers { mods_depressed, .. } => {
app.connection.send_event(event);
if let Some(client) = client {
app.tx.send((Event::Keyboard(event), *client)).unwrap();
}
if mods_depressed == 77 {
// ctrl shift super alt
app.ungrab();
@@ -322,8 +385,7 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for App {
size: _,
} => {
let mmap = unsafe { Mmap::map(&File::from_raw_fd(fd.as_raw_fd())).unwrap() };
app.connection
.offer_data(protocol::DataRequest::KeyMap, mmap);
app.server.offer_data(request::Request::KeyMap, mmap);
}
_ => (),
}
@@ -348,12 +410,18 @@ impl Dispatch<ZwpRelativePointerV1, ()> for App {
dy_unaccel: surface_y,
} = event
{
let time = (((utime_hi as u64) << 32 | utime_lo as u64) / 1000) as u32;
app.connection.send_event(wl_pointer::Event::Motion {
time,
surface_x,
surface_y,
});
if let Some((_window, client)) = &app.focused {
let time = (((utime_hi as u64) << 32 | utime_lo as u64) / 1000) as u32;
app.tx.send((
Event::Pointer(wl_pointer::Event::Motion {
time,
surface_x,
surface_y,
}),
*client,
)).unwrap();
}
}
}
}
@@ -368,10 +436,16 @@ impl Dispatch<ZwlrLayerSurfaceV1, ()> for App {
_: &QueueHandle<Self>,
) {
if let zwlr_layer_surface_v1::Event::Configure { serial, .. } = event {
let surface = &app.windows.right.as_ref().unwrap().surface;
let (window, _client) = app.client_for_window
.iter()
.find(|(w,_c)| &w.layer_surface == layer_surface)
.unwrap();
// client corresponding to the layer_surface
let surface = &window.surface;
let buffer = &window.buffer;
surface.commit();
layer_surface.ack_configure(serial);
surface.attach(Some(&app.windows.right.as_ref().unwrap().buffer), 0, 0);
surface.attach(Some(&buffer), 0, 0);
surface.commit();
}
}

119
src/event/server.rs Normal file
View File

@@ -0,0 +1,119 @@
use std::{
net::{UdpSocket, SocketAddr},
error::Error,
sync::{mpsc::{SyncSender, Receiver}, atomic::{AtomicBool, Ordering}, Arc},
thread::{self, JoinHandle}, collections::HashMap,
};
use crate::client::{ClientHandle, ClientManager};
use super::{Event, Encode, Decode};
pub struct Server {
listen_addr: SocketAddr,
sending: Arc<AtomicBool>,
}
impl Server {
pub fn new(port: u16) -> Self {
let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), port);
let sending = Arc::new(AtomicBool::new(false));
Server { listen_addr, sending }
}
pub fn run(self, client_manager: &mut ClientManager, produce_rx: Receiver<(Event, ClientHandle)>, consume_tx: SyncSender<(Event, ClientHandle)>) -> Result<(JoinHandle<()>, JoinHandle<()>), Box<dyn Error>> {
let udp_socket = UdpSocket::bind(self.listen_addr)?;
let rx = udp_socket.try_clone().unwrap();
let tx = udp_socket;
let sending = self.sending.clone();
let mut client_for_socket = HashMap::new();
for client in client_manager.get_clients() {
println!("{}: {}", client.handle, client.addr);
client_for_socket.insert(client.addr, client.handle);
}
let receiver = thread::Builder::new().name("event receiver".into()).spawn(move || {
loop {
let (event, addr) = match Server::receive_event(&rx) {
Some(e) => e,
None => { continue },
};
let client_handle = match client_for_socket.get(&addr) {
Some(c) => *c,
None => {
println!("Allow connection from {:?}? [Y/n]", addr);
continue
},
};
// There is a race condition between loading this
// value and handling the event:
// In the meantime a event could be produced, which
// should theoretically disable receiving of events.
//
// This is however not a huge problem, as some
// events that make it through are not a large problem
if sending.load(Ordering::Acquire) {
// ignore received events when in sending state
// if release event is received, switch state to receiving
if let Event::Release() = event {
sending.store(false, Ordering::Release);
consume_tx.send((event, client_handle)).expect("event consumer unavailable");
}
} else {
if let Event::Release() = event {
sending.store(false, Ordering::Release);
}
// we retrieve all events
consume_tx.send((event, client_handle)).expect("event consumer unavailable");
}
}
}).unwrap();
let sending = self.sending.clone();
let mut socket_for_client = HashMap::new();
for client in client_manager.get_clients() {
socket_for_client.insert(client.handle, client.addr);
}
let sender = thread::Builder::new().name("event sender".into()).spawn(move || {
loop {
let (event, client_handle) = produce_rx.recv().expect("event producer unavailable");
let addr = match socket_for_client.get(&client_handle) {
Some(addr) => addr,
None => continue,
};
if sending.load(Ordering::Acquire) {
Server::send_event(&tx, event, *addr);
} else {
// only accept enter event
if let Event::Release() = event {
// set state to sending, to ignore incoming events
// and enable sending of events
sending.store(true, Ordering::Release);
Server::send_event(&tx, event, *addr);
}
}
}
}).unwrap();
Ok((receiver, sender))
}
fn send_event<E: Encode>(tx: &UdpSocket, e: E, addr: SocketAddr) {
if let Err(e) = tx.send_to(&e.encode(), addr) {
eprintln!("{}", e);
}
}
fn receive_event(rx: &UdpSocket) -> Option<(Event, SocketAddr)> {
let mut buf = vec![0u8; 21];
if let Ok((_amt, src)) = rx.recv_from(&mut buf) {
Some((Event::decode(buf), src))
} else {
None
}
}
}

View File

@@ -1,3 +1,5 @@
pub mod config;
pub mod dns;
pub mod protocol;
pub mod event;
pub mod request;
pub mod client;

88
src/main.rs Normal file
View File

@@ -0,0 +1,88 @@
use std::{sync::mpsc, thread, net::SocketAddr};
use lan_mouse::{
event::{self, producer, consumer},
config,
request,
client::{ClientManager, Position}, dns,
};
fn add_client(client_manager: &mut ClientManager, client: &config::Client, pos: Position) {
let ip = match client.ip {
Some(ip) => ip,
None => match &client.host_name {
Some(host_name) => match dns::resolve(host_name) {
Ok(ip) => ip,
Err(e) => panic!("{}", e),
},
None => panic!("neither ip nor hostname specified"),
}
};
let addr = SocketAddr::new(ip, client.port.unwrap_or(42069));
client_manager.add_client(addr, pos);
}
pub fn main() {
// parse config file
let config = config::Config::new("config.toml").unwrap();
// port or default
let port = config.port.unwrap_or(42069);
// event channel for producing events
let (produce_tx, produce_rx) = mpsc::sync_channel(128);
// event channel for consuming events
let (consume_tx, consume_rx) = mpsc::sync_channel(128);
let mut client_manager = ClientManager::new();
// add clients from config
for client in vec![
&config.client.left,
&config.client.right,
&config.client.top,
&config.client.bottom,
] {
if let Some(client) = client {
let pos = match client {
client if Some(client) == config.client.left.as_ref() => Position::Left,
client if Some(client) == config.client.right.as_ref() => Position::Right,
client if Some(client) == config.client.top.as_ref() => Position::Top,
client if Some(client) == config.client.bottom.as_ref() => Position::Bottom,
_ => panic!(),
};
add_client(&mut client_manager, client, pos);
}
}
// start receiving client connection requests
let (request_server, request_thread) = request::Server::listen(port).unwrap();
let clients = client_manager.get_clients();
// start producing and consuming events
let event_producer = thread::Builder::new()
.name("event producer".into())
.spawn(|| {
producer::run(produce_tx, request_server, clients);
}).unwrap();
let clients = client_manager.get_clients();
let event_consumer = thread::Builder::new()
.name("event consumer".into())
.spawn(|| {
consumer::run(consume_rx, clients);
}).unwrap();
// start sending and receiving events
let event_server = event::server::Server::new(port);
let (receiver, sender) = event_server.run(&mut client_manager, produce_rx, consume_tx).unwrap();
request_thread.join().unwrap();
receiver.join().unwrap();
sender.join().unwrap();
event_producer.join().unwrap();
event_consumer.join().unwrap();
}

View File

@@ -1,302 +0,0 @@
use crate::config::{self, Config};
use crate::dns;
use memmap::Mmap;
use std::{
collections::HashMap,
io::prelude::*,
net::TcpListener,
process::exit,
sync::{Arc, RwLock},
thread,
};
use wayland_client::{
protocol::{wl_keyboard, wl_pointer},
WEnum,
};
use std::net::{SocketAddr, TcpStream, UdpSocket};
trait Resolve {
fn resolve(&self) -> Option<SocketAddr>;
}
impl Resolve for Option<config::Client> {
fn resolve(&self) -> Option<SocketAddr> {
let client = match self {
Some(client) => client,
None => return None,
};
let ip = match client.ip {
Some(ip) => ip,
None => dns::resolve(&client.host_name).unwrap(),
};
Some(SocketAddr::new(ip, client.port.unwrap_or(42069)))
}
}
struct ClientAddrs {
left: Option<SocketAddr>,
right: Option<SocketAddr>,
_top: Option<SocketAddr>,
_bottom: Option<SocketAddr>,
}
pub struct Connection {
udp_socket: UdpSocket,
client: ClientAddrs,
offer_data: Arc<RwLock<HashMap<DataRequest, Mmap>>>,
}
pub trait Encode {
fn encode(&self) -> Vec<u8>;
}
pub trait Decode {
fn decode(buf: Vec<u8>) -> Self;
}
impl Encode for wl_pointer::Event {
fn encode(&self) -> Vec<u8> {
let mut buf = Vec::new();
match *self {
Self::Motion {
time: t,
surface_x: x,
surface_y: y,
} => {
buf.push(0u8);
buf.extend_from_slice(t.to_ne_bytes().as_ref());
buf.extend_from_slice(x.to_ne_bytes().as_ref());
buf.extend_from_slice(y.to_ne_bytes().as_ref());
}
Self::Button {
serial: _,
time: t,
button: b,
state: s,
} => {
buf.push(1u8);
buf.extend_from_slice(t.to_ne_bytes().as_ref());
buf.extend_from_slice(b.to_ne_bytes().as_ref());
buf.push(u32::from(s) as u8);
}
Self::Axis {
time: t,
axis: a,
value: v,
} => {
buf.push(2u8);
buf.extend_from_slice(t.to_ne_bytes().as_ref());
buf.push(u32::from(a) as u8);
buf.extend_from_slice(v.to_ne_bytes().as_ref());
}
Self::Frame {} => {
buf.push(3u8);
}
_ => todo!(),
}
buf
}
}
impl Encode for wl_keyboard::Event {
fn encode(&self) -> Vec<u8> {
let mut buf = Vec::new();
match self {
Self::Key {
serial: _,
time: t,
key: k,
state: s,
} => {
buf.push(4u8);
buf.extend_from_slice(t.to_ne_bytes().as_ref());
buf.extend_from_slice(k.to_ne_bytes().as_ref());
buf.push(u32::from(*s) as u8);
}
Self::Modifiers {
serial: _,
mods_depressed,
mods_latched,
mods_locked,
group,
} => {
buf.push(5u8);
buf.extend_from_slice(mods_depressed.to_ne_bytes().as_ref());
buf.extend_from_slice(mods_latched.to_ne_bytes().as_ref());
buf.extend_from_slice(mods_locked.to_ne_bytes().as_ref());
buf.extend_from_slice(group.to_ne_bytes().as_ref());
}
_ => todo!(),
}
buf
}
}
pub enum Event {
Pointer(wl_pointer::Event),
Keyboard(wl_keyboard::Event),
}
impl Decode for Event {
fn decode(buf: Vec<u8>) -> Self {
match buf[0] {
0 => Self::Pointer(wl_pointer::Event::Motion {
time: u32::from_ne_bytes(buf[1..5].try_into().unwrap()),
surface_x: f64::from_ne_bytes(buf[5..13].try_into().unwrap()),
surface_y: f64::from_ne_bytes(buf[13..21].try_into().unwrap()),
}),
1 => Self::Pointer(wl_pointer::Event::Button {
serial: 0,
time: (u32::from_ne_bytes(buf[1..5].try_into().unwrap())),
button: (u32::from_ne_bytes(buf[5..9].try_into().unwrap())),
state: (WEnum::Value(wl_pointer::ButtonState::try_from(buf[9] as u32).unwrap())),
}),
2 => Self::Pointer(wl_pointer::Event::Axis {
time: (u32::from_ne_bytes(buf[1..5].try_into().unwrap())),
axis: (WEnum::Value(wl_pointer::Axis::try_from(buf[5] as u32).unwrap())),
value: (f64::from_ne_bytes(buf[6..14].try_into().unwrap())),
}),
3 => Self::Pointer(wl_pointer::Event::Frame {}),
4 => Self::Keyboard(wl_keyboard::Event::Key {
serial: 0,
time: u32::from_ne_bytes(buf[1..5].try_into().unwrap()),
key: u32::from_ne_bytes(buf[5..9].try_into().unwrap()),
state: WEnum::Value(wl_keyboard::KeyState::try_from(buf[9] as u32).unwrap()),
}),
5 => Self::Keyboard(wl_keyboard::Event::Modifiers {
serial: 0,
mods_depressed: u32::from_ne_bytes(buf[1..5].try_into().unwrap()),
mods_latched: u32::from_ne_bytes(buf[5..9].try_into().unwrap()),
mods_locked: u32::from_ne_bytes(buf[9..13].try_into().unwrap()),
group: u32::from_ne_bytes(buf[13..17].try_into().unwrap()),
}),
_ => panic!("protocol violation"),
}
}
}
#[derive(PartialEq, Eq, Hash)]
pub enum DataRequest {
KeyMap,
}
impl From<u32> for DataRequest {
fn from(idx: u32) -> Self {
match idx {
0 => Self::KeyMap,
_ => panic!("invalid enum value"),
}
}
}
impl From<[u8; 4]> for DataRequest {
fn from(buf: [u8; 4]) -> Self {
DataRequest::from(u32::from_ne_bytes(buf))
}
}
impl From<DataRequest> for u32 {
fn from(d: DataRequest) -> Self {
match d {
DataRequest::KeyMap => 0,
}
}
}
fn handle_request(data: &Arc<RwLock<HashMap<DataRequest, Mmap>>>, mut stream: TcpStream) {
let mut buf = [0u8; 4];
stream.read_exact(&mut buf).unwrap();
match DataRequest::from(buf) {
DataRequest::KeyMap => {
let data = data.read().unwrap();
let buf = data.get(&DataRequest::KeyMap);
match buf {
None => {
stream.write(&0u32.to_ne_bytes()).unwrap();
}
Some(buf) => {
stream.write(&buf[..].len().to_ne_bytes()).unwrap();
stream.write(&buf[..]).unwrap();
}
}
stream.flush().unwrap();
}
}
}
impl Connection {
pub fn new(config: Config) -> Connection {
let clients = ClientAddrs {
left: config.client.left.resolve(),
right: config.client.right.resolve(),
_top: config.client.top.resolve(),
_bottom: config.client.bottom.resolve(),
};
let data: Arc<RwLock<HashMap<DataRequest, Mmap>>> = Arc::new(RwLock::new(HashMap::new()));
let thread_data = data.clone();
let port = config.port.unwrap_or(42069);
let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), port);
thread::spawn(move || {
let sock = TcpListener::bind(listen_addr).unwrap();
for stream in sock.incoming() {
if let Ok(stream) = stream {
handle_request(&thread_data, stream);
}
}
});
let sock = UdpSocket::bind(listen_addr);
let sock = match sock {
Ok(sock) => sock,
Err(e) => match e.kind() {
std::io::ErrorKind::AddrInUse => {
eprintln!("Server already running on port {}", port);
exit(1);
}
_ => panic!("{}", e),
},
};
let c = Connection {
udp_socket: sock,
client: clients,
offer_data: data,
};
c
}
pub fn offer_data(&self, req: DataRequest, d: Mmap) {
self.offer_data.write().unwrap().insert(req, d);
}
pub fn receive_data(&self, req: DataRequest) -> Option<Vec<u8>> {
let mut sock = TcpStream::connect(self.client.left.unwrap()).unwrap();
sock.write(&u32::from(req).to_ne_bytes()).unwrap();
sock.flush().unwrap();
let mut buf = [0u8; 8];
sock.read_exact(&mut buf[..]).unwrap();
let len = usize::from_ne_bytes(buf);
if len == 0 {
return None;
}
let mut data: Vec<u8> = vec![0u8; len];
sock.read_exact(&mut data[..]).unwrap();
Some(data)
}
pub fn send_event<E: Encode>(&self, e: E) {
// TODO check which client
if let Some(addr) = self.client.right {
self.udp_socket.send_to(&e.encode(), addr).unwrap();
}
}
pub fn receive_event(&self) -> Option<Event> {
let mut buf = vec![0u8; 21];
if let Ok((_amt, _src)) = self.udp_socket.recv_from(&mut buf) {
Some(Event::decode(buf))
} else {
None
}
}
}

130
src/request.rs Normal file
View File

@@ -0,0 +1,130 @@
use std::{
net::{TcpListener, SocketAddr, TcpStream},
io::prelude::*,
collections::HashMap, sync::{RwLock, Arc},
error::Error,
thread::{self, JoinHandle},
};
use memmap::Mmap;
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
pub enum Request {
KeyMap,
Connect,
}
impl TryFrom<[u8; 4]> for Request {
fn try_from(buf: [u8; 4]) -> Result<Self, Self::Error> {
let val = u32::from_ne_bytes(buf);
match val {
x if x == Request::KeyMap as u32 => Ok(Self::KeyMap),
x if x == Request::Connect as u32 => Ok(Self::Connect),
_ => Err("Bad Request"),
}
}
type Error = &'static str;
}
#[derive(Clone)]
pub struct Server {
data: Arc<RwLock<HashMap<Request, Mmap>>>,
}
impl Server {
fn handle_request(&self, mut stream: TcpStream) {
let mut buf = [0u8; 4];
stream.read_exact(&mut buf).unwrap();
match Request::try_from(buf) {
Ok(Request::KeyMap) => {
let data = self.data.read().unwrap();
let buf = data.get(&Request::KeyMap);
match buf {
None => {
stream.write(&0u32.to_ne_bytes()).unwrap();
}
Some(buf) => {
stream.write(&buf[..].len().to_ne_bytes()).unwrap();
stream.write(&buf[..]).unwrap();
}
}
stream.flush().unwrap();
}
Ok(Request::Connect) => todo!(),
Err(msg) => eprintln!("{}", msg),
}
}
pub fn listen(port: u16) -> Result<(Server, JoinHandle<()>), Box<dyn Error>> {
let data: Arc<RwLock<HashMap<Request, Mmap>>> = Arc::new(RwLock::new(HashMap::new()));
let listen_addr = SocketAddr::new("0.0.0.0".parse().unwrap(), port);
let server = Server { data };
let server_copy = server.clone();
let thread = thread::spawn(move || {
let listen_socket = TcpListener::bind(listen_addr).unwrap();
for stream in listen_socket.incoming() {
match stream {
Ok(stream) => {
server.handle_request(stream);
}
Err(e) => {
eprintln!("{}", e);
}
}
}
});
Ok((server_copy, thread))
}
pub fn offer_data(&self, req: Request, d: Mmap) {
self.data.write().unwrap().insert(req, d);
}
}
pub fn request_data(addr: SocketAddr, req: Request) -> Option<Vec<u8>> {
// connect to server
let mut sock = match TcpStream::connect(addr) {
Ok(sock) => sock,
Err(e) => {
eprintln!("{}", e);
return None;
}
};
// write the request to the socket
// convert to u32
let req: u32 = req as u32;
if let Err(e) = sock.write(&req.to_ne_bytes()) {
eprintln!("{}", e);
return None;
}
if let Err(e) = sock.flush() {
eprintln!("{}", e);
return None;
}
// read the response = (len, data) - len 0 means no data / bad request
// read len
let mut buf = [0u8; 8];
if let Err(e) = sock.read_exact(&mut buf[..]) {
eprintln!("{}", e);
return None;
}
let len = usize::from_ne_bytes(buf);
// check for bad request
if len == 0 {
return None;
}
// read the data
let mut data: Vec<u8> = vec![0u8; len];
if let Err(e) = sock.read_exact(&mut data[..]) {
eprintln!("{}", e);
return None;
}
Some(data)
}