autocommit 2022-03-09 14:01:21 CET
This commit is contained in:
parent
aa0cb94143
commit
4df6b559b7
32 changed files with 1121 additions and 172 deletions
|
|
@ -1,12 +1,19 @@
|
|||
mod input;
|
||||
mod monitor;
|
||||
|
||||
use crate::async_engine::AsyncFd;
|
||||
use crate::dbus::DbusError;
|
||||
use crate::libinput::device::RegisteredDevice;
|
||||
use crate::libinput::{LibInput, LibInputAdapter, LibInputError};
|
||||
use crate::logind::{LogindError, Session};
|
||||
use crate::{AsyncQueue, ErrorFmt, State, Udev};
|
||||
use crate::udev::{UdevError, UdevMonitor};
|
||||
use crate::utils::copyhashmap::CopyHashMap;
|
||||
use crate::{AsyncQueue, CloneCell, ErrorFmt, NumCell, State, Udev};
|
||||
use std::cell::{Cell, RefCell};
|
||||
use std::ffi::{CStr, CString};
|
||||
use std::rc::Rc;
|
||||
use thiserror::Error;
|
||||
use uapi::OwnedFd;
|
||||
use crate::async_engine::{AsyncFd, FdStatus};
|
||||
use crate::libinput::{LibInput, LibInputError};
|
||||
use crate::udev::{UdevError, UdevMonitor};
|
||||
use uapi::{c, OwnedFd};
|
||||
|
||||
#[derive(Debug, Error)]
|
||||
pub enum MetalError {
|
||||
|
|
@ -16,12 +23,14 @@ pub enum MetalError {
|
|||
LogindSession(#[source] LogindError),
|
||||
#[error("Could not take control of the logind session")]
|
||||
TakeControl(#[source] LogindError),
|
||||
#[error("Could not enumerate devices")]
|
||||
Enumerate(#[source] Box<Self>),
|
||||
#[error(transparent)]
|
||||
Udev(#[from] UdevError),
|
||||
#[error(transparent)]
|
||||
LibInput(#[from] LibInputError),
|
||||
#[error("Dupfd failed")]
|
||||
Dup(#[source] std::io::Error),
|
||||
Dup(#[source] crate::utils::oserror::OsError),
|
||||
}
|
||||
|
||||
pub async fn run(state: Rc<State>) {
|
||||
|
|
@ -30,6 +39,18 @@ pub async fn run(state: Rc<State>) {
|
|||
}
|
||||
}
|
||||
|
||||
struct MetalBackend {
|
||||
state: Rc<State>,
|
||||
udev: Rc<Udev>,
|
||||
monitor: Rc<UdevMonitor>,
|
||||
monitor_fd: AsyncFd,
|
||||
libinput: Rc<LibInput>,
|
||||
libinput_fd: AsyncFd,
|
||||
device_holder: Rc<DeviceHolder>,
|
||||
session: Session,
|
||||
ids: NumCell<u64>,
|
||||
}
|
||||
|
||||
async fn run_(state: Rc<State>) -> Result<(), MetalError> {
|
||||
let socket = match state.dbus.system() {
|
||||
Ok(s) => s,
|
||||
|
|
@ -39,90 +60,83 @@ async fn run_(state: Rc<State>) -> Result<(), MetalError> {
|
|||
Ok(s) => s,
|
||||
Err(e) => return Err(MetalError::LogindSession(e)),
|
||||
};
|
||||
// if let Err(e) = session.take_control().await {
|
||||
// return Err(MetalError::TakeControl(e));
|
||||
// }
|
||||
if let Err(e) = session.take_control().await {
|
||||
return Err(MetalError::TakeControl(e));
|
||||
}
|
||||
let device_holder = Rc::new(DeviceHolder {
|
||||
input_devices: Default::default(),
|
||||
input_devices_: Default::default(),
|
||||
});
|
||||
let udev = Rc::new(Udev::new()?);
|
||||
let monitor = Rc::new(udev.create_monitor()?);
|
||||
monitor.add_match_subsystem_devtype(Some("input"), None)?;
|
||||
monitor.enable_receiving()?;
|
||||
let libinput = Rc::new(LibInput::new()?);
|
||||
let libinput = Rc::new(LibInput::new(device_holder.clone())?);
|
||||
let monitor_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) {
|
||||
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
|
||||
Err(e) => return Err(MetalError::Dup(e.into())),
|
||||
};
|
||||
let libinput_fd = match uapi::fcntl_dupfd_cloexec(libinput.fd(), 0) {
|
||||
Ok(m) => state.eng.fd(&Rc::new(m)).unwrap(),
|
||||
Err(e) => return Err(MetalError::Dup(e.into())),
|
||||
};
|
||||
let metal = Rc::new(MetalBackend {
|
||||
state: state.clone(),
|
||||
udev,
|
||||
monitor,
|
||||
monitor_fd,
|
||||
libinput,
|
||||
libinput_fd,
|
||||
device_holder,
|
||||
session,
|
||||
ids: Default::default(),
|
||||
});
|
||||
let _monitor = state.eng.spawn(metal.clone().monitor_devices());
|
||||
let mut queue = AsyncQueue::<String>::new();
|
||||
let _events = state.eng.spawn(metal.clone().handle_libinput_events());
|
||||
if let Err(e) = metal.enumerate_devices() {
|
||||
return Err(MetalError::Enumerate(Box::new(e)));
|
||||
}
|
||||
let queue = AsyncQueue::<String>::new();
|
||||
queue.pop().await;
|
||||
Ok(())
|
||||
// let libinput_fd = match uapi::fcntl_dupfd_cloexec(monitor.fd(), 0) {
|
||||
// Ok(m) => m,
|
||||
// Err(e) => Err(MetalError::Dup(e.into())),
|
||||
// };
|
||||
// let mut enumerate = udev.create_enumerate()?;
|
||||
// enumerate.add_match_subsystem("input")?;
|
||||
// enumerate.scan_devices()?;
|
||||
// let mut entry_opt = enumerate.get_list_entry()?;
|
||||
// while let Some(entry) = entry_opt {
|
||||
// let device = udev.create_device_from_syspath(entry.name()?)?;
|
||||
// if device.sysname()?.to_bytes().starts_with(b"event") {
|
||||
// let devnode = device.devnode()?;
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
struct MetalBackend {
|
||||
state: Rc<State>,
|
||||
udev: Rc<Udev>,
|
||||
monitor: Rc<UdevMonitor>,
|
||||
monitor_fd: AsyncFd,
|
||||
libinput: Rc<LibInput>,
|
||||
libinput_fd: AsyncFd,
|
||||
struct MetalDevice {
|
||||
slot: usize,
|
||||
device_id: u64,
|
||||
devnum: c::dev_t,
|
||||
fd: CloneCell<Option<Rc<OwnedFd>>>,
|
||||
inputdev: Cell<Option<RegisteredDevice>>,
|
||||
devnode: CString,
|
||||
sysname: CString,
|
||||
}
|
||||
|
||||
struct DeviceHolder {
|
||||
input_devices: CopyHashMap<c::dev_t, Rc<MetalDevice>>,
|
||||
input_devices_: RefCell<Vec<Option<Rc<MetalDevice>>>>,
|
||||
}
|
||||
|
||||
impl LibInputAdapter for DeviceHolder {
|
||||
fn open(&self, path: &CStr) -> Result<OwnedFd, LibInputError> {
|
||||
let stat = match uapi::stat(path) {
|
||||
Ok(s) => s,
|
||||
Err(e) => return Err(LibInputError::Stat(e.into())),
|
||||
};
|
||||
match self.input_devices.get(&stat.st_rdev) {
|
||||
Some(d) => match d.fd.get() {
|
||||
Some(fd) => match uapi::fcntl_dupfd_cloexec(fd.raw(), 0) {
|
||||
Ok(fd) => Ok(fd),
|
||||
Err(e) => Err(LibInputError::DupFd(e.into())),
|
||||
},
|
||||
_ => Err(LibInputError::DeviceUnavailable),
|
||||
},
|
||||
_ => Err(LibInputError::DeviceUnavailable),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl MetalBackend {
|
||||
async fn monitor_devices(self: Rc<Self>) {
|
||||
loop {
|
||||
match self.monitor_fd.readable().await {
|
||||
Err(e) => {
|
||||
log::error!("Cannot wait for udev_monitor to become readable: {}", ErrorFmt(e));
|
||||
break;
|
||||
}
|
||||
Ok(FdStatus::Err) => {
|
||||
log::error!("udev_monitor fd is in an error state");
|
||||
break;
|
||||
}
|
||||
_ => { },
|
||||
}
|
||||
while let Some(dev) = self.monitor.receive_device() {
|
||||
log::info!("x {:?}", dev.devnode());
|
||||
}
|
||||
}
|
||||
log::error!("Monitor task exited. Future hotplug events will be ignored.");
|
||||
}
|
||||
|
||||
async fn handle_libinput_events(self: Rc<Self>) {
|
||||
loop {
|
||||
match self.libinput_fd.readable().await {
|
||||
Err(e) => {
|
||||
log::error!("Cannot wait for udev_monitor to become readable: {}", ErrorFmt(e));
|
||||
break;
|
||||
}
|
||||
Ok(FdStatus::Err) => {
|
||||
log::error!("udev_monitor fd is in an error state");
|
||||
break;
|
||||
}
|
||||
_ => { },
|
||||
}
|
||||
self.libinput.fd()
|
||||
}
|
||||
log::error!("Monitor task exited. Future hotplug events will be ignored.");
|
||||
fn id(&self) -> u64 {
|
||||
self.ids.fetch_add(1)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
55
src/backends/metal/input.rs
Normal file
55
src/backends/metal/input.rs
Normal file
|
|
@ -0,0 +1,55 @@
|
|||
use crate::async_engine::FdStatus;
|
||||
use crate::libinput::consts::LIBINPUT_EVENT_KEYBOARD_KEY;
|
||||
use crate::libinput::event::LibInputEvent;
|
||||
use crate::metal::MetalBackend;
|
||||
use crate::ErrorFmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
impl MetalBackend {
|
||||
pub async fn handle_libinput_events(self: Rc<Self>) {
|
||||
loop {
|
||||
match self.libinput_fd.readable().await {
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Cannot wait for libinput fd to become readable: {}",
|
||||
ErrorFmt(e)
|
||||
);
|
||||
break;
|
||||
}
|
||||
Ok(FdStatus::Err) => {
|
||||
log::error!("libinput fd fd is in an error state");
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
if let Err(e) = self.libinput.dispatch() {
|
||||
log::error!("Could not dispatch libinput events: {}", ErrorFmt(e));
|
||||
break;
|
||||
}
|
||||
while let Some(event) = self.libinput.event() {
|
||||
self.handle_event(event);
|
||||
}
|
||||
}
|
||||
log::error!("Libinput task exited. Future input events will be ignored.");
|
||||
}
|
||||
|
||||
fn handle_event(self: &Rc<Self>, event: LibInputEvent) {
|
||||
match event.ty() {
|
||||
LIBINPUT_EVENT_KEYBOARD_KEY => self.handle_keyboard_event(event),
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_keyboard_event(self: &Rc<Self>, event: LibInputEvent) {
|
||||
let event = match event.keyboard_event() {
|
||||
Some(event) => event,
|
||||
_ => return,
|
||||
};
|
||||
log::info!(
|
||||
"key: {}, state: {:?}, time: {}",
|
||||
event.key(),
|
||||
event.key_state(),
|
||||
event.time_usec()
|
||||
);
|
||||
}
|
||||
}
|
||||
131
src/backends/metal/monitor.rs
Normal file
131
src/backends/metal/monitor.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
use crate::async_engine::FdStatus;
|
||||
use crate::dbus::TRUE;
|
||||
use crate::metal::{MetalBackend, MetalDevice, MetalError};
|
||||
use crate::udev::UdevDevice;
|
||||
use crate::ErrorFmt;
|
||||
use std::rc::Rc;
|
||||
|
||||
impl MetalBackend {
|
||||
pub async fn monitor_devices(self: Rc<Self>) {
|
||||
loop {
|
||||
match self.monitor_fd.readable().await {
|
||||
Err(e) => {
|
||||
log::error!(
|
||||
"Cannot wait for udev_monitor to become readable: {}",
|
||||
ErrorFmt(e)
|
||||
);
|
||||
break;
|
||||
}
|
||||
Ok(FdStatus::Err) => {
|
||||
log::error!("udev_monitor fd is in an error state");
|
||||
break;
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
while let Some(dev) = self.monitor.receive_device() {
|
||||
log::info!("x {:?}", dev.devnode());
|
||||
}
|
||||
}
|
||||
log::error!("Monitor task exited. Future hotplug events will be ignored.");
|
||||
}
|
||||
|
||||
pub fn enumerate_devices(self: &Rc<Self>) -> Result<(), MetalError> {
|
||||
let mut enumerate = self.udev.create_enumerate()?;
|
||||
enumerate.add_match_subsystem("input")?;
|
||||
enumerate.scan_devices()?;
|
||||
let mut entry_opt = enumerate.get_list_entry()?;
|
||||
while let Some(entry) = entry_opt.take() {
|
||||
'inner: {
|
||||
let device = match self.udev.create_device_from_syspath(entry.name()) {
|
||||
Ok(d) => d,
|
||||
_ => break 'inner,
|
||||
};
|
||||
let sysname = match device.sysname() {
|
||||
Ok(s) => s,
|
||||
_ => break 'inner,
|
||||
};
|
||||
if sysname.to_bytes().starts_with(b"event") {
|
||||
self.add_input_device(&device);
|
||||
}
|
||||
}
|
||||
entry_opt = entry.next();
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn add_input_device(self: &Rc<Self>, dev: &UdevDevice) {
|
||||
let slf = self.clone();
|
||||
let device_id = self.id();
|
||||
let devnum = dev.devnum();
|
||||
let devnode = match dev.devnode() {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
log::error!("Could not retrieve devnode of udev device: {}", ErrorFmt(e));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let sysname = match dev.sysname() {
|
||||
Ok(n) => n,
|
||||
Err(e) => {
|
||||
log::error!("Could not retrieve sysname of udev device: {}", ErrorFmt(e));
|
||||
return;
|
||||
}
|
||||
};
|
||||
let mut slots = self.device_holder.input_devices_.borrow_mut();
|
||||
let slot = 'slot: {
|
||||
for (i, s) in slots.iter().enumerate() {
|
||||
if s.is_none() {
|
||||
break 'slot i;
|
||||
}
|
||||
}
|
||||
slots.push(None);
|
||||
slots.len() - 1
|
||||
};
|
||||
let dev = Rc::new(MetalDevice {
|
||||
slot,
|
||||
device_id,
|
||||
devnum,
|
||||
fd: Default::default(),
|
||||
inputdev: Default::default(),
|
||||
devnode: devnode.to_owned(),
|
||||
sysname: sysname.to_owned(),
|
||||
});
|
||||
slots[slot] = Some(dev.clone());
|
||||
self.device_holder.input_devices.set(devnum, dev);
|
||||
self.session.get_device(devnum, move |res| {
|
||||
let id = &slf.device_holder.input_devices;
|
||||
let mut slots = slf.device_holder.input_devices_.borrow_mut();
|
||||
let dev = 'dev: {
|
||||
if let Some(dev) = id.get(&devnum) {
|
||||
if dev.device_id == device_id {
|
||||
break 'dev dev;
|
||||
}
|
||||
}
|
||||
return;
|
||||
};
|
||||
let res = match res {
|
||||
Ok(r) => r,
|
||||
Err(e) => {
|
||||
log::error!("Could not take control of input device: {}", ErrorFmt(e));
|
||||
slots[dev.slot] = None;
|
||||
id.remove(&devnum);
|
||||
return;
|
||||
}
|
||||
};
|
||||
if res.inactive == TRUE {
|
||||
return;
|
||||
}
|
||||
dev.fd.set(Some(res.fd.clone()));
|
||||
let inputdev = match slf.libinput.open(dev.devnode.as_c_str()) {
|
||||
Ok(d) => d,
|
||||
Err(_) => {
|
||||
slots[dev.slot] = None;
|
||||
id.remove(&devnum);
|
||||
return;
|
||||
}
|
||||
};
|
||||
inputdev.device().set_slot(slot);
|
||||
dev.inputdev.set(Some(inputdev));
|
||||
});
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue