blob: b60d7c971e211a2a924a05dddf19267b47829077 [file] [log] [blame]
Prabir Pradhan0762b1f2023-06-22 23:08:18 +00001/*
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
19use crate::ffi::RustPointerProperties;
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -070020use crate::input::{DeviceId, MotionAction, MotionFlags, Source, SourceClass};
Prabir Pradhan0762b1f2023-06-22 23:08:18 +000021use log::info;
22use std::collections::HashMap;
23use std::collections::HashSet;
24
Siarhei Vishniakou93992432023-10-09 15:47:48 -070025fn verify_event(
26 action: MotionAction,
27 pointer_properties: &[RustPointerProperties],
28 flags: &MotionFlags,
29) -> Result<(), String> {
30 let pointer_count = pointer_properties.len();
31 if pointer_count < 1 {
32 return Err(format!("Invalid {} event: no pointers", action));
33 }
34 match action {
35 MotionAction::Down
36 | MotionAction::HoverEnter
37 | MotionAction::HoverExit
38 | MotionAction::HoverMove
39 | MotionAction::Up => {
40 if pointer_count != 1 {
41 return Err(format!(
42 "Invalid {} event: there are {} pointers in the event",
43 action, pointer_count
44 ));
45 }
46 }
47
48 MotionAction::Cancel => {
49 if !flags.contains(MotionFlags::CANCELED) {
50 return Err(format!(
51 "For ACTION_CANCEL, must set FLAG_CANCELED. Received flags: {:#?}",
52 flags
53 ));
54 }
55 }
56
57 MotionAction::PointerDown { action_index } | MotionAction::PointerUp { action_index } => {
58 if action_index >= pointer_count {
59 return Err(format!("Got {}, but event has {} pointer(s)", action, pointer_count));
60 }
61 }
62
63 _ => {}
64 }
65 Ok(())
66}
67
Prabir Pradhan0762b1f2023-06-22 23:08:18 +000068/// The InputVerifier is used to validate a stream of input events.
69pub struct InputVerifier {
70 name: String,
71 should_log: bool,
72 touching_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -070073 hovering_pointer_ids_by_device: HashMap<DeviceId, HashSet<i32>>,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +000074}
75
76impl InputVerifier {
77 /// Create a new InputVerifier.
78 pub fn new(name: &str, should_log: bool) -> Self {
79 logger::init(
80 logger::Config::default()
81 .with_tag_on_device("InputVerifier")
82 .with_min_level(log::Level::Trace),
83 );
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -070084 Self {
85 name: name.to_owned(),
86 should_log,
87 touching_pointer_ids_by_device: HashMap::new(),
88 hovering_pointer_ids_by_device: HashMap::new(),
89 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +000090 }
91
92 /// Process a pointer movement event from an InputDevice.
93 /// If the event is not valid, we return an error string that describes the issue.
94 pub fn process_movement(
95 &mut self,
96 device_id: DeviceId,
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -070097 source: Source,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +000098 action: u32,
99 pointer_properties: &[RustPointerProperties],
100 flags: MotionFlags,
101 ) -> Result<(), String> {
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700102 if !source.is_from_class(SourceClass::Pointer) {
103 // Skip non-pointer sources like MOUSE_RELATIVE for now
104 return Ok(());
105 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000106 if self.should_log {
107 info!(
108 "Processing {} for device {:?} ({} pointer{}) on {}",
109 MotionAction::from(action).to_string(),
110 device_id,
111 pointer_properties.len(),
112 if pointer_properties.len() == 1 { "" } else { "s" },
113 self.name
114 );
115 }
116
Siarhei Vishniakou93992432023-10-09 15:47:48 -0700117 verify_event(action.into(), pointer_properties, &flags)?;
118
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000119 match action.into() {
120 MotionAction::Down => {
Siarhei Vishniakouae08b5e2023-10-19 18:58:07 -0700121 if self.touching_pointer_ids_by_device.contains_key(&device_id) {
122 return Err(format!(
123 "{}: Invalid DOWN event - pointers already down for device {:?}: {:?}",
124 self.name, device_id, self.touching_pointer_ids_by_device
125 ));
126 }
Chariseeab69fa72023-11-17 20:27:18 +0000127 let it = self.touching_pointer_ids_by_device.entry(device_id).or_default();
Siarhei Vishniakouae08b5e2023-10-19 18:58:07 -0700128 it.insert(pointer_properties[0].id);
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000129 }
130 MotionAction::PointerDown { action_index } => {
131 if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
132 return Err(format!(
133 "{}: Received POINTER_DOWN but no pointers are currently down \
134 for device {:?}",
135 self.name, device_id
136 ));
137 }
138 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700139 if it.len() != pointer_properties.len() - 1 {
140 return Err(format!(
141 "{}: There are currently {} touching pointers, but the incoming \
142 POINTER_DOWN event has {}",
143 self.name,
144 it.len(),
145 pointer_properties.len()
146 ));
147 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000148 let pointer_id = pointer_properties[action_index].id;
149 if it.contains(&pointer_id) {
150 return Err(format!(
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700151 "{}: Pointer with id={} already present found in the properties",
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000152 self.name, pointer_id
153 ));
154 }
155 it.insert(pointer_id);
156 }
157 MotionAction::Move => {
158 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
159 return Err(format!(
160 "{}: ACTION_MOVE touching pointers don't match",
161 self.name
162 ));
163 }
164 }
165 MotionAction::PointerUp { action_index } => {
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700166 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000167 return Err(format!(
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700168 "{}: ACTION_POINTER_UP touching pointers don't match",
169 self.name
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000170 ));
171 }
172 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
173 let pointer_id = pointer_properties[action_index].id;
174 it.remove(&pointer_id);
175 }
176 MotionAction::Up => {
177 if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
178 return Err(format!(
179 "{} Received ACTION_UP but no pointers are currently down for device {:?}",
180 self.name, device_id
181 ));
182 }
183 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
184 if it.len() != 1 {
185 return Err(format!(
186 "{}: Got ACTION_UP, but we have pointers: {:?} for device {:?}",
187 self.name, it, device_id
188 ));
189 }
190 let pointer_id = pointer_properties[0].id;
191 if !it.contains(&pointer_id) {
192 return Err(format!(
193 "{}: Got ACTION_UP, but pointerId {} is not touching. Touching pointers:\
194 {:?} for device {:?}",
195 self.name, pointer_id, it, device_id
196 ));
197 }
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700198 self.touching_pointer_ids_by_device.remove(&device_id);
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000199 }
200 MotionAction::Cancel => {
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000201 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
202 return Err(format!(
203 "{}: Got ACTION_CANCEL, but the pointers don't match. \
204 Existing pointers: {:?}",
205 self.name, self.touching_pointer_ids_by_device
206 ));
207 }
208 self.touching_pointer_ids_by_device.remove(&device_id);
209 }
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700210 /*
211 * The hovering protocol currently supports a single pointer only, because we do not
212 * have ACTION_HOVER_POINTER_ENTER or ACTION_HOVER_POINTER_EXIT.
213 * Still, we are keeping the infrastructure here pretty general in case that is
214 * eventually supported.
215 */
216 MotionAction::HoverEnter => {
217 if self.hovering_pointer_ids_by_device.contains_key(&device_id) {
218 return Err(format!(
219 "{}: Invalid HOVER_ENTER event - pointers already hovering for device {:?}:\
220 {:?}",
221 self.name, device_id, self.hovering_pointer_ids_by_device
222 ));
223 }
Chariseeab69fa72023-11-17 20:27:18 +0000224 let it = self.hovering_pointer_ids_by_device.entry(device_id).or_default();
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700225 it.insert(pointer_properties[0].id);
226 }
227 MotionAction::HoverMove => {
228 // For compatibility reasons, we allow HOVER_MOVE without a prior HOVER_ENTER.
229 // If there was no prior HOVER_ENTER, just start a new hovering pointer.
Chariseeab69fa72023-11-17 20:27:18 +0000230 let it = self.hovering_pointer_ids_by_device.entry(device_id).or_default();
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700231 it.insert(pointer_properties[0].id);
232 }
233 MotionAction::HoverExit => {
234 if !self.hovering_pointer_ids_by_device.contains_key(&device_id) {
235 return Err(format!(
236 "{}: Invalid HOVER_EXIT event - no pointers are hovering for device {:?}",
237 self.name, device_id
238 ));
239 }
240 let pointer_id = pointer_properties[0].id;
241 let it = self.hovering_pointer_ids_by_device.get_mut(&device_id).unwrap();
242 it.remove(&pointer_id);
243
244 if !it.is_empty() {
245 return Err(format!(
246 "{}: Removed hovering pointer {}, but pointers are still\
247 hovering for device {:?}: {:?}",
248 self.name, pointer_id, device_id, it
249 ));
250 }
251 self.hovering_pointer_ids_by_device.remove(&device_id);
252 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000253 _ => return Ok(()),
254 }
255 Ok(())
256 }
257
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700258 /// Notify the verifier that the device has been reset, which will cause the verifier to erase
259 /// the current internal state for this device. Subsequent events from this device are expected
260 //// to start a new gesture.
261 pub fn reset_device(&mut self, device_id: DeviceId) {
262 self.touching_pointer_ids_by_device.remove(&device_id);
263 self.hovering_pointer_ids_by_device.remove(&device_id);
264 }
265
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000266 fn ensure_touching_pointers_match(
267 &self,
268 device_id: DeviceId,
269 pointer_properties: &[RustPointerProperties],
270 ) -> bool {
271 let Some(pointers) = self.touching_pointer_ids_by_device.get(&device_id) else {
272 return false;
273 };
274
275 for pointer_property in pointer_properties.iter() {
276 let pointer_id = pointer_property.id;
277 if !pointers.contains(&pointer_id) {
278 return false;
279 }
280 }
281 true
282 }
283}
284
285#[cfg(test)]
286mod tests {
287 use crate::input_verifier::InputVerifier;
288 use crate::DeviceId;
289 use crate::MotionFlags;
290 use crate::RustPointerProperties;
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700291 use crate::Source;
Siarhei Vishniakou93992432023-10-09 15:47:48 -0700292
293 #[test]
294 /**
295 * Send a DOWN event with 2 pointers and ensure that it's marked as invalid.
296 */
297 fn bad_down_event() {
298 let mut verifier = InputVerifier::new("Test", /*should_log*/ true);
299 let pointer_properties =
300 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
301 assert!(verifier
302 .process_movement(
303 DeviceId(1),
304 Source::Touchscreen,
305 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
306 &pointer_properties,
307 MotionFlags::empty(),
308 )
309 .is_err());
310 }
311
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000312 #[test]
313 fn single_pointer_stream() {
314 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
315 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
316 assert!(verifier
317 .process_movement(
318 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700319 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000320 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
321 &pointer_properties,
322 MotionFlags::empty(),
323 )
324 .is_ok());
325 assert!(verifier
326 .process_movement(
327 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700328 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000329 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
330 &pointer_properties,
331 MotionFlags::empty(),
332 )
333 .is_ok());
334 assert!(verifier
335 .process_movement(
336 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700337 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000338 input_bindgen::AMOTION_EVENT_ACTION_UP,
339 &pointer_properties,
340 MotionFlags::empty(),
341 )
342 .is_ok());
343 }
344
345 #[test]
Siarhei Vishniakouae08b5e2023-10-19 18:58:07 -0700346 fn two_pointer_stream() {
347 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
348 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
349 assert!(verifier
350 .process_movement(
351 DeviceId(1),
352 Source::Touchscreen,
353 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
354 &pointer_properties,
355 MotionFlags::empty(),
356 )
357 .is_ok());
358 // POINTER 1 DOWN
359 let two_pointer_properties =
360 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
361 assert!(verifier
362 .process_movement(
363 DeviceId(1),
364 Source::Touchscreen,
365 input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
366 | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
367 &two_pointer_properties,
368 MotionFlags::empty(),
369 )
370 .is_ok());
371 // POINTER 0 UP
372 assert!(verifier
373 .process_movement(
374 DeviceId(1),
375 Source::Touchscreen,
376 input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP
377 | (0 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
378 &two_pointer_properties,
379 MotionFlags::empty(),
380 )
381 .is_ok());
382 // ACTION_UP for pointer id=1
383 let pointer_1_properties = Vec::from([RustPointerProperties { id: 1 }]);
384 assert!(verifier
385 .process_movement(
386 DeviceId(1),
387 Source::Touchscreen,
388 input_bindgen::AMOTION_EVENT_ACTION_UP,
389 &pointer_1_properties,
390 MotionFlags::empty(),
391 )
392 .is_ok());
393 }
394
395 #[test]
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000396 fn multi_device_stream() {
397 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
398 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
399 assert!(verifier
400 .process_movement(
401 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700402 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000403 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
404 &pointer_properties,
405 MotionFlags::empty(),
406 )
407 .is_ok());
408 assert!(verifier
409 .process_movement(
410 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700411 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000412 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
413 &pointer_properties,
414 MotionFlags::empty(),
415 )
416 .is_ok());
417 assert!(verifier
418 .process_movement(
419 DeviceId(2),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700420 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000421 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
422 &pointer_properties,
423 MotionFlags::empty(),
424 )
425 .is_ok());
426 assert!(verifier
427 .process_movement(
428 DeviceId(2),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700429 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000430 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
431 &pointer_properties,
432 MotionFlags::empty(),
433 )
434 .is_ok());
435 assert!(verifier
436 .process_movement(
437 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700438 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000439 input_bindgen::AMOTION_EVENT_ACTION_UP,
440 &pointer_properties,
441 MotionFlags::empty(),
442 )
443 .is_ok());
444 }
445
446 #[test]
Siarhei Vishniakoue65fa752023-06-28 14:09:09 -0700447 fn action_cancel() {
448 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
449 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
450 assert!(verifier
451 .process_movement(
452 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700453 Source::Touchscreen,
Siarhei Vishniakoue65fa752023-06-28 14:09:09 -0700454 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
455 &pointer_properties,
456 MotionFlags::empty(),
457 )
458 .is_ok());
459 assert!(verifier
460 .process_movement(
461 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700462 Source::Touchscreen,
Siarhei Vishniakoue65fa752023-06-28 14:09:09 -0700463 input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
464 &pointer_properties,
465 MotionFlags::CANCELED,
466 )
467 .is_ok());
468 }
469
470 #[test]
471 fn invalid_action_cancel() {
472 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
473 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
474 assert!(verifier
475 .process_movement(
476 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700477 Source::Touchscreen,
Siarhei Vishniakoue65fa752023-06-28 14:09:09 -0700478 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
479 &pointer_properties,
480 MotionFlags::empty(),
481 )
482 .is_ok());
483 assert!(verifier
484 .process_movement(
485 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700486 Source::Touchscreen,
Siarhei Vishniakoue65fa752023-06-28 14:09:09 -0700487 input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
488 &pointer_properties,
489 MotionFlags::empty(), // forgot to set FLAG_CANCELED
490 )
491 .is_err());
492 }
493
494 #[test]
495 fn invalid_up() {
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000496 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
497 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
498 assert!(verifier
499 .process_movement(
500 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700501 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000502 input_bindgen::AMOTION_EVENT_ACTION_UP,
503 &pointer_properties,
504 MotionFlags::empty(),
505 )
506 .is_err());
507 }
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700508
509 #[test]
510 fn correct_hover_sequence() {
511 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
512 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
513 assert!(verifier
514 .process_movement(
515 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700516 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700517 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
518 &pointer_properties,
519 MotionFlags::empty(),
520 )
521 .is_ok());
522
523 assert!(verifier
524 .process_movement(
525 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700526 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700527 input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
528 &pointer_properties,
529 MotionFlags::empty(),
530 )
531 .is_ok());
532
533 assert!(verifier
534 .process_movement(
535 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700536 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700537 input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT,
538 &pointer_properties,
539 MotionFlags::empty(),
540 )
541 .is_ok());
542
543 assert!(verifier
544 .process_movement(
545 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700546 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700547 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
548 &pointer_properties,
549 MotionFlags::empty(),
550 )
551 .is_ok());
552 }
553
554 #[test]
555 fn double_hover_enter() {
556 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
557 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
558 assert!(verifier
559 .process_movement(
560 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700561 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700562 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
563 &pointer_properties,
564 MotionFlags::empty(),
565 )
566 .is_ok());
567
568 assert!(verifier
569 .process_movement(
570 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700571 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700572 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
573 &pointer_properties,
574 MotionFlags::empty(),
575 )
576 .is_err());
577 }
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700578
579 // Send a MOVE without a preceding DOWN event. This is OK because it's from source
580 // MOUSE_RELATIVE, which is used during pointer capture. The verifier should allow such event.
581 #[test]
582 fn relative_mouse_move() {
583 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
584 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
585 assert!(verifier
586 .process_movement(
587 DeviceId(2),
588 Source::MouseRelative,
589 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
590 &pointer_properties,
591 MotionFlags::empty(),
592 )
593 .is_ok());
594 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000595}