ferroui_linuxframebuffer/
raw_event_grouping.rs1use ferroui_base::input::raw::{
9 IRawInputEventArgs, RawPointerEventArgs, RawPointerEventType, RawPointerPoint, RawTouchEventArgs,
10};
11use ferroui_base::input::IntermediatePoints;
12use ferroui_base::platform::IManagedDispatcherInputProvider;
13use ferroui_base::threading::{Dispatcher, DispatcherPriority};
14use std::cell::{Cell, LazyCell, RefCell};
15use std::collections::{HashMap, VecDeque};
16use std::rc::{Rc, Weak};
17use std::sync::Arc;
18
19pub type RawEvent = Rc<dyn IRawInputEventArgs>;
21pub type RawEventHandler = Rc<dyn Fn(RawEvent)>;
23
24pub trait IRawEventGrouperDispatchQueue {
26 fn add(&self, args: RawEvent, handler: RawEventHandler);
27}
28
29#[derive(Default)]
32pub struct ManualRawEventGrouperDispatchQueue {
33 input_queue: RefCell<VecDeque<(RawEvent, RawEventHandler)>>,
34}
35
36impl ManualRawEventGrouperDispatchQueue {
37 pub fn new() -> Self {
38 Self::default()
39 }
40
41 pub fn has_jobs(&self) -> bool {
42 !self.input_queue.borrow().is_empty()
43 }
44
45 pub fn dispatch_next(&self) {
46 let next = self.input_queue.borrow_mut().pop_front();
47 let Some((args, handler)) = next else {
48 return;
49 };
50 handler(args);
51 }
52}
53
54impl IRawEventGrouperDispatchQueue for ManualRawEventGrouperDispatchQueue {
55 fn add(&self, args: RawEvent, handler: RawEventHandler) {
56 self.input_queue.borrow_mut().push_back((args, handler));
57 }
58}
59
60pub struct ManualRawEventGrouperDispatchQueueDispatcherInputProvider {
62 queue: Rc<ManualRawEventGrouperDispatchQueue>,
63}
64
65impl ManualRawEventGrouperDispatchQueueDispatcherInputProvider {
66 pub fn new(queue: Rc<ManualRawEventGrouperDispatchQueue>) -> Self {
67 Self { queue }
68 }
69}
70
71impl IManagedDispatcherInputProvider for ManualRawEventGrouperDispatchQueueDispatcherInputProvider {
72 fn has_input(&self) -> bool {
73 self.queue.has_jobs()
74 }
75
76 fn dispatch_next_input_event(&self) {
77 self.queue.dispatch_next()
78 }
79}
80
81pub struct AutomaticRawEventGrouperDispatchQueue {
83 this: Weak<AutomaticRawEventGrouperDispatchQueue>,
84 input_queue: RefCell<VecDeque<(RawEvent, RawEventHandler)>>,
85 dispatcher: Arc<Dispatcher>,
86}
87
88impl AutomaticRawEventGrouperDispatchQueue {
89 pub fn new(dispatcher: Option<Arc<Dispatcher>>) -> Rc<Self> {
90 Rc::new_cyclic(|this| Self {
91 this: this.clone(),
92 input_queue: RefCell::new(VecDeque::new()),
93 dispatcher: dispatcher.unwrap_or_else(Dispatcher::current_dispatcher),
94 })
95 }
96
97 fn post_dispatch(&self) {
98 let this = self.this.clone();
99 self.dispatcher.post_local(
100 move || {
101 if let Some(this) = this.upgrade() {
102 this.dispatch_from_queue();
103 }
104 },
105 DispatcherPriority::INPUT,
106 );
107 }
108
109 fn dispatch_from_queue(&self) {
110 loop {
111 let next = self.input_queue.borrow_mut().pop_front();
112 let Some((args, handler)) = next else {
113 return;
114 };
115
116 handler(args);
117
118 if self.dispatcher.has_jobs_with_priority(DispatcherPriority::DEFAULT) {
120 self.post_dispatch();
121 return;
122 }
123 }
124 }
125}
126
127impl IRawEventGrouperDispatchQueue for AutomaticRawEventGrouperDispatchQueue {
128 fn add(&self, args: RawEvent, handler: RawEventHandler) {
129 let count = {
130 let mut queue = self.input_queue.borrow_mut();
131 queue.push_back((args, handler));
132 queue.len()
133 };
134
135 if count == 1 {
136 self.post_dispatch();
137 }
138 }
139}
140
141type MergedPoints = Rc<RefCell<Vec<RawPointerPoint>>>;
142
143struct GrouperState {
144 event_callback: RawEventHandler,
145 last_touch_points: RefCell<HashMap<i64, RawEvent>>,
146 last_event: RefCell<Option<RawEvent>>,
147 merged_points: RefCell<HashMap<usize, MergedPoints>>,
154 disposed: Cell<bool>,
155}
156
157pub struct RawEventGrouper {
159 state: Rc<GrouperState>,
160 queue: Rc<dyn IRawEventGrouperDispatchQueue>,
161 dispatch: RawEventHandler,
162}
163
164fn same_event(a: &RawEvent, b: &RawEvent) -> bool {
165 std::ptr::addr_eq(Rc::as_ptr(a), Rc::as_ptr(b))
166}
167
168fn as_pointer_event(args: &RawEvent) -> Option<&RawPointerEventArgs> {
169 args.downcast_ref::<RawPointerEventArgs>()
170}
171
172fn as_touch_event(args: &RawEvent) -> Option<&RawTouchEventArgs> {
173 args.downcast_ref::<RawTouchEventArgs>()
174}
175
176fn event_key(event: &RawPointerEventArgs) -> usize {
177 event as *const RawPointerEventArgs as usize
178}
179
180impl RawEventGrouper {
181 pub fn new(
182 event_callback: impl Fn(RawEvent) + 'static,
183 queue: Option<Rc<dyn IRawEventGrouperDispatchQueue>>,
184 ) -> Self {
185 let state = Rc::new(GrouperState {
186 event_callback: Rc::new(event_callback),
187 last_touch_points: RefCell::new(HashMap::new()),
188 last_event: RefCell::new(None),
189 merged_points: RefCell::new(HashMap::new()),
190 disposed: Cell::new(false),
191 });
192 let queue = queue.unwrap_or_else(|| AutomaticRawEventGrouperDispatchQueue::new(None));
193 let dispatch: RawEventHandler = {
194 let state = state.clone();
195 Rc::new(move |ev| Self::dispatch(&state, ev))
196 };
197 Self { state, queue, dispatch }
198 }
199
200 fn add_to_queue(&self, args: RawEvent) {
201 *self.state.last_event.borrow_mut() = Some(args.clone());
202 self.queue.add(args, self.dispatch.clone());
203 }
204
205 fn dispatch(state: &Rc<GrouperState>, ev: RawEvent) {
206 if !state.disposed.get() {
207 let is_last = state.last_event.borrow().as_ref().is_some_and(|last| same_event(last, &ev));
208 if is_last {
209 *state.last_event.borrow_mut() = None;
210 }
211
212 if let Some(touch_update) = as_touch_event(&ev) {
213 if touch_update.type_() == RawPointerEventType::TouchUpdate {
214 state.last_touch_points.borrow_mut().remove(&touch_update.raw_pointer_id());
215 }
216 }
217
218 (state.event_callback)(ev.clone());
219 }
220
221 if let Some(pointer) = as_pointer_event(&ev) {
224 state.merged_points.borrow_mut().remove(&event_key(pointer));
225 }
226 }
227
228 pub fn handle_event(&self, args: RawEvent) {
229 let last_event = self.state.last_event.borrow().clone();
241 let merged = (|| {
242 let pointer_event = as_pointer_event(&args)?;
243 let last_event = last_event.as_ref()?;
244 let last_pointer_event = as_pointer_event(last_event)?;
245 let same_block = Rc::ptr_eq(last_event.device(), args.device())
246 && last_pointer_event.input_modifiers() == pointer_event.input_modifiers()
247 && last_pointer_event.type_() == pointer_event.type_()
248 && matches!(last_pointer_event.type_(), RawPointerEventType::Move | RawPointerEventType::TouchUpdate);
249 if !same_block {
250 return None;
251 }
252
253 if let Some(touch_event) = as_touch_event(&args) {
254 let last_touch_event =
255 self.state.last_touch_points.borrow().get(&touch_event.raw_pointer_id()).cloned();
256 match last_touch_event {
257 Some(last_touch_event) => {
258 let last = as_pointer_event(&last_touch_event).expect("a touch event is a pointer event");
259 Self::merge_events(&self.state, last, pointer_event);
260 }
261 None => {
262 self.state.last_touch_points.borrow_mut().insert(touch_event.raw_pointer_id(), args.clone());
263 self.add_to_queue(args.clone());
264 }
265 }
266 } else {
267 Self::merge_events(&self.state, last_pointer_event, pointer_event);
268 }
269
270 Some(())
271 })();
272 if merged.is_some() {
273 return;
274 }
275
276 self.state.last_touch_points.borrow_mut().clear();
277 if let Some(touch_event) = as_touch_event(&args) {
278 if touch_event.type_() == RawPointerEventType::TouchUpdate {
279 self.state.last_touch_points.borrow_mut().insert(touch_event.raw_pointer_id(), args.clone());
280 }
281 }
282 self.add_to_queue(args);
283 }
284
285 fn merge_events(state: &GrouperState, last: &RawPointerEventArgs, current: &RawPointerEventArgs) {
286 let list = state.merged_points.borrow_mut().entry(event_key(last)).or_default().clone();
287 if last.intermediate_points().is_none() {
288 let list = list.clone();
289 let points: IntermediatePoints = Rc::new(LazyCell::new(Box::new(move || Some(list.borrow().clone()))));
290 last.set_intermediate_points(Some(points));
291 }
292 let point = last.point();
293 let mut merged = RawPointerPoint::new();
294 merged.position = last.position();
295 merged.pressure = point.pressure;
296 merged.set_contact_rect(point.contact_rect());
297 merged.twist = point.twist;
298 merged.x_tilt = point.x_tilt;
299 merged.y_tilt = point.y_tilt;
300 list.borrow_mut().push(merged);
301 last.set_position(current.position());
302 last.set_timestamp(current.timestamp());
303 last.set_input_modifiers(current.input_modifiers());
304 }
305
306 pub fn dispose(&self) {
307 self.state.disposed.set(true);
308 *self.state.last_event.borrow_mut() = None;
309 self.state.last_touch_points.borrow_mut().clear();
310 self.state.merged_points.borrow_mut().clear();
311 }
312}