fix(detect): unregister device from epoll when removed on Wayland. #836
This commit is contained in:
parent
846d0a2be3
commit
ec7f1772dd
|
@ -2,7 +2,7 @@
|
||||||
// https://github.com/xkbcommon/libxkbcommon/blob/master/tools/interactive-evdev.c
|
// https://github.com/xkbcommon/libxkbcommon/blob/master/tools/interactive-evdev.c
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use libc::{input_event, size_t, ssize_t, EWOULDBLOCK, O_CLOEXEC, O_NONBLOCK, O_RDONLY};
|
use libc::{input_event, size_t, ssize_t, ENODEV, EWOULDBLOCK, O_CLOEXEC, O_NONBLOCK, O_RDONLY};
|
||||||
use log::trace;
|
use log::trace;
|
||||||
use scopeguard::ScopeGuard;
|
use scopeguard::ScopeGuard;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
@ -127,7 +127,11 @@ impl Device {
|
||||||
}
|
}
|
||||||
|
|
||||||
if len < 0 && unsafe { *errno_ptr } != EWOULDBLOCK {
|
if len < 0 && unsafe { *errno_ptr } != EWOULDBLOCK {
|
||||||
return Err(DeviceError::BlockingReadOperation().into());
|
if unsafe { *errno_ptr } == ENODEV {
|
||||||
|
return Err(DeviceError::FailedReadNoSuchDevice.into());
|
||||||
|
}
|
||||||
|
|
||||||
|
return Err(DeviceError::FailedRead(unsafe { *errno_ptr }).into());
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(events)
|
Ok(events)
|
||||||
|
@ -322,6 +326,9 @@ pub enum DeviceError {
|
||||||
#[error("no devices found")]
|
#[error("no devices found")]
|
||||||
NoDevicesFound(),
|
NoDevicesFound(),
|
||||||
|
|
||||||
#[error("read operation can't block device")]
|
#[error("read operation failed with code: `{0}`")]
|
||||||
BlockingReadOperation(),
|
FailedRead(i32),
|
||||||
|
|
||||||
|
#[error("read operation failed: ENODEV No such device")]
|
||||||
|
FailedReadNoSuchDevice,
|
||||||
}
|
}
|
||||||
|
|
|
@ -38,8 +38,9 @@ use keymap::Keymap;
|
||||||
use lazycell::LazyCell;
|
use lazycell::LazyCell;
|
||||||
use libc::{
|
use libc::{
|
||||||
__errno_location, close, epoll_ctl, epoll_event, epoll_wait, EINTR, EPOLLIN, EPOLL_CTL_ADD,
|
__errno_location, close, epoll_ctl, epoll_event, epoll_wait, EINTR, EPOLLIN, EPOLL_CTL_ADD,
|
||||||
|
EPOLL_CTL_DEL,
|
||||||
};
|
};
|
||||||
use log::{debug, error, info, trace};
|
use log::{debug, error, info, trace, warn};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
use crate::event::{InputEvent, Key, KeyboardEvent, Variant};
|
use crate::event::{InputEvent, Key, KeyboardEvent, Variant};
|
||||||
|
@ -204,7 +205,9 @@ impl Source for EVDEVSource {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for ev in evs.iter() {
|
#[allow(clippy::needless_range_loop)]
|
||||||
|
for i in 0usize..(ret as usize) {
|
||||||
|
let ev = evs[i];
|
||||||
let device = &self.devices[ev.u64 as usize];
|
let device = &self.devices[ev.u64 as usize];
|
||||||
match device.read() {
|
match device.read() {
|
||||||
Ok(events) if !events.is_empty() => {
|
Ok(events) if !events.is_empty() => {
|
||||||
|
@ -226,7 +229,30 @@ impl Source for EVDEVSource {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Ok(_) => { /* SKIP EMPTY */ }
|
Ok(_) => { /* SKIP EMPTY */ }
|
||||||
Err(err) => error!("Can't read from device {}: {}", device.get_path(), err),
|
Err(err) => {
|
||||||
|
if let Some(DeviceError::FailedReadNoSuchDevice) = err.downcast_ref::<DeviceError>() {
|
||||||
|
warn!("Can't read from device {}, this error usually means the device has been disconnected, removing from epoll.", device.get_path());
|
||||||
|
|
||||||
|
if unsafe {
|
||||||
|
epoll_ctl(
|
||||||
|
*epfd,
|
||||||
|
EPOLL_CTL_DEL,
|
||||||
|
device.get_raw_fd(),
|
||||||
|
std::ptr::null_mut(),
|
||||||
|
)
|
||||||
|
} != 0
|
||||||
|
{
|
||||||
|
error!(
|
||||||
|
"Could not remove {} from epoll, errno {}",
|
||||||
|
device.get_path(),
|
||||||
|
unsafe { *errno_ptr }
|
||||||
|
);
|
||||||
|
return Err(EVDEVSourceError::Internal().into());
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
error!("Can't read from device {}: {}", device.get_path(), err)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue
Block a user