mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-29 08:00:55 +03:00
major refactor
every instance of lan-mouse can now simultaneously send and receive events
This commit is contained in:
197
src/event/consumer.rs
Normal file
197
src/event/consumer.rs
Normal 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>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
471
src/event/producer.rs
Normal file
471
src/event/producer.rs
Normal file
@@ -0,0 +1,471 @@
|
||||
use crate::{request, client::{ClientHandle, Position, Client}};
|
||||
|
||||
use memmap::Mmap;
|
||||
|
||||
use std::{
|
||||
fs::File,
|
||||
io::{BufWriter, Write},
|
||||
os::unix::prelude::{AsRawFd, FromRawFd}, sync::mpsc::SyncSender, rc::Rc,
|
||||
};
|
||||
|
||||
use wayland_protocols::wp::{
|
||||
keyboard_shortcuts_inhibit::zv1::client::{
|
||||
zwp_keyboard_shortcuts_inhibit_manager_v1::ZwpKeyboardShortcutsInhibitManagerV1,
|
||||
zwp_keyboard_shortcuts_inhibitor_v1::ZwpKeyboardShortcutsInhibitorV1,
|
||||
},
|
||||
pointer_constraints::zv1::client::{
|
||||
zwp_locked_pointer_v1::ZwpLockedPointerV1,
|
||||
zwp_pointer_constraints_v1::{Lifetime, ZwpPointerConstraintsV1},
|
||||
},
|
||||
relative_pointer::zv1::client::{
|
||||
zwp_relative_pointer_manager_v1::ZwpRelativePointerManagerV1,
|
||||
zwp_relative_pointer_v1::{self, ZwpRelativePointerV1},
|
||||
},
|
||||
};
|
||||
|
||||
use wayland_protocols_wlr::layer_shell::v1::client::{
|
||||
zwlr_layer_shell_v1::{Layer, ZwlrLayerShellV1},
|
||||
zwlr_layer_surface_v1::{self, Anchor, KeyboardInteractivity, ZwlrLayerSurfaceV1},
|
||||
};
|
||||
|
||||
use wayland_client::{
|
||||
delegate_noop, delegate_dispatch,
|
||||
globals::{registry_queue_init, GlobalListContents},
|
||||
protocol::{
|
||||
wl_buffer, wl_compositor, wl_keyboard, wl_pointer, wl_region, wl_registry, wl_seat, wl_shm,
|
||||
wl_shm_pool, wl_surface,
|
||||
},
|
||||
Connection, Dispatch, QueueHandle, WEnum,
|
||||
};
|
||||
|
||||
use tempfile;
|
||||
|
||||
use super::Event;
|
||||
|
||||
struct Globals {
|
||||
compositor: wl_compositor::WlCompositor,
|
||||
pointer_constraints: ZwpPointerConstraintsV1,
|
||||
relative_pointer_manager: ZwpRelativePointerManagerV1,
|
||||
shortcut_inhibit_manager: ZwpKeyboardShortcutsInhibitManagerV1,
|
||||
seat: wl_seat::WlSeat,
|
||||
shm: wl_shm::WlShm,
|
||||
layer_shell: ZwlrLayerShellV1,
|
||||
}
|
||||
|
||||
struct App {
|
||||
running: bool,
|
||||
pointer_lock: Option<ZwpLockedPointerV1>,
|
||||
rel_pointer: Option<ZwpRelativePointerV1>,
|
||||
shortcut_inhibitor: Option<ZwpKeyboardShortcutsInhibitorV1>,
|
||||
client_for_window: Vec<(Rc<Window>, ClientHandle)>,
|
||||
focused: Option<(Rc<Window>, ClientHandle)>,
|
||||
g: Globals,
|
||||
tx: SyncSender<(Event, ClientHandle)>,
|
||||
server: request::Server,
|
||||
qh: QueueHandle<Self>,
|
||||
}
|
||||
|
||||
struct Window {
|
||||
buffer: wl_buffer::WlBuffer,
|
||||
surface: wl_surface::WlSurface,
|
||||
layer_surface: ZwlrLayerSurfaceV1,
|
||||
}
|
||||
|
||||
impl 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, ());
|
||||
let buffer = pool.create_buffer(
|
||||
0,
|
||||
width as i32,
|
||||
height as i32,
|
||||
(width * 4) as i32,
|
||||
wl_shm::Format::Argb8888,
|
||||
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,
|
||||
(),
|
||||
);
|
||||
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);
|
||||
layer_surface.set_size(1, 1440);
|
||||
layer_surface.set_exclusive_zone(0);
|
||||
layer_surface.set_margin(0, 0, 0, 0);
|
||||
surface.set_input_region(None);
|
||||
surface.commit();
|
||||
Window {
|
||||
buffer,
|
||||
surface,
|
||||
layer_surface,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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();
|
||||
|
||||
let compositor: wl_compositor::WlCompositor = g
|
||||
.bind(&qh, 4..=5, ())
|
||||
.expect("wl_compositor >= v4 not supported");
|
||||
let shm: wl_shm::WlShm = g
|
||||
.bind(&qh, 1..=1, ())
|
||||
.expect("wl_shm v1 not supported");
|
||||
let layer_shell: ZwlrLayerShellV1 = g
|
||||
.bind(&qh, 3..=4, ())
|
||||
.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");
|
||||
let pointer_constraints: ZwpPointerConstraintsV1 = g
|
||||
.bind(&qh, 1..=1, ())
|
||||
.expect("zwp_pointer_constraints_v1 not supported");
|
||||
let relative_pointer_manager: ZwpRelativePointerManagerV1 = g
|
||||
.bind(&qh, 1..=1, ())
|
||||
.expect("zwp_relative_pointer_manager_v1 not supported");
|
||||
let shortcut_inhibit_manager: ZwpKeyboardShortcutsInhibitManagerV1 = g
|
||||
.bind(&qh, 1..=1, ())
|
||||
.expect("zwp_keyboard_shortcuts_inhibit_manager_v1 not supported");
|
||||
|
||||
let g = Globals {
|
||||
compositor,
|
||||
shm,
|
||||
layer_shell,
|
||||
seat,
|
||||
pointer_constraints,
|
||||
relative_pointer_manager,
|
||||
shortcut_inhibit_manager,
|
||||
};
|
||||
|
||||
let client_for_window = Vec::new();
|
||||
|
||||
let mut app = App {
|
||||
running: true,
|
||||
g,
|
||||
pointer_lock: None,
|
||||
rel_pointer: None,
|
||||
shortcut_inhibitor: None,
|
||||
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();
|
||||
}
|
||||
}
|
||||
|
||||
fn draw(f: &mut File, (width, height): (u32, u32)) {
|
||||
let mut buf = BufWriter::new(f);
|
||||
for _ in 0..height {
|
||||
for _ in 0..width {
|
||||
buf.write_all(&0x44FbF1C7u32.to_ne_bytes()).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl 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);
|
||||
|
||||
// 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,
|
||||
pointer,
|
||||
None,
|
||||
Lifetime::Oneshot,
|
||||
qh,
|
||||
(),
|
||||
));
|
||||
}
|
||||
|
||||
// request relative input
|
||||
if self.rel_pointer.is_none() {
|
||||
self.rel_pointer = Some(self.g.relative_pointer_manager.get_relative_pointer(
|
||||
pointer,
|
||||
qh,
|
||||
(),
|
||||
));
|
||||
}
|
||||
|
||||
// capture modifier keys
|
||||
if self.shortcut_inhibitor.is_none() {
|
||||
self.shortcut_inhibitor = Some(self.g.shortcut_inhibit_manager.inhibit_shortcuts(
|
||||
surface,
|
||||
&self.g.seat,
|
||||
qh,
|
||||
(),
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
fn ungrab(&mut self) {
|
||||
// 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 {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
seat: &wl_seat::WlSeat,
|
||||
event: <wl_seat::WlSeat as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
qh: &QueueHandle<Self>,
|
||||
) {
|
||||
if let wl_seat::Event::Capabilities {
|
||||
capabilities: WEnum::Value(capabilities),
|
||||
} = event
|
||||
{
|
||||
if capabilities.contains(wl_seat::Capability::Pointer) {
|
||||
seat.get_pointer(qh, ());
|
||||
}
|
||||
if capabilities.contains(wl_seat::Capability::Keyboard) {
|
||||
seat.get_keyboard(qh, ());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_pointer::WlPointer, ()> for App {
|
||||
fn event(
|
||||
app: &mut Self,
|
||||
pointer: &wl_pointer::WlPointer,
|
||||
event: <wl_pointer::WlPointer as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
qh: &QueueHandle<Self>,
|
||||
) {
|
||||
match event {
|
||||
wl_pointer::Event::Enter {
|
||||
serial,
|
||||
surface,
|
||||
surface_x: _,
|
||||
surface_y: _,
|
||||
} => {
|
||||
// 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 { .. } => {
|
||||
let (_, client) = app.focused.as_ref().unwrap();
|
||||
app.tx.send((Event::Pointer(event), *client)).unwrap();
|
||||
}
|
||||
wl_pointer::Event::Axis { .. } => {
|
||||
let (_, client) = app.focused.as_ref().unwrap();
|
||||
app.tx.send((Event::Pointer(event), *client)).unwrap();
|
||||
}
|
||||
wl_pointer::Event::Frame { .. } => {
|
||||
let (_, client) = app.focused.as_ref().unwrap();
|
||||
app.tx.send((Event::Pointer(event), *client)).unwrap();
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_keyboard::WlKeyboard, ()> for App {
|
||||
fn event(
|
||||
app: &mut Self,
|
||||
_: &wl_keyboard::WlKeyboard,
|
||||
event: wl_keyboard::Event,
|
||||
_: &(),
|
||||
_: &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 { .. } => {
|
||||
if let Some(client) = client {
|
||||
app.tx.send((Event::Keyboard(event), *client)).unwrap();
|
||||
}
|
||||
}
|
||||
wl_keyboard::Event::Modifiers { mods_depressed, .. } => {
|
||||
if let Some(client) = client {
|
||||
app.tx.send((Event::Keyboard(event), *client)).unwrap();
|
||||
}
|
||||
if mods_depressed == 77 {
|
||||
// ctrl shift super alt
|
||||
app.ungrab();
|
||||
}
|
||||
}
|
||||
wl_keyboard::Event::Keymap {
|
||||
format: _,
|
||||
fd,
|
||||
size: _,
|
||||
} => {
|
||||
let mmap = unsafe { Mmap::map(&File::from_raw_fd(fd.as_raw_fd())).unwrap() };
|
||||
app.server.offer_data(request::Request::KeyMap, mmap);
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<ZwpRelativePointerV1, ()> for App {
|
||||
fn event(
|
||||
app: &mut Self,
|
||||
_: &ZwpRelativePointerV1,
|
||||
event: <ZwpRelativePointerV1 as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
if let zwp_relative_pointer_v1::Event::RelativeMotion {
|
||||
utime_hi,
|
||||
utime_lo,
|
||||
dx: _,
|
||||
dy: _,
|
||||
dx_unaccel: surface_x,
|
||||
dy_unaccel: surface_y,
|
||||
} = event
|
||||
{
|
||||
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();
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<ZwlrLayerSurfaceV1, ()> for App {
|
||||
fn event(
|
||||
app: &mut Self,
|
||||
layer_surface: &ZwlrLayerSurfaceV1,
|
||||
event: <ZwlrLayerSurfaceV1 as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
if let zwlr_layer_surface_v1::Event::Configure { serial, .. } = event {
|
||||
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(&buffer), 0, 0);
|
||||
surface.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// delegate wl_registry events to App itself
|
||||
delegate_dispatch!(App: [wl_registry::WlRegistry: GlobalListContents] => App);
|
||||
|
||||
// don't emit any events
|
||||
delegate_noop!(App: wl_region::WlRegion);
|
||||
delegate_noop!(App: wl_shm_pool::WlShmPool);
|
||||
delegate_noop!(App: wl_compositor::WlCompositor);
|
||||
delegate_noop!(App: ZwlrLayerShellV1);
|
||||
delegate_noop!(App: ZwpRelativePointerManagerV1);
|
||||
delegate_noop!(App: ZwpKeyboardShortcutsInhibitManagerV1);
|
||||
delegate_noop!(App: ZwpPointerConstraintsV1);
|
||||
|
||||
// ignore events
|
||||
delegate_noop!(App: ignore wl_shm::WlShm);
|
||||
delegate_noop!(App: ignore wl_buffer::WlBuffer);
|
||||
delegate_noop!(App: ignore wl_surface::WlSurface);
|
||||
delegate_noop!(App: ignore ZwpKeyboardShortcutsInhibitorV1);
|
||||
delegate_noop!(App: ignore ZwpLockedPointerV1);
|
||||
119
src/event/server.rs
Normal file
119
src/event/server.rs
Normal 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
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user