diff --git a/src/bin/client.rs b/src/bin/client.rs index efcee76..2ef78b6 100644 --- a/src/bin/client.rs +++ b/src/bin/client.rs @@ -1,18 +1,15 @@ -use std::{net::UdpSocket, f64::consts::PI}; use std::io::{self, Write}; +use std::{f64::consts::PI, net::UdpSocket}; use wayland_protocols_wlr::virtual_pointer::v1::client::{ - zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1 as Vp, zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1 as VpManager, + zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1 as Vp, }; -use wayland_client::{ - protocol::wl_registry, - Connection, Dispatch, QueueHandle, EventQueue, -}; +use wayland_client::{protocol::wl_registry, Connection, Dispatch, EventQueue, QueueHandle}; // App State, implements Dispatch event handlers -struct AppData{ +struct AppData { vpm: Option, } @@ -28,20 +25,23 @@ impl Dispatch for AppData { qh: &QueueHandle, ) { // Match global event to get globals after requesting them in main - if let wl_registry::Event::Global { name, interface, .. } = event { + if let wl_registry::Event::Global { + name, interface, .. + } = event + { // println!("[{}] {} (v{})", name, interface, version); match &interface[..] { - "zwlr_virtual_pointer_manager_v1" => { // virtual pointer protocol - let vpm = registry.bind::(name, 1, qh, ()); // get the vp manager - app.vpm = Some(vpm); // save it to app state - }, + "zwlr_virtual_pointer_manager_v1" => { + // virtual pointer protocol + let vpm = registry.bind::(name, 1, qh, ()); // get the vp manager + app.vpm = Some(vpm); // save it to app state + } _ => {} } } } } - // The main function of our program fn main() { // establish connection via environment-provided configuration. @@ -58,7 +58,7 @@ fn main() { let _registry = display.get_registry(&qh, ()); let mut app_data = AppData { vpm: None }; - + // use roundtrip to process this event synchronously event_queue.roundtrip(&mut app_data).unwrap(); if let Some(vpm) = app_data.vpm { @@ -71,31 +71,21 @@ fn main() { } /// main loop handling udp packets -fn udp_loop(pointer: Vp, q: EventQueue) -> std::io::Result<()>{ +fn udp_loop(pointer: Vp, q: EventQueue) -> std::io::Result<()> { let socket = UdpSocket::bind("0.0.0.0:42069")?; // we don't care about possible dropped packets for now - let mut buf = [0; 0]; - let rps = 1.0; - let rpms = rps * 0.001; - let radpms = rpms * 2.0 * PI; - let mut rad = 0_f64; - let mut time = 0; + let mut buf = [0u8; 20]; loop { - let (_amt, _src) = socket.recv_from(&mut buf)?; + let (amt, _src) = socket.recv_from(&mut buf)?; + assert!(amt == 20); - let x = rad.cos(); - let y = rad.sin(); + let time: u32 = u32::from_ne_bytes(buf[0..4].try_into().unwrap()); + let x: f64 = f64::from_ne_bytes(buf[4..12].try_into().unwrap()); + let y: f64 = f64::from_ne_bytes(buf[12..20].try_into().unwrap()); - let scale = 100.0; - - pointer.motion(time, x * scale * radpms, y * scale * radpms); + pointer.motion(time, x, y); q.flush().unwrap(); - rad += radpms; - rad %= 2.0*PI; - time+=1; - print!("{}\r", time); - io::stdout().flush().unwrap(); } } diff --git a/src/bin/server.rs b/src/bin/server.rs index cec6727..19fc696 100644 --- a/src/bin/server.rs +++ b/src/bin/server.rs @@ -1,9 +1,349 @@ -use std::{net::UdpSocket, thread, time::Duration}; +use std::{ + fs::File, + io::{BufWriter, Write}, + net::UdpSocket, + os::unix::prelude::AsRawFd, +}; + +use wayland_protocols::xdg::shell::client::{xdg_surface, xdg_toplevel, xdg_wm_base}; + +use wayland_client::{ + protocol::{ + wl_buffer, wl_compositor, wl_keyboard, wl_pointer, wl_registry, wl_seat, wl_shm, + wl_shm_pool, wl_surface, + }, + Connection, Dispatch, QueueHandle, WEnum, +}; + +use tempfile; + +struct App { + running: bool, + compositor: Option, + buffer: Option, + wm_base: Option, + surface: Option, + top_level: Option, + xdg_surface: Option, + socket: UdpSocket, + surface_coords: (f64, f64), +} fn main() { - let socket = UdpSocket::bind("127.0.0.1:42070").expect("couldn't bind to address"); - loop { - socket.send_to(&[0; 0], "127.0.0.1:42069").expect("couldn't send data"); - thread::sleep(Duration::from_millis(1)); + // establish connection via environment-provided configuration. + let conn = Connection::connect_to_env().unwrap(); + + // Retrieve the wayland display object + let display = conn.display(); + + // Create an event queue for our event processing + let mut event_queue = conn.new_event_queue(); + let qh = event_queue.handle(); + + // Create a wl_registry object by sending the wl_display.get_registry request + display.get_registry(&qh, ()); + + let mut app = App { + running: true, + compositor: None, + buffer: None, + wm_base: None, + surface: None, + xdg_surface: None, + top_level: None, + socket: UdpSocket::bind("127.0.0.1:42070").expect("couldn't bind to address"), + surface_coords: (0.0, 0.0), + }; + + // use roundtrip to process this event synchronously + event_queue.roundtrip(&mut app).unwrap(); + + // + let compositor = app.compositor.as_ref().unwrap(); + app.surface = Some(compositor.create_surface(&qh, ())); + let wm_base = app.wm_base.as_ref().unwrap(); + app.xdg_surface = Some(wm_base.get_xdg_surface(&app.surface.as_mut().unwrap(), &qh, ())); + app.top_level = Some(app.xdg_surface.as_ref().unwrap().get_toplevel(&qh, ())); + app.top_level + .as_ref() + .unwrap() + .set_title("LAN Mouse".into()); + app.surface.as_ref().unwrap().commit(); + + while app.running { + event_queue.blocking_dispatch(&mut app).unwrap(); + } +} + +fn draw(f: &mut File, (width, height): (u32, u32)) { + let mut buf = BufWriter::new(f); + for y in 0..height { + for x in 0..width { + let color: u32 = if (x + y / 32 * 32) % 64 < 32 { + 0x0 + } else { + 0xFF000000 + }; + buf.write_all(&color.to_ne_bytes()).unwrap(); + } + } +} + +impl App { + fn send_motion_event(&self, time: u32, x: f64, y: f64) { + let time_bytes = time.to_ne_bytes(); + let x_bytes = x.to_ne_bytes(); + let y_bytes = y.to_ne_bytes(); + let mut buf: [u8; 20] = [0u8; 20]; + buf[0..4].copy_from_slice(&time_bytes); + buf[4..12].copy_from_slice(&x_bytes); + buf[12..20].copy_from_slice(&y_bytes); + self.socket.send_to(&buf, "127.0.0.1:42069").unwrap(); + } +} + +impl Dispatch for App { + fn event( + app: &mut Self, + registry: &wl_registry::WlRegistry, + event: wl_registry::Event, + _: &(), + _: &Connection, + qh: &QueueHandle, + ) { + // Match global event to get globals after requesting them in main + if let wl_registry::Event::Global { + name, interface, .. + } = event + { + // println!("[{}] {} (v{})", name, interface, version); + match &interface[..] { + "wl_compositor" => { + app.compositor = + Some(registry.bind::(name, 4, qh, ())); + // get the vp manager + } + "wl_shm" => { + let shm = registry.bind::(name, 1, qh, ()); + let (width, height) = (512, 512); + let mut file = tempfile::tempfile().unwrap(); + draw(&mut file, (width, height)); + let pool = + 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, + (), + ); + app.buffer = Some(buffer); + } + "wl_seat" => { + registry.bind::(name, 1, qh, ()); + } + "xdg_wm_base" => { + app.wm_base = + Some(registry.bind::(name, 1, &qh, ())); + } + _ => {} + } + } + } +} + +impl Dispatch for App { + fn event( + _: &mut Self, + _: &wl_compositor::WlCompositor, + _: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + todo!() + } +} + +impl Dispatch for App { + fn event( + _: &mut Self, + _: &wl_surface::WlSurface, + _: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + todo!() + } +} + +impl Dispatch for App { + fn event( + _: &mut Self, + _: &wl_shm::WlShm, + _: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + // ignore + } +} + +impl Dispatch for App { + fn event( + _: &mut Self, + _: &wl_shm_pool::WlShmPool, + _: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + todo!() + } +} + +impl Dispatch for App { + fn event( + _: &mut Self, + _: &wl_buffer::WlBuffer, + _: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + // + } +} + +impl Dispatch for App { + fn event( + _: &mut Self, + proxy: &xdg_wm_base::XdgWmBase, + event: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + match event { + xdg_wm_base::Event::Ping { serial } => { + proxy.pong(serial); + } + _ => {} + } + } +} + +impl Dispatch for App { + fn event( + app: &mut Self, + xdg_surface: &xdg_surface::XdgSurface, + event: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + match event { + xdg_surface::Event::Configure { serial } => { + xdg_surface.ack_configure(serial); + let surface = app.surface.as_ref().unwrap(); + if let Some(ref buffer) = app.buffer { + surface.attach(Some(buffer), 0, 0); + surface.commit(); + } + } + _ => {} + } + } +} + +impl Dispatch for App { + fn event( + app: &mut Self, + _: &xdg_toplevel::XdgToplevel, + event: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + if let xdg_toplevel::Event::Close {} = event { + app.running = false; + } + } +} + +impl Dispatch for App { + fn event( + _: &mut Self, + seat: &wl_seat::WlSeat, + event: ::Event, + _: &(), + _: &Connection, + qh: &QueueHandle, + ) { + 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 for App { + fn event( + app: &mut Self, + _: &wl_pointer::WlPointer, + event: ::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + match event { + wl_pointer::Event::Enter { + serial: _, + surface: _, + surface_x, + surface_y, + } => { + app.surface_coords = (surface_x, surface_y); + } + wl_pointer::Event::Motion { + time, + surface_x, + surface_y, + } => { + let (last_x, last_y) = app.surface_coords; + app.send_motion_event(time, surface_x - last_x, surface_y - last_y); + app.surface_coords = (surface_x, surface_y); + } + _ => (), + } + } +} + +impl Dispatch for App { + fn event( + state: &mut Self, + _: &wl_keyboard::WlKeyboard, + event: wl_keyboard::Event, + _: &(), + _: &Connection, + _: &QueueHandle, + ) { + if let wl_keyboard::Event::Key { key, .. } = event { + if key == 1 { + // ESC key + state.running = false; + } + } } }