pub(crate) mod analyze;
mod read;
pub(crate) mod touch_group;
use std::{
collections::HashMap,
error::Error,
fs,
ops::Deref,
sync::{
atomic::AtomicUsize,
mpsc::{self, Receiver},
Arc,
},
thread,
time::Duration,
};
use atomic::{Atomic, Ordering};
use evdev::{Device, EventType};
#[derive(Debug)]
pub struct TouchListener {
status_map: HashMap<usize, Arc<AtomicTouchStatus>>,
wait: Receiver<()>,
min_pixel: Arc<AtomicUsize>,
}
pub(crate) type AtomicTouchStatus = Atomic<TouchStatus>;
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum TouchStatus {
Slide,
Click,
None,
}
impl Deref for TouchListener {
type Target = HashMap<usize, Arc<AtomicTouchStatus>>;
fn deref(&self) -> &Self::Target {
&self.status_map
}
}
impl TouchListener {
pub fn new(min_pixel: usize) -> Result<Self, Box<dyn Error>> {
let devices: Vec<_> = fs::read_dir("/dev/input")?
.filter_map(|f| {
let f = f.ok()?;
let path = f.path();
let device = Device::open(path).ok()?;
let event_len = "event".len();
let id: usize = f.file_name().into_string().ok()?[event_len..]
.trim()
.parse()
.ok()?;
Some((id, device))
})
.filter(|(_, d)| d.supported_events().contains(EventType::ABSOLUTE))
.collect();
if devices.is_empty() {
return Err("No usable touch device".into());
}
let mut status_map = HashMap::new();
let (sx, rx) = mpsc::sync_channel(1);
let min_pixel = Arc::new(AtomicUsize::new(min_pixel));
for (id, device) in devices {
let touch_status = Arc::new(Atomic::new(TouchStatus::None));
let touch_status_clone = touch_status.clone();
let sx = sx.clone();
let min_pixel = min_pixel.clone();
status_map.insert(id, touch_status);
thread::Builder::new()
.name("TouchDeviceListener".into())
.spawn(move || read::daemon_thread(device, &touch_status_clone, &sx, &min_pixel))?;
}
if status_map.is_empty() {
return Err("No usable touch device".into());
}
Ok(Self {
status_map,
wait: rx,
min_pixel,
})
}
pub fn min_pixel(&self, p: usize) {
self.min_pixel.store(p, Ordering::Release);
}
#[inline]
pub fn wait(&self) -> Result<(), &'static str> {
self.wait.recv().map_err(|_| "Monitor threads had paniced")
}
#[inline]
pub fn wait_timeout(&self, t: Duration) -> Result<(), &'static str> {
self.wait
.recv_timeout(t)
.map_err(|_| "Monitor threads had paniced")
}
pub fn status(&self) -> (bool, bool, bool) {
let slide = self
.status_map
.values()
.any(|s| s.load(Ordering::Acquire) == TouchStatus::Slide);
let click = self
.status_map
.values()
.any(|s| s.load(Ordering::Acquire) == TouchStatus::Click);
let none = self
.status_map
.values()
.any(|s| s.load(Ordering::Acquire) == TouchStatus::None);
(slide, click, none)
}
}