mirror of
https://github.com/htrefil/rkvm.git
synced 2025-01-30 20:34:13 +01:00
Implement libevdev event reading
This commit is contained in:
parent
5e2e7becb4
commit
68fa721095
4 changed files with 129 additions and 16 deletions
|
@ -4,6 +4,7 @@ use std::path::PathBuf;
|
|||
|
||||
fn main() {
|
||||
println!("cargo:rerun-if-changed=glue/glue.h");
|
||||
println!("cargo:rustc-link-lib=evdev");
|
||||
|
||||
let bindings = Builder::default()
|
||||
.header("glue/glue.h")
|
||||
|
|
|
@ -1 +1 @@
|
|||
#include <linux/input.h>
|
||||
#include <libevdev-1.0/libevdev/libevdev.h>
|
|
@ -1,5 +1,5 @@
|
|||
use crate::event::Event;
|
||||
use crate::event_reader::{EventReader, OpenError};
|
||||
use crate::event_reader::EventReader;
|
||||
use crate::event_writer::EventWriter;
|
||||
use crate::glue::input_event;
|
||||
use std::io::{Error, ErrorKind};
|
||||
|
@ -21,11 +21,17 @@ impl EventManager {
|
|||
continue;
|
||||
}
|
||||
|
||||
let reader = match EventReader::new(&path).await {
|
||||
Ok(reader) => reader,
|
||||
Err(OpenError::NotSupported) => continue,
|
||||
Err(OpenError::Io(err)) => return Err(err),
|
||||
};
|
||||
// Skip non input event files.
|
||||
if path
|
||||
.file_name()
|
||||
.and_then(|name| name.to_str())
|
||||
.map(|name| !name.starts_with("event"))
|
||||
.unwrap_or(true)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
let reader = EventReader::new(&path).await?;
|
||||
let sender = sender.clone();
|
||||
|
||||
tokio::spawn(handle_events(reader, sender));
|
||||
|
|
|
@ -1,21 +1,127 @@
|
|||
use crate::glue::input_event;
|
||||
use crate::glue::{self, input_event, libevdev};
|
||||
use mio::event::Evented;
|
||||
use mio::unix::EventedFd;
|
||||
use mio::{PollOpt, Ready, Token};
|
||||
use std::fs::{File, OpenOptions};
|
||||
use std::future::Future;
|
||||
use std::io::Error;
|
||||
use std::mem::MaybeUninit;
|
||||
use std::os::unix::fs::OpenOptionsExt;
|
||||
use std::os::unix::io::AsRawFd;
|
||||
use std::path::Path;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use tokio::io::Registration;
|
||||
|
||||
pub(crate) struct EventReader {}
|
||||
pub(crate) struct EventReader {
|
||||
file: EventedFile,
|
||||
registration: Registration,
|
||||
evdev: *mut libevdev,
|
||||
}
|
||||
|
||||
impl EventReader {
|
||||
pub async fn new(path: &Path) -> Result<Self, OpenError> {
|
||||
todo!()
|
||||
pub async fn new(path: &Path) -> Result<Self, Error> {
|
||||
let path = path.to_owned();
|
||||
|
||||
tokio::task::spawn_blocking(move || Self::open_sync(&path)).await?
|
||||
}
|
||||
|
||||
pub async fn read(&mut self) -> Result<input_event, Error> {
|
||||
todo!()
|
||||
Read { reader: self }.await
|
||||
}
|
||||
|
||||
fn open_sync(path: &Path) -> Result<Self, Error> {
|
||||
let file = OpenOptions::new()
|
||||
.read(true)
|
||||
.custom_flags(libc::O_NONBLOCK)
|
||||
.open(path)
|
||||
.map(|file| EventedFile { file })?;
|
||||
let registration = Registration::new(&file)?;
|
||||
|
||||
let mut evdev = std::ptr::null_mut();
|
||||
|
||||
let ret =
|
||||
unsafe { glue::libevdev_new_from_fd(file.file.as_raw_fd(), &mut evdev as *mut _) };
|
||||
if ret < 0 {
|
||||
return Err(Error::from_raw_os_error(-ret));
|
||||
}
|
||||
|
||||
let ret = unsafe { glue::libevdev_grab(evdev, glue::libevdev_grab_mode_LIBEVDEV_GRAB) };
|
||||
if ret < 0 {
|
||||
unsafe { glue::libevdev_free(evdev) };
|
||||
return Err(Error::from_raw_os_error(-ret));
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
file,
|
||||
registration,
|
||||
evdev,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum OpenError {
|
||||
NotSupported,
|
||||
Io(Error),
|
||||
unsafe impl Send for EventReader {}
|
||||
|
||||
impl Drop for EventReader {
|
||||
fn drop(&mut self) {
|
||||
unsafe { glue::libevdev_free(self.evdev) };
|
||||
}
|
||||
}
|
||||
|
||||
struct EventedFile {
|
||||
file: File,
|
||||
}
|
||||
|
||||
impl Evented for EventedFile {
|
||||
fn register(
|
||||
&self,
|
||||
poll: &mio::Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> Result<(), Error> {
|
||||
EventedFd(&self.file.as_raw_fd()).register(poll, token, interest, opts)
|
||||
}
|
||||
|
||||
fn reregister(
|
||||
&self,
|
||||
poll: &mio::Poll,
|
||||
token: Token,
|
||||
interest: Ready,
|
||||
opts: PollOpt,
|
||||
) -> Result<(), Error> {
|
||||
EventedFd(&self.file.as_raw_fd()).reregister(poll, token, interest, opts)
|
||||
}
|
||||
|
||||
fn deregister(&self, poll: &mio::Poll) -> Result<(), Error> {
|
||||
EventedFd(&self.file.as_raw_fd()).deregister(poll)
|
||||
}
|
||||
}
|
||||
|
||||
struct Read<'a> {
|
||||
reader: &'a mut EventReader,
|
||||
}
|
||||
|
||||
impl Future for Read<'_> {
|
||||
type Output = Result<input_event, Error>;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, context: &mut Context) -> Poll<Self::Output> {
|
||||
if let Poll::Pending = self.reader.registration.poll_read_ready(context)? {
|
||||
return Poll::Pending;
|
||||
}
|
||||
|
||||
let mut event = MaybeUninit::uninit();
|
||||
let ret = unsafe {
|
||||
glue::libevdev_next_event(
|
||||
self.reader.evdev,
|
||||
glue::libevdev_read_flag_LIBEVDEV_READ_FLAG_NORMAL,
|
||||
event.as_mut_ptr(),
|
||||
)
|
||||
};
|
||||
if ret < 0 {
|
||||
return Poll::Ready(Err(Error::from_raw_os_error(-ret)));
|
||||
}
|
||||
|
||||
Poll::Ready(Ok(unsafe { event.assume_init() }))
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue