use crate::events::errors::{LibinputError, ProcessorError};
use crate::events::libinput::Interface;
use crate::events::{ActionEvent, FingerCount, Processor};
use std::f64::consts::PI;
use std::os::unix::io::{AsRawFd, RawFd};
use filedescriptor::{poll, pollfd, POLLIN};
use input::event::gesture::{
GestureEvent, GestureEventCoordinates, GestureEventTrait, GestureSwipeEvent,
};
use input::event::Event;
use input::Libinput;
use log::{debug, info};
pub struct DefaultProcessor {
pub threshold: f64,
pub input: Libinput,
pub poll_array: Vec<pollfd>,
pub invert_x: bool,
pub invert_y: bool,
}
impl DefaultProcessor {
pub fn new(
threshold: f64,
seat_id: &str,
invert_x: bool,
invert_y: bool,
) -> Result<Self, LibinputError> {
let mut input = Libinput::new_with_udev(Interface {});
input
.udev_assign_seat(seat_id)
.map_err(|_| LibinputError::SeatError)?;
info!("Assigned seat {seat_id} to the libinput context.");
let raw_fd: RawFd = input.as_raw_fd();
let poll_array = [pollfd {
fd: raw_fd,
events: POLLIN,
revents: 0,
}]
.to_vec();
Ok(DefaultProcessor {
threshold,
input,
poll_array,
invert_x,
invert_y,
})
}
}
impl Default for DefaultProcessor {
fn default() -> Self {
DefaultProcessor::new(5.0, "seat0", false, false).unwrap()
}
}
impl Processor for DefaultProcessor {
fn process_event(
&mut self,
event: GestureEvent,
dx: &mut f64,
dy: &mut f64,
) -> Result<Option<ActionEvent>, ProcessorError> {
if let GestureEvent::Swipe(event) = event {
match event {
GestureSwipeEvent::Begin(_begin_event) => {
(*dx) = 0.0;
(*dy) = 0.0;
}
GestureSwipeEvent::Update(update_event) => {
(*dx) += update_event.dx();
(*dy) += update_event.dy();
}
GestureSwipeEvent::End(ref _end_event) => {
return match self._end_event_to_action_event(*dx, *dy, event.finger_count()) {
Ok(event) => Ok(Some(event)),
Err(e) => Err(e),
};
}
other => return Err(ProcessorError::UnsupportedSwipeEvent(other)),
}
}
Ok(None)
}
fn _end_event_to_action_event(
&mut self,
mut dx: f64,
mut dy: f64,
finger_count: i32,
) -> Result<ActionEvent, ProcessorError> {
fn get_event_octant(dx: f64, dy: f64) -> i8 {
let mut angle = -dy.atan2(-dx);
if angle < 0.0 {
angle += 2.0 * PI;
};
angle /= 2.0 * PI;
#[allow(clippy::cast_possible_truncation)]
let mut octant = (angle * 8.0).round() as i8;
if octant == 8 {
octant = 0;
}
octant
}
let finger_count_as_enum = FingerCount::try_from(finger_count)?;
if (dx.powi(2) + dy.powi(2)).sqrt() < self.threshold {
return Err(ProcessorError::DisplacementBelowThreshold(self.threshold));
};
if self.invert_x {
dx = -dx;
}
if self.invert_y {
dy = -dy;
}
Ok(match (get_event_octant(dx, dy), finger_count_as_enum) {
(0, FingerCount::ThreeFinger) => ActionEvent::ThreeFingerSwipeLeft,
(1, FingerCount::ThreeFinger) => ActionEvent::ThreeFingerSwipeLeftUp,
(2, FingerCount::ThreeFinger) => ActionEvent::ThreeFingerSwipeUp,
(3, FingerCount::ThreeFinger) => ActionEvent::ThreeFingerSwipeRightUp,
(4, FingerCount::ThreeFinger) => ActionEvent::ThreeFingerSwipeRight,
(5, FingerCount::ThreeFinger) => ActionEvent::ThreeFingerSwipeRightDown,
(6, FingerCount::ThreeFinger) => ActionEvent::ThreeFingerSwipeDown,
(7, FingerCount::ThreeFinger) => ActionEvent::ThreeFingerSwipeLeftDown,
(0, FingerCount::FourFinger) => ActionEvent::FourFingerSwipeLeft,
(1, FingerCount::FourFinger) => ActionEvent::FourFingerSwipeLeftUp,
(2, FingerCount::FourFinger) => ActionEvent::FourFingerSwipeUp,
(3, FingerCount::FourFinger) => ActionEvent::FourFingerSwipeRightUp,
(4, FingerCount::FourFinger) => ActionEvent::FourFingerSwipeRight,
(5, FingerCount::FourFinger) => ActionEvent::FourFingerSwipeRightDown,
(6, FingerCount::FourFinger) => ActionEvent::FourFingerSwipeDown,
(7, FingerCount::FourFinger) => ActionEvent::FourFingerSwipeLeftDown,
(_, _) => todo!(),
})
}
fn dispatch(&mut self, dx: &mut f64, dy: &mut f64) -> Result<Vec<ActionEvent>, LibinputError> {
poll(&mut self.poll_array, None)?;
self.input.dispatch()?;
let mut action_events = Vec::new();
let events: Vec<Event> = (&mut self.input).collect();
for event in events {
if let Event::Gesture(gesture_event) = event {
let result = self.process_event(gesture_event, dx, dy);
match result {
Err(e) => {
debug!("Discarding event: {}", e);
}
Ok(None) => {}
Ok(Some(action_event)) => action_events.push(action_event),
}
}
}
Ok(action_events)
}
}
#[cfg(test)]
mod test {
use super::DefaultProcessor;
use crate::events::{ActionEvent, Processor, ProcessorError};
use crate::test_utils::init_listener;
use std::sync::{Arc, Mutex};
use serial_test::serial;
#[test]
#[serial]
fn test_parse_finger_count() {
let message_log = Arc::new(Mutex::new(vec![]));
let socket_file = init_listener(Arc::clone(&message_log));
let mut processor = DefaultProcessor::default();
let action_event = processor._end_event_to_action_event(5.0, 0.0, 3);
assert!(action_event.is_ok());
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeRight);
let action_event = processor._end_event_to_action_event(5.0, 0.0, 4);
assert!(action_event.is_ok());
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeRight);
let action_event = processor._end_event_to_action_event(5.0, 0.0, 5);
assert!(action_event.is_err());
assert!(matches!(
action_event,
Err(ProcessorError::UnsupportedFingerCount(5))
));
std::fs::remove_file(socket_file.path().file_name().unwrap()).ok();
}
#[test]
#[serial]
fn test_parse_threshold() {
let message_log = Arc::new(Mutex::new(vec![]));
let socket_file = init_listener(Arc::clone(&message_log));
let mut processor = DefaultProcessor::default();
let action_event = processor._end_event_to_action_event(4.99, 0.0, 3);
#[allow(clippy::no_effect_underscore_binding)]
let _expected_err = ProcessorError::DisplacementBelowThreshold(5.0);
assert!(matches!(action_event, Err(_expected_err)));
let action_event = processor._end_event_to_action_event(5.0, 0.0, 3);
assert!(action_event.is_ok());
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeRight);
std::fs::remove_file(socket_file.path().file_name().unwrap()).ok();
}
#[test]
#[serial]
fn test_multiple_directions() {
let message_log = Arc::new(Mutex::new(vec![]));
let socket_file = init_listener(Arc::clone(&message_log));
let mut processor = DefaultProcessor::default();
let s = 5.0f64.powi(2) / 2.0;
let action_event = processor._end_event_to_action_event(-5.0, 0.0, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeLeft);
let action_event = processor._end_event_to_action_event(-s, -s, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeLeftUp);
let action_event = processor._end_event_to_action_event(0.0, -5.0, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeUp);
let action_event = processor._end_event_to_action_event(s, -s, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeRightUp);
let action_event = processor._end_event_to_action_event(5.0, 0.0, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeRight);
let action_event = processor._end_event_to_action_event(s, s, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeRightDown);
let action_event = processor._end_event_to_action_event(0.0, 5.0, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeDown);
let action_event = processor._end_event_to_action_event(-s, s, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeLeftDown);
let action_event = processor._end_event_to_action_event(-5.0, 0.0, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeLeft);
let action_event = processor._end_event_to_action_event(-s, -s, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeLeftUp);
let action_event = processor._end_event_to_action_event(0.0, -5.0, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeUp);
let action_event = processor._end_event_to_action_event(s, -s, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeRightUp);
let action_event = processor._end_event_to_action_event(5.0, 0.0, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeRight);
let action_event = processor._end_event_to_action_event(s, s, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeRightDown);
let action_event = processor._end_event_to_action_event(0.0, 5.0, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeDown);
let action_event = processor._end_event_to_action_event(-s, s, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeLeftDown);
std::fs::remove_file(socket_file.path().file_name().unwrap()).ok();
}
#[test]
#[serial]
fn test_multiple_directions_inverted() {
let message_log = Arc::new(Mutex::new(vec![]));
let socket_file = init_listener(Arc::clone(&message_log));
let mut processor = DefaultProcessor {
invert_x: true,
invert_y: true,
..Default::default()
};
let s = 5.0f64.powi(2) / 2.0;
let action_event = processor._end_event_to_action_event(5.0, 0.0, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeLeft);
let action_event = processor._end_event_to_action_event(s, s, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeLeftUp);
let action_event = processor._end_event_to_action_event(0.0, 5.0, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeUp);
let action_event = processor._end_event_to_action_event(-s, s, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeRightUp);
let action_event = processor._end_event_to_action_event(-5.0, 0.0, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeRight);
let action_event = processor._end_event_to_action_event(-s, -s, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeRightDown);
let action_event = processor._end_event_to_action_event(0.0, -5.0, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeDown);
let action_event = processor._end_event_to_action_event(s, -s, 3);
assert!(action_event.unwrap() == ActionEvent::ThreeFingerSwipeLeftDown);
let action_event = processor._end_event_to_action_event(5.0, 0.0, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeLeft);
let action_event = processor._end_event_to_action_event(s, s, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeLeftUp);
let action_event = processor._end_event_to_action_event(0.0, 5.0, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeUp);
let action_event = processor._end_event_to_action_event(-s, s, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeRightUp);
let action_event = processor._end_event_to_action_event(-5.0, 0.0, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeRight);
let action_event = processor._end_event_to_action_event(-s, -s, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeRightDown);
let action_event = processor._end_event_to_action_event(0.0, -5.0, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeDown);
let action_event = processor._end_event_to_action_event(s, -s, 4);
assert!(action_event.unwrap() == ActionEvent::FourFingerSwipeLeftDown);
std::fs::remove_file(socket_file.path().file_name().unwrap()).ok();
}
}