use std::fs::{File, OpenOptions}; use std::io::{self, Read, Write}; use std::mem::size_of; use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd}; use std::os::unix::fs::OpenOptionsExt; use std::path::PathBuf; use std::slice; use libredox::flag::{O_CLOEXEC, O_NONBLOCK, O_RDWR}; use orbclient::Event; use syscall::ESTALE; fn read_to_slice( file: BorrowedFd, buf: &mut [T], ) -> Result { unsafe { libredox::call::read( file.as_raw_fd() as usize, slice::from_raw_parts_mut(buf.as_mut_ptr() as *mut u8, buf.len() * size_of::()), ) .map(|count| count / size_of::()) } } pub unsafe fn any_as_u8_slice(p: &T) -> &[u8] { slice::from_raw_parts((p as *const T) as *const u8, size_of::()) } unsafe fn any_as_u8_slice_mut(p: &mut T) -> &mut [u8] { slice::from_raw_parts_mut((p as *mut T) as *mut u8, size_of::()) } pub struct ConsumerHandle(File); pub enum ConsumerHandleEvent<'a> { Events(&'a [Event]), Handoff, } impl ConsumerHandle { pub fn new_vt() -> io::Result { let file = OpenOptions::new() .read(true) .custom_flags(O_NONBLOCK as i32) .open(format!("/scheme/input/consumer"))?; Ok(Self(file)) } pub fn bootlog_vt() -> io::Result { let file = OpenOptions::new() .read(true) .custom_flags(O_NONBLOCK as i32) .open(format!("/scheme/input/consumer_bootlog"))?; Ok(Self(file)) } pub fn event_handle(&self) -> BorrowedFd<'_> { self.0.as_fd() } pub fn open_display_v2(&self) -> io::Result { let mut buffer = [0; 1024]; let fd = self.0.as_raw_fd(); let written = libredox::call::fpath(fd as usize, &mut buffer)?; assert!(written <= buffer.len()); let mut display_path = PathBuf::from( std::str::from_utf8(&buffer[..written]) .expect("init: display path UTF-8 check failed") .to_owned(), ); display_path.set_file_name(format!( "v2/{}", display_path.file_name().unwrap().to_str().unwrap() )); let display_path = display_path.to_str().unwrap(); let display_file = libredox::call::open(display_path, (O_CLOEXEC | O_NONBLOCK | O_RDWR) as _, 0) .map(|socket| unsafe { File::from_raw_fd(socket as RawFd) }) .unwrap_or_else(|err| { panic!("failed to open display {}: {}", display_path, err); }); Ok(display_file) } pub fn read_events<'a>(&self, events: &'a mut [Event]) -> io::Result> { match read_to_slice(self.0.as_fd(), events) { Ok(count) => Ok(ConsumerHandleEvent::Events(&events[..count])), Err(err) if err.errno() == ESTALE => Ok(ConsumerHandleEvent::Handoff), Err(err) => Err(err.into()), } } } #[derive(Debug, Clone)] #[repr(C)] pub struct ControlEvent { pub kind: usize, pub data: usize, } impl From for ControlEvent { fn from(value: VtActivate) -> Self { ControlEvent { kind: 1, data: value.vt, } } } impl From for ControlEvent { fn from(value: KeymapActivate) -> Self { ControlEvent { kind: 2, data: value.keymap, } } } pub struct VtActivate { pub vt: usize, } pub struct KeymapActivate { pub keymap: usize, } pub struct DisplayHandle(File); impl DisplayHandle { pub fn new>(scheme_name: S) -> io::Result { let path = format!("/scheme/input/handle/{}", scheme_name.into()); Ok(Self(File::open(path)?)) } pub fn new_early>(scheme_name: S) -> io::Result { let path = format!("/scheme/input/handle_early/{}", scheme_name.into()); Ok(Self(File::open(path)?)) } pub fn read_vt_event(&mut self) -> io::Result> { let mut event = VtEvent { kind: VtEventKind::Activate, vt: usize::MAX, }; let nread = self.0.read(unsafe { any_as_u8_slice_mut(&mut event) })?; if nread == 0 { Ok(None) } else { assert_eq!(nread, size_of::()); Ok(Some(event)) } } pub fn inner(&self) -> BorrowedFd<'_> { self.0.as_fd() } } pub struct ControlHandle(File); impl ControlHandle { pub fn new() -> io::Result { let path = format!("/scheme/input/control"); Ok(Self(File::open(path)?)) } /// Sent to Handle::Display pub fn activate_vt(&mut self, vt: usize) -> io::Result { let cmd = ControlEvent::from(VtActivate { vt }); self.0.write(unsafe { any_as_u8_slice(&cmd) }) } /// Sent to Handle::Producer pub fn activate_keymap(&mut self, keymap: usize) -> io::Result { let cmd = ControlEvent::from(KeymapActivate { keymap }); self.0.write(unsafe { any_as_u8_slice(&cmd) }) } } #[derive(Debug)] #[repr(usize)] pub enum VtEventKind { Activate, } #[derive(Debug)] #[repr(C)] pub struct VtEvent { pub kind: VtEventKind, pub vt: usize, } pub struct ProducerHandle(File); impl ProducerHandle { pub fn new() -> io::Result { File::open("/scheme/input/producer").map(ProducerHandle) } pub fn write_event(&mut self, event: orbclient::Event) -> io::Result<()> { self.0.write(&event)?; Ok(()) } }