1use fidl_fuchsia_ui_pointer::{
6 EventPhase as FidlEventPhase, TouchEvent as FidlTouchEvent, TouchPointerSample,
7};
8use starnix_logging::log_warn;
9use starnix_types::time::timeval_from_time;
10use starnix_uapi::uapi;
11use std::collections::{BTreeMap, HashMap, VecDeque};
12
13type SlotId = usize;
14type TrackingId = u32;
15type TimeNanos = i64;
16
17const LIFTED_TRACKING_ID: i32 = -1;
19
20#[derive(Debug, thiserror::Error)]
21enum TouchEventConversionError {
22 #[error("Event does not include enough information")]
23 NotEnoughInformation,
24 #[error("no more available slot id")]
25 NoMoreAvailableSlotId,
26 #[error("receive pointer add already added")]
27 PointerAdded,
28 #[error("receive pointer change/remove before added")]
29 PointerNotFound,
30 #[error("Input pipeline does not send out Cancel")]
31 PointerCancel,
32}
33
34#[derive(Debug, Clone, PartialEq)]
35struct TouchEvent {
36 time_nanos: TimeNanos,
37 pointer_id: TrackingId,
38 phase: FidlEventPhase,
39 x: i32,
40 y: i32,
41}
42
43impl TryFrom<FidlTouchEvent> for TouchEvent {
44 type Error = TouchEventConversionError;
45 fn try_from(e: FidlTouchEvent) -> Result<TouchEvent, Self::Error> {
46 match e {
47 FidlTouchEvent {
48 timestamp: Some(time_nanos),
49 pointer_sample:
50 Some(TouchPointerSample {
51 position_in_viewport: Some([x, y]),
52 phase: Some(phase),
53 interaction: Some(id),
54 ..
55 }),
56 ..
57 } => Ok(TouchEvent {
58 time_nanos,
59 pointer_id: id.pointer_id,
60 phase,
61 x: x as i32,
62 y: y as i32,
63 }),
64 _ => Err(TouchEventConversionError::NotEnoughInformation),
65 }
66 }
67}
68
69#[derive(Debug, Default, PartialEq)]
72pub struct FuchsiaTouchEventToLinuxTouchEventConverter {
73 pointer_id_to_slot_id: HashMap<TrackingId, SlotId>,
74 pointer_id_to_event: HashMap<TrackingId, TouchEvent>,
75}
76
77const MAX_TOUCH_CONTACT: usize = 10;
78
79pub struct LinuxTouchEventBatch {
80 pub events: VecDeque<uapi::input_event>,
82 pub last_event_time_ns: i64,
83 pub count_converted_fidl_events: u64,
84 pub count_ignored_fidl_events: u64,
85 pub count_unexpected_fidl_events: u64,
86}
87
88impl LinuxTouchEventBatch {
89 pub fn new() -> Self {
90 Self {
91 events: VecDeque::new(),
92 last_event_time_ns: 0,
93 count_converted_fidl_events: 0,
94 count_ignored_fidl_events: 0,
95 count_unexpected_fidl_events: 0,
96 }
97 }
98}
99
100impl FuchsiaTouchEventToLinuxTouchEventConverter {
101 pub fn create() -> Self {
102 Self { pointer_id_to_slot_id: HashMap::new(), pointer_id_to_event: HashMap::new() }
103 }
104
105 fn available_slot_id(&self) -> Option<SlotId> {
108 let mut used_slot_ids = bit_vec::BitVec::<u32>::from_elem(MAX_TOUCH_CONTACT, false);
109 for slot_id in self.pointer_id_to_slot_id.values() {
110 used_slot_ids.set(*slot_id, true);
111 }
112
113 used_slot_ids.iter().position(|used| !used)
114 }
115
116 pub fn handle(&mut self, events: Vec<FidlTouchEvent>) -> LinuxTouchEventBatch {
124 let mut batch = LinuxTouchEventBatch::new();
125
126 let mut sequences: BTreeMap<TimeNanos, Vec<TouchEvent>> = BTreeMap::new();
129 for event in events.into_iter() {
130 match TouchEvent::try_from(event) {
131 Ok(e) => {
132 sequences.entry(e.time_nanos).or_default().push(e);
133 }
134 Err(_) => {
135 batch.count_ignored_fidl_events += 1;
136 }
137 }
138 }
139
140 if sequences.is_empty() {
141 return batch;
142 }
143
144 batch.last_event_time_ns = *sequences.last_key_value().unwrap().0;
145
146 for (time_nanos, seq) in sequences.iter() {
147 let count_events = seq.len() as u64;
148 match self.translate_sequence(*time_nanos, seq) {
149 Ok(mut res) => {
150 batch.events.append(&mut res);
151 batch.count_converted_fidl_events += count_events;
152 }
153 Err(e) => {
154 batch.count_unexpected_fidl_events += count_events;
155 self.reset_state();
156 log_warn!("{}", e);
157 }
158 }
159 }
160
161 batch
162 }
163
164 fn translate_sequence(
172 &mut self,
173 time_nanos: TimeNanos,
174 events: &Vec<TouchEvent>,
175 ) -> Result<VecDeque<uapi::input_event>, TouchEventConversionError> {
176 let mut existing_slot: VecDeque<uapi::input_event> = VecDeque::new();
177 let mut new_slots: VecDeque<uapi::input_event> = VecDeque::new();
178
179 let time = timeval_from_time(zx::MonotonicInstant::from_nanos(time_nanos));
180
181 let no_contact_before_process_events = self.pointer_id_to_slot_id.is_empty();
182 let mut need_btn_touch_down = false;
183 let mut need_btn_touch_up = false;
184
185 for (index, event) in events.iter().enumerate() {
189 let pointer_id = event.pointer_id;
190 let slot_id = self.pointer_id_to_slot_id.get(&pointer_id).copied();
191 let previous_event = self.pointer_id_to_event.insert(pointer_id, event.clone());
192
193 match event.phase {
194 FidlEventPhase::Add => match (slot_id, previous_event) {
195 (None, None) => {
196 let new_slot_id = match self.available_slot_id() {
197 Some(index) => index,
198 None => {
199 return Err(TouchEventConversionError::NoMoreAvailableSlotId);
200 }
201 };
202
203 if no_contact_before_process_events {
204 need_btn_touch_down = true;
205 }
206
207 self.pointer_id_to_slot_id.insert(pointer_id, new_slot_id);
208
209 new_slots.push_back(uapi::input_event {
210 time,
211 type_: uapi::EV_ABS as u16,
212 code: uapi::ABS_MT_SLOT as u16,
213 value: new_slot_id as i32,
214 });
215
216 new_slots.push_back(uapi::input_event {
217 time,
218 type_: uapi::EV_ABS as u16,
219 code: uapi::ABS_MT_TRACKING_ID as u16,
220 value: pointer_id as i32,
221 });
222
223 new_slots.push_back(uapi::input_event {
224 time,
225 type_: uapi::EV_ABS as u16,
226 code: uapi::ABS_MT_POSITION_X as u16,
227 value: event.x,
228 });
229
230 new_slots.push_back(uapi::input_event {
231 time,
232 type_: uapi::EV_ABS as u16,
233 code: uapi::ABS_MT_POSITION_Y as u16,
234 value: event.y,
235 });
236 }
237 (_, _) => {
238 return Err(TouchEventConversionError::PointerAdded);
239 }
240 },
241 FidlEventPhase::Change => match (slot_id, previous_event) {
242 (Some(slot_id), Some(prev)) => {
243 if prev.x != event.x || prev.y != event.y {
244 existing_slot.push_back(uapi::input_event {
245 time,
246 type_: uapi::EV_ABS as u16,
247 code: uapi::ABS_MT_SLOT as u16,
248 value: slot_id as i32,
249 });
250 }
251
252 if prev.x != event.x {
253 existing_slot.push_back(uapi::input_event {
254 time,
255 type_: uapi::EV_ABS as u16,
256 code: uapi::ABS_MT_POSITION_X as u16,
257 value: event.x,
258 });
259 }
260
261 if prev.y != event.y {
262 existing_slot.push_back(uapi::input_event {
263 time,
264 type_: uapi::EV_ABS as u16,
265 code: uapi::ABS_MT_POSITION_Y as u16,
266 value: event.y,
267 });
268 }
269 }
270 (_, _) => {
271 return Err(TouchEventConversionError::PointerNotFound);
272 }
273 },
274 FidlEventPhase::Remove => match (slot_id, previous_event) {
275 (Some(slot_id), Some(_)) => {
276 self.pointer_id_to_slot_id.remove(&pointer_id);
277 self.pointer_id_to_event.remove(&pointer_id);
278
279 if index == events.len() - 1 && self.pointer_id_to_slot_id.is_empty() {
283 need_btn_touch_up = true;
284 }
285
286 existing_slot.push_back(uapi::input_event {
287 time,
288 type_: uapi::EV_ABS as u16,
289 code: uapi::ABS_MT_SLOT as u16,
290 value: slot_id as i32,
291 });
292
293 existing_slot.push_back(uapi::input_event {
294 time,
295 type_: uapi::EV_ABS as u16,
296 code: uapi::ABS_MT_TRACKING_ID as u16,
297 value: LIFTED_TRACKING_ID,
298 });
299 }
300 (_, _) => {
301 return Err(TouchEventConversionError::PointerNotFound);
302 }
303 },
304 FidlEventPhase::Cancel => {
305 return Err(TouchEventConversionError::PointerCancel);
306 }
307 }
308 }
309
310 let mut result: VecDeque<uapi::input_event> = VecDeque::new();
311
312 result.append(&mut existing_slot);
313 result.append(&mut new_slots);
314
315 if need_btn_touch_down {
316 result.push_back(uapi::input_event {
317 time,
318 type_: uapi::EV_KEY as u16,
319 code: uapi::BTN_TOUCH as u16,
320 value: 1,
321 });
322 } else if need_btn_touch_up {
323 result.push_back(uapi::input_event {
324 time,
325 type_: uapi::EV_KEY as u16,
326 code: uapi::BTN_TOUCH as u16,
327 value: 0,
328 });
329 }
330
331 if result.len() > 0 {
332 result.push_back(uapi::input_event {
333 time,
334 type_: uapi::EV_SYN as u16,
335 code: uapi::SYN_REPORT as u16,
336 value: 0,
337 });
338 }
339
340 Ok(result)
341 }
342
343 fn reset_state(&mut self) {
344 self.pointer_id_to_slot_id = HashMap::new();
345 self.pointer_id_to_event = HashMap::new();
346 }
347}
348
349#[cfg(test)]
350mod touchscreen_fuchsia_linux_tests {
351 use super::*;
352 use fidl_fuchsia_ui_pointer::TouchInteractionId;
353 use pretty_assertions::assert_eq;
354 use test_case::test_case;
355
356 fn make_touch_event_with_coords_phase_id_time(
357 x: f32,
358 y: f32,
359 phase: FidlEventPhase,
360 pointer_id: u32,
361 time_nanos: i64,
362 ) -> FidlTouchEvent {
363 FidlTouchEvent {
364 timestamp: Some(time_nanos),
365 pointer_sample: Some(TouchPointerSample {
366 position_in_viewport: Some([x, y]),
367 phase: Some(phase),
368 interaction: Some(TouchInteractionId {
369 pointer_id,
370 device_id: 0,
371 interaction_id: 0,
372 }),
373 ..Default::default()
374 }),
375 ..Default::default()
376 }
377 }
378
379 fn make_touch_event_with_coords_phase_id(
380 x: f32,
381 y: f32,
382 phase: FidlEventPhase,
383 pointer_id: u32,
384 ) -> FidlTouchEvent {
385 make_touch_event_with_coords_phase_id_time(x, y, phase, pointer_id, 0)
386 }
387
388 fn make_uapi_input_event_with_time(
389 ty: u32,
390 code: u32,
391 value: i32,
392 time_nanos: i64,
393 ) -> uapi::input_event {
394 uapi::input_event {
395 time: timeval_from_time(zx::MonotonicInstant::from_nanos(time_nanos)),
396 type_: ty as u16,
397 code: code as u16,
398 value,
399 }
400 }
401
402 fn make_uapi_input_event(ty: u32, code: u32, value: i32) -> uapi::input_event {
403 make_uapi_input_event_with_time(ty, code, value, 0)
404 }
405
406 fn make_internal_touch_event(
407 time_nanos: i64,
408 x: i32,
409 y: i32,
410 phase: FidlEventPhase,
411 pointer_id: u32,
412 ) -> TouchEvent {
413 TouchEvent { time_nanos, pointer_id, phase, x, y }
414 }
415
416 #[test_case(FidlTouchEvent::default(); "not enough fields")]
417 fn ignored_events(e: FidlTouchEvent) {
418 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
419 let _ = converter.handle(vec![make_touch_event_with_coords_phase_id(
420 10.0,
421 20.0,
422 FidlEventPhase::Add,
423 1,
424 )]);
425 let batch = converter.handle(vec![e]);
426 assert_eq!(batch.events, vec![]);
427 assert_eq!(batch.last_event_time_ns, 0);
428 assert_eq!(batch.count_converted_fidl_events, 0);
429 assert_eq!(batch.count_ignored_fidl_events, 1);
430 assert_eq!(batch.count_unexpected_fidl_events, 0);
431 }
432
433 #[test_case(make_touch_event_with_coords_phase_id(
434 1.0,
435 2.0,
436 FidlEventPhase::Add,
437 1,
438 ); "touch add pointer already added")]
439 #[test_case(make_touch_event_with_coords_phase_id(
440 1.0,
441 2.0,
442 FidlEventPhase::Change,
443 2,
444 ); "touch change pointer not added")]
445 #[test_case(make_touch_event_with_coords_phase_id(
446 0.0,
447 0.0,
448 FidlEventPhase::Remove,
449 2,
450 ); "touch remove pointer not added")]
451 #[test_case(make_touch_event_with_coords_phase_id(
452 0.0,
453 0.0,
454 FidlEventPhase::Cancel,
455 1,
456 ); "touch cancel")]
457 fn unexpected_events(e: FidlTouchEvent) {
458 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
459 let _ = converter.handle(vec![make_touch_event_with_coords_phase_id(
460 10.0,
461 20.0,
462 FidlEventPhase::Add,
463 1,
464 )]);
465 let batch = converter.handle(vec![e]);
466 assert_eq!(batch.events, vec![]);
467 assert_eq!(batch.last_event_time_ns, 0);
468 assert_eq!(batch.count_converted_fidl_events, 0);
469 assert_eq!(batch.count_ignored_fidl_events, 0);
470 assert_eq!(batch.count_unexpected_fidl_events, 1);
471 }
472
473 #[test]
474 fn touch_add() {
475 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
476 let batch = converter.handle(vec![make_touch_event_with_coords_phase_id(
477 10.0,
478 20.0,
479 FidlEventPhase::Add,
480 1,
481 )]);
482
483 assert_eq!(
484 batch.events,
485 vec![
486 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
487 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1),
488 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10),
489 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20),
490 make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
491 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
492 ]
493 );
494 assert_eq!(batch.last_event_time_ns, 0);
495 assert_eq!(batch.count_converted_fidl_events, 1);
496 assert_eq!(batch.count_ignored_fidl_events, 0);
497 assert_eq!(batch.count_unexpected_fidl_events, 0);
498
499 let mut want_converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
500 want_converter.pointer_id_to_slot_id.insert(1, 0);
501 want_converter
502 .pointer_id_to_event
503 .insert(1, make_internal_touch_event(0, 10, 20, FidlEventPhase::Add, 1));
504
505 assert_eq!(converter, want_converter);
506 }
507
508 #[test]
509 fn touch_change() {
510 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
511 let _ = converter.handle(vec![make_touch_event_with_coords_phase_id(
512 10.0,
513 20.0,
514 FidlEventPhase::Add,
515 1,
516 )]);
517
518 let batch = converter.handle(vec![make_touch_event_with_coords_phase_id(
519 11.0,
520 21.0,
521 FidlEventPhase::Change,
522 1,
523 )]);
524 assert_eq!(
525 batch.events,
526 vec![
527 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
528 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 11),
529 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 21),
530 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
531 ]
532 );
533 assert_eq!(batch.last_event_time_ns, 0);
534 assert_eq!(batch.count_converted_fidl_events, 1);
535 assert_eq!(batch.count_ignored_fidl_events, 0);
536 assert_eq!(batch.count_unexpected_fidl_events, 0);
537
538 let mut want_converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
539
540 want_converter.pointer_id_to_slot_id.insert(1, 0);
541 want_converter
542 .pointer_id_to_event
543 .insert(1, make_internal_touch_event(0, 11, 21, FidlEventPhase::Change, 1));
544
545 assert_eq!(converter, want_converter);
546 }
547
548 #[test]
549 fn touch_change_no_change() {
550 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
551 let _ = converter.handle(vec![make_touch_event_with_coords_phase_id(
552 10.0,
553 20.0,
554 FidlEventPhase::Add,
555 1,
556 )]);
557
558 let batch = converter.handle(vec![make_touch_event_with_coords_phase_id(
559 10.0,
560 20.0,
561 FidlEventPhase::Change,
562 1,
563 )]);
564 assert_eq!(batch.events, vec![]);
565 assert_eq!(batch.last_event_time_ns, 0);
566 assert_eq!(batch.count_converted_fidl_events, 1);
567 assert_eq!(batch.count_ignored_fidl_events, 0);
568 assert_eq!(batch.count_unexpected_fidl_events, 0);
569
570 let mut want_converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
571
572 want_converter.pointer_id_to_slot_id.insert(1, 0);
573 want_converter
574 .pointer_id_to_event
575 .insert(1, make_internal_touch_event(0, 10, 20, FidlEventPhase::Change, 1));
576
577 assert_eq!(converter, want_converter);
578 }
579
580 #[test]
581 fn touch_remove() {
582 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
583 let _ = converter.handle(vec![make_touch_event_with_coords_phase_id(
584 10.0,
585 20.0,
586 FidlEventPhase::Add,
587 1,
588 )]);
589 let batch = converter.handle(vec![make_touch_event_with_coords_phase_id(
590 0.0,
591 0.0,
592 FidlEventPhase::Remove,
593 1,
594 )]);
595 assert_eq!(batch.last_event_time_ns, 0);
596 assert_eq!(batch.count_converted_fidl_events, 1);
597 assert_eq!(batch.count_ignored_fidl_events, 0);
598 assert_eq!(batch.count_unexpected_fidl_events, 0);
599
600 assert_eq!(
601 batch.events,
602 vec![
603 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
604 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, -1),
605 make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 0),
606 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
607 ]
608 );
609
610 assert_eq!(
611 converter,
612 FuchsiaTouchEventToLinuxTouchEventConverter {
613 pointer_id_to_slot_id: HashMap::new(),
614 pointer_id_to_event: HashMap::new()
615 }
616 );
617 }
618
619 #[test]
620 fn multi_touch_sequence() {
621 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
622
623 let _ = converter.handle(vec![make_touch_event_with_coords_phase_id(
625 10.0,
626 20.0,
627 FidlEventPhase::Add,
628 1,
629 )]);
630
631 let batch = converter.handle(vec![
633 make_touch_event_with_coords_phase_id(11.0, 21.0, FidlEventPhase::Change, 1),
634 make_touch_event_with_coords_phase_id(100.0, 200.0, FidlEventPhase::Add, 2),
635 ]);
636
637 assert_eq!(
638 batch.events,
639 vec![
640 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
641 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 11),
642 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 21),
643 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1),
644 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 2),
645 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 100),
646 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 200),
647 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
648 ]
649 );
650 assert_eq!(batch.last_event_time_ns, 0);
651 assert_eq!(batch.count_converted_fidl_events, 2);
652 assert_eq!(batch.count_ignored_fidl_events, 0);
653 assert_eq!(batch.count_unexpected_fidl_events, 0);
654
655 let mut want_converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
656
657 want_converter.pointer_id_to_slot_id.insert(1, 0);
658 want_converter.pointer_id_to_slot_id.insert(2, 1);
659 want_converter
660 .pointer_id_to_event
661 .insert(1, make_internal_touch_event(0, 11, 21, FidlEventPhase::Change, 1));
662 want_converter
663 .pointer_id_to_event
664 .insert(2, make_internal_touch_event(0, 100, 200, FidlEventPhase::Add, 2));
665
666 assert_eq!(converter, want_converter);
667
668 let batch = converter.handle(vec![
670 make_touch_event_with_coords_phase_id(12.0, 22.0, FidlEventPhase::Change, 1),
671 make_touch_event_with_coords_phase_id(101.0, 201.0, FidlEventPhase::Change, 2),
672 ]);
673
674 assert_eq!(
675 batch.events,
676 vec![
677 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
678 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 12),
679 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 22),
680 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1),
681 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 101),
682 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 201),
683 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
684 ]
685 );
686 assert_eq!(batch.last_event_time_ns, 0);
687 assert_eq!(batch.count_converted_fidl_events, 2);
688 assert_eq!(batch.count_ignored_fidl_events, 0);
689 assert_eq!(batch.count_unexpected_fidl_events, 0);
690
691 want_converter
692 .pointer_id_to_event
693 .insert(1, make_internal_touch_event(0, 12, 22, FidlEventPhase::Change, 1));
694 want_converter
695 .pointer_id_to_event
696 .insert(2, make_internal_touch_event(0, 101, 201, FidlEventPhase::Change, 2));
697 assert_eq!(converter, want_converter);
698
699 let batch = converter.handle(vec![
701 make_touch_event_with_coords_phase_id(13.0, 23.0, FidlEventPhase::Change, 1),
702 make_touch_event_with_coords_phase_id(0.0, 0.0, FidlEventPhase::Remove, 2),
703 ]);
704
705 assert_eq!(
706 batch.events,
707 vec![
708 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
709 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 13),
710 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 23),
711 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1),
712 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, -1),
713 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
714 ]
715 );
716 assert_eq!(batch.last_event_time_ns, 0);
717 assert_eq!(batch.count_converted_fidl_events, 2);
718 assert_eq!(batch.count_ignored_fidl_events, 0);
719 assert_eq!(batch.count_unexpected_fidl_events, 0);
720
721 want_converter
722 .pointer_id_to_event
723 .insert(1, make_internal_touch_event(0, 13, 23, FidlEventPhase::Change, 1));
724 want_converter.pointer_id_to_slot_id.remove(&2);
725 want_converter.pointer_id_to_event.remove(&2);
726
727 assert_eq!(converter, want_converter);
728
729 let batch = converter.handle(vec![
731 make_touch_event_with_coords_phase_id(14.0, 24.0, FidlEventPhase::Change, 1),
732 make_touch_event_with_coords_phase_id(50.0, 60.0, FidlEventPhase::Add, 3),
733 ]);
734
735 assert_eq!(
736 batch.events,
737 vec![
738 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
739 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 14),
740 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 24),
741 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1),
743 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 3),
744 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 50),
745 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 60),
746 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
747 ]
748 );
749 assert_eq!(batch.last_event_time_ns, 0);
750 assert_eq!(batch.count_converted_fidl_events, 2);
751 assert_eq!(batch.count_ignored_fidl_events, 0);
752 assert_eq!(batch.count_unexpected_fidl_events, 0);
753
754 want_converter.pointer_id_to_slot_id.insert(3, 1);
755 want_converter
756 .pointer_id_to_event
757 .insert(1, make_internal_touch_event(0, 14, 24, FidlEventPhase::Change, 1));
758 want_converter
759 .pointer_id_to_event
760 .insert(3, make_internal_touch_event(0, 50, 60, FidlEventPhase::Add, 3));
761
762 assert_eq!(converter, want_converter);
763
764 let batch = converter.handle(vec![
766 make_touch_event_with_coords_phase_id(15.0, 25.0, FidlEventPhase::Change, 1),
767 make_touch_event_with_coords_phase_id(0.0, 0.0, FidlEventPhase::Remove, 3),
768 ]);
769
770 assert_eq!(
771 batch.events,
772 vec![
773 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
774 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 15),
775 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 25),
776 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1),
777 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, -1),
778 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
779 ]
780 );
781 assert_eq!(batch.last_event_time_ns, 0);
782 assert_eq!(batch.count_converted_fidl_events, 2);
783 assert_eq!(batch.count_ignored_fidl_events, 0);
784 assert_eq!(batch.count_unexpected_fidl_events, 0);
785
786 want_converter
787 .pointer_id_to_event
788 .insert(1, make_internal_touch_event(0, 15, 25, FidlEventPhase::Change, 1));
789 want_converter.pointer_id_to_slot_id.remove(&3);
790 want_converter.pointer_id_to_event.remove(&3);
791
792 assert_eq!(converter, want_converter);
793
794 let batch = converter.handle(vec![make_touch_event_with_coords_phase_id(
796 0.0,
797 0.0,
798 FidlEventPhase::Remove,
799 1,
800 )]);
801
802 assert_eq!(
803 batch.events,
804 vec![
805 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
806 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, -1),
807 make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 0),
808 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
809 ]
810 );
811 assert_eq!(batch.last_event_time_ns, 0);
812 assert_eq!(batch.count_converted_fidl_events, 1);
813 assert_eq!(batch.count_ignored_fidl_events, 0);
814 assert_eq!(batch.count_unexpected_fidl_events, 0);
815
816 want_converter.reset_state();
817 assert_eq!(converter, want_converter);
818 }
819
820 #[test]
821 fn multi_touch_sequence_receive_only_one_pointer_change_when_two_pointer_contacting() {
822 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
823
824 let batch = converter.handle(vec![
826 make_touch_event_with_coords_phase_id(10.0, 20.0, FidlEventPhase::Add, 1),
827 make_touch_event_with_coords_phase_id(100.0, 200.0, FidlEventPhase::Add, 2),
828 ]);
829
830 assert_eq!(
831 batch.events,
832 vec![
833 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
834 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1),
835 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10),
836 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20),
837 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 1),
838 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 2),
839 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 100),
840 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 200),
841 make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
842 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
843 ]
844 );
845 assert_eq!(batch.last_event_time_ns, 0);
846 assert_eq!(batch.count_converted_fidl_events, 2);
847 assert_eq!(batch.count_ignored_fidl_events, 0);
848 assert_eq!(batch.count_unexpected_fidl_events, 0);
849
850 let mut want_converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
851
852 want_converter.pointer_id_to_slot_id.insert(1, 0);
853 want_converter.pointer_id_to_slot_id.insert(2, 1);
854 want_converter
855 .pointer_id_to_event
856 .insert(1, make_internal_touch_event(0, 10, 20, FidlEventPhase::Add, 1));
857 want_converter
858 .pointer_id_to_event
859 .insert(2, make_internal_touch_event(0, 100, 200, FidlEventPhase::Add, 2));
860 assert_eq!(converter, want_converter);
861
862 let batch = converter.handle(vec![make_touch_event_with_coords_phase_id(
864 12.0,
865 22.0,
866 FidlEventPhase::Change,
867 1,
868 )]);
869
870 assert_eq!(
871 batch.events,
872 vec![
873 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
874 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 12),
875 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 22),
876 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
877 ]
878 );
879 assert_eq!(batch.last_event_time_ns, 0);
880 assert_eq!(batch.count_converted_fidl_events, 1);
881 assert_eq!(batch.count_ignored_fidl_events, 0);
882 assert_eq!(batch.count_unexpected_fidl_events, 0);
883
884 want_converter
885 .pointer_id_to_event
886 .insert(1, make_internal_touch_event(0, 12, 22, FidlEventPhase::Change, 1));
887 assert_eq!(converter, want_converter);
888 }
889
890 #[test]
891 fn handle_return_multi_protocl_b_seq() {
892 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
893
894 let batch = converter.handle(vec![
895 FidlTouchEvent::default(),
897 make_touch_event_with_coords_phase_id_time(10.0, 20.0, FidlEventPhase::Add, 1, 1),
898 make_touch_event_with_coords_phase_id_time(11.0, 21.0, FidlEventPhase::Change, 1, 1000),
899 ]);
900
901 assert_eq!(
902 batch.events,
903 vec![
904 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0, 1),
905 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1, 1),
906 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10, 1),
907 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20, 1),
908 make_uapi_input_event_with_time(uapi::EV_KEY, uapi::BTN_TOUCH, 1, 1),
909 make_uapi_input_event_with_time(uapi::EV_SYN, uapi::SYN_REPORT, 0, 1),
910 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0, 1000),
911 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 11, 1000),
912 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 21, 1000),
913 make_uapi_input_event_with_time(uapi::EV_SYN, uapi::SYN_REPORT, 0, 1000),
914 ]
915 );
916 assert_eq!(batch.last_event_time_ns, 1000);
917 assert_eq!(batch.count_converted_fidl_events, 2);
918 assert_eq!(batch.count_ignored_fidl_events, 1);
919 assert_eq!(batch.count_unexpected_fidl_events, 0);
920
921 let mut want_converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
922
923 want_converter.pointer_id_to_slot_id.insert(1, 0);
924 want_converter
925 .pointer_id_to_event
926 .insert(1, make_internal_touch_event(1000, 11, 21, FidlEventPhase::Change, 1));
927
928 assert_eq!(converter, want_converter);
929 }
930
931 #[test]
932 fn handle_unsorted_events() {
933 let mut converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
934
935 let batch = converter.handle(vec![
936 FidlTouchEvent::default(),
938 make_touch_event_with_coords_phase_id_time(11.0, 21.0, FidlEventPhase::Change, 1, 1000),
939 make_touch_event_with_coords_phase_id_time(10.0, 20.0, FidlEventPhase::Add, 1, 1),
940 ]);
941
942 assert_eq!(
943 batch.events,
944 vec![
945 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0, 1),
946 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1, 1),
947 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10, 1),
948 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20, 1),
949 make_uapi_input_event_with_time(uapi::EV_KEY, uapi::BTN_TOUCH, 1, 1),
950 make_uapi_input_event_with_time(uapi::EV_SYN, uapi::SYN_REPORT, 0, 1),
951 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0, 1000),
952 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 11, 1000),
953 make_uapi_input_event_with_time(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 21, 1000),
954 make_uapi_input_event_with_time(uapi::EV_SYN, uapi::SYN_REPORT, 0, 1000),
955 ]
956 );
957 assert_eq!(batch.last_event_time_ns, 1000);
958 assert_eq!(batch.count_converted_fidl_events, 2);
959 assert_eq!(batch.count_ignored_fidl_events, 1);
960 assert_eq!(batch.count_unexpected_fidl_events, 0);
961
962 let mut want_converter = FuchsiaTouchEventToLinuxTouchEventConverter::create();
963
964 want_converter.pointer_id_to_slot_id.insert(1, 0);
965 want_converter
966 .pointer_id_to_event
967 .insert(1, make_internal_touch_event(1000, 11, 21, FidlEventPhase::Change, 1));
968
969 assert_eq!(converter, want_converter);
970 }
971}