mirror of
https://github.com/feschber/lan-mouse.git
synced 2026-03-15 09:10:53 +03:00
implement server side code (as a window for the time being)
This commit is contained in:
@@ -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<VpManager>,
|
||||
}
|
||||
|
||||
@@ -28,20 +25,23 @@ impl Dispatch<wl_registry::WlRegistry, ()> for AppData {
|
||||
qh: &QueueHandle<AppData>,
|
||||
) {
|
||||
// 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::<VpManager, _, _>(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::<VpManager, _, _>(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<AppData>) -> std::io::Result<()>{
|
||||
fn udp_loop(pointer: Vp, q: EventQueue<AppData>) -> 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();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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<wl_compositor::WlCompositor>,
|
||||
buffer: Option<wl_buffer::WlBuffer>,
|
||||
wm_base: Option<xdg_wm_base::XdgWmBase>,
|
||||
surface: Option<wl_surface::WlSurface>,
|
||||
top_level: Option<xdg_toplevel::XdgToplevel>,
|
||||
xdg_surface: Option<xdg_surface::XdgSurface>,
|
||||
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<wl_registry::WlRegistry, ()> for App {
|
||||
fn event(
|
||||
app: &mut Self,
|
||||
registry: &wl_registry::WlRegistry,
|
||||
event: wl_registry::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
qh: &QueueHandle<App>,
|
||||
) {
|
||||
// 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::<wl_compositor::WlCompositor, _, _>(name, 4, qh, ()));
|
||||
// get the vp manager
|
||||
}
|
||||
"wl_shm" => {
|
||||
let shm = registry.bind::<wl_shm::WlShm, _, _>(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::<wl_seat::WlSeat, _, _>(name, 1, qh, ());
|
||||
}
|
||||
"xdg_wm_base" => {
|
||||
app.wm_base =
|
||||
Some(registry.bind::<xdg_wm_base::XdgWmBase, _, _>(name, 1, &qh, ()));
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_compositor::WlCompositor, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_compositor::WlCompositor,
|
||||
_: <wl_compositor::WlCompositor as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_surface::WlSurface, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_surface::WlSurface,
|
||||
_: <wl_surface::WlSurface as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_shm::WlShm, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_shm::WlShm,
|
||||
_: <wl_shm::WlShm as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_shm_pool::WlShmPool, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_shm_pool::WlShmPool,
|
||||
_: <wl_shm_pool::WlShmPool as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<wl_buffer::WlBuffer, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
_: &wl_buffer::WlBuffer,
|
||||
_: <wl_buffer::WlBuffer as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<xdg_wm_base::XdgWmBase, ()> for App {
|
||||
fn event(
|
||||
_: &mut Self,
|
||||
proxy: &xdg_wm_base::XdgWmBase,
|
||||
event: <xdg_wm_base::XdgWmBase as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
match event {
|
||||
xdg_wm_base::Event::Ping { serial } => {
|
||||
proxy.pong(serial);
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Dispatch<xdg_surface::XdgSurface, ()> for App {
|
||||
fn event(
|
||||
app: &mut Self,
|
||||
xdg_surface: &xdg_surface::XdgSurface,
|
||||
event: <xdg_surface::XdgSurface as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
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<xdg_toplevel::XdgToplevel, ()> for App {
|
||||
fn event(
|
||||
app: &mut Self,
|
||||
_: &xdg_toplevel::XdgToplevel,
|
||||
event: <xdg_toplevel::XdgToplevel as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
if let xdg_toplevel::Event::Close {} = event {
|
||||
app.running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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,
|
||||
_: &wl_pointer::WlPointer,
|
||||
event: <wl_pointer::WlPointer as wayland_client::Proxy>::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
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<wl_keyboard::WlKeyboard, ()> for App {
|
||||
fn event(
|
||||
state: &mut Self,
|
||||
_: &wl_keyboard::WlKeyboard,
|
||||
event: wl_keyboard::Event,
|
||||
_: &(),
|
||||
_: &Connection,
|
||||
_: &QueueHandle<Self>,
|
||||
) {
|
||||
if let wl_keyboard::Event::Key { key, .. } = event {
|
||||
if key == 1 {
|
||||
// ESC key
|
||||
state.running = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user