1 /*
2 * Copyright 2023 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 //! Contains the InputVerifier, used to validate a stream of input events.
18
19 use crate::ffi::RustPointerProperties;
20 use crate::input::{DeviceId, MotionAction, MotionButton, MotionFlags, Source, SourceClass};
21 use log::info;
22 use std::collections::HashMap;
23 use std::collections::HashSet;
24
25 /// Represents a movement or state change event from a pointer device. The Rust equivalent of the
26 /// C++ NotifyMotionArgs struct.
27 #[derive(Clone, Copy)]
28 pub struct NotifyMotionArgs<'a> {
29 /// The ID of the device that emitted the event.
30 pub device_id: DeviceId,
31
32 /// The type of device that emitted the event.
33 pub source: Source,
34
35 /// The type of event that took place.
36 pub action: MotionAction,
37
38 /// The properties of each of the pointers involved in the event.
39 pub pointer_properties: &'a [RustPointerProperties],
40
41 /// Flags applied to the event.
42 pub flags: MotionFlags,
43
44 /// The set of buttons that were pressed at the time of the event.
45 ///
46 /// We allow DOWN events to include buttons in their state for which BUTTON_PRESS events haven't
47 /// been sent yet. In that case, the DOWN should be immediately followed by BUTTON_PRESS events
48 /// for those buttons, building up to a button state matching that of the DOWN. For example, if
49 /// the user presses the primary and secondary buttons at exactly the same time, we'd expect
50 /// this sequence:
51 ///
52 /// | Action | Action button | Button state |
53 /// |----------------|---------------|------------------------|
54 /// | `HOVER_EXIT` | - | - |
55 /// | `DOWN` | - | `PRIMARY`, `SECONDARY` |
56 /// | `BUTTON_PRESS` | `PRIMARY` | `PRIMARY` |
57 /// | `BUTTON_PRESS` | `SECONDARY` | `PRIMARY`, `SECONDARY` |
58 /// | `MOVE` | - | `PRIMARY`, `SECONDARY` |
59 pub button_state: MotionButton,
60 }
61
62 /// Verifies the properties of an event that should always be true, regardless of the current state.
verify_event(event: NotifyMotionArgs<'_>, verify_buttons: bool) -> Result<(), String>63 fn verify_event(event: NotifyMotionArgs<'_>, verify_buttons: bool) -> Result<(), String> {
64 let pointer_count = event.pointer_properties.len();
65 if pointer_count < 1 {
66 return Err(format!("Invalid {} event: no pointers", event.action));
67 }
68 match event.action {
69 MotionAction::Down
70 | MotionAction::HoverEnter
71 | MotionAction::HoverExit
72 | MotionAction::HoverMove
73 | MotionAction::Up => {
74 if pointer_count != 1 {
75 return Err(format!(
76 "Invalid {} event: there are {} pointers in the event",
77 event.action, pointer_count
78 ));
79 }
80 }
81
82 MotionAction::Cancel => {
83 if !event.flags.contains(MotionFlags::CANCELED) {
84 return Err(format!(
85 "For ACTION_CANCEL, must set FLAG_CANCELED. Received flags: {:#?}",
86 event.flags
87 ));
88 }
89 }
90
91 MotionAction::PointerDown { action_index } | MotionAction::PointerUp { action_index } => {
92 if action_index >= pointer_count {
93 return Err(format!(
94 "Got {}, but event has {} pointer(s)",
95 event.action, pointer_count
96 ));
97 }
98 }
99
100 MotionAction::ButtonPress { action_button }
101 | MotionAction::ButtonRelease { action_button } => {
102 if verify_buttons {
103 let button_count = action_button.iter().count();
104 if button_count != 1 {
105 return Err(format!(
106 "Invalid {} event: must specify a single action button, not {} action \
107 buttons",
108 event.action, button_count
109 ));
110 }
111 }
112 }
113
114 _ => {}
115 }
116 Ok(())
117 }
118
119 /// Keeps track of the button state for a single device and verifies events against it.
120 #[derive(Default)]
121 struct ButtonVerifier {
122 /// The current button state of the device.
123 button_state: MotionButton,
124
125 /// The set of "pending buttons", which were seen in the last DOWN event's button state but
126 /// for which we haven't seen BUTTON_PRESS events yet (see [`NotifyMotionArgs::button_state`]).
127 pending_buttons: MotionButton,
128 }
129
130 impl ButtonVerifier {
process_event(&mut self, event: NotifyMotionArgs<'_>) -> Result<(), String>131 pub fn process_event(&mut self, event: NotifyMotionArgs<'_>) -> Result<(), String> {
132 if !self.pending_buttons.is_empty() {
133 // We just saw a DOWN with some additional buttons in its state, so it should be
134 // immediately followed by ButtonPress events for those buttons.
135 match event.action {
136 MotionAction::ButtonPress { action_button }
137 if self.pending_buttons.contains(action_button) =>
138 {
139 self.pending_buttons -= action_button;
140 }
141 _ => {
142 return Err(format!(
143 "After DOWN event, expected BUTTON_PRESS event(s) for {:?}, but got {}",
144 self.pending_buttons, event.action
145 ));
146 }
147 }
148 }
149 let expected_state = match event.action {
150 MotionAction::Down => {
151 if self.button_state - event.button_state != MotionButton::empty() {
152 return Err(format!(
153 "DOWN event button state is missing {:?}",
154 self.button_state - event.button_state
155 ));
156 }
157 self.pending_buttons = event.button_state - self.button_state;
158 // We've already checked that the state isn't missing any already-down buttons, and
159 // extra buttons are valid on DOWN actions, so bypass the expected state check.
160 event.button_state
161 }
162 MotionAction::ButtonPress { action_button } => {
163 if self.button_state.contains(action_button) {
164 return Err(format!(
165 "Duplicate BUTTON_PRESS; button state already contains {action_button:?}"
166 ));
167 }
168 self.button_state | action_button
169 }
170 MotionAction::ButtonRelease { action_button } => {
171 if !self.button_state.contains(action_button) {
172 return Err(format!(
173 "Invalid BUTTON_RELEASE; button state doesn't contain {action_button:?}",
174 ));
175 }
176 self.button_state - action_button
177 }
178 _ => self.button_state,
179 };
180 if event.button_state != expected_state {
181 return Err(format!(
182 "Expected {} button state to be {:?}, but was {:?}",
183 event.action, expected_state, event.button_state
184 ));
185 }
186 // DOWN events can have pending buttons, so don't update the state for them.
187 if event.action != MotionAction::Down {
188 self.button_state = event.button_state;
189 }
190 Ok(())
191 }
192 }
193
194 /// The InputVerifier is used to validate a stream of input events.
195 pub struct InputVerifier {
196 name: String,
197 should_log: bool,
198 verify_buttons: bool,
199 touching_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
200 hovering_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
201 button_verifier_by_device: HashMap<DeviceId, ButtonVerifier>,
202 }
203
204 impl InputVerifier {
205 /// Create a new InputVerifier.
new(name: &str, should_log: bool, verify_buttons: bool) -> Self206 pub fn new(name: &str, should_log: bool, verify_buttons: bool) -> Self {
207 logger::init(
208 logger::Config::default()
209 .with_tag_on_device("InputVerifier")
210 .with_max_level(log::LevelFilter::Trace),
211 );
212 Self {
213 name: name.to_owned(),
214 should_log,
215 verify_buttons,
216 touching_pointer_ids_by_device: HashMap::new(),
217 hovering_pointer_ids_by_device: HashMap::new(),
218 button_verifier_by_device: HashMap::new(),
219 }
220 }
221
222 /// Process a pointer movement event from an InputDevice.
223 /// If the event is not valid, we return an error string that describes the issue.
process_movement(&mut self, event: NotifyMotionArgs<'_>) -> Result<(), String>224 pub fn process_movement(&mut self, event: NotifyMotionArgs<'_>) -> Result<(), String> {
225 if !event.source.is_from_class(SourceClass::Pointer) {
226 // Skip non-pointer sources like MOUSE_RELATIVE for now
227 return Ok(());
228 }
229 if self.should_log {
230 info!(
231 "Processing {} for device {:?} ({} pointer{}) on {}",
232 event.action,
233 event.device_id,
234 event.pointer_properties.len(),
235 if event.pointer_properties.len() == 1 { "" } else { "s" },
236 self.name
237 );
238 }
239
240 verify_event(event, self.verify_buttons)?;
241
242 if self.verify_buttons {
243 self.button_verifier_by_device
244 .entry(event.device_id)
245 .or_default()
246 .process_event(event)?;
247 }
248
249 match event.action {
250 MotionAction::Down => {
251 if self.touching_pointer_ids_by_device.contains_key(&event.device_id) {
252 return Err(format!(
253 "{}: Invalid DOWN event - pointers already down for device {:?}: {:?}",
254 self.name, event.device_id, self.touching_pointer_ids_by_device
255 ));
256 }
257 let it = self.touching_pointer_ids_by_device.entry(event.device_id).or_default();
258 it.insert(event.pointer_properties[0].id);
259 }
260 MotionAction::PointerDown { action_index } => {
261 if !self.touching_pointer_ids_by_device.contains_key(&event.device_id) {
262 return Err(format!(
263 "{}: Received POINTER_DOWN but no pointers are currently down \
264 for device {:?}",
265 self.name, event.device_id
266 ));
267 }
268 let it = self.touching_pointer_ids_by_device.get_mut(&event.device_id).unwrap();
269 if it.len() != event.pointer_properties.len() - 1 {
270 return Err(format!(
271 "{}: There are currently {} touching pointers, but the incoming \
272 POINTER_DOWN event has {}",
273 self.name,
274 it.len(),
275 event.pointer_properties.len()
276 ));
277 }
278 let pointer_id = event.pointer_properties[action_index].id;
279 if it.contains(&pointer_id) {
280 return Err(format!(
281 "{}: Pointer with id={} already present found in the properties",
282 self.name, pointer_id
283 ));
284 }
285 it.insert(pointer_id);
286 }
287 MotionAction::Move => {
288 if !self.ensure_touching_pointers_match(event.device_id, event.pointer_properties) {
289 return Err(format!(
290 "{}: ACTION_MOVE touching pointers don't match",
291 self.name
292 ));
293 }
294 }
295 MotionAction::PointerUp { action_index } => {
296 if !self.ensure_touching_pointers_match(event.device_id, event.pointer_properties) {
297 return Err(format!(
298 "{}: ACTION_POINTER_UP touching pointers don't match",
299 self.name
300 ));
301 }
302 let it = self.touching_pointer_ids_by_device.get_mut(&event.device_id).unwrap();
303 let pointer_id = event.pointer_properties[action_index].id;
304 it.remove(&pointer_id);
305 }
306 MotionAction::Up => {
307 if !self.touching_pointer_ids_by_device.contains_key(&event.device_id) {
308 return Err(format!(
309 "{} Received ACTION_UP but no pointers are currently down for device {:?}",
310 self.name, event.device_id
311 ));
312 }
313 let it = self.touching_pointer_ids_by_device.get_mut(&event.device_id).unwrap();
314 if it.len() != 1 {
315 return Err(format!(
316 "{}: Got ACTION_UP, but we have pointers: {:?} for device {:?}",
317 self.name, it, event.device_id
318 ));
319 }
320 let pointer_id = event.pointer_properties[0].id;
321 if !it.contains(&pointer_id) {
322 return Err(format!(
323 "{}: Got ACTION_UP, but pointerId {} is not touching. Touching pointers:\
324 {:?} for device {:?}",
325 self.name, pointer_id, it, event.device_id
326 ));
327 }
328 self.touching_pointer_ids_by_device.remove(&event.device_id);
329 }
330 MotionAction::Cancel => {
331 if !self.ensure_touching_pointers_match(event.device_id, event.pointer_properties) {
332 return Err(format!(
333 "{}: Got ACTION_CANCEL, but the pointers don't match. \
334 Existing pointers: {:?}",
335 self.name, self.touching_pointer_ids_by_device
336 ));
337 }
338 self.touching_pointer_ids_by_device.remove(&event.device_id);
339 }
340 /*
341 * The hovering protocol currently supports a single pointer only, because we do not
342 * have ACTION_HOVER_POINTER_ENTER or ACTION_HOVER_POINTER_EXIT.
343 * Still, we are keeping the infrastructure here pretty general in case that is
344 * eventually supported.
345 */
346 MotionAction::HoverEnter => {
347 if self.hovering_pointer_ids_by_device.contains_key(&event.device_id) {
348 return Err(format!(
349 "{}: Invalid HOVER_ENTER event - pointers already hovering for device {:?}:\
350 {:?}",
351 self.name, event.device_id, self.hovering_pointer_ids_by_device
352 ));
353 }
354 let it = self.hovering_pointer_ids_by_device.entry(event.device_id).or_default();
355 it.insert(event.pointer_properties[0].id);
356 }
357 MotionAction::HoverMove => {
358 // For compatibility reasons, we allow HOVER_MOVE without a prior HOVER_ENTER.
359 // If there was no prior HOVER_ENTER, just start a new hovering pointer.
360 let it = self.hovering_pointer_ids_by_device.entry(event.device_id).or_default();
361 it.insert(event.pointer_properties[0].id);
362 }
363 MotionAction::HoverExit => {
364 if !self.hovering_pointer_ids_by_device.contains_key(&event.device_id) {
365 return Err(format!(
366 "{}: Invalid HOVER_EXIT event - no pointers are hovering for device {:?}",
367 self.name, event.device_id
368 ));
369 }
370 let pointer_id = event.pointer_properties[0].id;
371 let it = self.hovering_pointer_ids_by_device.get_mut(&event.device_id).unwrap();
372 it.remove(&pointer_id);
373
374 if !it.is_empty() {
375 return Err(format!(
376 "{}: Removed hovering pointer {}, but pointers are still\
377 hovering for device {:?}: {:?}",
378 self.name, pointer_id, event.device_id, it
379 ));
380 }
381 self.hovering_pointer_ids_by_device.remove(&event.device_id);
382 }
383 _ => return Ok(()),
384 }
385 Ok(())
386 }
387
388 /// Notify the verifier that the device has been reset, which will cause the verifier to erase
389 /// the current internal state for this device. Subsequent events from this device are expected
390 //// to start a new gesture.
reset_device(&mut self, device_id: DeviceId)391 pub fn reset_device(&mut self, device_id: DeviceId) {
392 self.touching_pointer_ids_by_device.remove(&device_id);
393 self.hovering_pointer_ids_by_device.remove(&device_id);
394 }
395
ensure_touching_pointers_match( &self, device_id: DeviceId, pointer_properties: &[RustPointerProperties], ) -> bool396 fn ensure_touching_pointers_match(
397 &self,
398 device_id: DeviceId,
399 pointer_properties: &[RustPointerProperties],
400 ) -> bool {
401 let Some(pointers) = self.touching_pointer_ids_by_device.get(&device_id) else {
402 return false;
403 };
404
405 if pointers.len() != pointer_properties.len() {
406 return false;
407 }
408
409 for pointer_property in pointer_properties.iter() {
410 let pointer_id = pointer_property.id;
411 if !pointers.contains(&pointer_id) {
412 return false;
413 }
414 }
415 true
416 }
417 }
418
419 #[cfg(test)]
420 mod tests {
421 use crate::input::MotionButton;
422 use crate::input_verifier::InputVerifier;
423 use crate::input_verifier::NotifyMotionArgs;
424 use crate::DeviceId;
425 use crate::MotionAction;
426 use crate::MotionFlags;
427 use crate::RustPointerProperties;
428 use crate::Source;
429
430 const BASE_POINTER_PROPERTIES: [RustPointerProperties; 1] = [RustPointerProperties { id: 0 }];
431 const BASE_EVENT: NotifyMotionArgs = NotifyMotionArgs {
432 device_id: DeviceId(1),
433 source: Source::Touchscreen,
434 action: MotionAction::Down,
435 pointer_properties: &BASE_POINTER_PROPERTIES,
436 flags: MotionFlags::empty(),
437 button_state: MotionButton::empty(),
438 };
439 const BASE_MOUSE_EVENT: NotifyMotionArgs =
440 NotifyMotionArgs { source: Source::Mouse, ..BASE_EVENT };
441
442 #[test]
443 /**
444 * Send a DOWN event with 2 pointers and ensure that it's marked as invalid.
445 */
bad_down_event()446 fn bad_down_event() {
447 let mut verifier =
448 InputVerifier::new("Test", /*should_log*/ true, /*verify_buttons*/ true);
449 let pointer_properties =
450 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
451 assert!(verifier
452 .process_movement(NotifyMotionArgs {
453 action: MotionAction::Down,
454 pointer_properties: &pointer_properties,
455 ..BASE_EVENT
456 })
457 .is_err());
458 }
459
460 #[test]
single_pointer_stream()461 fn single_pointer_stream() {
462 let mut verifier =
463 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
464 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
465 assert!(verifier
466 .process_movement(NotifyMotionArgs {
467 action: MotionAction::Down,
468 pointer_properties: &pointer_properties,
469 ..BASE_EVENT
470 })
471 .is_ok());
472 assert!(verifier
473 .process_movement(NotifyMotionArgs {
474 action: MotionAction::Move,
475 pointer_properties: &pointer_properties,
476 ..BASE_EVENT
477 })
478 .is_ok());
479 assert!(verifier
480 .process_movement(NotifyMotionArgs {
481 action: MotionAction::Up,
482 pointer_properties: &pointer_properties,
483 ..BASE_EVENT
484 })
485 .is_ok());
486 }
487
488 #[test]
two_pointer_stream()489 fn two_pointer_stream() {
490 let mut verifier =
491 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
492 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
493 assert!(verifier
494 .process_movement(NotifyMotionArgs {
495 action: MotionAction::Down,
496 pointer_properties: &pointer_properties,
497 ..BASE_EVENT
498 })
499 .is_ok());
500 // POINTER 1 DOWN
501 let two_pointer_properties =
502 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
503 assert!(verifier
504 .process_movement(NotifyMotionArgs {
505 action: MotionAction::PointerDown { action_index: 1 },
506 pointer_properties: &two_pointer_properties,
507 ..BASE_EVENT
508 })
509 .is_ok());
510 // POINTER 0 UP
511 assert!(verifier
512 .process_movement(NotifyMotionArgs {
513 action: MotionAction::PointerUp { action_index: 0 },
514 pointer_properties: &two_pointer_properties,
515 ..BASE_EVENT
516 })
517 .is_ok());
518 // ACTION_UP for pointer id=1
519 let pointer_1_properties = Vec::from([RustPointerProperties { id: 1 }]);
520 assert!(verifier
521 .process_movement(NotifyMotionArgs {
522 action: MotionAction::Up,
523 pointer_properties: &pointer_1_properties,
524 ..BASE_EVENT
525 })
526 .is_ok());
527 }
528
529 #[test]
multi_device_stream()530 fn multi_device_stream() {
531 let mut verifier =
532 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
533 assert!(verifier
534 .process_movement(NotifyMotionArgs {
535 device_id: DeviceId(1),
536 action: MotionAction::Down,
537 ..BASE_EVENT
538 })
539 .is_ok());
540 assert!(verifier
541 .process_movement(NotifyMotionArgs {
542 device_id: DeviceId(1),
543 action: MotionAction::Move,
544 ..BASE_EVENT
545 })
546 .is_ok());
547 assert!(verifier
548 .process_movement(NotifyMotionArgs {
549 device_id: DeviceId(2),
550 action: MotionAction::Down,
551 ..BASE_EVENT
552 })
553 .is_ok());
554 assert!(verifier
555 .process_movement(NotifyMotionArgs {
556 device_id: DeviceId(2),
557 action: MotionAction::Move,
558 ..BASE_EVENT
559 })
560 .is_ok());
561 assert!(verifier
562 .process_movement(NotifyMotionArgs {
563 device_id: DeviceId(1),
564 action: MotionAction::Up,
565 ..BASE_EVENT
566 })
567 .is_ok());
568 }
569
570 #[test]
action_cancel()571 fn action_cancel() {
572 let mut verifier =
573 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
574 assert!(verifier
575 .process_movement(NotifyMotionArgs {
576 action: MotionAction::Down,
577 flags: MotionFlags::empty(),
578 ..BASE_EVENT
579 })
580 .is_ok());
581 assert!(verifier
582 .process_movement(NotifyMotionArgs {
583 action: MotionAction::Cancel,
584 flags: MotionFlags::CANCELED,
585 ..BASE_EVENT
586 })
587 .is_ok());
588 }
589
590 #[test]
invalid_action_cancel()591 fn invalid_action_cancel() {
592 let mut verifier =
593 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
594 assert!(verifier
595 .process_movement(NotifyMotionArgs { action: MotionAction::Down, ..BASE_EVENT })
596 .is_ok());
597 assert!(verifier
598 .process_movement(NotifyMotionArgs { action: MotionAction::Cancel, ..BASE_EVENT })
599 .is_err());
600 }
601
602 #[test]
invalid_up()603 fn invalid_up() {
604 let mut verifier =
605 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
606 assert!(verifier
607 .process_movement(NotifyMotionArgs { action: MotionAction::Up, ..BASE_EVENT })
608 .is_err());
609 }
610
611 #[test]
correct_hover_sequence()612 fn correct_hover_sequence() {
613 let mut verifier =
614 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
615 assert!(verifier
616 .process_movement(NotifyMotionArgs { action: MotionAction::HoverEnter, ..BASE_EVENT })
617 .is_ok());
618
619 assert!(verifier
620 .process_movement(NotifyMotionArgs { action: MotionAction::HoverMove, ..BASE_EVENT })
621 .is_ok());
622
623 assert!(verifier
624 .process_movement(NotifyMotionArgs { action: MotionAction::HoverExit, ..BASE_EVENT })
625 .is_ok());
626
627 assert!(verifier
628 .process_movement(NotifyMotionArgs { action: MotionAction::HoverEnter, ..BASE_EVENT })
629 .is_ok());
630 }
631
632 #[test]
double_hover_enter()633 fn double_hover_enter() {
634 let mut verifier =
635 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
636 assert!(verifier
637 .process_movement(NotifyMotionArgs { action: MotionAction::HoverEnter, ..BASE_EVENT })
638 .is_ok());
639
640 assert!(verifier
641 .process_movement(NotifyMotionArgs { action: MotionAction::HoverEnter, ..BASE_EVENT })
642 .is_err());
643 }
644
645 // Send a MOVE without a preceding DOWN event. This is OK because it's from source
646 // MOUSE_RELATIVE, which is used during pointer capture. The verifier should allow such event.
647 #[test]
relative_mouse_move()648 fn relative_mouse_move() {
649 let mut verifier =
650 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
651 assert!(verifier
652 .process_movement(NotifyMotionArgs {
653 device_id: DeviceId(2),
654 source: Source::MouseRelative,
655 action: MotionAction::Move,
656 ..BASE_EVENT
657 })
658 .is_ok());
659 }
660
661 // Send a MOVE event with incorrect number of pointers (one of the pointers is missing).
662 #[test]
move_with_wrong_number_of_pointers()663 fn move_with_wrong_number_of_pointers() {
664 let mut verifier =
665 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
666 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
667 assert!(verifier
668 .process_movement(NotifyMotionArgs {
669 action: MotionAction::Down,
670 pointer_properties: &pointer_properties,
671 ..BASE_EVENT
672 })
673 .is_ok());
674 // POINTER 1 DOWN
675 let two_pointer_properties =
676 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
677 assert!(verifier
678 .process_movement(NotifyMotionArgs {
679 action: MotionAction::PointerDown { action_index: 1 },
680 pointer_properties: &two_pointer_properties,
681 ..BASE_EVENT
682 })
683 .is_ok());
684 // MOVE event with 1 pointer missing (the pointer with id = 1). It should be rejected
685 assert!(verifier
686 .process_movement(NotifyMotionArgs {
687 action: MotionAction::Move,
688 pointer_properties: &pointer_properties,
689 ..BASE_EVENT
690 })
691 .is_err());
692 }
693
694 #[test]
correct_button_press()695 fn correct_button_press() {
696 let mut verifier =
697 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
698 assert!(verifier
699 .process_movement(NotifyMotionArgs {
700 action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
701 button_state: MotionButton::Primary,
702 ..BASE_MOUSE_EVENT
703 })
704 .is_ok());
705 }
706
707 #[test]
button_press_without_action_button()708 fn button_press_without_action_button() {
709 let mut verifier =
710 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
711 assert!(verifier
712 .process_movement(NotifyMotionArgs {
713 action: MotionAction::ButtonPress { action_button: MotionButton::empty() },
714 button_state: MotionButton::empty(),
715 ..BASE_MOUSE_EVENT
716 })
717 .is_err());
718 }
719
720 #[test]
button_press_with_multiple_action_buttons()721 fn button_press_with_multiple_action_buttons() {
722 let mut verifier =
723 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
724 assert!(verifier
725 .process_movement(NotifyMotionArgs {
726 action: MotionAction::ButtonPress {
727 action_button: MotionButton::Back | MotionButton::Forward
728 },
729 button_state: MotionButton::Back | MotionButton::Forward,
730 ..BASE_MOUSE_EVENT
731 })
732 .is_err());
733 }
734
735 #[test]
button_press_without_action_button_in_state()736 fn button_press_without_action_button_in_state() {
737 let mut verifier =
738 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
739 assert!(verifier
740 .process_movement(NotifyMotionArgs {
741 action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
742 button_state: MotionButton::empty(),
743 ..BASE_MOUSE_EVENT
744 })
745 .is_err());
746 }
747
748 #[test]
button_release_with_action_button_in_state()749 fn button_release_with_action_button_in_state() {
750 let mut verifier =
751 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
752 assert!(verifier
753 .process_movement(NotifyMotionArgs {
754 action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
755 button_state: MotionButton::Primary,
756 ..BASE_MOUSE_EVENT
757 })
758 .is_ok());
759 assert!(verifier
760 .process_movement(NotifyMotionArgs {
761 action: MotionAction::ButtonRelease { action_button: MotionButton::Primary },
762 button_state: MotionButton::Primary,
763 ..BASE_MOUSE_EVENT
764 })
765 .is_err());
766 }
767
768 #[test]
nonbutton_action_with_button_state_change()769 fn nonbutton_action_with_button_state_change() {
770 let mut verifier =
771 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
772 assert!(verifier
773 .process_movement(NotifyMotionArgs {
774 action: MotionAction::HoverEnter,
775 button_state: MotionButton::empty(),
776 ..BASE_MOUSE_EVENT
777 })
778 .is_ok());
779 assert!(verifier
780 .process_movement(NotifyMotionArgs {
781 action: MotionAction::HoverMove,
782 button_state: MotionButton::Back,
783 ..BASE_MOUSE_EVENT
784 })
785 .is_err());
786 }
787
788 #[test]
nonbutton_action_missing_button_state()789 fn nonbutton_action_missing_button_state() {
790 let mut verifier =
791 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
792 assert!(verifier
793 .process_movement(NotifyMotionArgs {
794 action: MotionAction::HoverEnter,
795 button_state: MotionButton::empty(),
796 ..BASE_MOUSE_EVENT
797 })
798 .is_ok());
799 assert!(verifier
800 .process_movement(NotifyMotionArgs {
801 action: MotionAction::ButtonPress { action_button: MotionButton::Back },
802 button_state: MotionButton::Back,
803 ..BASE_MOUSE_EVENT
804 })
805 .is_ok());
806 assert!(verifier
807 .process_movement(NotifyMotionArgs {
808 action: MotionAction::HoverMove,
809 button_state: MotionButton::empty(),
810 ..BASE_MOUSE_EVENT
811 })
812 .is_err());
813 }
814
815 #[test]
up_without_button_release()816 fn up_without_button_release() {
817 let mut verifier =
818 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
819 assert!(verifier
820 .process_movement(NotifyMotionArgs {
821 action: MotionAction::Down,
822 button_state: MotionButton::Primary,
823 ..BASE_MOUSE_EVENT
824 })
825 .is_ok());
826 assert!(verifier
827 .process_movement(NotifyMotionArgs {
828 action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
829 button_state: MotionButton::Primary,
830 ..BASE_MOUSE_EVENT
831 })
832 .is_ok());
833 // This UP event shouldn't change the button state; a BUTTON_RELEASE before it should.
834 assert!(verifier
835 .process_movement(NotifyMotionArgs {
836 action: MotionAction::Up,
837 button_state: MotionButton::empty(),
838 ..BASE_MOUSE_EVENT
839 })
840 .is_err());
841 }
842
843 #[test]
button_press_for_already_pressed_button()844 fn button_press_for_already_pressed_button() {
845 let mut verifier =
846 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
847 assert!(verifier
848 .process_movement(NotifyMotionArgs {
849 action: MotionAction::ButtonPress { action_button: MotionButton::Back },
850 button_state: MotionButton::Back,
851 ..BASE_MOUSE_EVENT
852 })
853 .is_ok());
854 assert!(verifier
855 .process_movement(NotifyMotionArgs {
856 action: MotionAction::ButtonPress { action_button: MotionButton::Back },
857 button_state: MotionButton::Back,
858 ..BASE_MOUSE_EVENT
859 })
860 .is_err());
861 }
862
863 #[test]
button_release_for_unpressed_button()864 fn button_release_for_unpressed_button() {
865 let mut verifier =
866 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
867 assert!(verifier
868 .process_movement(NotifyMotionArgs {
869 action: MotionAction::ButtonRelease { action_button: MotionButton::Back },
870 button_state: MotionButton::empty(),
871 ..BASE_MOUSE_EVENT
872 })
873 .is_err());
874 }
875
876 #[test]
correct_multiple_button_presses_without_down()877 fn correct_multiple_button_presses_without_down() {
878 let mut verifier =
879 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
880 assert!(verifier
881 .process_movement(NotifyMotionArgs {
882 action: MotionAction::ButtonPress { action_button: MotionButton::Back },
883 button_state: MotionButton::Back,
884 ..BASE_MOUSE_EVENT
885 })
886 .is_ok());
887 assert!(verifier
888 .process_movement(NotifyMotionArgs {
889 action: MotionAction::ButtonPress { action_button: MotionButton::Forward },
890 button_state: MotionButton::Back | MotionButton::Forward,
891 ..BASE_MOUSE_EVENT
892 })
893 .is_ok());
894 }
895
896 #[test]
correct_down_with_button_press()897 fn correct_down_with_button_press() {
898 let mut verifier =
899 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
900 assert!(verifier
901 .process_movement(NotifyMotionArgs {
902 action: MotionAction::Down,
903 button_state: MotionButton::Primary | MotionButton::Secondary,
904 ..BASE_MOUSE_EVENT
905 })
906 .is_ok());
907 assert!(verifier
908 .process_movement(NotifyMotionArgs {
909 action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
910 button_state: MotionButton::Primary,
911 ..BASE_MOUSE_EVENT
912 })
913 .is_ok());
914 assert!(verifier
915 .process_movement(NotifyMotionArgs {
916 action: MotionAction::ButtonPress { action_button: MotionButton::Secondary },
917 button_state: MotionButton::Primary | MotionButton::Secondary,
918 ..BASE_MOUSE_EVENT
919 })
920 .is_ok());
921 // Also check that the MOVE afterwards is OK, as that's where errors would be raised if not
922 // enough BUTTON_PRESSes were sent.
923 assert!(verifier
924 .process_movement(NotifyMotionArgs {
925 action: MotionAction::Move,
926 button_state: MotionButton::Primary | MotionButton::Secondary,
927 ..BASE_MOUSE_EVENT
928 })
929 .is_ok());
930 }
931
932 #[test]
down_with_button_state_change_not_followed_by_button_press()933 fn down_with_button_state_change_not_followed_by_button_press() {
934 let mut verifier =
935 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
936 assert!(verifier
937 .process_movement(NotifyMotionArgs {
938 action: MotionAction::Down,
939 button_state: MotionButton::Primary,
940 ..BASE_MOUSE_EVENT
941 })
942 .is_ok());
943 // The DOWN event itself is OK, but it needs to be immediately followed by a BUTTON_PRESS.
944 assert!(verifier
945 .process_movement(NotifyMotionArgs {
946 action: MotionAction::Move,
947 button_state: MotionButton::Primary,
948 ..BASE_MOUSE_EVENT
949 })
950 .is_err());
951 }
952
953 #[test]
down_with_button_state_change_not_followed_by_enough_button_presses()954 fn down_with_button_state_change_not_followed_by_enough_button_presses() {
955 let mut verifier =
956 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
957 assert!(verifier
958 .process_movement(NotifyMotionArgs {
959 action: MotionAction::Down,
960 button_state: MotionButton::Primary | MotionButton::Secondary,
961 ..BASE_MOUSE_EVENT
962 })
963 .is_ok());
964 // The DOWN event itself is OK, but it needs to be immediately followed by two
965 // BUTTON_PRESSes, one for each button.
966 assert!(verifier
967 .process_movement(NotifyMotionArgs {
968 action: MotionAction::ButtonPress { action_button: MotionButton::Primary },
969 button_state: MotionButton::Primary,
970 ..BASE_MOUSE_EVENT
971 })
972 .is_ok());
973 assert!(verifier
974 .process_movement(NotifyMotionArgs {
975 action: MotionAction::Move,
976 button_state: MotionButton::Primary,
977 ..BASE_MOUSE_EVENT
978 })
979 .is_err());
980 }
981
982 #[test]
down_missing_already_pressed_button()983 fn down_missing_already_pressed_button() {
984 let mut verifier =
985 InputVerifier::new("Test", /*should_log*/ false, /*verify_buttons*/ true);
986 assert!(verifier
987 .process_movement(NotifyMotionArgs {
988 action: MotionAction::ButtonPress { action_button: MotionButton::Back },
989 button_state: MotionButton::Back,
990 ..BASE_MOUSE_EVENT
991 })
992 .is_ok());
993 assert!(verifier
994 .process_movement(NotifyMotionArgs {
995 action: MotionAction::Down,
996 button_state: MotionButton::empty(),
997 ..BASE_MOUSE_EVENT
998 })
999 .is_err());
1000 }
1001 }
1002