1#![warn(missing_docs)]
26#![cfg_attr(docsrs, feature(doc_cfg))]
27
28use std::path::Path;
29
30use evdev::{AbsoluteAxisCode, EventSummary, FetchEventsSynced, KeyCode};
31use slint::{
32 LogicalPosition, PhysicalPosition,
33 platform::{PointerEventButton, WindowEvent},
34};
35
36#[derive(Clone, Copy, Debug, Default, PartialEq)]
37enum ButtonChange {
38 #[default]
39 None,
40 Up,
41 Down,
42}
43
44struct Collector {
46 last_position: (i32, i32),
47 scale_factor: f32,
48 button_change: ButtonChange,
49}
50
51impl Collector {
52 pub fn new(scale_factor: f32, last_position: (i32, i32)) -> Self {
53 Self {
54 last_position,
55 scale_factor,
56 button_change: ButtonChange::None,
57 }
58 }
59
60 pub fn push(&mut self, event: evdev::EventSummary) -> Option<WindowEvent> {
61 match event {
62 EventSummary::Synchronization(_, _, _) => {
63 let button_change = self.button_change;
64 self.button_change = ButtonChange::None;
65 if button_change == ButtonChange::Down {
66 return Some(WindowEvent::PointerPressed {
67 position: self.last_logical_position(),
68 button: PointerEventButton::Left,
69 });
70 } else if button_change == ButtonChange::Up {
71 return Some(WindowEvent::PointerReleased {
72 position: self.last_logical_position(),
73 button: PointerEventButton::Left,
74 });
75 } else {
76 return Some(WindowEvent::PointerMoved {
77 position: self.last_logical_position(),
78 });
79 };
80 }
81 EventSummary::AbsoluteAxis(_event, code, value) => match code {
82 AbsoluteAxisCode::ABS_X => self.last_position.0 = value,
83 AbsoluteAxisCode::ABS_Y => self.last_position.1 = value,
84 _ => (),
85 },
86 EventSummary::Key(_event, key, value) => {
87 if matches!(key, KeyCode::BTN_TOUCH) {
88 if value == 1 {
89 self.button_change = ButtonChange::Down
90 } else {
91 self.button_change = ButtonChange::Up;
92 }
93 }
94 }
95 _ => (),
96 }
97 None
98 }
99
100 fn last_logical_position(&self) -> LogicalPosition {
101 let (x, y) = self.last_position;
102 LogicalPosition::from_physical(PhysicalPosition::new(x, y), self.scale_factor)
103 }
104}
105
106pub struct SlintEventsWrapper {
127 device: evdev::Device,
128 last_position: (i32, i32),
129 scale_factor: f32,
130}
131
132impl SlintEventsWrapper {
133 pub fn new(device: impl AsRef<Path>, scale_factor: f32) -> std::io::Result<Self> {
141 let device = evdev::Device::open(device)?;
142 Ok(Self {
143 device,
144 last_position: (0, 0),
145 scale_factor,
146 })
147 }
148
149 pub fn fetch_events<'a>(&'a mut self) -> SlintEventsIterator<'a> {
151 SlintEventsIterator {
152 inner: self.device.fetch_events().unwrap(),
153 collector: Collector::new(self.scale_factor, self.last_position),
154 }
155 }
156
157 #[cfg(feature = "tokio")]
161 #[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
162 pub fn into_event_stream(self) -> std::io::Result<tokio::EventStream> {
163 Ok(tokio::EventStream {
164 evdev_stream: self.device.into_event_stream()?,
165 collector: Collector::new(self.scale_factor, self.last_position),
166 })
167 }
168}
169
170pub struct SlintEventsIterator<'a> {
172 inner: FetchEventsSynced<'a>,
173 collector: Collector,
174}
175
176impl Iterator for SlintEventsIterator<'_> {
177 type Item = WindowEvent;
178
179 fn next(&mut self) -> Option<Self::Item> {
180 loop {
182 match self.inner.next() {
183 Some(event) => {
184 if let Some(window_event) = self.collector.push(event.destructure()) {
185 return Some(window_event);
186 }
187 }
188 None => return None,
189 }
190 }
191 }
192}
193
194#[cfg(feature = "tokio")]
195#[cfg_attr(docsrs, doc(cfg(feature = "tokio")))]
196mod tokio {
197 use super::*;
198 pub struct EventStream {
200 pub(super) evdev_stream: evdev::EventStream,
201 pub(super) collector: Collector,
202 }
203
204 impl EventStream {
205 pub async fn next_event(&mut self) -> Result<WindowEvent, std::io::Error> {
207 loop {
208 let event = self.evdev_stream.next_event().await?;
209 if let Some(ret) = self.collector.push(event.destructure()) {
210 return Ok(ret);
211 }
212 }
213 }
214 }
215}