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