mod device; mod gesture; mod key_filter; mod scheme; mod translate; mod types; use std::env; use std::fs::File; use std::fs::OpenOptions; use std::io::{ErrorKind, Read}; use std::mem::{size_of, MaybeUninit}; #[cfg(target_os = "redox")] use std::os::fd::AsRawFd; use std::os::unix::fs::OpenOptionsExt; use std::process; #[cfg(not(target_os = "redox"))] use std::thread; #[cfg(not(target_os = "redox"))] use std::time::Duration; use log::{error, info, LevelFilter, Metadata, Record}; use orbclient::{Event, EventOption}; use redox_scheme::scheme::SchemeState; use redox_scheme::scheme::SchemeSync; use redox_scheme::{RequestKind, SignalBehavior, Socket}; use syscall::error::EAGAIN; use syscall::flag::O_NONBLOCK; use scheme::EvdevScheme; #[cfg(target_os = "redox")] use event::{EventFlags as QueueEventFlags, RawEventQueue}; #[cfg(target_os = "redox")] const SCHEME_QUEUE_TOKEN: usize = 1; #[cfg(target_os = "redox")] const INPUT_QUEUE_TOKEN: usize = 2; struct StderrLogger { level: LevelFilter, } impl log::Log for StderrLogger { fn enabled(&self, metadata: &Metadata) -> bool { metadata.level() <= self.level } fn log(&self, record: &Record) { if self.enabled(record.metadata()) { eprintln!("[{}] {}", record.level(), record.args()); } } fn flush(&self) {} } struct InputConsumer { file: File, partial: Vec, } impl InputConsumer { fn open() -> Result { let file = OpenOptions::new() .read(true) .custom_flags(O_NONBLOCK as i32) .open("/scheme/input/consumer") .map_err(|e| format!("failed to open /scheme/input/consumer: {e}"))?; Ok(Self { file, partial: Vec::new(), }) } #[cfg(target_os = "redox")] fn fd(&self) -> usize { self.file.as_raw_fd() as usize } fn read_available(&mut self, scheme: &mut EvdevScheme) -> Result { let event_size = size_of::(); let mut buf = vec![0u8; event_size * 32]; let mut progress = false; loop { match self.file.read(&mut buf) { Ok(0) => break, Ok(count) => { progress = true; self.partial.extend_from_slice(&buf[..count]); while self.partial.len() >= event_size { let event = read_event_from_bytes(&self.partial[..event_size]); self.partial.drain(..event_size); dispatch_input_event(event, scheme); } } Err(err) if err.kind() == ErrorKind::WouldBlock => break, Err(err) => return Err(format!("failed to read /scheme/input/consumer: {err}")), } } Ok(progress) } } #[derive(Clone, Copy, Debug, Default)] struct SchemePoll { mounted: bool, progress: bool, } fn read_event_from_bytes(bytes: &[u8]) -> Event { let mut event = MaybeUninit::::uninit(); unsafe { std::ptr::copy_nonoverlapping(bytes.as_ptr(), event.as_mut_ptr() as *mut u8, bytes.len()); event.assume_init() } } fn dispatch_input_event(event: Event, scheme: &mut EvdevScheme) { match event.to_option() { EventOption::Key(key) => scheme.feed_keyboard_event(key.scancode, key.pressed), EventOption::Mouse(mouse) => scheme.feed_touchpad_position(mouse.x, mouse.y), EventOption::MouseRelative(mouse) => scheme.feed_mouse_move(mouse.dx, mouse.dy), EventOption::Button(button) => { scheme.feed_mouse_buttons(button.left, button.middle, button.right) } EventOption::Scroll(scroll) => scheme.feed_mouse_scroll(scroll.x, scroll.y), _ => {} } } fn is_would_block_socket(err: &syscall::Error) -> bool { err.errno == EAGAIN } fn read_scheme_requests( socket: &Socket, scheme: &mut EvdevScheme, state: &mut SchemeState, ) -> Result { let mut poll = SchemePoll { mounted: true, progress: false, }; loop { match socket.next_request(SignalBehavior::Restart) { Ok(Some(request)) => { poll.progress = true; match request.kind() { RequestKind::Call(call_request) => { let response = call_request.handle_sync(scheme, state); if let Err(err) = socket.write_response(response, SignalBehavior::Restart) { return Err(format!("failed to write response: {err}")); } } RequestKind::OnClose { id } => { scheme.on_close(id); } _ => {} } } Ok(None) => { poll.mounted = false; break; } Err(err) if is_would_block_socket(&err) => break, Err(err) => return Err(format!("failed to read scheme request: {err}")), } } Ok(poll) } #[cfg(target_os = "redox")] fn run_redox_event_loop( socket: &Socket, scheme: &mut EvdevScheme, input: &mut InputConsumer, state: &mut SchemeState, ) -> Result<(), String> { let event_queue = RawEventQueue::new().map_err(|e| format!("failed to create event queue: {e}"))?; event_queue .subscribe( socket.inner().raw(), SCHEME_QUEUE_TOKEN, QueueEventFlags::READ, ) .map_err(|e| format!("failed to subscribe scheme socket: {e}"))?; event_queue .subscribe(input.fd(), INPUT_QUEUE_TOKEN, QueueEventFlags::READ) .map_err(|e| format!("failed to subscribe input consumer: {e}"))?; loop { let raw_event = event_queue .next_event() .map_err(|e| format!("failed to wait for events: {e}"))?; match raw_event.user_data { SCHEME_QUEUE_TOKEN => { let poll = read_scheme_requests(socket, scheme, state)?; if !poll.mounted { info!("evdevd: scheme unmounted, exiting"); break; } } INPUT_QUEUE_TOKEN => { let _ = input.read_available(scheme)?; } _ => {} } } Ok(()) } #[cfg(not(target_os = "redox"))] fn run_host_event_loop( socket: &Socket, scheme: &mut EvdevScheme, input: &mut InputConsumer, state: &mut SchemeState, ) -> Result<(), String> { loop { let mut progress = input.read_available(scheme)?; let poll = read_scheme_requests(socket, scheme, state)?; if !poll.mounted { info!("evdevd: scheme unmounted, exiting"); break; } progress |= poll.progress; if !progress { thread::sleep(Duration::from_millis(10)); } } Ok(()) } fn run() -> Result<(), String> { let mut scheme = EvdevScheme::new(); let mut input = InputConsumer::open()?; let mut state = SchemeState::new(); let socket = Socket::nonblock().map_err(|e| format!("failed to create scheme socket: {}", e))?; redox_scheme::scheme::register_sync_scheme(&socket, "evdev", &mut scheme) .map_err(|e| format!("failed to register evdev scheme: {}", e))?; info!("evdevd: registered scheme:evdev"); info!("evdevd: consuming orbclient::Event from /scheme/input/consumer"); #[cfg(target_os = "redox")] { run_redox_event_loop(&socket, &mut scheme, &mut input, &mut state) } #[cfg(not(target_os = "redox"))] { run_host_event_loop(&socket, &mut scheme, &mut input, &mut state) } } fn main() { let log_level = match env::var("EVDEVD_LOG").as_deref() { Ok("debug") => LevelFilter::Debug, Ok("trace") => LevelFilter::Trace, _ => LevelFilter::Info, }; let _ = log::set_boxed_logger(Box::new(StderrLogger { level: log_level })); log::set_max_level(log_level); if let Err(e) = run() { error!("evdevd: fatal error: {}", e); process::exit(1); } }