1extern crate alloc;
48use alloc::vec::Vec;
49
50use ui_events::pointer::{
51 PointerButton, PointerButtonEvent, PointerButtons, PointerEvent, PointerState, PointerUpdate,
52};
53
54use dpi::{LogicalPosition, PhysicalPosition};
55
56#[derive(Clone, Debug, Default)]
58pub struct PrimaryPointerState {
59 just_pressed: PointerButtons,
61 just_released: PointerButtons,
63 current: PointerState,
65 coalesced: Vec<PointerState>,
67 predicted: Vec<PointerState>,
69}
70
71impl PrimaryPointerState {
72 pub fn is_just_pressed(&self, button: PointerButton) -> bool {
77 self.just_pressed.contains(button)
78 }
79
80 pub fn is_just_released(&self, button: PointerButton) -> bool {
85 self.just_released.contains(button)
86 }
87
88 pub fn is_auxiliary_just_pressed(&self) -> bool {
91 self.is_just_pressed(PointerButton::Auxiliary)
92 }
93
94 pub fn is_auxiliary_just_released(&self) -> bool {
96 self.is_just_released(PointerButton::Auxiliary)
97 }
98
99 pub fn is_primary_just_pressed(&self) -> bool {
102 self.is_just_pressed(PointerButton::Primary)
103 }
104
105 pub fn is_primary_just_released(&self) -> bool {
107 self.is_just_released(PointerButton::Primary)
108 }
109
110 pub fn is_secondary_just_pressed(&self) -> bool {
113 self.is_just_pressed(PointerButton::Secondary)
114 }
115
116 pub fn is_secondary_just_released(&self) -> bool {
118 self.is_just_released(PointerButton::Secondary)
119 }
120
121 pub fn is_any_down(&self) -> bool {
123 !self.current.buttons.is_empty()
124 }
125
126 pub fn is_down(&self, button: PointerButton) -> bool {
128 self.current.buttons.contains(button)
129 }
130
131 pub fn clear_frame(&mut self) {
133 self.just_pressed.clear();
134 self.just_released.clear();
135 self.coalesced.clear();
136 self.predicted.clear();
138 }
139
140 pub fn current_position(&self) -> PhysicalPosition<f64> {
144 self.current.position
145 }
146
147 pub fn current_logical_position(&self) -> LogicalPosition<f64> {
151 self.current.logical_position()
152 }
153
154 pub fn motion(&self) -> PhysicalPosition<f64> {
156 let current = self.current.position;
157 let first = self
158 .coalesced
159 .first()
160 .map(|s| s.position)
161 .unwrap_or(current);
162 PhysicalPosition {
163 x: current.x - first.x,
164 y: current.y - first.y,
165 }
166 }
167
168 pub fn logical_motion(&self) -> LogicalPosition<f64> {
170 let current = self.current.logical_position();
171 let first = self
172 .coalesced
173 .first()
174 .map(|s| s.logical_position())
175 .unwrap_or(current);
176 LogicalPosition {
177 x: current.x - first.x,
178 y: current.y - first.y,
179 }
180 }
181
182 fn push_state(&mut self, state: PointerState) {
184 if state.time != 0 {
185 self.coalesced.push(state);
187 }
188 }
189
190 pub fn process_pointer_event(&mut self, event: PointerEvent) {
195 if !event.is_primary_pointer() {
196 return;
197 }
198
199 match event {
200 PointerEvent::Down(PointerButtonEvent {
201 button: Some(b),
202 state,
203 ..
204 }) => {
205 self.just_pressed.insert(b);
206 let mut state = state.clone();
207 core::mem::swap(&mut self.current, &mut state);
208 self.push_state(state);
209 self.predicted.clear();
211 }
212 PointerEvent::Up(PointerButtonEvent {
213 button: Some(b),
214 state,
215 ..
216 }) => {
217 self.just_released.insert(b);
218 let mut state = state.clone();
219 core::mem::swap(&mut self.current, &mut state);
220 self.push_state(state);
221 self.predicted.clear();
223 }
224 PointerEvent::Move(PointerUpdate {
225 current,
226 coalesced,
227 predicted,
228 ..
229 }) => {
230 self.coalesced.push(self.current.clone());
231 self.current = current.clone();
232 self.coalesced.extend(coalesced);
233 self.predicted.clear();
234 self.predicted.extend(predicted);
235 }
236 PointerEvent::Cancel(_) | PointerEvent::Leave(_) => {
237 self.predicted.clear();
239 self.coalesced.clear();
240 self.current.buttons.clear();
241 }
242 _ => {}
243 }
244 }
245}
246
247#[cfg(test)]
248mod tests {
249 use super::*;
250 use alloc::vec;
251 use ui_events::pointer::{
252 PointerButtonEvent, PointerEvent, PointerId, PointerInfo, PointerState, PointerType,
253 };
254
255 fn phony_time() -> u64 {
257 use core::sync::atomic::AtomicU64;
258 use core::sync::atomic::Ordering;
259 static TIME: AtomicU64 = AtomicU64::new(0);
260 TIME.fetch_add(1, Ordering::SeqCst)
261 }
262
263 fn make_down_event(button: PointerButton) -> PointerEvent {
264 PointerEvent::Down(PointerButtonEvent {
265 button: Some(button),
266 pointer: PointerInfo {
267 pointer_id: Some(PointerId::PRIMARY),
268 persistent_device_id: None,
269 pointer_type: PointerType::Mouse,
270 },
271 state: PointerState {
272 time: phony_time(),
273 buttons: button.into(),
274 ..Default::default()
275 },
276 })
277 }
278
279 fn make_up_event(button: PointerButton) -> PointerEvent {
280 PointerEvent::Up(PointerButtonEvent {
281 button: Some(button),
282 pointer: PointerInfo {
283 pointer_id: Some(PointerId::PRIMARY),
284 persistent_device_id: None,
285 pointer_type: PointerType::Mouse,
286 },
287 state: PointerState {
288 time: phony_time(),
289 ..Default::default()
290 },
291 })
292 }
293
294 #[test]
295 fn press_and_hold_primary() {
296 let mut state = PrimaryPointerState::default();
297 state.process_pointer_event(make_down_event(PointerButton::Primary));
298
299 assert!(state.is_primary_just_pressed());
300 assert!(state.is_down(PointerButton::Primary));
301 assert!(!state.is_primary_just_released());
302
303 state.clear_frame();
304
305 assert!(!state.is_primary_just_pressed());
306 assert!(state.is_down(PointerButton::Primary));
307 }
308
309 #[test]
310 fn press_and_release_primary_same_frame() {
311 let mut state = PrimaryPointerState::default();
312 state.process_pointer_event(make_down_event(PointerButton::Primary));
313 state.process_pointer_event(make_up_event(PointerButton::Primary));
314
315 assert!(state.is_primary_just_pressed());
316 assert!(state.is_primary_just_released());
317 assert!(!state.is_down(PointerButton::Primary));
318 }
319
320 #[test]
321 fn release_after_hold() {
322 let mut state = PrimaryPointerState::default();
323 state.process_pointer_event(make_down_event(PointerButton::Primary));
324 state.clear_frame();
325 state.process_pointer_event(make_up_event(PointerButton::Primary));
326
327 assert!(!state.is_primary_just_pressed());
328 assert!(state.is_primary_just_released());
329 assert!(!state.is_down(PointerButton::Primary));
330 }
331
332 fn make_move_event(
333 position: PhysicalPosition<f64>,
334 coalesced: Vec<PhysicalPosition<f64>>,
335 predicted: Vec<PhysicalPosition<f64>>,
336 ) -> PointerEvent {
337 let coalesced = coalesced
338 .iter()
339 .copied()
340 .map(|position| PointerState {
341 time: phony_time(),
342 position,
343 ..Default::default()
344 })
345 .collect();
346
347 let current = PointerState {
348 time: phony_time(),
349 position,
350 ..Default::default()
351 };
352
353 let predicted = predicted
354 .iter()
355 .copied()
356 .map(|position| PointerState {
357 time: phony_time(),
358 position,
359 ..Default::default()
360 })
361 .collect();
362
363 PointerEvent::Move(PointerUpdate {
364 pointer: PointerInfo {
365 pointer_id: Some(PointerId::PRIMARY),
366 persistent_device_id: None,
367 pointer_type: PointerType::Mouse,
368 },
369 current,
370 coalesced,
371 predicted,
372 })
373 }
374
375 fn make_cancel_event() -> PointerEvent {
376 PointerEvent::Cancel(PointerInfo {
377 pointer_id: Some(PointerId::PRIMARY),
378 persistent_device_id: None,
379 pointer_type: PointerType::Mouse,
380 })
381 }
382
383 fn make_leave_event() -> PointerEvent {
384 PointerEvent::Leave(PointerInfo {
385 pointer_id: Some(PointerId::PRIMARY),
386 persistent_device_id: None,
387 pointer_type: PointerType::Mouse,
388 })
389 }
390
391 #[test]
392 fn down_updates_current_buttons() {
393 let mut state = PrimaryPointerState::default();
394 state.process_pointer_event(make_down_event(PointerButton::Primary));
395
396 assert!(state.current.buttons.contains(PointerButton::Primary));
397 assert!(state.is_down(PointerButton::Primary));
398 assert!(state.is_any_down());
399 }
400
401 #[test]
402 fn up_updates_current_buttons() {
403 let mut state = PrimaryPointerState::default();
404 state.process_pointer_event(make_down_event(PointerButton::Primary));
405 state.process_pointer_event(make_up_event(PointerButton::Primary));
406
407 assert!(!state.current.buttons.contains(PointerButton::Primary));
408 assert!(!state.is_down(PointerButton::Primary));
409 assert!(!state.is_any_down());
410 }
411
412 #[test]
413 fn move_appends_to_coalesced_if_down() {
414 let mut state = PrimaryPointerState::default();
415 state.process_pointer_event(make_down_event(PointerButton::Primary));
416
417 state.process_pointer_event(make_move_event(
418 PhysicalPosition { x: 10.0, y: 10.0 },
419 vec![PhysicalPosition { x: 5.0, y: 5.0 }],
420 vec![],
421 ));
422
423 assert_eq!(state.coalesced.len(), 2);
424 assert_eq!(
425 state.coalesced[1].position,
426 PhysicalPosition { x: 5.0, y: 5.0 }
427 );
428 assert_eq!(
429 state.current.position,
430 PhysicalPosition { x: 10.0, y: 10.0 }
431 );
432 }
433
434 #[test]
435 fn move_appends_to_coalesced_even_if_not_down() {
436 let mut state = PrimaryPointerState::default();
437
438 state.process_pointer_event(make_move_event(
439 PhysicalPosition { x: 10.0, y: 10.0 },
440 vec![PhysicalPosition { x: 5.0, y: 5.0 }],
441 vec![],
442 ));
443
444 assert_eq!(state.coalesced.len(), 2);
445 assert_eq!(state.coalesced[0].position, PhysicalPosition::default());
446 assert_eq!(
447 state.coalesced[1].position,
448 PhysicalPosition { x: 5.0, y: 5.0 }
449 );
450 assert_eq!(
451 state.current.position,
452 PhysicalPosition { x: 10.0, y: 10.0 }
453 );
454 }
455
456 #[test]
457 fn move_sets_predicted() {
458 let mut state = PrimaryPointerState::default();
459
460 state.process_pointer_event(make_move_event(
461 PhysicalPosition { x: 10.0, y: 10.0 },
462 vec![],
463 vec![PhysicalPosition { x: 15.0, y: 15.0 }],
464 ));
465
466 assert_eq!(state.predicted.len(), 1);
467 assert_eq!(
468 state.predicted[0].position,
469 PhysicalPosition { x: 15.0, y: 15.0 }
470 );
471 }
472
473 #[test]
474 fn down_clears_predicted() {
475 let mut state = PrimaryPointerState::default();
476
477 state.process_pointer_event(make_move_event(
478 PhysicalPosition { x: 10.0, y: 10.0 },
479 vec![],
480 vec![PhysicalPosition { x: 15.0, y: 15.0 }],
481 ));
482
483 assert!(!state.predicted.is_empty());
484
485 state.process_pointer_event(make_down_event(PointerButton::Primary));
486
487 assert!(state.predicted.is_empty());
488 }
489
490 #[test]
491 fn up_clears_predicted() {
492 let mut state = PrimaryPointerState::default();
493 state.process_pointer_event(make_down_event(PointerButton::Primary));
494
495 state.process_pointer_event(make_move_event(
496 PhysicalPosition { x: 10.0, y: 10.0 },
497 vec![],
498 vec![PhysicalPosition { x: 15.0, y: 15.0 }],
499 ));
500
501 assert!(!state.predicted.is_empty());
502
503 state.process_pointer_event(make_up_event(PointerButton::Primary));
504
505 assert!(state.predicted.is_empty());
506 }
507
508 #[test]
509 fn cancel_clears_states() {
510 let mut state = PrimaryPointerState::default();
511 state.process_pointer_event(make_down_event(PointerButton::Primary));
512
513 assert!(state.predicted.is_empty());
514 assert!(!state.current.buttons.is_empty());
515
516 state.process_pointer_event(make_cancel_event());
517
518 assert!(state.coalesced.is_empty());
519 assert!(state.predicted.is_empty());
520 assert!(state.current.buttons.is_empty());
521 }
522
523 #[test]
524 fn leave_clears_states() {
525 let mut state = PrimaryPointerState::default();
526 state.process_pointer_event(make_down_event(PointerButton::Primary));
527
528 assert!(state.predicted.is_empty());
529 assert!(!state.current.buttons.is_empty());
530
531 state.process_pointer_event(make_leave_event());
532
533 assert!(state.coalesced.is_empty());
534 assert!(state.predicted.is_empty());
535 assert!(state.current.buttons.is_empty());
536 }
537
538 #[test]
539 fn clear_frame_clears_coalesced_and_predicted() {
540 let mut state = PrimaryPointerState::default();
541
542 state.process_pointer_event(make_move_event(
543 PhysicalPosition { x: 10.0, y: 10.0 },
544 vec![PhysicalPosition { x: 5.0, y: 5.0 }],
545 vec![PhysicalPosition { x: 15.0, y: 15.0 }],
546 ));
547
548 assert!(!state.coalesced.is_empty());
549 assert!(!state.predicted.is_empty());
550
551 state.clear_frame();
552
553 assert!(state.coalesced.is_empty());
554 assert!(state.predicted.is_empty());
555 }
556
557 #[test]
558 fn current_position_and_logical() {
559 let mut state = PrimaryPointerState::default();
560 let position = PhysicalPosition { x: 100.0, y: 200.0 };
561 let scale_factor = 2.0;
562
563 let current = PointerState {
564 time: phony_time(),
565 position,
566 scale_factor,
567 ..Default::default()
568 };
569
570 state.process_pointer_event(PointerEvent::Move(PointerUpdate {
571 pointer: PointerInfo {
572 pointer_id: Some(PointerId::PRIMARY),
573 persistent_device_id: None,
574 pointer_type: PointerType::Mouse,
575 },
576 current,
577 coalesced: vec![],
578 predicted: vec![],
579 }));
580
581 assert_eq!(state.current_position(), position);
582 assert_eq!(
583 state.current_logical_position(),
584 position.to_logical(scale_factor)
585 );
586 }
587
588 #[test]
589 fn motion_with_coalesced() {
590 let mut state = PrimaryPointerState::default();
591
592 state.process_pointer_event(make_move_event(
593 PhysicalPosition { x: 10.0, y: 20.0 },
594 vec![],
595 vec![],
596 ));
597
598 state.process_pointer_event(make_move_event(
599 PhysicalPosition { x: 30.0, y: 40.0 },
600 vec![PhysicalPosition { x: 15.0, y: 25.0 }],
601 vec![],
602 ));
603
604 assert_eq!(state.motion(), PhysicalPosition { x: 30.0, y: 40.0 });
605 assert_eq!(state.logical_motion(), LogicalPosition { x: 30.0, y: 40.0 });
606 }
607
608 #[test]
609 fn motion_without_coalesced() {
610 let mut state = PrimaryPointerState::default();
611
612 state.process_pointer_event(make_move_event(
613 PhysicalPosition { x: 30.0, y: 40.0 },
614 vec![],
615 vec![],
616 ));
617
618 assert_eq!(state.motion(), PhysicalPosition { x: 30.0, y: 40.0 });
619 assert_eq!(state.logical_motion(), LogicalPosition { x: 30.0, y: 40.0 });
620 }
621}