From 70319a98cb4c89e2d204e0c557714fbe7acc03de Mon Sep 17 00:00:00 2001 From: william Date: Thu, 25 May 2023 13:13:06 -0400 Subject: [PATCH] Starting input system --- server/src/input/events/keyboard.rs | 12 ++- server/src/input/events/mod.rs | 13 +-- server/src/input/events/pointer.rs | 56 ++++++++++- server/src/input/mappings.rs | 21 ++-- server/src/input/mod.rs | 142 +++++++++++++++++++++------- server/src/main.rs | 30 +++++- server/src/multi_index_queue.rs | 96 +++++++++++++++++++ 7 files changed, 310 insertions(+), 60 deletions(-) create mode 100644 server/src/multi_index_queue.rs diff --git a/server/src/input/events/keyboard.rs b/server/src/input/events/keyboard.rs index 8305135..2a7b565 100644 --- a/server/src/input/events/keyboard.rs +++ b/server/src/input/events/keyboard.rs @@ -1,3 +1,4 @@ +use std::fmt::{Display, Formatter}; use crate::input::events::{KvmButtonState, KvmEvent, KvmEventTrait}; pub struct KvmKeyboardEvent { @@ -9,4 +10,13 @@ impl KvmEventTrait for KvmKeyboardEvent { fn into_kvm_event(self) -> KvmEvent { KvmEvent::Keyboard(self) } -} \ No newline at end of file +} + +impl Display for KvmKeyboardEvent { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.state { + KvmButtonState::Pressed => write!(f, "Press {}", self.key_code), + KvmButtonState::Released => write!(f, "Press {}", self.key_code) + } + } +} diff --git a/server/src/input/events/mod.rs b/server/src/input/events/mod.rs index 477a5bf..5159bc4 100644 --- a/server/src/input/events/mod.rs +++ b/server/src/input/events/mod.rs @@ -22,17 +22,8 @@ pub trait KvmEventTrait { impl Display for KvmEvent { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { match self { - KvmEvent::Pointer(_) => write!(f, "Pointer"), - KvmEvent::Keyboard(_) => write!(f, "Keyboard") + KvmEvent::Pointer(e) => write!(f, "Pointer({e})"), + KvmEvent::Keyboard(e) => write!(f, "Keyboard({e})") } } } - -impl Display for KvmButtonState { - fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { - match self { - KvmButtonState::Pressed => write!(f, "Pressed"), - KvmButtonState::Released => write!(f, "Released") - } - } -} \ No newline at end of file diff --git a/server/src/input/events/pointer.rs b/server/src/input/events/pointer.rs index 2b0e843..d8ac2bd 100644 --- a/server/src/input/events/pointer.rs +++ b/server/src/input/events/pointer.rs @@ -1,7 +1,9 @@ +use std::fmt::{Display, Formatter}; use crate::input::events::{KvmButtonState, KvmEvent, KvmEventTrait}; pub enum KvmPointerEvent { - Motion(KvmPointerMotionEvent), + MotionRelative(KvmPointerMotionRelativeEvent), + MotionAbsolute(KvmPointerMotionAbsoluteEvent), Button(KvmPointerButtonEvent), Scroll(KvmPointerScrollEvent), } @@ -11,13 +13,20 @@ pub struct KvmPointerButtonEvent { pub state: KvmButtonState, } -pub struct KvmPointerMotionEvent { +pub struct KvmPointerMotionRelativeEvent { pub dx: f64, pub dx_unaccelerated: f64, pub dy: f64, pub dy_unaccelerated: f64, } +pub struct KvmPointerMotionAbsoluteEvent { + pub x: f64, + pub x_mm: f64, + pub y: f64, + pub y_mm: f64, +} + pub struct KvmPointerScrollEvent { pub horizontal_scroll_value: f64, pub vertical_scroll_value: f64, @@ -49,6 +58,45 @@ macro_rules! kvm_event_traits { } } -kvm_event_traits!(Motion, KvmPointerMotionEvent); +kvm_event_traits!(MotionRelative, KvmPointerMotionRelativeEvent); +kvm_event_traits!(MotionAbsolute, KvmPointerMotionAbsoluteEvent); kvm_event_traits!(Button, KvmPointerButtonEvent); -kvm_event_traits!(Scroll, KvmPointerScrollEvent); \ No newline at end of file +kvm_event_traits!(Scroll, KvmPointerScrollEvent); + +impl Display for KvmPointerEvent { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self { + KvmPointerEvent::Button(e) => write!(f, "Button({e})"), + KvmPointerEvent::MotionRelative(e) => write!(f, "MotionRelative({e})"), + KvmPointerEvent::MotionAbsolute(e) => write!(f, "MotionAbsolute({e})"), + KvmPointerEvent::Scroll(e) => write!(f, "Scroll({e})") + } + } +} + +impl Display for KvmPointerButtonEvent { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + match self.state { + KvmButtonState::Pressed => write!(f, "Press {}", self.button), + KvmButtonState::Released => write!(f, "Release {}", self.button) + } + } +} + +impl Display for KvmPointerMotionRelativeEvent { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "x: {} ({}), y: {} ({})", self.dx, self.dx_unaccelerated, self.dy, self.dy_unaccelerated) + } +} + +impl Display for KvmPointerMotionAbsoluteEvent { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "x: {} ({}), y: {} ({})", self.x, self.x_mm, self.y, self.y_mm) + } +} + +impl Display for KvmPointerScrollEvent { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "h: {}, v: {}", self.horizontal_scroll_value, self.vertical_scroll_value) + } +} diff --git a/server/src/input/mappings.rs b/server/src/input/mappings.rs index 52eab7b..07e3ff8 100644 --- a/server/src/input/mappings.rs +++ b/server/src/input/mappings.rs @@ -5,7 +5,7 @@ use input::event::pointer::{Axis, ButtonState, PointerButtonEvent, PointerMotion use crate::input::events::{KvmButtonState, KvmEvent, KvmEventTrait}; use crate::input::events::keyboard::KvmKeyboardEvent; -use crate::input::events::pointer::{KvmPointerButtonEvent, KvmPointerEvent, KvmPointerEventTrait, KvmPointerMotionEvent, KvmPointerScrollEvent}; +use crate::input::events::pointer::{KvmPointerButtonEvent, KvmPointerEvent, KvmPointerEventTrait, KvmPointerMotionAbsoluteEvent, KvmPointerMotionRelativeEvent, KvmPointerScrollEvent}; use crate::input::mappings::MappingError::{UnknownEvent, UnsupportedEvent}; #[derive(Debug)] @@ -47,8 +47,8 @@ impl FromLibinputEvent for KvmPointerEvent { fn from_libinput(event: PointerEvent) -> Result { #[allow(deprecated)] match event { - PointerEvent::Motion(event) => get_pointer_event::(event), - PointerEvent::MotionAbsolute(event) => get_pointer_event::(event), + PointerEvent::Motion(event) => get_pointer_event::(event), + PointerEvent::MotionAbsolute(event) => get_pointer_event::(event), PointerEvent::Button(event) => get_pointer_event::(event), PointerEvent::ScrollWheel(event) => get_pointer_event::(event), PointerEvent::ScrollFinger(event) => get_pointer_event::(event), @@ -64,9 +64,9 @@ fn get_pointer_event(event: T) -> Result Ok(U::from_libinput(event)?.into_kvm_pointer_event()) } -impl FromLibinputEvent for KvmPointerMotionEvent { +impl FromLibinputEvent for KvmPointerMotionRelativeEvent { fn from_libinput(event: PointerMotionEvent) -> Result { - Ok(KvmPointerMotionEvent { + Ok(KvmPointerMotionRelativeEvent { dx: event.dx(), dx_unaccelerated: event.dx_unaccelerated(), dy: event.dy(), @@ -75,9 +75,14 @@ impl FromLibinputEvent for KvmPointerMotionEvent { } } -impl FromLibinputEvent for KvmPointerMotionEvent { +impl FromLibinputEvent for KvmPointerMotionAbsoluteEvent { fn from_libinput(event: PointerMotionAbsoluteEvent) -> Result { - Err(UnsupportedEvent(event.into_event())) // TODO + Ok(KvmPointerMotionAbsoluteEvent { + x: event.absolute_x_transformed(1920), + x_mm: event.absolute_x(), + y: event.absolute_y_transformed(1080), + y_mm: event.absolute_y(), + }) } } @@ -126,4 +131,4 @@ impl KvmButtonState { ButtonState::Pressed => Self::Pressed, } } -} \ No newline at end of file +} diff --git a/server/src/input/mod.rs b/server/src/input/mod.rs index 7fdab3c..d08bce4 100644 --- a/server/src/input/mod.rs +++ b/server/src/input/mod.rs @@ -1,25 +1,26 @@ use std::fs::{File, OpenOptions}; -use std::io; -use std::os::fd::OwnedFd; +use std::os::fd::{AsRawFd, OwnedFd}; use std::os::unix::fs::OpenOptionsExt; use std::path::Path; use input::{Libinput, LibinputInterface}; use input::Event; -use input::Event::{Keyboard, Pointer}; -use input::event::keyboard::{KeyboardEventTrait, KeyState}; -use input::event::{KeyboardEvent, PointerEvent}; -use input::event::PointerEvent::{Button, Motion}; use libc::{O_RDONLY, O_RDWR, O_WRONLY}; -use crate::input::events::keyboard::KvmKeyboardEvent; -use crate::input::events::KvmEvent; -use crate::input::events::pointer::{KvmPointerButtonEvent, KvmPointerMotionEvent}; -use crate::input::mappings::FromLibinputEvent; +use linux::epoll::{Epoll, EpollFlags}; -mod events; +use crate::input::events::KvmEvent; +use crate::input::mappings::{FromLibinputEvent, MappingError}; + +pub mod events; mod mappings; const UDEV_SEAT: &str = "seat0"; +const CLIENT_SWITCH_KEY_CODE: u32 = 100; // Alt Right + +pub struct InputSystem { + sub_system: S, + epoll: Epoll, +} struct Interface; @@ -39,31 +40,108 @@ impl LibinputInterface for Interface { } } -pub fn listen_inputs() -> io::Result<()> { - let input = prepare_libinput(); - read_inputs(input) +impl InputSystem { + pub fn new() -> Result { + let mut libinput = prepare_libinput()?; + let epoll = create_epoll(&libinput)?; + + Ok(Self { + sub_system: libinput, + epoll, + }) + } + + fn wait_for_events(&mut self) -> Result<(), LibinputSubsystemError> { + match self.epoll.wait() { + Ok(e) => self.dispatch(), + Err(e) => Err(LibinputSubsystemError::Polling(format!("Failed to wait for epoll: {}", e))) + } + } + + fn dispatch(&mut self) -> Result<(), LibinputSubsystemError> { + let dispatch_result = self.sub_system.dispatch(); + if dispatch_result.is_err() { + return Err(LibinputSubsystemError::Polling("Failed to dispatch libinput events".to_string())); + } + + Ok(()) + } } -fn prepare_libinput() -> Libinput { - let mut input = Libinput::new_with_udev(Interface); - input.udev_assign_seat(UDEV_SEAT).unwrap(); - input -} +impl Iterator for InputSystem { + type Item = KvmEvent; -fn read_inputs(mut input: Libinput) -> io::Result<()> { - loop { - input.dispatch().unwrap(); - for event in &mut input { - let mapping_result = KvmEvent::from_libinput(event); - if mapping_result.is_err() { - println!("Error: {:?}", &mapping_result.err()); - } else { - let kvm_event = mapping_result.unwrap(); - match kvm_event { - KvmEvent::Keyboard(event) => println!("Key event: {} ({})", event.key_code, event.state), - _ => {} + fn next(&mut self) -> Option { + let mut next = self.sub_system.next(); + if next.is_none() { + // Try to get more events + match self.wait_for_events() { + Ok(_) => { + next = self.sub_system.next(); + } + Err(e) => { + println!("Failed to wait for events: {:?}", e); } } } + + match next { + Some(e) => { + match map_libinput_event(e) { + Ok(e) => Some(e), + Err(e) => { + println!("Event failed: {:?}", e); + None + } + } + } + None => None + } } -} \ No newline at end of file +} + +#[derive(Debug)] +pub enum LibinputSubsystemError { + Initialization(String), + Polling(String), + Mapping(MappingError), +} + +fn prepare_libinput() -> Result { + let mut input = Libinput::new_with_udev(Interface); + match input.udev_assign_seat(UDEV_SEAT) { + Ok(_) => Ok(input), + Err(_) => Err(LibinputSubsystemError::Initialization("Failed to assign a seat to the libinput context".to_string())) + } +} + +fn create_epoll(input: &Libinput) -> Result { + match Epoll::with_flags(&[EpollFlags::In]) { + Ok(epoll) => { + let interest = epoll.add_interest(input.as_raw_fd(), 0u64, &[]); + match interest { + Ok(_) => Ok(epoll), + Err(e) => Err(LibinputSubsystemError::Initialization(format!("Failed to add epoll interest: {}", e))) + } + } + Err(e) => Err(LibinputSubsystemError::Initialization(format!("Failed to create poll context: {}", e))) + } +} + +fn map_libinput_event(event: Event) -> Result { + match KvmEvent::from_libinput(event) { + Err(error) => Err(LibinputSubsystemError::Mapping(error)), + Ok(mapped_event) => Ok(mapped_event) + } +} + +fn intercept_client_switch_event(event: &KvmEvent) -> bool { + match event { + KvmEvent::Keyboard(event) if event.key_code == CLIENT_SWITCH_KEY_CODE => { + // Do stuff + println!("Right Alt key event"); + false + } + _ => true + } +} diff --git a/server/src/main.rs b/server/src/main.rs index d7e3d6e..aae5340 100644 --- a/server/src/main.rs +++ b/server/src/main.rs @@ -1,24 +1,46 @@ -use std::collections::VecDeque; -use std::io; +use std::collections::{HashMap, VecDeque}; +use std::fmt::Error; +use std::{io, thread}; use std::net::SocketAddr; +use std::sync::mpsc; use messages::client_registration::ClientRegistration; use messages::serialization::{DeserializeMessage, read_message_data, SerializeMessage}; -use crate::input::{listen_inputs}; +use crate::input::{InputSystem, LibinputSubsystemError}; +use crate::input::events::KvmEvent; +use crate::multi_index_queue::MultiIndexQueue; use crate::net::tcp_server::{NextIntent, TcpClient, TcpServer}; mod net; mod input; mod client; +mod multi_index_queue; + fn main() -> io::Result<()> { // let addr = SocketAddr::from(([127, 0, 0, 1], 4433)); // let mut server: TcpServer = TcpServer::new(addr)?; // // server.listen()?; - listen_inputs()?; + let mut input_system = InputSystem::new().expect("Failed to initialize input system"); + + loop { + for event in &mut input_system { + println!("Received event: {}", event); + } + } + + // let mut queue = MultiIndexQueue::new(Box::new(input_system)); + // let mut index = queue.create_index(); + // + // loop { + // let next: Option<&KvmEvent> = queue.next(&mut index); + // if next.is_some() { + // println!("Received event: {}", next.unwrap()); + // } + // } Ok(()) } diff --git a/server/src/multi_index_queue.rs b/server/src/multi_index_queue.rs new file mode 100644 index 0000000..8dfea8b --- /dev/null +++ b/server/src/multi_index_queue.rs @@ -0,0 +1,96 @@ +use std::cmp::Ordering; +use std::collections::VecDeque; + +const QUEUE_CAPACITY: usize = 1000; + +pub struct MultiIndexQueue { + iterator: Box>, + items: VecDeque, + offset: usize, +} + +#[derive(Eq)] +pub struct QueueIndex { + index: usize, +} + +impl MultiIndexQueue { + pub fn new(iterator: Box>) -> Self { + Self { + iterator, + items: VecDeque::with_capacity(QUEUE_CAPACITY), + offset: 0, + } + } + + pub fn create_index(&self) -> QueueIndex { + QueueIndex { index: self.offset } + } + + pub fn next(&mut self, index: &mut QueueIndex) -> Option<&T> { + if self.items.is_empty() { + self.fill_queue(); + } + + let real_index = index.index - self.offset; + if real_index > QUEUE_CAPACITY { + let next = self.fill_next(); + index.index += 1; + return next; + } + + let real_index = index.index - self.offset; + let item = self.items.get(real_index); + index.index += 1; + + item + } + + fn fill_queue(&mut self) { + let mut index = 0usize; + let initial_queue_len = self.items.len(); + + loop { + if initial_queue_len + index >= QUEUE_CAPACITY { + break; + } + + if self.fill_next().is_none() { + break; + } + + index += 1; + } + } + + fn fill_next(&mut self) -> Option<&T> { + let next = self.iterator.next(); + match next { + Some(next) => { + self.items.pop_front(); + self.items.push_back(next); + self.offset += 1; + self.items.get(QUEUE_CAPACITY) + } + None => None + } + } +} + +impl PartialOrd for QueueIndex { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for QueueIndex { + fn cmp(&self, other: &Self) -> Ordering { + self.index.cmp(&other.index) + } +} + +impl PartialEq for QueueIndex { + fn eq(&self, other: &Self) -> bool { + self.index == other.index + } +}