blob: 5f05a0f454b679a36102705bf1b72349b8bac075 [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 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000127 let it = self
128 .touching_pointer_ids_by_device
129 .entry(device_id)
130 .or_insert_with(HashSet::new);
Siarhei Vishniakouae08b5e2023-10-19 18:58:07 -0700131 it.insert(pointer_properties[0].id);
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000132 }
133 MotionAction::PointerDown { action_index } => {
134 if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
135 return Err(format!(
136 "{}: Received POINTER_DOWN but no pointers are currently down \
137 for device {:?}",
138 self.name, device_id
139 ));
140 }
141 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700142 if it.len() != pointer_properties.len() - 1 {
143 return Err(format!(
144 "{}: There are currently {} touching pointers, but the incoming \
145 POINTER_DOWN event has {}",
146 self.name,
147 it.len(),
148 pointer_properties.len()
149 ));
150 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000151 let pointer_id = pointer_properties[action_index].id;
152 if it.contains(&pointer_id) {
153 return Err(format!(
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700154 "{}: Pointer with id={} already present found in the properties",
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000155 self.name, pointer_id
156 ));
157 }
158 it.insert(pointer_id);
159 }
160 MotionAction::Move => {
161 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
162 return Err(format!(
163 "{}: ACTION_MOVE touching pointers don't match",
164 self.name
165 ));
166 }
167 }
168 MotionAction::PointerUp { action_index } => {
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700169 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000170 return Err(format!(
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700171 "{}: ACTION_POINTER_UP touching pointers don't match",
172 self.name
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000173 ));
174 }
175 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
176 let pointer_id = pointer_properties[action_index].id;
177 it.remove(&pointer_id);
178 }
179 MotionAction::Up => {
180 if !self.touching_pointer_ids_by_device.contains_key(&device_id) {
181 return Err(format!(
182 "{} Received ACTION_UP but no pointers are currently down for device {:?}",
183 self.name, device_id
184 ));
185 }
186 let it = self.touching_pointer_ids_by_device.get_mut(&device_id).unwrap();
187 if it.len() != 1 {
188 return Err(format!(
189 "{}: Got ACTION_UP, but we have pointers: {:?} for device {:?}",
190 self.name, it, device_id
191 ));
192 }
193 let pointer_id = pointer_properties[0].id;
194 if !it.contains(&pointer_id) {
195 return Err(format!(
196 "{}: Got ACTION_UP, but pointerId {} is not touching. Touching pointers:\
197 {:?} for device {:?}",
198 self.name, pointer_id, it, device_id
199 ));
200 }
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700201 self.touching_pointer_ids_by_device.remove(&device_id);
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000202 }
203 MotionAction::Cancel => {
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000204 if !self.ensure_touching_pointers_match(device_id, pointer_properties) {
205 return Err(format!(
206 "{}: Got ACTION_CANCEL, but the pointers don't match. \
207 Existing pointers: {:?}",
208 self.name, self.touching_pointer_ids_by_device
209 ));
210 }
211 self.touching_pointer_ids_by_device.remove(&device_id);
212 }
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700213 /*
214 * The hovering protocol currently supports a single pointer only, because we do not
215 * have ACTION_HOVER_POINTER_ENTER or ACTION_HOVER_POINTER_EXIT.
216 * Still, we are keeping the infrastructure here pretty general in case that is
217 * eventually supported.
218 */
219 MotionAction::HoverEnter => {
220 if self.hovering_pointer_ids_by_device.contains_key(&device_id) {
221 return Err(format!(
222 "{}: Invalid HOVER_ENTER event - pointers already hovering for device {:?}:\
223 {:?}",
224 self.name, device_id, self.hovering_pointer_ids_by_device
225 ));
226 }
227 let it = self
228 .hovering_pointer_ids_by_device
229 .entry(device_id)
230 .or_insert_with(HashSet::new);
231 it.insert(pointer_properties[0].id);
232 }
233 MotionAction::HoverMove => {
234 // For compatibility reasons, we allow HOVER_MOVE without a prior HOVER_ENTER.
235 // If there was no prior HOVER_ENTER, just start a new hovering pointer.
236 let it = self
237 .hovering_pointer_ids_by_device
238 .entry(device_id)
239 .or_insert_with(HashSet::new);
240 it.insert(pointer_properties[0].id);
241 }
242 MotionAction::HoverExit => {
243 if !self.hovering_pointer_ids_by_device.contains_key(&device_id) {
244 return Err(format!(
245 "{}: Invalid HOVER_EXIT event - no pointers are hovering for device {:?}",
246 self.name, device_id
247 ));
248 }
249 let pointer_id = pointer_properties[0].id;
250 let it = self.hovering_pointer_ids_by_device.get_mut(&device_id).unwrap();
251 it.remove(&pointer_id);
252
253 if !it.is_empty() {
254 return Err(format!(
255 "{}: Removed hovering pointer {}, but pointers are still\
256 hovering for device {:?}: {:?}",
257 self.name, pointer_id, device_id, it
258 ));
259 }
260 self.hovering_pointer_ids_by_device.remove(&device_id);
261 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000262 _ => return Ok(()),
263 }
264 Ok(())
265 }
266
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700267 /// Notify the verifier that the device has been reset, which will cause the verifier to erase
268 /// the current internal state for this device. Subsequent events from this device are expected
269 //// to start a new gesture.
270 pub fn reset_device(&mut self, device_id: DeviceId) {
271 self.touching_pointer_ids_by_device.remove(&device_id);
272 self.hovering_pointer_ids_by_device.remove(&device_id);
273 }
274
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000275 fn ensure_touching_pointers_match(
276 &self,
277 device_id: DeviceId,
278 pointer_properties: &[RustPointerProperties],
279 ) -> bool {
280 let Some(pointers) = self.touching_pointer_ids_by_device.get(&device_id) else {
281 return false;
282 };
283
284 for pointer_property in pointer_properties.iter() {
285 let pointer_id = pointer_property.id;
286 if !pointers.contains(&pointer_id) {
287 return false;
288 }
289 }
290 true
291 }
292}
293
294#[cfg(test)]
295mod tests {
296 use crate::input_verifier::InputVerifier;
297 use crate::DeviceId;
298 use crate::MotionFlags;
299 use crate::RustPointerProperties;
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700300 use crate::Source;
Siarhei Vishniakou93992432023-10-09 15:47:48 -0700301
302 #[test]
303 /**
304 * Send a DOWN event with 2 pointers and ensure that it's marked as invalid.
305 */
306 fn bad_down_event() {
307 let mut verifier = InputVerifier::new("Test", /*should_log*/ true);
308 let pointer_properties =
309 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
310 assert!(verifier
311 .process_movement(
312 DeviceId(1),
313 Source::Touchscreen,
314 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
315 &pointer_properties,
316 MotionFlags::empty(),
317 )
318 .is_err());
319 }
320
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000321 #[test]
322 fn single_pointer_stream() {
323 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
324 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
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_DOWN,
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_MOVE,
339 &pointer_properties,
340 MotionFlags::empty(),
341 )
342 .is_ok());
343 assert!(verifier
344 .process_movement(
345 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700346 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000347 input_bindgen::AMOTION_EVENT_ACTION_UP,
348 &pointer_properties,
349 MotionFlags::empty(),
350 )
351 .is_ok());
352 }
353
354 #[test]
Siarhei Vishniakouae08b5e2023-10-19 18:58:07 -0700355 fn two_pointer_stream() {
356 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
357 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
358 assert!(verifier
359 .process_movement(
360 DeviceId(1),
361 Source::Touchscreen,
362 input_bindgen::AMOTION_EVENT_ACTION_DOWN,
363 &pointer_properties,
364 MotionFlags::empty(),
365 )
366 .is_ok());
367 // POINTER 1 DOWN
368 let two_pointer_properties =
369 Vec::from([RustPointerProperties { id: 0 }, RustPointerProperties { id: 1 }]);
370 assert!(verifier
371 .process_movement(
372 DeviceId(1),
373 Source::Touchscreen,
374 input_bindgen::AMOTION_EVENT_ACTION_POINTER_DOWN
375 | (1 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
376 &two_pointer_properties,
377 MotionFlags::empty(),
378 )
379 .is_ok());
380 // POINTER 0 UP
381 assert!(verifier
382 .process_movement(
383 DeviceId(1),
384 Source::Touchscreen,
385 input_bindgen::AMOTION_EVENT_ACTION_POINTER_UP
386 | (0 << input_bindgen::AMOTION_EVENT_ACTION_POINTER_INDEX_SHIFT),
387 &two_pointer_properties,
388 MotionFlags::empty(),
389 )
390 .is_ok());
391 // ACTION_UP for pointer id=1
392 let pointer_1_properties = Vec::from([RustPointerProperties { id: 1 }]);
393 assert!(verifier
394 .process_movement(
395 DeviceId(1),
396 Source::Touchscreen,
397 input_bindgen::AMOTION_EVENT_ACTION_UP,
398 &pointer_1_properties,
399 MotionFlags::empty(),
400 )
401 .is_ok());
402 }
403
404 #[test]
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000405 fn multi_device_stream() {
406 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
407 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
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_DOWN,
413 &pointer_properties,
414 MotionFlags::empty(),
415 )
416 .is_ok());
417 assert!(verifier
418 .process_movement(
419 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700420 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000421 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
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_DOWN,
431 &pointer_properties,
432 MotionFlags::empty(),
433 )
434 .is_ok());
435 assert!(verifier
436 .process_movement(
437 DeviceId(2),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700438 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000439 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
440 &pointer_properties,
441 MotionFlags::empty(),
442 )
443 .is_ok());
444 assert!(verifier
445 .process_movement(
446 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700447 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000448 input_bindgen::AMOTION_EVENT_ACTION_UP,
449 &pointer_properties,
450 MotionFlags::empty(),
451 )
452 .is_ok());
453 }
454
455 #[test]
Siarhei Vishniakoue65fa752023-06-28 14:09:09 -0700456 fn action_cancel() {
457 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
458 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
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_DOWN,
464 &pointer_properties,
465 MotionFlags::empty(),
466 )
467 .is_ok());
468 assert!(verifier
469 .process_movement(
470 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700471 Source::Touchscreen,
Siarhei Vishniakoue65fa752023-06-28 14:09:09 -0700472 input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
473 &pointer_properties,
474 MotionFlags::CANCELED,
475 )
476 .is_ok());
477 }
478
479 #[test]
480 fn invalid_action_cancel() {
481 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
482 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
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_DOWN,
488 &pointer_properties,
489 MotionFlags::empty(),
490 )
491 .is_ok());
492 assert!(verifier
493 .process_movement(
494 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700495 Source::Touchscreen,
Siarhei Vishniakoue65fa752023-06-28 14:09:09 -0700496 input_bindgen::AMOTION_EVENT_ACTION_CANCEL,
497 &pointer_properties,
498 MotionFlags::empty(), // forgot to set FLAG_CANCELED
499 )
500 .is_err());
501 }
502
503 #[test]
504 fn invalid_up() {
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000505 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
506 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
507 assert!(verifier
508 .process_movement(
509 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700510 Source::Touchscreen,
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000511 input_bindgen::AMOTION_EVENT_ACTION_UP,
512 &pointer_properties,
513 MotionFlags::empty(),
514 )
515 .is_err());
516 }
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700517
518 #[test]
519 fn correct_hover_sequence() {
520 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
521 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
522 assert!(verifier
523 .process_movement(
524 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700525 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700526 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
527 &pointer_properties,
528 MotionFlags::empty(),
529 )
530 .is_ok());
531
532 assert!(verifier
533 .process_movement(
534 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700535 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700536 input_bindgen::AMOTION_EVENT_ACTION_HOVER_MOVE,
537 &pointer_properties,
538 MotionFlags::empty(),
539 )
540 .is_ok());
541
542 assert!(verifier
543 .process_movement(
544 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700545 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700546 input_bindgen::AMOTION_EVENT_ACTION_HOVER_EXIT,
547 &pointer_properties,
548 MotionFlags::empty(),
549 )
550 .is_ok());
551
552 assert!(verifier
553 .process_movement(
554 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700555 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700556 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
557 &pointer_properties,
558 MotionFlags::empty(),
559 )
560 .is_ok());
561 }
562
563 #[test]
564 fn double_hover_enter() {
565 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
566 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
567 assert!(verifier
568 .process_movement(
569 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700570 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700571 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
572 &pointer_properties,
573 MotionFlags::empty(),
574 )
575 .is_ok());
576
577 assert!(verifier
578 .process_movement(
579 DeviceId(1),
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700580 Source::Touchscreen,
Siarhei Vishniakou1160ecd2023-06-28 15:57:47 -0700581 input_bindgen::AMOTION_EVENT_ACTION_HOVER_ENTER,
582 &pointer_properties,
583 MotionFlags::empty(),
584 )
585 .is_err());
586 }
Siarhei Vishniakou2d151ac2023-09-19 13:30:24 -0700587
588 // Send a MOVE without a preceding DOWN event. This is OK because it's from source
589 // MOUSE_RELATIVE, which is used during pointer capture. The verifier should allow such event.
590 #[test]
591 fn relative_mouse_move() {
592 let mut verifier = InputVerifier::new("Test", /*should_log*/ false);
593 let pointer_properties = Vec::from([RustPointerProperties { id: 0 }]);
594 assert!(verifier
595 .process_movement(
596 DeviceId(2),
597 Source::MouseRelative,
598 input_bindgen::AMOTION_EVENT_ACTION_MOVE,
599 &pointer_properties,
600 MotionFlags::empty(),
601 )
602 .is_ok());
603 }
Prabir Pradhan0762b1f2023-06-22 23:08:18 +0000604}