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