Abstract Event Types into a general struct

Ground work for supporting different input / emulation backends
This commit is contained in:
Ferdinand Schober
2023-02-08 00:41:25 +01:00
parent 9daa63bbea
commit f545fe2686
9 changed files with 688 additions and 309 deletions

View File

@@ -1,14 +1,15 @@
use crate::client::{Client, ClientHandle};
use crate::request::{self, Request};
use std::collections::HashMap;
use std::sync::mpsc::Receiver;
use std::time::Duration;
use std::{io, thread};
use std::sync::mpsc::Receiver;
use std::{
io::{BufWriter, Write},
os::unix::prelude::AsRawFd,
};
use wayland_client::protocol::wl_pointer::{Axis, ButtonState};
use wayland_protocols_wlr::virtual_pointer::v1::client::{
zwlr_virtual_pointer_manager_v1::ZwlrVirtualPointerManagerV1 as VpManager,
zwlr_virtual_pointer_v1::ZwlrVirtualPointerV1 as Vp,
@@ -22,13 +23,13 @@ use wayland_protocols_misc::zwp_virtual_keyboard_v1::client::{
use wayland_client::{
delegate_noop,
globals::{registry_queue_init, GlobalListContents},
protocol::{wl_keyboard, wl_pointer, wl_registry, wl_seat},
protocol::{wl_registry, wl_seat},
Connection, Dispatch, EventQueue, QueueHandle,
};
use tempfile;
use super::Event;
use super::{Event, KeyboardEvent, PointerEvent};
// App State, implements Dispatch event handlers
struct App {
@@ -52,11 +53,23 @@ impl App {
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 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 };
let mut app = App {
input_for_client,
seat,
event_rx,
vpm,
vkm,
queue,
qh,
};
for client in clients {
app.add_client(client);
}
@@ -65,7 +78,7 @@ impl App {
pub fn run(&mut self) {
loop {
let (event, client) = self.event_rx.recv().unwrap();
let (event, client) = self.event_rx.recv().expect("event receiver unavailable");
if let Some(virtual_input) = self.input_for_client.get(&client) {
virtual_input.consume_event(event).unwrap();
if let Err(e) = self.queue.flush() {
@@ -76,7 +89,6 @@ impl App {
}
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, ());
@@ -106,7 +118,6 @@ impl App {
self.input_for_client.insert(client.handle, vinput);
}
}
struct VirtualInput {
@@ -115,59 +126,53 @@ struct VirtualInput {
}
impl VirtualInput {
/// main loop handling udp packets
/// 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 {
PointerEvent::Motion {
time,
surface_x,
surface_y,
relative_x,
relative_y,
} => {
self.pointer.motion(time, surface_x, surface_y);
self.pointer.motion(time, relative_x, relative_y);
self.pointer.frame();
}
wl_pointer::Event::Button {
serial: _,
time: t,
button: b,
state: s,
PointerEvent::Button {
time,
button,
state,
} => {
self.pointer.button(t, b, s.into_result().unwrap());
let state: ButtonState = state.try_into().unwrap();
self.pointer.button(time, button, state);
self.pointer.frame();
}
wl_pointer::Event::Axis {
time: t,
axis: a,
value: v,
} => {
self.pointer.axis(t, a.into_result().unwrap(), v);
PointerEvent::Axis { time, axis, value } => {
let axis: Axis = (axis as u32).try_into().unwrap();
self.pointer.axis(time, axis, value);
self.pointer.frame();
}
wl_pointer::Event::Frame => {
PointerEvent::Frame {} => {
self.pointer.frame();
}
_ => todo!(),
},
Event::Keyboard(e) => match e {
wl_keyboard::Event::Key {
serial: _,
time: t,
key: k,
state: s,
KeyboardEvent::Key {
time,
key,
state,
} => {
self.keyboard.key(t, k, u32::from(s));
self.keyboard.key(time, key, state as u32);
}
wl_keyboard::Event::Modifiers {
serial: _,
KeyboardEvent::Modifiers {
mods_depressed,
mods_latched,
mods_locked,
group,
} => {
self.keyboard.modifiers(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);

View File

@@ -1,11 +1,18 @@
use crate::{request, client::{ClientHandle, Position, Client}};
use crate::{
client::{Client, ClientHandle, Position},
request,
};
use memmap::Mmap;
use std::{
fs::File,
io::{BufWriter, Write},
os::unix::prelude::{AsRawFd, FromRawFd}, sync::mpsc::SyncSender, rc::Rc, thread, time::Duration,
os::unix::prelude::{AsRawFd, FromRawFd},
rc::Rc,
sync::mpsc::SyncSender,
thread,
time::Duration,
};
use wayland_protocols::wp::{
@@ -29,18 +36,19 @@ use wayland_protocols_wlr::layer_shell::v1::client::{
};
use wayland_client::{
backend::WaylandError,
delegate_noop,
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, DispatchError, backend::WaylandError,
Connection, Dispatch, DispatchError, QueueHandle, WEnum,
};
use tempfile;
use super::Event;
use super::{Event, KeyboardEvent, PointerEvent};
struct Globals {
compositor: wl_compositor::WlCompositor,
@@ -119,27 +127,20 @@ impl Window {
}
}
pub fn run(
tx: SyncSender<(Event, ClientHandle)>,
server: request::Server,
clients: Vec<Client>,
) {
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 (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 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 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");
@@ -181,15 +182,19 @@ pub fn run(
while app.running {
match queue.blocking_dispatch(&mut app) {
Ok(_) => { },
Ok(_) => {}
Err(DispatchError::Backend(WaylandError::Io(e))) => {
eprintln!("Wayland Error: {}", e);
thread::sleep(Duration::from_millis(500));
},
}
Err(DispatchError::Backend(e)) => {
panic!("{}", e);
}
Err(DispatchError::BadMessage{ sender_id, interface, opcode }) => {
Err(DispatchError::BadMessage {
sender_id,
interface,
opcode,
}) => {
panic!("bad message {}, {} , {}", sender_id, interface, opcode);
}
}
@@ -206,13 +211,12 @@ fn draw(f: &mut File, (width, height): (u32, u32)) {
}
impl App {
fn grab(
&mut self,
surface: &wl_surface::WlSurface,
pointer: &wl_pointer::WlPointer,
serial: u32,
qh: &QueueHandle<App>
qh: &QueueHandle<App>,
) {
let (window, _) = self.focused.as_ref().unwrap();
@@ -220,7 +224,9 @@ impl App {
pointer.set_cursor(serial, None, 0, 0);
// capture input
window.layer_surface.set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
window
.layer_surface
.set_keyboard_interactivity(KeyboardInteractivity::Exclusive);
window.surface.commit();
// lock pointer
@@ -260,7 +266,9 @@ impl App {
let (window, _client) = self.focused.as_ref().unwrap();
// ungrab surface
window.layer_surface.set_keyboard_interactivity(KeyboardInteractivity::None);
window
.layer_surface
.set_keyboard_interactivity(KeyboardInteractivity::None);
window.surface.commit();
// release pointer
@@ -328,35 +336,62 @@ impl Dispatch<wl_pointer::WlPointer, ()> for App {
surface_y: _,
} => {
// get client corresponding to the focused surface
{
let (window, client) = app.client_for_window
let (window, client) = app
.client_for_window
.iter()
.find(|(w,_c)| w.surface == surface)
.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
let (_, client) = app
.client_for_window
.iter()
.find(|(w,_c)| w.surface == surface)
.find(|(w, _c)| w.surface == surface)
.unwrap();
app.tx.send((Event::Release(), *client)).unwrap();
}
wl_pointer::Event::Leave { .. } => {
app.ungrab();
}
wl_pointer::Event::Button { .. } => {
wl_pointer::Event::Button {
serial: _,
time,
button,
state,
} => {
let (_, client) = app.focused.as_ref().unwrap();
app.tx.send((Event::Pointer(event), *client)).unwrap();
app.tx
.send((
Event::Pointer(PointerEvent::Button {
time,
button,
state: u32::from(state),
}),
*client,
))
.unwrap();
}
wl_pointer::Event::Axis { .. } => {
wl_pointer::Event::Axis { time, axis, value } => {
let (_, client) = app.focused.as_ref().unwrap();
app.tx.send((Event::Pointer(event), *client)).unwrap();
app.tx
.send((
Event::Pointer(PointerEvent::Axis {
time,
axis: u32::from(axis) as u8,
value,
}),
*client,
))
.unwrap();
}
wl_pointer::Event::Frame { .. } => {
wl_pointer::Event::Frame {} => {
let (_, client) = app.focused.as_ref().unwrap();
app.tx.send((Event::Pointer(event), *client)).unwrap();
app.tx
.send((Event::Pointer(PointerEvent::Frame {}), *client))
.unwrap();
}
_ => {}
}
@@ -377,14 +412,44 @@ impl Dispatch<wl_keyboard::WlKeyboard, ()> for App {
None => (None, None),
};
match event {
wl_keyboard::Event::Key { .. } => {
wl_keyboard::Event::Key {
serial: _,
time,
key,
state,
} => {
if let Some(client) = client {
app.tx.send((Event::Keyboard(event), *client)).unwrap();
app.tx
.send((
Event::Keyboard(KeyboardEvent::Key {
time,
key,
state: u32::from(state) as u8,
}),
*client,
))
.unwrap();
}
}
wl_keyboard::Event::Modifiers { mods_depressed, .. } => {
wl_keyboard::Event::Modifiers {
serial: _,
mods_depressed,
mods_latched,
mods_locked,
group,
} => {
if let Some(client) = client {
app.tx.send((Event::Keyboard(event), *client)).unwrap();
app.tx
.send((
Event::Keyboard(KeyboardEvent::Modifiers {
mods_depressed,
mods_latched,
mods_locked,
group,
}),
*client,
))
.unwrap();
}
if mods_depressed == 77 {
// ctrl shift super alt
@@ -424,15 +489,16 @@ impl Dispatch<ZwpRelativePointerV1, ()> for App {
{
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();
app.tx
.send((
Event::Pointer(PointerEvent::Motion {
time,
relative_x: surface_x,
relative_y: surface_y,
}),
*client,
))
.unwrap();
}
}
}
@@ -448,9 +514,10 @@ impl Dispatch<ZwlrLayerSurfaceV1, ()> for App {
_: &QueueHandle<Self>,
) {
if let zwlr_layer_surface_v1::Event::Configure { serial, .. } = event {
let (window, _client) = app.client_for_window
let (window, _client) = app
.client_for_window
.iter()
.find(|(w,_c)| &w.layer_surface == layer_surface)
.find(|(w, _c)| &w.layer_surface == layer_surface)
.unwrap();
// client corresponding to the layer_surface
let surface = &window.surface;
@@ -473,7 +540,8 @@ impl Dispatch<wl_registry::WlRegistry, GlobalListContents> for App {
_data: &GlobalListContents,
_conn: &Connection,
_qhandle: &QueueHandle<Self>,
) {}
) {
}
}
// don't emit any events

View File

@@ -1,13 +1,18 @@
use std::{
net::{UdpSocket, SocketAddr},
collections::HashMap,
error::Error,
sync::{mpsc::{SyncSender, Receiver}, atomic::{AtomicBool, Ordering}, Arc},
thread::{self, JoinHandle}, collections::HashMap,
net::{SocketAddr, UdpSocket},
sync::{
atomic::{AtomicBool, Ordering},
mpsc::{Receiver, SyncSender},
Arc,
},
thread::{self, JoinHandle},
};
use crate::client::{ClientHandle, ClientManager};
use super::{Event, Encode, Decode};
use super::Event;
pub struct Server {
listen_addr: SocketAddr,
@@ -18,10 +23,18 @@ 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 }
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>> {
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;
@@ -33,44 +46,54 @@ impl Server {
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 receiver = thread::Builder::new()
.name("event receiver".into())
.spawn(move || {
loop {
let (event, addr) = match Server::receive_event(&rx) {
Ok(e) => e,
Err(e) => {
eprintln!("{}", e);
continue;
}
};
let client_handle = match client_for_socket.get(&addr) {
Some(c) => *c,
None => {
println!("Allow connection from {:?}? [Y/n]", addr);
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");
// 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");
}
} 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();
})
.unwrap();
let sending = self.sending.clone();
@@ -78,42 +101,46 @@ impl Server {
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,
};
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);
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();
})
.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) {
fn send_event(tx: &UdpSocket, e: Event, addr: SocketAddr) {
let data: Vec<u8> = (&e).into();
if let Err(e) = tx.send_to(&data[..], 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
fn receive_event(rx: &UdpSocket) -> Result<(Event, SocketAddr), Box<dyn Error>> {
let mut buf = vec![0u8; 22];
match rx.recv_from(&mut buf) {
Ok((_amt, src)) => Ok((Event::try_from(buf)?, src)),
Err(e) => Err(Box::new(e)),
}
}
}