1use fidl_fuchsia_input_report as fir;
6use starnix_logging::log_warn;
7use starnix_types::time::time_from_timeval;
8use starnix_uapi::errors::Errno;
9use starnix_uapi::{error, uapi};
10use std::collections::{HashMap, HashSet};
11
12type SlotId = usize;
13type TrackingId = u32;
14
15const LIFTED_TRACKING_ID: i32 = -1;
17
18enum MtPosition {
20 X(i64),
21 Y(i64),
22}
23
24#[derive(Debug, Default, PartialEq)]
47pub struct LinuxTouchEventParser {
48 slot_id_to_tracking_id: HashMap<SlotId, TrackingId>,
51 slot_id_to_contact: HashMap<SlotId, fir::ContactInputReport>,
53
54 cached_events: Vec<uapi::input_event>,
56
57 current_slot_id: Option<SlotId>,
62 processed_slots: HashSet<SlotId>,
65
66 single_pointer_sequence: bool,
69}
70
71impl LinuxTouchEventParser {
72 pub fn create() -> Self {
74 Self {
75 slot_id_to_tracking_id: HashMap::new(),
76 slot_id_to_contact: HashMap::new(),
77 cached_events: vec![],
78 current_slot_id: None,
79 processed_slots: HashSet::new(),
80 single_pointer_sequence: false,
81 }
82 }
83
84 fn reset_state(&mut self) {
86 self.cached_events = vec![];
87 self.slot_id_to_tracking_id = HashMap::new();
88 self.slot_id_to_contact = HashMap::new();
89
90 self.reset_sequence_state();
91 }
92
93 fn reset_sequence_state(&mut self) {
95 self.current_slot_id = None;
96 self.processed_slots = HashSet::new();
97 self.single_pointer_sequence = false;
98 }
99
100 fn mt_slot(&mut self, new_slot_id: SlotId) -> Result<(), Errno> {
110 if self.single_pointer_sequence {
111 log_warn!("sequence contains events in slot and out of slot");
112 self.reset_state();
113 return error!(EINVAL);
114 }
115
116 if self.processed_slots.contains(&new_slot_id) {
117 log_warn!("duplicated slot_id in one sequence, slot_id = {}", new_slot_id);
118 self.reset_state();
119 return error!(EINVAL);
120 }
121
122 self.processed_slots.insert(new_slot_id);
123 self.current_slot_id = Some(new_slot_id);
124
125 self.slot_id_to_contact.entry(new_slot_id).or_insert_with(|| fir::ContactInputReport {
126 contact_id: Some(new_slot_id as u32),
127 ..fir::ContactInputReport::default()
128 });
129
130 Ok(())
131 }
132
133 fn get_current_slot_id_or_err(&mut self, curr_event: &str) -> Result<SlotId, Errno> {
137 match self.current_slot_id {
138 Some(slot_id) => Ok(slot_id),
139 None => {
140 log_warn!(
141 "{:?} is not following ABS_MT_SLOT, fallback to single_pointer_sequence",
142 curr_event
143 );
144 let res = self.mt_slot(0);
145 match res {
146 Ok(_) => {
147 self.single_pointer_sequence = true;
148 Ok(0)
149 }
150 Err(e) => Err(e),
151 }
152 }
153 }
154 }
155
156 fn mt_tracking_id(&mut self, tracking_id: i32) -> Result<(), Errno> {
168 let slot_id = self.get_current_slot_id_or_err("ABS_MT_TRACKING_ID")?;
169
170 if tracking_id < LIFTED_TRACKING_ID {
171 log_warn!("invalid TRACKING_ID {}", tracking_id);
173 self.reset_state();
174 return error!(EINVAL);
175 }
176
177 if tracking_id == LIFTED_TRACKING_ID {
178 self.slot_id_to_tracking_id.remove(&slot_id);
179 self.slot_id_to_contact.remove(&slot_id);
180
181 return Ok(());
182 }
183
184 let tid = tracking_id as TrackingId;
186 match self.slot_id_to_tracking_id.get(&slot_id) {
187 Some(id) => {
188 if tid != *id {
189 log_warn!(
190 "TRACKING_ID changed form {} to {} for unknown reason for slot {}",
191 *id,
192 tid,
193 slot_id
194 );
195 self.reset_state();
196 return error!(EINVAL);
197 }
198 }
199 None => {
200 self.slot_id_to_tracking_id.insert(slot_id, tid);
201 }
202 }
203
204 Ok(())
205 }
206
207 fn mt_position_x_y(&mut self, mt_position: MtPosition) -> Result<(), Errno> {
211 let ty = match mt_position {
212 MtPosition::X(_) => "ABS_MT_POSITION_X",
213 MtPosition::Y(_) => "ABS_MT_POSITION_Y",
214 };
215 let slot_id = self.get_current_slot_id_or_err(ty)?;
216
217 match self.slot_id_to_contact.get_mut(&slot_id) {
218 Some(contact) => {
219 match mt_position {
220 MtPosition::X(x) => {
221 contact.position_x = Some(x);
222 }
223 MtPosition::Y(y) => {
224 contact.position_y = Some(y);
225 }
226 }
227 Ok(())
228 }
229 None => {
230 log_warn!("current_contact is None when set position");
231 self.reset_state();
232 return error!(EINVAL);
233 }
234 }
235 }
236
237 fn produce_input_report(
238 &mut self,
239 event_time: zx::MonotonicInstant,
240 ) -> Result<Option<fir::InputReport>, Errno> {
241 self.reset_sequence_state();
242
243 let cached_events = std::mem::take(&mut self.cached_events);
244
245 for e in cached_events {
246 match e.code as u32 {
247 uapi::ABS_MT_SLOT => {
248 let slot_id = e.value as SlotId;
249 self.mt_slot(slot_id)?;
250 }
251 uapi::ABS_MT_TRACKING_ID => {
252 self.mt_tracking_id(e.value)?;
253 }
254 uapi::ABS_MT_POSITION_X => {
255 self.mt_position_x_y(MtPosition::X(e.value as i64))?;
256 }
257 uapi::ABS_MT_POSITION_Y => {
258 self.mt_position_x_y(MtPosition::Y(e.value as i64))?;
259 }
260 _ => {
261 unreachable!();
263 }
264 }
265 }
266
267 let mut contacts: Vec<fir::ContactInputReport> = vec![];
268 for contact in self.slot_id_to_contact.values() {
269 if validate_contact_input_report(contact) {
270 contacts.push(contact.clone());
271 } else {
272 log_warn!(
273 "current contact does not have required information, current_contact = {:?}",
274 contact
275 );
276 self.reset_state();
277 return error!(EINVAL);
278 }
279 }
280
281 contacts.sort_by(|a, b| a.contact_id.unwrap().cmp(&b.contact_id.unwrap()));
283
284 let res = Ok(Some(fir::InputReport {
285 event_time: Some(event_time.into_nanos()),
286 touch: Some(fir::TouchInputReport { contacts: Some(contacts), ..Default::default() }),
287 ..Default::default()
288 }));
289
290 self.reset_sequence_state();
291
292 res
293 }
294
295 pub fn handle(&mut self, e: uapi::input_event) -> Result<Option<fir::InputReport>, Errno> {
297 let event_code = e.code as u32;
298 match e.type_ as u32 {
299 uapi::EV_SYN => match event_code {
300 uapi::SYN_REPORT => self.produce_input_report(time_from_timeval(e.time)?),
301 uapi::SYN_MT_REPORT => {
302 log_warn!("Touchscreen got 'Type A' event SYN_MT_REPORT");
303 self.reset_state();
304 error!(EINVAL)
305 }
306 _ => {
307 log_warn!("Touchscreen got unexpected EV_SYN, event = {:?}", e);
308 self.reset_state();
309 error!(EINVAL)
310 }
311 },
312 uapi::EV_ABS => match event_code {
313 uapi::ABS_MT_SLOT
314 | uapi::ABS_MT_TRACKING_ID
315 | uapi::ABS_MT_POSITION_X
316 | uapi::ABS_MT_POSITION_Y => {
317 self.cached_events.push(e);
318 Ok(None)
319 }
320 uapi::ABS_MT_TOUCH_MAJOR
321 | uapi::ABS_MT_TOUCH_MINOR
322 | uapi::ABS_MT_WIDTH_MAJOR
323 | uapi::ABS_MT_WIDTH_MINOR
324 | uapi::ABS_MT_ORIENTATION
325 | uapi::ABS_MT_TOOL_TYPE
326 | uapi::ABS_MT_BLOB_ID
327 | uapi::ABS_MT_PRESSURE
328 | uapi::ABS_MT_DISTANCE
329 | uapi::ABS_MT_TOOL_X
330 | uapi::ABS_MT_TOOL_Y => {
331 Ok(None)
333 }
334 _ => {
335 log_warn!("Touchscreen got unexpected EV_ABS, event = {:?}", e);
336 self.reset_state();
337 error!(EINVAL)
338 }
339 },
340 uapi::EV_KEY => {
341 match event_code {
342 uapi::BTN_TOUCH => Ok(None),
344 _ => {
345 log_warn!("Touchscreen got unexpected EV_KEY, event = {:?}", e);
346 self.reset_state();
347 error!(EINVAL)
348 }
349 }
350 }
351 _ => {
352 log_warn!("Touchscreen got unexpected event type, got = {:?}", e);
353 self.reset_state();
354 error!(EINVAL)
355 }
356 }
357 }
358}
359
360fn validate_contact_input_report(c: &fir::ContactInputReport) -> bool {
362 match c {
363 &fir::ContactInputReport {
364 contact_id: Some(_),
365 position_x: Some(_),
366 position_y: Some(_),
367 ..
368 } => true,
369 _ => false,
370 }
371}
372
373#[cfg(test)]
374mod touchscreen_linux_fuchsia_tests {
375 use super::*;
376 use pretty_assertions::assert_eq;
377 use test_case::test_case;
378 use uapi::timeval;
379
380 fn input_event(ty: u32, code: u32, value: i32) -> uapi::input_event {
381 uapi::input_event { time: timeval::default(), type_: ty as u16, code: code as u16, value }
382 }
383
384 #[test]
385 fn handle_btn_touch_ok_does_not_produce_input_report() {
386 let e = input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1);
387 let mut parser = LinuxTouchEventParser::create();
388 assert_eq!(parser.handle(e), Ok(None));
389 assert_eq!(parser, LinuxTouchEventParser::default());
390 }
391
392 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1); "ABS_MT_SLOT")]
393 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1); "ABS_MT_TRACKING_ID")]
394 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 1); "ABS_MT_POSITION_X")]
395 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 1); "ABS_MT_POSITION_Y")]
396 fn handle_input_event_ok_does_not_produce_input_report(e: uapi::input_event) {
397 let mut parser = LinuxTouchEventParser::create();
398 assert_eq!(parser.handle(e), Ok(None));
399 assert_eq!(
400 parser,
401 LinuxTouchEventParser {
402 cached_events: vec![e],
403 slot_id_to_tracking_id: HashMap::new(),
404 ..LinuxTouchEventParser::default()
405 }
406 );
407 }
408
409 #[test_case(input_event(uapi::EV_KEY, uapi::KEY_A, 1); "unsupported keycode")]
410 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_PRESSURE, 1); "unsupported ABS event")]
411 #[test_case(input_event(uapi::EV_SYN, uapi::SYN_MT_REPORT, 1); "Type A")]
412 #[test_case(input_event(uapi::EV_SYN, uapi::SYN_CONFIG, 1); "unsupported SYN event")]
413 fn handle_input_event_error(e: uapi::input_event) {
414 let mut parser = LinuxTouchEventParser::create();
415 assert_eq!(parser.handle(e), error!(EINVAL));
416 assert_eq!(parser, LinuxTouchEventParser::default());
417 }
418
419 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_TOUCH_MAJOR, 1); "ignore ABS_MT_TOUCH_MAJOR event")]
420 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_TOUCH_MINOR, 1); "ignore ABS_MT_TOUCH_MINOR event")]
421 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_WIDTH_MAJOR, 1); "ignore ABS_MT_WIDTH_MAJOR event")]
422 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_WIDTH_MINOR, 1); "ignore ABS_MT_WIDTH_MINOR event")]
423 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_ORIENTATION, 1); "ignore ABS_MT_ORIENTATION event")]
424 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_TOOL_TYPE, 1); "ignore ABS_MT_TOOL_TYPE event")]
425 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_BLOB_ID, 1); "ignore ABS_MT_BLOB_ID event")]
426 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_PRESSURE, 1); "ignore ABS_MT_PRESSURE event")]
427 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_DISTANCE, 1); "ignore ABS_MT_DISTANCE event")]
428 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_TOOL_X, 1); "ignore ABS_MT_TOOL_X event")]
429 #[test_case(input_event(uapi::EV_ABS, uapi::ABS_MT_TOOL_Y , 1); "ignore ABS_MT_TOOL_Y event")]
430 fn handle_input_event_ignore(e: uapi::input_event) {
431 let mut parser = LinuxTouchEventParser::create();
432 assert_eq!(parser.handle(e), Ok(None));
433 assert_eq!(parser, LinuxTouchEventParser::default());
434 }
435
436 #[test]
437 fn no_slot_leading_event_fallback_to_single_pointer_mode() {
438 let syn = input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
439
440 let mut parser = LinuxTouchEventParser::create();
441 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1)), Ok(None));
442 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 2)), Ok(None));
443 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 3)), Ok(None));
444 assert_eq!(
445 parser.handle(syn),
446 Ok(Some(fir::InputReport {
447 event_time: Some(0),
448 touch: Some(fir::TouchInputReport {
449 contacts: Some(vec![fir::ContactInputReport {
450 contact_id: Some(0),
451 position_x: Some(2),
452 position_y: Some(3),
453 ..fir::ContactInputReport::default()
454 },]),
455 ..fir::TouchInputReport::default()
456 }),
457 ..fir::InputReport::default()
458 }))
459 );
460 assert_eq!(
461 parser,
462 LinuxTouchEventParser {
463 cached_events: vec![],
464 slot_id_to_tracking_id: HashMap::from([(0, 1)]),
465 slot_id_to_contact: HashMap::from([(
466 0,
467 fir::ContactInputReport {
468 contact_id: Some(0),
469 position_x: Some(2),
470 position_y: Some(3),
471 ..fir::ContactInputReport::default()
472 }
473 )]),
474 ..LinuxTouchEventParser::default()
475 }
476 );
477 }
478
479 #[test]
480 fn single_pointer_mode_slot_does_not_have_enough_information() {
481 let syn = input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
482
483 let mut parser = LinuxTouchEventParser::create();
484 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1)), Ok(None));
485 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 2)), Ok(None));
486 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 3)), Ok(None));
487 assert_eq!(
488 parser.handle(syn),
489 Ok(Some(fir::InputReport {
490 event_time: Some(0),
491 touch: Some(fir::TouchInputReport {
492 contacts: Some(vec![fir::ContactInputReport {
493 contact_id: Some(0),
494 position_x: Some(2),
495 position_y: Some(3),
496 ..fir::ContactInputReport::default()
497 },]),
498 ..fir::TouchInputReport::default()
499 }),
500 ..fir::InputReport::default()
501 }))
502 );
503 assert_eq!(
504 parser,
505 LinuxTouchEventParser {
506 cached_events: vec![],
507 slot_id_to_tracking_id: HashMap::from([(0, 1)]),
508 slot_id_to_contact: HashMap::from([(
509 0,
510 fir::ContactInputReport {
511 contact_id: Some(0),
512 position_x: Some(2),
513 position_y: Some(3),
514 ..fir::ContactInputReport::default()
515 }
516 )]),
517 ..LinuxTouchEventParser::default()
518 }
519 );
520
521 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 4)), Ok(None));
523 assert_eq!(
524 parser.handle(syn),
525 Ok(Some(fir::InputReport {
526 event_time: Some(0),
527 touch: Some(fir::TouchInputReport {
528 contacts: Some(vec![fir::ContactInputReport {
529 contact_id: Some(0),
530 position_x: Some(2),
531 position_y: Some(4),
532 ..fir::ContactInputReport::default()
533 },]),
534 ..fir::TouchInputReport::default()
535 }),
536 ..fir::InputReport::default()
537 }))
538 );
539 assert_eq!(
540 parser,
541 LinuxTouchEventParser {
542 cached_events: vec![],
543 slot_id_to_tracking_id: HashMap::from([(0, 1)]),
544 slot_id_to_contact: HashMap::from([(
545 0,
546 fir::ContactInputReport {
547 contact_id: Some(0),
548 position_x: Some(2),
549 position_y: Some(4),
550 ..fir::ContactInputReport::default()
551 }
552 )]),
553 ..LinuxTouchEventParser::default()
554 }
555 );
556
557 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_PRESSURE, 10)), Ok(None));
559 assert_eq!(
560 parser.handle(syn),
561 Ok(Some(fir::InputReport {
562 event_time: Some(0),
563 touch: Some(fir::TouchInputReport {
564 contacts: Some(vec![fir::ContactInputReport {
565 contact_id: Some(0),
566 position_x: Some(2),
567 position_y: Some(4),
568 ..fir::ContactInputReport::default()
569 },]),
570 ..fir::TouchInputReport::default()
571 }),
572 ..fir::InputReport::default()
573 }))
574 );
575 assert_eq!(
576 parser,
577 LinuxTouchEventParser {
578 cached_events: vec![],
579 slot_id_to_tracking_id: HashMap::from([(0, 1)]),
580 slot_id_to_contact: HashMap::from([(
581 0,
582 fir::ContactInputReport {
583 contact_id: Some(0),
584 position_x: Some(2),
585 position_y: Some(4),
586 ..fir::ContactInputReport::default()
587 }
588 )]),
589 ..LinuxTouchEventParser::default()
590 }
591 );
592 }
593
594 #[test]
595 fn slot_has_only_pressure_event() {
596 let slot_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0);
597 let syn = input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
598
599 let mut parser = LinuxTouchEventParser::create();
600 assert_eq!(parser.handle(slot_0), Ok(None));
601 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1)), Ok(None));
602 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 2)), Ok(None));
603 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 3)), Ok(None));
604 assert_eq!(
605 parser.handle(syn),
606 Ok(Some(fir::InputReport {
607 event_time: Some(0),
608 touch: Some(fir::TouchInputReport {
609 contacts: Some(vec![fir::ContactInputReport {
610 contact_id: Some(0),
611 position_x: Some(2),
612 position_y: Some(3),
613 ..fir::ContactInputReport::default()
614 },]),
615 ..fir::TouchInputReport::default()
616 }),
617 ..fir::InputReport::default()
618 }))
619 );
620 assert_eq!(
621 parser,
622 LinuxTouchEventParser {
623 cached_events: vec![],
624 slot_id_to_tracking_id: HashMap::from([(0, 1)]),
625 slot_id_to_contact: HashMap::from([(
626 0,
627 fir::ContactInputReport {
628 contact_id: Some(0),
629 position_x: Some(2),
630 position_y: Some(3),
631 ..fir::ContactInputReport::default()
632 }
633 )]),
634 ..LinuxTouchEventParser::default()
635 }
636 );
637
638 assert_eq!(parser.handle(slot_0), Ok(None));
640 assert_eq!(parser.handle(input_event(uapi::EV_ABS, uapi::ABS_MT_PRESSURE, 10)), Ok(None));
641 assert_eq!(
642 parser.handle(syn),
643 Ok(Some(fir::InputReport {
644 event_time: Some(0),
645 touch: Some(fir::TouchInputReport {
646 contacts: Some(vec![fir::ContactInputReport {
647 contact_id: Some(0),
648 position_x: Some(2),
649 position_y: Some(3),
650 ..fir::ContactInputReport::default()
651 },]),
652 ..fir::TouchInputReport::default()
653 }),
654 ..fir::InputReport::default()
655 }))
656 );
657 assert_eq!(
658 parser,
659 LinuxTouchEventParser {
660 cached_events: vec![],
661 slot_id_to_tracking_id: HashMap::from([(0, 1)]),
662 slot_id_to_contact: HashMap::from([(
663 0,
664 fir::ContactInputReport {
665 contact_id: Some(0),
666 position_x: Some(2),
667 position_y: Some(3),
668 ..fir::ContactInputReport::default()
669 }
670 )]),
671 ..LinuxTouchEventParser::default()
672 }
673 );
674 }
675
676 #[test]
677 fn slot_does_not_have_enough_information() {
678 let slot_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0);
679 let syn = input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
680
681 let mut parser = LinuxTouchEventParser::create();
682
683 assert_eq!(parser.handle(slot_0), Ok(None));
685 assert_eq!(parser.handle(syn), error!(EINVAL));
686 assert_eq!(parser, LinuxTouchEventParser::default());
687
688 let slot_1 = input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1);
690 assert_eq!(parser.handle(slot_0), Ok(None));
691 assert_eq!(parser.handle(slot_1), Ok(None));
692 assert_eq!(parser.handle(syn), error!(EINVAL));
693 assert_eq!(parser, LinuxTouchEventParser::default());
694 }
695
696 #[test]
697 fn same_slot_id_in_one_event() {
698 let slot_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0);
699 let traking_id = input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 0);
700 let x = input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 0);
701 let y = input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 0);
702 let syn = input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
703
704 let mut parser = LinuxTouchEventParser::create();
705 assert_eq!(parser.handle(slot_0), Ok(None));
706 assert_eq!(parser.handle(traking_id), Ok(None));
707 assert_eq!(parser.handle(x), Ok(None));
708 assert_eq!(parser.handle(y), Ok(None));
709 assert_eq!(parser.handle(slot_0), Ok(None));
710 assert_eq!(parser.handle(syn), error!(EINVAL));
711 assert_eq!(parser, LinuxTouchEventParser::default());
712 }
713
714 #[test]
715 fn tracking_id_changed_in_slot() {
716 let slot_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0);
717 let traking_id_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 0);
718 let traking_id_1 = input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1);
719 let syn = input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
720
721 let mut parser = LinuxTouchEventParser::create();
722 assert_eq!(parser.handle(slot_0), Ok(None));
723 assert_eq!(parser.handle(traking_id_0), Ok(None));
724 assert_eq!(parser.handle(traking_id_1), Ok(None));
725 assert_eq!(parser.handle(syn), error!(EINVAL));
726 assert_eq!(parser, LinuxTouchEventParser::default());
727 }
728
729 #[test]
730 fn tracking_id_different_with_parser_recorded() {
731 let slot_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0);
732 let traking_id_1 = input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1);
733 let syn = input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
734
735 let mut parser = LinuxTouchEventParser::create();
736 parser.slot_id_to_tracking_id.insert(0, 0);
737 assert_eq!(parser.handle(slot_0), Ok(None));
738 assert_eq!(parser.handle(traking_id_1), Ok(None));
739 assert_eq!(parser.handle(syn), error!(EINVAL));
740 assert_eq!(parser, LinuxTouchEventParser::default());
741 }
742
743 #[test]
744 fn produce_input_report() {
745 let slot_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0);
747 let traking_id_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1);
748 let x_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 2);
749 let y_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 3);
750 let syn = input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0);
751
752 let mut parser = LinuxTouchEventParser::create();
753 assert_eq!(parser.handle(slot_0), Ok(None));
754 assert_eq!(parser.handle(traking_id_0), Ok(None));
755 assert_eq!(parser.handle(x_0), Ok(None));
756 assert_eq!(parser.handle(y_0), Ok(None));
757 assert_eq!(
758 parser.handle(syn),
759 Ok(Some(fir::InputReport {
760 event_time: Some(0),
761 touch: Some(fir::TouchInputReport {
762 contacts: Some(vec![fir::ContactInputReport {
763 contact_id: Some(0),
764 position_x: Some(2),
765 position_y: Some(3),
766 ..fir::ContactInputReport::default()
767 },]),
768 ..fir::TouchInputReport::default()
769 }),
770 ..fir::InputReport::default()
771 }))
772 );
773 assert_eq!(
774 parser,
775 LinuxTouchEventParser {
776 cached_events: vec![],
777 slot_id_to_tracking_id: HashMap::from([(0, 1)]),
778 slot_id_to_contact: HashMap::from([(
779 0,
780 fir::ContactInputReport {
781 contact_id: Some(0),
782 position_x: Some(2),
783 position_y: Some(3),
784 ..fir::ContactInputReport::default()
785 }
786 )]),
787 ..LinuxTouchEventParser::default()
788 }
789 );
790
791 let x_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 4);
793 let y_0 = input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 5);
794
795 let slot_1 = input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1);
796 let traking_id_1 = input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 2);
797 let x_1 = input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10);
798 let y_1 = input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 11);
799
800 assert_eq!(parser.handle(slot_0), Ok(None));
801 assert_eq!(parser.handle(x_0), Ok(None));
802 assert_eq!(parser.handle(y_0), Ok(None));
803 assert_eq!(parser.handle(slot_1), Ok(None));
804 assert_eq!(parser.handle(traking_id_1), Ok(None));
805 assert_eq!(parser.handle(x_1), Ok(None));
806 assert_eq!(parser.handle(y_1), Ok(None));
807 assert_eq!(
808 parser.handle(syn),
809 Ok(Some(fir::InputReport {
810 event_time: Some(0),
811 touch: Some(fir::TouchInputReport {
812 contacts: Some(vec![
813 fir::ContactInputReport {
814 contact_id: Some(0),
815 position_x: Some(4),
816 position_y: Some(5),
817 ..fir::ContactInputReport::default()
818 },
819 fir::ContactInputReport {
820 contact_id: Some(1),
821 position_x: Some(10),
822 position_y: Some(11),
823 ..fir::ContactInputReport::default()
824 },
825 ]),
826 ..fir::TouchInputReport::default()
827 }),
828 ..fir::InputReport::default()
829 }))
830 );
831 assert_eq!(
832 parser,
833 LinuxTouchEventParser {
834 cached_events: vec![],
835 slot_id_to_tracking_id: HashMap::from([(0, 1), (1, 2)]),
836 slot_id_to_contact: HashMap::from([
837 (
838 0,
839 fir::ContactInputReport {
840 contact_id: Some(0),
841 position_x: Some(4),
842 position_y: Some(5),
843 ..fir::ContactInputReport::default()
844 }
845 ),
846 (
847 1,
848 fir::ContactInputReport {
849 contact_id: Some(1),
850 position_x: Some(10),
851 position_y: Some(11),
852 ..fir::ContactInputReport::default()
853 }
854 )
855 ]),
856 ..LinuxTouchEventParser::default()
857 }
858 );
859
860 let tracking_id_lifted = input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, -1);
862
863 assert_eq!(parser.handle(slot_0), Ok(None));
864 assert_eq!(parser.handle(tracking_id_lifted), Ok(None));
865 assert_eq!(parser.handle(slot_1), Ok(None));
866 assert_eq!(parser.handle(x_1), Ok(None));
867 assert_eq!(parser.handle(y_1), Ok(None));
868 assert_eq!(
869 parser.handle(syn),
870 Ok(Some(fir::InputReport {
871 event_time: Some(0),
872 touch: Some(fir::TouchInputReport {
873 contacts: Some(vec![fir::ContactInputReport {
874 contact_id: Some(1),
875 position_x: Some(10),
876 position_y: Some(11),
877 ..fir::ContactInputReport::default()
878 },]),
879 ..fir::TouchInputReport::default()
880 }),
881 ..fir::InputReport::default()
882 }))
883 );
884 assert_eq!(
886 parser,
887 LinuxTouchEventParser {
888 cached_events: vec![],
889 slot_id_to_tracking_id: HashMap::from([(1, 2)]),
890 slot_id_to_contact: HashMap::from([(
891 1,
892 fir::ContactInputReport {
893 contact_id: Some(1),
894 position_x: Some(10),
895 position_y: Some(11),
896 ..fir::ContactInputReport::default()
897 }
898 )]),
899 ..LinuxTouchEventParser::default()
900 }
901 );
902
903 assert_eq!(parser.handle(slot_1), Ok(None));
905 assert_eq!(parser.handle(tracking_id_lifted), Ok(None));
906 assert_eq!(
907 parser.handle(syn),
908 Ok(Some(fir::InputReport {
909 event_time: Some(0),
910 touch: Some(fir::TouchInputReport {
911 contacts: Some(vec![]),
912 ..fir::TouchInputReport::default()
913 }),
914 ..fir::InputReport::default()
915 }))
916 );
917 assert_eq!(parser, LinuxTouchEventParser::default());
919 }
920}