use std::{
sync::mpsc::{channel, Receiver},
thread,
};
use error_utils_derive::Errors;
use evdev::{AbsoluteAxisType, Device, InputEvent, InputEventKind};
use log::info;
#[derive(Debug, Errors)]
pub enum PenError {
#[error("No compatible device was found")]
NoDeviceFound,
#[error("Device listener thread lost connection to main thread")]
SenderLostConnection,
}
pub struct PenDevice {
receiver: Receiver<InputEvent>,
x_tilt: i32,
y_tilt: i32,
pressure: i32,
pub max_pressure: i32,
}
pub struct DeviceQuery {
with_position: bool,
with_tilt: bool,
with_pressure: bool,
}
impl DeviceQuery {
pub fn new() -> DeviceQuery {
DeviceQuery {
with_position: false,
with_tilt: false,
with_pressure: false,
}
}
pub fn with_position(mut self) -> Self {
self.with_position = true;
self
}
pub fn with_tilt(mut self) -> Self {
self.with_tilt = true;
self
}
pub fn with_pressure(mut self) -> Self {
self.with_pressure = true;
self
}
pub fn query(self) -> Vec<Device> {
info!("Searching for inputs with pen pressure and tilt");
let mut inputs = vec![];
for (path, item) in evdev::enumerate() {
if let Some(axes) = item.supported_absolute_axes() {
if !self.with_pressure || axes.contains(AbsoluteAxisType::ABS_PRESSURE) {
if !self.with_position
|| (axes.contains(AbsoluteAxisType::ABS_X)
&& axes.contains(AbsoluteAxisType::ABS_Y))
{
if !self.with_tilt
|| (axes.contains(AbsoluteAxisType::ABS_TILT_X)
&& axes.contains(AbsoluteAxisType::ABS_TILT_Y))
{
info!("Found input device at {:?}", path);
inputs.push(item);
}
}
}
}
}
inputs
}
pub fn first(self) -> Result<Device, PenError> {
let mut devices = self.query();
if devices.len() == 0 {
Err(PenError::NoDeviceFound)
} else {
Ok(devices.remove(0))
}
}
}
pub fn watch_device(mut backend: Device) -> PenDevice {
let (send, recv) = channel();
thread::spawn(move || -> Result<(), PenError> {
while let Ok(events) = backend.fetch_events() {
for event in events {
send.send(event)
.map_err(|_| PenError::SenderLostConnection)?;
}
}
Ok(())
});
PenDevice {
receiver: recv,
x_tilt: 0,
y_tilt: 0,
pressure: 0,
max_pressure: 65535,
}
}
impl PenDevice {
pub fn process_events(&mut self) {
while let Ok(event) = self.receiver.try_recv() {
match event.kind() {
InputEventKind::AbsAxis(AbsoluteAxisType::ABS_TILT_X) => {
self.x_tilt = event.value();
}
InputEventKind::AbsAxis(AbsoluteAxisType::ABS_TILT_Y) => {
self.y_tilt = event.value();
}
InputEventKind::AbsAxis(AbsoluteAxisType::ABS_PRESSURE) => {
self.pressure = event.value();
}
_ => {}
}
}
}
pub fn x_tilt(&self) -> i32 {
self.x_tilt
}
pub fn y_tilt(&self) -> i32 {
self.y_tilt
}
pub fn pressure(&self) -> f32 {
self.pressure as f32 / self.max_pressure as f32
}
}