use std::{alloc::System, fs::File, str::FromStr};
use chrono::{DateTime, Duration, Utc};
use evdev_rs::{Device, InputEvent, ReadFlag, ReadStatus};
use crate::coords::PixelSpaceCoord;
#[derive(Debug, Clone)]
pub struct Touch {
pub position: PixelSpaceCoord,
pub pressure: i32,
pub timestamp: DateTime<Utc>,
}
impl Touch {
pub fn is_down(&self) -> bool {
self.pressure > 0
}
}
pub struct TouchEventListener {
device: Device,
}
impl TouchEventListener {
pub fn open() -> std::io::Result<Self> {
let touch_path: String = std::env::var("KOBO_TS_INPUT")
.or(String::from_str("/dev/input/event1"))
.unwrap();
let file = File::open(touch_path)?;
let device = Device::new_from_file(file)?;
Ok(Self { device })
}
pub fn next_raw_event(&self) -> std::io::Result<(ReadStatus, InputEvent)> {
self.device
.next_event(ReadFlag::NORMAL | ReadFlag::BLOCKING)
}
pub fn next_touch(
&self,
screen_size: PixelSpaceCoord,
timeout: Option<Duration>,
) -> Option<Touch> {
let start = Utc::now();
let mut x = None;
let mut y = None;
let mut pressure = None;
loop {
if let Some(timeout) = timeout {
let elapsed = Utc::now().signed_duration_since(start);
if elapsed > timeout {
return None;
}
}
let (status, event) = self.next_raw_event().unwrap();
if status == ReadStatus::Success {
match event.event_code {
evdev_rs::enums::EventCode::EV_ABS(kind) => match kind {
evdev_rs::enums::EV_ABS::ABS_X => {
y = Some(event.value);
}
evdev_rs::enums::EV_ABS::ABS_Y => {
x = Some(screen_size.x - event.value);
}
evdev_rs::enums::EV_ABS::ABS_MT_POSITION_X => {
y = Some(event.value);
}
evdev_rs::enums::EV_ABS::ABS_MT_POSITION_Y => {
x = Some(screen_size.x - event.value);
}
evdev_rs::enums::EV_ABS::ABS_PRESSURE => {
pressure = Some(event.value);
}
evdev_rs::enums::EV_ABS::ABS_MT_PRESSURE => {
pressure = Some(event.value);
}
_ => {}
},
_ => { }
}
}
if x.is_some() && y.is_some() && pressure.is_some() {
return Some(Touch {
position: PixelSpaceCoord::new(x.unwrap(), y.unwrap()),
pressure: pressure.unwrap(),
timestamp: Utc::now(),
});
}
}
}
}