mirror of
https://github.com/htrefil/rkvm.git
synced 2024-12-27 09:58:13 +01:00
Intercept BUS_VIRTUAL devices
This commit is contained in:
parent
a0e98e43fc
commit
adcab7b2c6
5 changed files with 95 additions and 13 deletions
|
@ -6,6 +6,7 @@ use crate::abs::{AbsAxis, AbsEvent, ToolType};
|
|||
use crate::event::Event;
|
||||
use crate::glue::{self, libevdev};
|
||||
use crate::key::{Key, KeyEvent};
|
||||
use crate::registry::{Entry, Handle, Registry};
|
||||
use crate::rel::{RelAxis, RelEvent};
|
||||
use crate::sync::SyncEvent;
|
||||
use crate::writer::Writer;
|
||||
|
@ -16,6 +17,7 @@ use std::fs::{File, OpenOptions};
|
|||
use std::io::{Error, ErrorKind};
|
||||
use std::mem::MaybeUninit;
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::os::unix::prelude::OpenOptionsExt;
|
||||
use std::path::Path;
|
||||
use std::ptr::NonNull;
|
||||
|
@ -31,6 +33,9 @@ pub struct Interceptor {
|
|||
events: VecDeque<Event>,
|
||||
writing: Option<(u16, u16, i32)>,
|
||||
dropped: bool,
|
||||
|
||||
_reader_handle: Handle,
|
||||
_writer_handle: Handle,
|
||||
}
|
||||
|
||||
impl Interceptor {
|
||||
|
@ -173,20 +178,30 @@ impl Interceptor {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) async fn open(path: &Path) -> Result<Self, OpenError> {
|
||||
pub(crate) async fn open(path: &Path, registry: &Registry) -> Result<Self, OpenError> {
|
||||
let path = path.to_owned();
|
||||
task::spawn_blocking(move || Self::open_sync(&path))
|
||||
let registry = registry.clone();
|
||||
|
||||
task::spawn_blocking(move || Self::open_sync(&path, ®istry))
|
||||
.await
|
||||
.map_err(|err| OpenError::Io(err.into()))?
|
||||
}
|
||||
|
||||
fn open_sync(path: &Path) -> Result<Self, OpenError> {
|
||||
fn open_sync(path: &Path, registry: &Registry) -> Result<Self, OpenError> {
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.custom_flags(libc::O_NONBLOCK)
|
||||
.open(path)
|
||||
.and_then(AsyncFd::new)?;
|
||||
|
||||
let metadata = file.get_ref().metadata()?;
|
||||
let reader_handle = registry
|
||||
.register(Entry {
|
||||
device: metadata.dev(),
|
||||
inode: metadata.ino(),
|
||||
})
|
||||
.ok_or(OpenError::NotAppliable)?;
|
||||
|
||||
let mut evdev = MaybeUninit::uninit();
|
||||
|
||||
let ret = unsafe { glue::libevdev_new_from_fd(file.as_raw_fd(), evdev.as_mut_ptr()) };
|
||||
|
@ -202,11 +217,7 @@ impl Interceptor {
|
|||
// state is in sync."
|
||||
// We have no way of knowing that.
|
||||
let sw = unsafe { glue::libevdev_has_event_type(evdev.as_ptr(), glue::EV_SW) };
|
||||
|
||||
// Check if we're not opening our own virtual device.
|
||||
let bus_type = unsafe { glue::libevdev_get_id_bustype(evdev.as_ptr()) };
|
||||
|
||||
if bus_type == glue::BUS_VIRTUAL as _ || sw == 1 {
|
||||
if sw == 1 {
|
||||
unsafe {
|
||||
glue::libevdev_free(evdev.as_ptr());
|
||||
}
|
||||
|
@ -275,6 +286,20 @@ impl Interceptor {
|
|||
}
|
||||
};
|
||||
|
||||
// TODO: This is ugly. Need to refactor the evdev wrappers.
|
||||
let entry = match writer.entry() {
|
||||
Ok(entry) => entry,
|
||||
Err(err) => {
|
||||
unsafe {
|
||||
glue::libevdev_free(evdev.as_ptr());
|
||||
}
|
||||
|
||||
return Err(err.into());
|
||||
}
|
||||
};
|
||||
|
||||
let writer_handle = registry.register(entry).unwrap();
|
||||
|
||||
Ok(Self {
|
||||
file,
|
||||
evdev,
|
||||
|
@ -282,6 +307,9 @@ impl Interceptor {
|
|||
events: VecDeque::new(),
|
||||
dropped: false,
|
||||
writing: None,
|
||||
|
||||
_reader_handle: reader_handle,
|
||||
_writer_handle: writer_handle,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -8,3 +8,4 @@ pub mod sync;
|
|||
pub mod writer;
|
||||
|
||||
mod glue;
|
||||
mod registry;
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
use crate::interceptor::{Interceptor, OpenError};
|
||||
use crate::registry::Registry;
|
||||
|
||||
use futures::StreamExt;
|
||||
use inotify::{Inotify, WatchMask};
|
||||
|
@ -20,6 +21,8 @@ impl Monitor {
|
|||
|
||||
tokio::spawn(async move {
|
||||
let run = async {
|
||||
let registry = Registry::new();
|
||||
|
||||
let mut read_dir = fs::read_dir(EVENT_PATH).await?;
|
||||
|
||||
let mut inotify = Inotify::init()?;
|
||||
|
@ -54,7 +57,7 @@ impl Monitor {
|
|||
continue;
|
||||
}
|
||||
|
||||
let interceptor = match Interceptor::open(&path).await {
|
||||
let interceptor = match Interceptor::open(&path, ®istry).await {
|
||||
Ok(interceptor) => interceptor,
|
||||
Err(OpenError::Io(err)) => return Err(err),
|
||||
Err(OpenError::NotAppliable) => continue,
|
||||
|
|
43
rkvm-input/src/registry.rs
Normal file
43
rkvm-input/src/registry.rs
Normal file
|
@ -0,0 +1,43 @@
|
|||
use std::collections::HashSet;
|
||||
use std::sync::{Arc, Mutex};
|
||||
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Debug)]
|
||||
pub struct Entry {
|
||||
pub device: u64,
|
||||
pub inode: u64,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Registry {
|
||||
entries: Arc<Mutex<HashSet<Entry>>>,
|
||||
}
|
||||
|
||||
impl Registry {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
entries: Arc::new(Mutex::new(HashSet::new())),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn register(&self, entry: Entry) -> Option<Handle> {
|
||||
if !self.entries.lock().unwrap().insert(entry) {
|
||||
return None;
|
||||
}
|
||||
|
||||
Some(Handle {
|
||||
entries: self.entries.clone(),
|
||||
entry,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Handle {
|
||||
entries: Arc<Mutex<HashSet<Entry>>>,
|
||||
entry: Entry,
|
||||
}
|
||||
|
||||
impl Drop for Handle {
|
||||
fn drop(&mut self) {
|
||||
assert!(self.entries.lock().unwrap().remove(&self.entry));
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ use crate::abs::{AbsAxis, AbsEvent, AbsInfo};
|
|||
use crate::event::Event;
|
||||
use crate::glue::{self, input_absinfo, libevdev, libevdev_uinput};
|
||||
use crate::key::{Key, KeyEvent};
|
||||
use crate::registry::Entry;
|
||||
use crate::rel::{RelAxis, RelEvent};
|
||||
|
||||
use std::ffi::{CStr, OsStr};
|
||||
|
@ -10,10 +11,11 @@ use std::io::{Error, ErrorKind};
|
|||
use std::mem::MaybeUninit;
|
||||
use std::os::fd::AsRawFd;
|
||||
use std::os::unix::ffi::OsStrExt;
|
||||
use std::os::unix::fs::MetadataExt;
|
||||
use std::os::unix::prelude::OpenOptionsExt;
|
||||
use std::path::Path;
|
||||
use std::ptr;
|
||||
use std::ptr::NonNull;
|
||||
use std::{fs, ptr};
|
||||
use tokio::io::unix::AsyncFd;
|
||||
use tokio::task;
|
||||
|
||||
|
@ -44,17 +46,22 @@ impl Writer {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn path(&self) -> Option<&Path> {
|
||||
pub(crate) fn entry(&self) -> Result<Entry, Error> {
|
||||
let path = unsafe { glue::libevdev_uinput_get_devnode(self.uinput.as_ptr()) };
|
||||
if path.is_null() {
|
||||
return None;
|
||||
return Err(Error::new(ErrorKind::Other, "No syspath for device"));
|
||||
}
|
||||
|
||||
let path = unsafe { CStr::from_ptr(path) };
|
||||
let path = OsStr::from_bytes(path.to_bytes());
|
||||
let path = Path::new(path);
|
||||
|
||||
Some(path)
|
||||
let metadata = fs::metadata(path)?;
|
||||
|
||||
Ok(Entry {
|
||||
device: metadata.dev(),
|
||||
inode: metadata.ino(),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn from_evdev(evdev: *const libevdev) -> Result<Self, Error> {
|
||||
|
|
Loading…
Reference in a new issue