Implement libevdev event management

This commit is contained in:
htrefil 2020-10-28 19:45:49 +01:00
parent 68fa721095
commit ed7d5bcf06
4 changed files with 202 additions and 64 deletions

View file

@ -6,8 +6,10 @@ fn main() {
println!("cargo:rerun-if-changed=glue/glue.h");
println!("cargo:rustc-link-lib=evdev");
// TODO: pkg-config
let bindings = Builder::default()
.header("glue/glue.h")
.clang_arg("-I/usr/include/libevdev-1.0/")
.parse_callbacks(Box::new(CargoCallbacks))
.generate()
.unwrap();

View file

@ -1 +1,2 @@
#include <libevdev-1.0/libevdev/libevdev.h>
#include <libevdev/libevdev.h>
#include <libevdev/libevdev-uinput.h>

View file

@ -1,7 +1,5 @@
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;
@ -14,7 +12,7 @@ use std::task::{Context, Poll};
use tokio::io::Registration;
pub(crate) struct EventReader {
file: EventedFile,
file: File,
registration: Registration,
evdev: *mut libevdev,
}
@ -22,33 +20,29 @@ pub(crate) struct EventReader {
impl EventReader {
pub async fn new(path: &Path) -> Result<Self, Error> {
let path = path.to_owned();
tokio::task::spawn_blocking(move || Self::open_sync(&path)).await?
tokio::task::spawn_blocking(move || Self::new_sync(&path)).await?
}
pub async fn read(&mut self) -> Result<input_event, Error> {
Read { reader: self }.await
}
fn open_sync(path: &Path) -> Result<Self, Error> {
fn new_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)?;
.open(path)?;
let registration = Registration::new(&EventedFd(&file.as_raw_fd()))?;
let mut evdev = std::ptr::null_mut();
let ret =
unsafe { glue::libevdev_new_from_fd(file.file.as_raw_fd(), &mut evdev as *mut _) };
let mut evdev = MaybeUninit::uninit();
let ret = unsafe { glue::libevdev_new_from_fd(file.as_raw_fd(), evdev.as_mut_ptr()) };
if ret < 0 {
return Err(Error::from_raw_os_error(-ret));
}
let evdev = unsafe { evdev.assume_init() };
let ret = unsafe { glue::libevdev_grab(evdev, glue::libevdev_grab_mode_LIBEVDEV_GRAB) };
if ret < 0 {
unsafe { glue::libevdev_free(evdev) };
unsafe {
glue::libevdev_free(evdev);
}
return Err(Error::from_raw_os_error(-ret));
}
@ -58,56 +52,39 @@ impl EventReader {
evdev,
})
}
pub async fn read(&mut self) -> Result<input_event, Error> {
Read {
reader: self,
polling: false,
}
.await
}
}
impl Drop for EventReader {
fn drop(&mut self) {
unsafe {
glue::libevdev_free(self.evdev);
}
}
}
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,
polling: bool,
}
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;
fn poll(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<Self::Output> {
if self.polling {
if let Poll::Pending = self.reader.registration.poll_read_ready(context)? {
return Poll::Pending;
}
}
let mut event = MaybeUninit::uninit();
@ -118,10 +95,19 @@ impl Future for Read<'_> {
event.as_mut_ptr(),
)
};
if !self.polling && ret == -libc::EAGAIN {
self.polling = true;
return self.poll(context);
}
self.polling = false;
if ret < 0 {
return Poll::Ready(Err(Error::from_raw_os_error(-ret)));
}
Poll::Ready(Ok(unsafe { event.assume_init() }))
let event = unsafe { event.assume_init() };
Poll::Ready(Ok(event))
}
}

View file

@ -1,12 +1,75 @@
use crate::event::Event;
use crate::glue::input_event;
use std::io::Error;
use crate::glue::{self, input_event, libevdev, libevdev_uinput};
use mio::unix::EventedFd;
use std::fs::OpenOptions;
use std::future::Future;
use std::io::{Error, ErrorKind};
use std::mem::MaybeUninit;
use std::ops::RangeInclusive;
use std::os::unix::fs::OpenOptionsExt;
use std::os::unix::io::AsRawFd;
use std::pin::Pin;
use std::task::{Context, Poll};
use tokio::io::Registration;
pub struct EventWriter {}
pub struct EventWriter {
evdev: *mut libevdev,
uinput: *mut libevdev_uinput,
registration: Registration,
}
impl EventWriter {
pub async fn new() -> Result<Self, Error> {
todo!()
tokio::task::spawn_blocking(|| Self::new_sync()).await?
}
fn new_sync() -> Result<Self, Error> {
let evdev = unsafe { glue::libevdev_new() };
if evdev.is_null() {
return Err(Error::new(ErrorKind::Other, "Failed to create device"));
}
if let Err(err) = unsafe { setup_evdev(evdev) } {
unsafe {
glue::libevdev_free(evdev);
}
return Err(err);
}
let mut uinput = MaybeUninit::uninit();
let ret = unsafe {
glue::libevdev_uinput_create_from_device(
evdev,
glue::libevdev_uinput_open_mode_LIBEVDEV_UINPUT_OPEN_MANAGED,
uinput.as_mut_ptr(),
)
};
if ret < 0 {
unsafe { glue::libevdev_free(evdev) };
return Err(Error::from_raw_os_error(-ret));
}
let uinput = unsafe { uinput.assume_init() };
let fd = unsafe { glue::libevdev_uinput_get_fd(uinput) };
let registration = match Registration::new(&EventedFd(&fd)) {
Ok(registration) => registration,
Err(err) => {
unsafe {
glue::libevdev_uinput_destroy(uinput);
glue::libevdev_free(evdev);
};
return Err(err);
}
};
Ok(Self {
evdev,
uinput,
registration,
})
}
pub async fn write(&mut self, event: Event) -> Result<(), Error> {
@ -14,6 +77,92 @@ impl EventWriter {
}
pub(crate) async fn write_raw(&mut self, event: input_event) -> Result<(), Error> {
todo!()
WriteRaw {
writer: self,
event,
polling: false,
}
.await
}
}
impl Drop for EventWriter {
fn drop(&mut self) {
unsafe {
glue::libevdev_uinput_destroy(self.uinput);
glue::libevdev_free(self.evdev);
}
}
}
unsafe impl Send for EventWriter {}
struct WriteRaw<'a> {
writer: &'a mut EventWriter,
event: input_event,
polling: bool,
}
impl Future for WriteRaw<'_> {
type Output = Result<(), Error>;
fn poll(mut self: Pin<&mut Self>, context: &mut Context) -> Poll<Self::Output> {
if self.polling {
if let Poll::Pending = self.writer.registration.poll_write_ready(context)? {
return Poll::Pending;
}
}
let ret = unsafe {
glue::libevdev_uinput_write_event(
self.writer.uinput as *const _,
self.event.type_ as _,
self.event.code as _,
self.event.value,
)
};
if !self.polling && ret == -libc::EAGAIN {
self.polling = true;
return self.poll(context);
}
self.polling = false;
if ret < 0 {
return Poll::Ready(Err(Error::from_raw_os_error(-ret)));
}
Poll::Ready(Ok(()))
}
}
const TYPES: &[(u32, &[RangeInclusive<u32>])] = &[
(glue::EV_SYN, &[glue::SYN_REPORT..=glue::SYN_REPORT]),
(glue::EV_REL, &[0..=glue::REL_MAX]),
(glue::EV_KEY, &[0..=glue::KEY_MAX]),
];
unsafe fn setup_evdev(evdev: *mut libevdev) -> Result<(), Error> {
glue::libevdev_set_name(evdev, b"rkvm\0".as_ptr() as *const _);
glue::libevdev_set_id_product(evdev, 1);
glue::libevdev_set_id_version(evdev, 1);
glue::libevdev_set_id_vendor(evdev, i32::from_be_bytes(*b"rkvm"));
glue::libevdev_set_id_bustype(evdev, glue::BUS_USB as _);
for (r#type, codes) in TYPES.iter().copied() {
let ret = glue::libevdev_enable_event_type(evdev, r#type);
if ret < 0 {
return Err(Error::from_raw_os_error(-ret));
}
for code in codes.iter().cloned().flat_map(|code| code) {
let ret = glue::libevdev_enable_event_code(evdev, r#type, code, std::ptr::null_mut());
if ret < 0 {
return Err(Error::from_raw_os_error(-ret));
}
}
}
Ok(())
}