1use crate::{InputDeviceStatus, InputFile, LinuxEventWithTraceId, uinput};
6use fidl::endpoints::{ClientEnd, RequestStream};
7use fidl_fuchsia_ui_input::TouchDeviceInfo;
8use fidl_fuchsia_ui_input3::{
9 KeyEventStatus, KeyboardListenerMarker, KeyboardListenerRequest, KeyboardListenerRequestStream,
10 KeyboardSynchronousProxy,
11};
12use fidl_fuchsia_ui_pointer::{
13 MouseEvent as FidlMouseEvent, MousePointerSample, TouchEvent as FidlTouchEvent,
14 TouchPointerSample, TouchResponse as FidlTouchResponse, TouchResponseType,
15 {self as fuipointer},
16};
17use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender, unbounded};
18use futures::channel::oneshot::{self, Sender};
19use futures::executor::block_on;
20use futures::{FutureExt, StreamExt as _};
21use starnix_core::power::{
22 ContainerWakingProxy, ContainerWakingStream, create_proxy_for_wake_events_counter,
23};
24use starnix_core::task::dynamic_thread_spawner::SpawnRequestBuilder;
25use starnix_core::task::{Kernel, LockedAndTask};
26use starnix_logging::{
27 log_warn, trace_duration, trace_duration_begin, trace_duration_end, trace_flow_end,
28};
29use starnix_modules_input_event_conversion::button_fuchsia_to_linux::{
30 parse_fidl_media_button_event, parse_fidl_touch_button_event,
31};
32use starnix_modules_input_event_conversion::key_fuchsia_to_linux::parse_fidl_keyboard_event_to_linux_input_event;
33use starnix_modules_input_event_conversion::touch_fuchsia_to_linux::FuchsiaTouchEventToLinuxTouchEventConverter;
34use starnix_sync::Mutex;
35use starnix_types::time::timeval_from_time;
36use starnix_uapi::uapi;
37use starnix_uapi::vfs::FdEvents;
38use std::cell::RefCell;
39use std::collections::{HashMap, VecDeque};
40use std::rc::Rc;
41use std::sync::{Arc, Weak};
42use {fidl_fuchsia_ui_policy as fuipolicy, fidl_fuchsia_ui_views as fuiviews};
43
44const INPUT_RELAY_ROLE_NAME: &str = "fuchsia.starnix.kthread.input_relay";
45
46#[derive(Clone, Copy)]
47pub enum EventProxyMode {
48 None,
50
51 WakeContainer,
55}
56
57pub type OpenedFiles = Arc<Mutex<Vec<Weak<InputFile>>>>;
58
59pub enum InputDeviceType {
60 Touch(FuchsiaTouchEventToLinuxTouchEventConverter),
61 Keyboard,
62 Mouse,
63}
64
65impl std::fmt::Display for InputDeviceType {
66 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
67 match self {
68 InputDeviceType::Touch(_) => write!(f, "touch"),
69 InputDeviceType::Keyboard => write!(f, "keyboard"),
70 InputDeviceType::Mouse => write!(f, "mouse"),
71 }
72 }
73}
74
75pub struct DeviceState {
76 device_type: InputDeviceType,
77 open_files: OpenedFiles,
78 inspect_status: Option<Arc<InputDeviceStatus>>,
79}
80
81pub type DeviceId = u32;
82
83pub const DEFAULT_TOUCH_DEVICE_ID: DeviceId = 0;
84pub const DEFAULT_KEYBOARD_DEVICE_ID: DeviceId = 1;
85pub const DEFAULT_MOUSE_DEVICE_ID: DeviceId = 2;
86
87enum DeviceStateChange {
88 Add(DeviceId, DeviceState, Sender<()>),
89 Remove(DeviceId, Sender<()>),
90}
91
92pub fn new_input_relay() -> (InputEventsRelay, Arc<InputEventsRelayHandle>) {
93 let (sender, receiver) = unbounded();
94
95 (
96 InputEventsRelay { devices: HashMap::new(), receiver },
97 Arc::new(InputEventsRelayHandle { sender }),
98 )
99}
100
101pub struct InputEventsRelayHandle {
102 sender: UnboundedSender<DeviceStateChange>,
103}
104
105impl InputEventsRelayHandle {
106 pub fn add_touch_device(
107 self: &Arc<Self>,
108 device_id: DeviceId,
109 open_files: OpenedFiles,
110 inspect_status: Option<Arc<InputDeviceStatus>>,
111 ) {
112 let (sender, receiver) = oneshot::channel();
113 let _ = self.sender.unbounded_send(DeviceStateChange::Add(
114 device_id,
115 DeviceState {
116 device_type: InputDeviceType::Touch(
117 FuchsiaTouchEventToLinuxTouchEventConverter::create(),
118 ),
119 open_files,
120 inspect_status,
121 },
122 sender,
123 ));
124 let _ = block_on(receiver);
125 }
126
127 pub fn add_keyboard_device(
128 &self,
129 device_id: DeviceId,
130 open_files: OpenedFiles,
131 inspect_status: Option<Arc<InputDeviceStatus>>,
132 ) {
133 let (sender, receiver) = oneshot::channel();
134 let _ = self.sender.unbounded_send(DeviceStateChange::Add(
135 device_id,
136 DeviceState { device_type: InputDeviceType::Keyboard, open_files, inspect_status },
137 sender,
138 ));
139 let _ = block_on(receiver);
140 }
141
142 pub fn remove_device(&self, device_id: DeviceId) {
143 let (sender, receiver) = oneshot::channel();
144 let _ = self.sender.unbounded_send(DeviceStateChange::Remove(device_id, sender));
145 let _ = block_on(receiver);
146 }
147}
148
149pub struct InputEventsRelay {
150 devices: HashMap<DeviceId, DeviceState>,
151 receiver: UnboundedReceiver<DeviceStateChange>,
152}
153
154impl InputEventsRelay {
155 pub fn start_relays(
159 mut self: Self,
160 kernel: &Kernel,
161 event_proxy_mode: EventProxyMode,
162 touch_source_client_end: ClientEnd<fuipointer::TouchSourceMarker>,
163 keyboard: KeyboardSynchronousProxy,
164 mouse_source_client_end: ClientEnd<fuipointer::MouseSourceMarker>,
165 view_ref: fuiviews::ViewRef,
166 registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
167 default_touch_device_opened_files: OpenedFiles,
168 default_keyboard_device_opened_files: OpenedFiles,
169 default_mouse_device_opened_files: OpenedFiles,
170 default_touch_device_inspect: Option<Arc<InputDeviceStatus>>,
171 default_keyboard_device_inspect: Option<Arc<InputDeviceStatus>>,
172 default_mouse_device_inspect: Option<Arc<InputDeviceStatus>>,
173 ) {
174 let f = async move |locked_and_task: LockedAndTask<'_>| {
175 let kernel = locked_and_task.current_task().kernel();
176 let previous_touch_event_disposition: Rc<RefCell<Vec<FidlTouchResponse>>> =
178 Default::default();
179 let touch_waking_fn = |p: &fuipointer::TouchSourceProxy| {
180 p.watch(&previous_touch_event_disposition.borrow_mut())
181 };
182 let (mut default_touch_device, touch_waking_proxy) = setup_touch_relay(
183 kernel,
184 event_proxy_mode,
185 touch_source_client_end,
186 default_touch_device_opened_files,
187 default_touch_device_inspect,
188 );
189 let mut touch_future = touch_waking_proxy.call(touch_waking_fn.clone()).fuse();
190
191 let (mut default_mouse_device, mouse_waking_proxy) = setup_mouse_relay(
193 kernel,
194 event_proxy_mode,
195 mouse_source_client_end,
196 default_mouse_device_opened_files,
197 default_mouse_device_inspect,
198 );
199 let mut mouse_future =
200 mouse_waking_proxy.call(fuipointer::MouseSourceProxy::watch).fuse();
201
202 let (mut default_keyboard_device, mut keyboard_event_stream) = setup_keyboard_relay(
204 keyboard,
205 view_ref,
206 default_keyboard_device_opened_files.clone(),
207 default_keyboard_device_inspect.clone(),
208 );
209
210 let (
212 mut default_button_device,
213 mut media_buttons_waking_stream,
214 mut touch_buttons_waking_stream,
215 ) = setup_button_relay(
216 kernel,
217 registry_proxy,
218 event_proxy_mode,
219 default_keyboard_device_opened_files,
220 default_keyboard_device_inspect,
221 );
222 let mut media_buttons_future = media_buttons_waking_stream.next();
223 let mut touch_buttons_future = touch_buttons_waking_stream.next();
224
225 let mut power_was_pressed = false;
226 let mut function_was_pressed = false;
227 let mut palm_was_pressed = false;
228
229 loop {
230 futures::select! {
231 touch_future_res = touch_future => {
232 match touch_future_res {
233 Ok(touch_events) => {
234 *previous_touch_event_disposition.borrow_mut() =
235 self.process_touch_event(
236 &mut default_touch_device,
237 touch_events,
238 );
239 touch_future = touch_waking_proxy
240 .call(touch_waking_fn.clone())
241 .fuse();
242 }
243 Err(e) => {
244 log_warn!(
245 "error {:?} reading from TouchSourceProxy; input is stopped",
246 e
247 );
248 }
249 }
250 }
251 mouse_future_res = mouse_future => {
252 match mouse_future_res {
253 Ok(mouse_events) => {
254 self.process_mouse_event(&mut default_mouse_device, mouse_events);
255 mouse_future = mouse_waking_proxy
256 .call(fuipointer::MouseSourceProxy::watch)
257 .fuse();
258 }
259 Err(e) => {
260 log_warn!(
261 "error {:?} reading from MouseSourceProxy; input is stopped",
262 e
263 );
264 }
265 }
266 }
267 media_buttons_res = media_buttons_future => {
268 match media_buttons_res {
269 Some(Ok(event)) => {
270 (power_was_pressed, function_was_pressed) =
271 self.process_media_button_event(
272 &mut default_button_device,
273 event,
274 power_was_pressed,
275 function_was_pressed,
276 );
277 }
278 _ => {}
279 }
280 media_buttons_future = media_buttons_waking_stream.next();
281 }
282 touch_buttons_res = touch_buttons_future => {
283 match touch_buttons_res {
284 Some(Ok(event)) => {
285 palm_was_pressed = self.process_touch_button_event(
286 &mut default_touch_device,
287 event,
288 palm_was_pressed,
289 );
290 }
291 _ => {}
292 }
293 touch_buttons_future = touch_buttons_waking_stream.next();
294 }
295 e = keyboard_event_stream.next() => {
296 match e {
297 Some(Ok(request)) => {
298 self.process_keyboard(&mut default_keyboard_device, request);
299 }
300 _ => {}
301 }
302 }
303 e = self.receiver.next() => {
304 match e {
305 Some(event) => {
306 match event {
307 DeviceStateChange::Add(id, device_state, sender) => {
308 self.devices.insert(id, device_state);
309 let _ = sender.send(());
310 }
311 DeviceStateChange::Remove(id, sender) => {
312 self.devices.remove(&id);
313 let _ = sender.send(());
314 }
315 }
316 }
317 _ => {}
318 }
319 }
320 complete => break,
321 }
322 }
323 };
324 let req = SpawnRequestBuilder::new()
325 .with_debug_name("input-event-relay")
326 .with_role(INPUT_RELAY_ROLE_NAME)
327 .with_async_closure(f)
328 .build();
329 kernel.kthreads.spawner().spawn_from_request(req);
330 }
331
332 fn process_touch_event(
333 self: &mut Self,
334 default_touch_device: &mut DeviceState,
335 touch_events: Vec<FidlTouchEvent>,
336 ) -> Vec<FidlTouchResponse> {
337 trace_duration!("input", "starnix_process_touch_event");
338 for e in &touch_events {
339 match e.trace_flow_id {
340 Some(trace_flow_id) => {
341 trace_flow_end!("input", "dispatch_event_to_client", trace_flow_id.into());
342 }
343 None => {
344 log_warn!("touch event has not tracing id");
345 }
346 }
347 }
348 let num_received_events: u64 = touch_events.len().try_into().unwrap();
349
350 let previous_event_disposition =
351 touch_events.iter().map(make_response_for_fidl_event).collect();
352
353 let mut num_ignored_events: u64 = 0;
354
355 let (events_by_device, ignored_events) = group_touch_events_by_device_id(touch_events);
357 num_ignored_events += ignored_events;
358
359 for (device_id, events) in events_by_device {
360 trace_duration_begin!("input", "starnix_process_per_device_touch_event");
361
362 let dev = self.devices.get_mut(&device_id).unwrap_or(default_touch_device);
363
364 let mut num_converted_events: u64 = 0;
365 let mut num_unexpected_events: u64 = 0;
366 let mut new_events: VecDeque<uapi::input_event> = VecDeque::new();
367
368 let last_event_time_ns: i64;
369 if let InputDeviceType::Touch(ref mut converter) = dev.device_type {
370 let mut batch = converter.handle(events);
371 new_events.append(&mut batch.events);
372 num_converted_events += batch.count_converted_fidl_events;
373 num_ignored_events += batch.count_ignored_fidl_events;
374 num_unexpected_events += batch.count_unexpected_fidl_events;
375 last_event_time_ns = batch.last_event_time_ns;
376 } else {
377 trace_duration_end!("input", "starnix_process_per_device_touch_event");
378 log_warn!(
379 "Non touch device received touch events: device_id = {}, device_type = {}",
380 device_id,
381 dev.device_type
382 );
383 continue;
384 }
385
386 if let Some(dev_inspect_status) = &dev.inspect_status {
387 dev_inspect_status.count_total_received_events(num_received_events);
388 dev_inspect_status.count_total_ignored_events(num_ignored_events);
389 dev_inspect_status.count_total_unexpected_events(num_unexpected_events);
390 dev_inspect_status.count_total_converted_events(num_converted_events);
391 dev_inspect_status.count_total_generated_events(
392 new_events.len().try_into().unwrap(),
393 last_event_time_ns,
394 );
395 } else {
396 log_warn!(
397 "unable to record inspect for device_id: {}, device_type: {}",
398 device_id,
399 dev.device_type
400 );
401 }
402
403 trace_duration_end!("input", "starnix_process_per_device_touch_event");
404 dev.open_files.lock().retain(|f| {
405 let Some(file) = f.upgrade() else {
406 log_warn!("Dropping input file for touch that failed to upgrade");
407 return false;
408 };
409 match &file.inspect_status {
410 Some(file_inspect_status) => {
411 file_inspect_status.count_received_events(num_received_events);
412 file_inspect_status.count_ignored_events(num_ignored_events);
413 file_inspect_status.count_unexpected_events(num_unexpected_events);
414 file_inspect_status.count_converted_events(num_converted_events);
415 }
416 None => {
417 log_warn!("unable to record inspect within the input file")
418 }
419 }
420 if !new_events.is_empty() {
421 if let Some(file_inspect_status) = &file.inspect_status {
425 file_inspect_status.count_generated_events(
426 new_events.len().try_into().unwrap(),
427 last_event_time_ns,
428 );
429 }
430 let mut inner = file.inner.lock();
431 inner
432 .events
433 .extend(new_events.clone().into_iter().map(LinuxEventWithTraceId::new));
434 inner.waiters.notify_fd_events(FdEvents::POLLIN);
435 }
436
437 true
438 });
439 }
440
441 previous_event_disposition
442 }
443
444 fn process_keyboard(
445 self: &mut Self,
446 default_keyboard_device: &mut DeviceState,
447 request: KeyboardListenerRequest,
448 ) {
449 match request {
450 KeyboardListenerRequest::OnKeyEvent { event, responder } => {
451 trace_duration!("input", "starnix_process_keyboard_event");
452
453 let new_events = parse_fidl_keyboard_event_to_linux_input_event(
454 &event,
455 uinput::uinput_running(),
456 );
457
458 let dev = match event.device_id {
459 Some(device_id) => {
460 self.devices.get_mut(&device_id).unwrap_or(default_keyboard_device)
461 }
462 None => default_keyboard_device,
463 };
464
465 dev.open_files.lock().retain(|f| {
466 let Some(file) = f.upgrade() else {
467 log_warn!("Dropping input file for keyboard that failed to upgrade");
468 return false;
469 };
470 let mut inner = file.inner.lock();
471
472 if !new_events.is_empty() {
473 inner
474 .events
475 .extend(new_events.clone().into_iter().map(LinuxEventWithTraceId::new));
476 inner.waiters.notify_fd_events(FdEvents::POLLIN);
477 }
478
479 true
480 });
481
482 responder.send(KeyEventStatus::Handled).expect("");
483 }
484 }
485 }
486
487 fn process_media_button_event(
488 &mut self,
489 default_button_device: &mut DeviceState,
490 button_event: fuipolicy::MediaButtonsListenerRequest,
491 power_was_pressed: bool,
492 function_was_pressed: bool,
493 ) -> (bool, bool) {
494 let mut power_was_pressed_after = false;
495 let mut function_was_pressed_after = false;
496 match button_event {
497 fuipolicy::MediaButtonsListenerRequest::OnEvent { event, responder } => {
498 trace_duration!("input", "starnix_process_media_button_event");
499
500 let batch =
501 parse_fidl_media_button_event(&event, power_was_pressed, function_was_pressed);
502
503 power_was_pressed_after = batch.power_is_pressed;
504 function_was_pressed_after = batch.function_is_pressed;
505
506 let (converted_events, ignored_events, generated_events) = match batch.events.len()
507 {
508 0 => (0u64, 1u64, 0u64),
509 len => {
510 if len % 2 == 1 {
511 log_warn!(
512 "unexpectedly received {} events: there should always be an even number of non-empty events.",
513 len
514 );
515 }
516 (1u64, 0u64, len as u64)
517 }
518 };
519
520 let dev = match event.device_id {
521 Some(device_id) => {
522 self.devices.get_mut(&device_id).unwrap_or(default_button_device)
523 }
524 None => default_button_device,
525 };
526
527 if let Some(dev_inspect_status) = &dev.inspect_status {
528 dev_inspect_status.count_total_received_events(1);
529 dev_inspect_status.count_total_ignored_events(ignored_events);
530 dev_inspect_status.count_total_converted_events(converted_events);
531 dev_inspect_status.count_total_generated_events(
532 generated_events,
533 batch.event_time.into_nanos().try_into().unwrap(),
534 );
535 } else {
536 log_warn!("unable to record inspect for button device");
537 }
538
539 dev.open_files.lock().retain(|f| {
540 let Some(file) = f.upgrade() else {
541 log_warn!("Dropping input file for buttons that failed to upgrade");
542 return false;
543 };
544 match &file.inspect_status {
545 Some(file_inspect_status) => {
546 file_inspect_status.count_received_events(1);
547 file_inspect_status.count_ignored_events(ignored_events);
548 file_inspect_status.count_converted_events(converted_events);
549 }
550 None => {
551 log_warn!("unable to record inspect within the input file")
552 }
553 }
554 if !batch.events.is_empty() {
555 if let Some(file_inspect_status) = &file.inspect_status {
556 file_inspect_status.count_generated_events(
557 generated_events,
558 batch.event_time.into_nanos().try_into().unwrap(),
559 );
560 }
561 let mut inner = file.inner.lock();
562 inner.events.extend(
563 batch.events.clone().into_iter().map(LinuxEventWithTraceId::new),
564 );
565 inner.waiters.notify_fd_events(FdEvents::POLLIN);
566 }
567
568 true
569 });
570
571 responder.send().expect("media buttons responder failed to respond");
572 }
573 _ => { }
574 }
575
576 (power_was_pressed_after, function_was_pressed_after)
577 }
578
579 fn process_touch_button_event(
580 &mut self,
581 default_touch_device: &mut DeviceState,
582 button_event: fuipolicy::TouchButtonsListenerRequest,
583 palm_was_pressed: bool,
584 ) -> bool {
585 trace_duration!("input", "starnix_process_touch_button_event");
586 match button_event {
587 fuipolicy::TouchButtonsListenerRequest::OnEvent { event, responder } => {
588 let batch = parse_fidl_touch_button_event(&event, palm_was_pressed);
589
590 let (converted_events, ignored_events, generated_events) = match batch.events.len()
591 {
592 0 => (0u64, 1u64, 0u64),
593 len => {
594 if len % 2 == 1 {
595 log_warn!(
596 "unexpectedly received {} events: there should always be an even number of non-empty events.",
597 len
598 );
599 }
600 (1u64, 0u64, len as u64)
601 }
602 };
603
604 let dev = match event.device_info {
605 Some(TouchDeviceInfo { id: Some(device_id), .. }) => {
606 self.devices.get_mut(&device_id).unwrap_or(default_touch_device)
607 }
608 _ => default_touch_device,
609 };
610
611 if let Some(dev_inspect_status) = &dev.inspect_status {
612 dev_inspect_status.count_total_received_events(1);
613 dev_inspect_status.count_total_ignored_events(ignored_events);
614 dev_inspect_status.count_total_converted_events(converted_events);
615 dev_inspect_status.count_total_generated_events(
616 generated_events,
617 batch.event_time.into_nanos().try_into().unwrap(),
618 );
619 } else {
620 log_warn!("unable to record inspect for touch device");
621 }
622
623 dev.open_files.lock().retain(|f| {
624 let Some(file) = f.upgrade() else {
625 log_warn!("Dropping input file for touch that failed to upgrade");
626 return false;
627 };
628 match &file.inspect_status {
629 Some(file_inspect_status) => {
630 file_inspect_status.count_received_events(1);
631 file_inspect_status.count_ignored_events(ignored_events);
632 file_inspect_status.count_converted_events(converted_events);
633 }
634 None => {
635 log_warn!("unable to record inspect within the input file")
636 }
637 }
638 if !batch.events.is_empty() {
639 if let Some(file_inspect_status) = &file.inspect_status {
640 file_inspect_status.count_generated_events(
641 generated_events,
642 batch.event_time.into_nanos().try_into().unwrap(),
643 );
644 }
645 let mut inner = file.inner.lock();
646 inner.events.extend(
647 batch.events.clone().into_iter().map(LinuxEventWithTraceId::new),
648 );
649 inner.waiters.notify_fd_events(FdEvents::POLLIN);
650 }
651
652 true
653 });
654
655 responder.send().expect("touch buttons responder failed to respond");
656
657 batch.palm_is_pressed
658 }
659 fuipolicy::TouchButtonsListenerRequest::_UnknownMethod { ordinal, .. } => {
660 log_warn!("Received an unknown method with ordinal {ordinal}");
661 palm_was_pressed
662 }
663 }
664 }
665
666 fn process_mouse_event(
667 self: &Self,
668 default_mouse_device: &mut DeviceState,
669 mouse_events: Vec<FidlMouseEvent>,
670 ) {
671 let num_received_events: u64 = mouse_events.len().try_into().unwrap();
672 let mut num_ignored_events: u64 = 0;
673 let mut num_converted_events: u64 = 0;
674 let mut num_unexpected_events: u64 = 0;
675 let mut new_events: VecDeque<uapi::input_event> = VecDeque::new();
676 let mut last_event_time_ns = zx::MonotonicInstant::get();
677 for event in mouse_events {
678 match event {
679 FidlMouseEvent {
680 timestamp: Some(time),
681 pointer_sample: Some(MousePointerSample { scroll_v: Some(ticks), .. }),
682 ..
683 } => {
684 last_event_time_ns = zx::MonotonicInstant::from_nanos(time);
685 if ticks != 0 {
687 new_events.push_back(uapi::input_event {
688 time: timeval_from_time(last_event_time_ns),
689 type_: uapi::EV_REL as u16,
690 code: uapi::REL_WHEEL as u16,
691 value: ticks as i32,
692 });
693 num_converted_events += 1;
694 } else {
695 num_ignored_events += 1;
696 }
697 }
698 _ => {
699 num_unexpected_events += 1;
700 }
701 }
702 }
703 if new_events.len() > 0 {
704 new_events.push_back(uapi::input_event {
705 time: timeval_from_time(last_event_time_ns),
707 type_: uapi::EV_SYN as u16,
708 code: uapi::SYN_REPORT as u16,
709 value: 0,
710 });
711 }
712
713 if let Some(dev_inspect_status) = &default_mouse_device.inspect_status {
714 dev_inspect_status.count_total_received_events(num_received_events);
715 dev_inspect_status.count_total_ignored_events(num_ignored_events);
716 dev_inspect_status.count_total_unexpected_events(num_unexpected_events);
717 dev_inspect_status.count_total_converted_events(num_converted_events);
718 if !new_events.is_empty() {
719 dev_inspect_status.count_total_generated_events(
720 new_events.len().try_into().unwrap(),
721 last_event_time_ns.into_nanos().try_into().unwrap(),
722 );
723 }
724 } else {
725 log_warn!("unable to record inspect for mouse device");
726 }
727
728 default_mouse_device.open_files.lock().retain(|f| {
729 let Some(file) = f.upgrade() else {
730 log_warn!("Dropping input file for mouse that failed to upgrade");
731 return false;
732 };
733 match &file.inspect_status {
734 Some(file_inspect_status) => {
735 file_inspect_status.count_received_events(num_received_events);
736 file_inspect_status.count_ignored_events(num_ignored_events);
737 file_inspect_status.count_unexpected_events(num_unexpected_events);
738 file_inspect_status.count_converted_events(num_converted_events);
739 }
740 None => {
741 log_warn!("unable to record inspect within the input file")
742 }
743 }
744 if !new_events.is_empty() {
745 if let Some(file_inspect_status) = &file.inspect_status {
746 file_inspect_status.count_generated_events(
747 new_events.len().try_into().unwrap(),
748 last_event_time_ns.into_nanos().try_into().unwrap(),
749 );
750 }
751 let mut inner = file.inner.lock();
752 inner.events.extend(new_events.clone().into_iter().map(LinuxEventWithTraceId::new));
753 inner.waiters.notify_fd_events(FdEvents::POLLIN);
754 }
755 true
756 });
757 }
758}
759
760fn setup_touch_relay(
761 kernel: &Arc<Kernel>,
762 event_proxy_mode: EventProxyMode,
763 touch_source_client_end: ClientEnd<fuipointer::TouchSourceMarker>,
764 default_touch_device_opened_files: OpenedFiles,
765 device_inspect_status: Option<Arc<InputDeviceStatus>>,
766) -> (DeviceState, ContainerWakingProxy<fuipointer::TouchSourceProxy>) {
767 let touch_counter_name = "touch";
768 let default_touch_device = DeviceState {
769 device_type: InputDeviceType::Touch(FuchsiaTouchEventToLinuxTouchEventConverter::create()),
770 open_files: default_touch_device_opened_files,
771 inspect_status: device_inspect_status,
772 };
773 let (touch_source_proxy, counter) = match event_proxy_mode {
774 EventProxyMode::WakeContainer => {
775 let (touch_source_channel, counter) = create_proxy_for_wake_events_counter(
778 touch_source_client_end.into_channel(),
779 touch_counter_name.to_string(),
780 );
781 (
782 fuipointer::TouchSourceProxy::new(fidl::AsyncChannel::from_channel(
783 touch_source_channel,
784 )),
785 Some(counter),
786 )
787 }
788 EventProxyMode::None => (touch_source_client_end.into_proxy(), None),
789 };
790 (
791 default_touch_device,
792 ContainerWakingProxy::new(
793 kernel.suspend_resume_manager.add_message_counter(touch_counter_name, counter),
794 touch_source_proxy,
795 ),
796 )
797}
798
799fn setup_keyboard_relay(
800 keyboard: KeyboardSynchronousProxy,
801 view_ref: fuiviews::ViewRef,
802 default_keyboard_device_opened_files: OpenedFiles,
803 device_inspect_status: Option<Arc<InputDeviceStatus>>,
804) -> (DeviceState, KeyboardListenerRequestStream) {
805 let default_keyboard_device = DeviceState {
806 device_type: InputDeviceType::Keyboard,
807 open_files: default_keyboard_device_opened_files,
808 inspect_status: device_inspect_status,
809 };
810 let (keyboard_listener, event_stream) =
811 fidl::endpoints::create_request_stream::<KeyboardListenerMarker>();
812 if keyboard.add_listener(view_ref, keyboard_listener, zx::MonotonicInstant::INFINITE).is_err() {
813 log_warn!("Could not register keyboard listener");
814 }
815
816 (default_keyboard_device, event_stream)
817}
818
819fn setup_button_relay(
820 kernel: &Arc<Kernel>,
821 registry_proxy: fuipolicy::DeviceListenerRegistrySynchronousProxy,
822 event_proxy_mode: EventProxyMode,
823 default_keyboard_device_opened_files: OpenedFiles,
824 device_inspect_status: Option<Arc<InputDeviceStatus>>,
825) -> (
826 DeviceState,
827 ContainerWakingStream<fuipolicy::MediaButtonsListenerRequestStream>,
828 ContainerWakingStream<fuipolicy::TouchButtonsListenerRequestStream>,
829) {
830 let default_keyboard_device = DeviceState {
831 device_type: InputDeviceType::Keyboard,
832 open_files: default_keyboard_device_opened_files,
833 inspect_status: device_inspect_status,
834 };
835 let media_buttons_name = "media buttons";
836 let touch_buttons_name = "touch buttons";
837
838 let (remote_media_button_client, remote_media_button_server) =
839 fidl::endpoints::create_endpoints::<fuipolicy::MediaButtonsListenerMarker>();
840 if let Err(e) =
841 registry_proxy.register_listener(remote_media_button_client, zx::MonotonicInstant::INFINITE)
842 {
843 log_warn!("Failed to register media buttons listener: {:?}", e);
844 }
845
846 let (remote_touch_button_client, remote_touch_button_server) =
847 fidl::endpoints::create_endpoints::<fuipolicy::TouchButtonsListenerMarker>();
848 if let Err(e) = registry_proxy
849 .register_touch_buttons_listener(remote_touch_button_client, zx::MonotonicInstant::INFINITE)
850 {
851 log_warn!("Failed to register touch buttons listener: {:?}", e);
852 }
853
854 let (
855 local_media_buttons_listener_stream,
856 media_buttons_counter,
857 local_touch_buttons_listener_stream,
858 touch_buttons_counter,
859 ) = match event_proxy_mode {
860 EventProxyMode::WakeContainer => {
861 let (local_media_buttons_channel, media_buttons_counter) =
862 create_proxy_for_wake_events_counter(
863 remote_media_button_server.into_channel(),
864 media_buttons_name.to_string(),
865 );
866 let local_media_buttons_listener_stream =
867 fuipolicy::MediaButtonsListenerRequestStream::from_channel(
868 fidl::AsyncChannel::from_channel(local_media_buttons_channel),
869 );
870
871 let (local_touch_buttons_channel, touch_buttons_counter) =
872 create_proxy_for_wake_events_counter(
873 remote_touch_button_server.into_channel(),
874 touch_buttons_name.to_string(),
875 );
876 let local_touch_buttons_listener_stream =
877 fuipolicy::TouchButtonsListenerRequestStream::from_channel(
878 fidl::AsyncChannel::from_channel(local_touch_buttons_channel),
879 );
880 (
881 local_media_buttons_listener_stream,
882 Some(media_buttons_counter),
883 local_touch_buttons_listener_stream,
884 Some(touch_buttons_counter),
885 )
886 }
887 EventProxyMode::None => (
888 remote_media_button_server.into_stream(),
889 None,
890 remote_touch_button_server.into_stream(),
891 None,
892 ),
893 };
894
895 (
896 default_keyboard_device,
897 ContainerWakingStream::new(
898 kernel
899 .suspend_resume_manager
900 .add_message_counter(media_buttons_name, media_buttons_counter),
901 local_media_buttons_listener_stream,
902 ),
903 ContainerWakingStream::new(
904 kernel
905 .suspend_resume_manager
906 .add_message_counter(touch_buttons_name, touch_buttons_counter),
907 local_touch_buttons_listener_stream,
908 ),
909 )
910}
911
912fn setup_mouse_relay(
913 kernel: &Arc<Kernel>,
914 event_proxy_mode: EventProxyMode,
915 mouse_source_client_end: ClientEnd<fuipointer::MouseSourceMarker>,
916 default_mouse_device_opened_files: OpenedFiles,
917 device_inspect_status: Option<Arc<InputDeviceStatus>>,
918) -> (DeviceState, ContainerWakingProxy<fuipointer::MouseSourceProxy>) {
919 let mouse_counter_name = "mouse";
920 let default_mouse_device = DeviceState {
921 device_type: InputDeviceType::Mouse,
922 open_files: default_mouse_device_opened_files,
923 inspect_status: device_inspect_status,
924 };
925 let (mouse_source_proxy, counter) = match event_proxy_mode {
926 EventProxyMode::WakeContainer => {
927 let (mouse_source_channel, resume_event) = create_proxy_for_wake_events_counter(
930 mouse_source_client_end.into_channel(),
931 "mouse".to_string(),
932 );
933 (
934 fuipointer::MouseSourceProxy::new(fidl::AsyncChannel::from_channel(
935 mouse_source_channel,
936 )),
937 Some(resume_event),
938 )
939 }
940 EventProxyMode::None => (mouse_source_client_end.into_proxy(), None),
941 };
942
943 (
944 default_mouse_device,
945 ContainerWakingProxy::new(
946 kernel.suspend_resume_manager.add_message_counter(mouse_counter_name, counter),
947 mouse_source_proxy,
948 ),
949 )
950}
951
952fn make_response_for_fidl_event(fidl_event: &FidlTouchEvent) -> FidlTouchResponse {
954 match fidl_event {
955 FidlTouchEvent { pointer_sample: Some(_), .. } => FidlTouchResponse {
956 response_type: Some(TouchResponseType::Yes), trace_flow_id: fidl_event.trace_flow_id,
958 ..Default::default()
959 },
960 _ => FidlTouchResponse::default(),
961 }
962}
963
964fn group_touch_events_by_device_id(
965 events: Vec<FidlTouchEvent>,
966) -> (HashMap<DeviceId, Vec<FidlTouchEvent>>, u64) {
967 let mut events_by_device: HashMap<u32, Vec<FidlTouchEvent>> = HashMap::new();
968 let mut ignored_events: u64 = 0;
969 for e in events {
970 match e {
971 FidlTouchEvent {
972 pointer_sample: Some(TouchPointerSample { interaction: Some(id), .. }),
973 ..
974 } => {
975 events_by_device.entry(id.device_id).or_default().push(e);
976 }
977 _ => {
978 ignored_events += 1;
979 }
980 }
981 }
982
983 (events_by_device, ignored_events)
984}
985
986#[cfg(test)]
987pub async fn start_input_relays_for_test(
988 locked: &mut starnix_sync::Locked<starnix_sync::Unlocked>,
989 current_task: &starnix_core::task::CurrentTask,
990 event_proxy_mode: EventProxyMode,
991) -> (
992 Arc<InputEventsRelayHandle>,
993 crate::InputDevice,
994 crate::InputDevice,
995 crate::InputDevice,
996 starnix_core::vfs::FileHandle,
997 starnix_core::vfs::FileHandle,
998 starnix_core::vfs::FileHandle,
999 fuipointer::TouchSourceRequestStream,
1000 fuipointer::MouseSourceRequestStream,
1001 fidl_fuchsia_ui_input3::KeyboardListenerProxy,
1002 fuipolicy::MediaButtonsListenerProxy,
1003 fuipolicy::TouchButtonsListenerProxy,
1004) {
1005 let inspector = fuchsia_inspect::Inspector::default();
1006
1007 let touch_device = crate::InputDevice::new_touch(700, 1200, inspector.root());
1008 let touch_file =
1009 touch_device.open_test(locked, current_task).expect("Failed to create input file");
1010
1011 let keyboard_device = crate::InputDevice::new_keyboard(inspector.root());
1012 let keyboard_file =
1013 keyboard_device.open_test(locked, current_task).expect("Failed to create input file");
1014
1015 let mouse_device = crate::InputDevice::new_mouse(inspector.root());
1016 let mouse_file =
1017 mouse_device.open_test(locked, current_task).expect("Failed to create input file");
1018
1019 let (touch_source_client_end, touch_source_stream) =
1020 fidl::endpoints::create_request_stream::<fuipointer::TouchSourceMarker>();
1021 let (mouse_source_client_end, mouse_stream) =
1022 fidl::endpoints::create_request_stream::<fuipointer::MouseSourceMarker>();
1023 let (keyboard_proxy, mut keyboard_stream) =
1024 fidl::endpoints::create_sync_proxy_and_stream::<fidl_fuchsia_ui_input3::KeyboardMarker>();
1025 let view_ref_pair = fuchsia_scenic::ViewRefPair::new().expect("Failed to create ViewRefPair");
1026 let (device_registry_proxy, mut device_listener_stream) =
1027 fidl::endpoints::create_sync_proxy_and_stream::<fuipolicy::DeviceListenerRegistryMarker>();
1028
1029 let (relay, relay_handle) = new_input_relay();
1030 relay.start_relays(
1031 ¤t_task.kernel(),
1032 event_proxy_mode,
1033 touch_source_client_end,
1034 keyboard_proxy,
1035 mouse_source_client_end,
1036 view_ref_pair.view_ref,
1037 device_registry_proxy,
1038 touch_device.open_files.clone(),
1039 keyboard_device.open_files.clone(),
1040 mouse_device.open_files.clone(),
1041 Some(touch_device.inspect_status.clone()),
1042 Some(keyboard_device.inspect_status.clone()),
1043 Some(mouse_device.inspect_status.clone()),
1044 );
1045
1046 let keyboard_listener = match keyboard_stream.next().await {
1047 Some(Ok(fidl_fuchsia_ui_input3::KeyboardRequest::AddListener {
1048 view_ref: _,
1049 listener,
1050 responder,
1051 })) => {
1052 let _ = responder.send();
1053 listener.into_proxy()
1054 }
1055 _ => {
1056 panic!("Failed to get event");
1057 }
1058 };
1059
1060 let media_buttons_listener = match device_listener_stream.next().await {
1061 Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterListener {
1062 listener,
1063 responder,
1064 })) => {
1065 let _ = responder.send();
1066 listener.into_proxy()
1067 }
1068 _ => {
1069 panic!("Failed to get event");
1070 }
1071 };
1072
1073 let touch_buttons_listener = match device_listener_stream.next().await {
1074 Some(Ok(fuipolicy::DeviceListenerRegistryRequest::RegisterTouchButtonsListener {
1075 listener,
1076 responder,
1077 })) => {
1078 let _ = responder.send();
1079 listener.into_proxy()
1080 }
1081 _ => {
1082 panic!("Failed to get event");
1083 }
1084 };
1085
1086 (
1087 relay_handle,
1088 touch_device,
1089 keyboard_device,
1090 mouse_device,
1091 touch_file,
1092 keyboard_file,
1093 mouse_file,
1094 touch_source_stream,
1095 mouse_stream,
1096 keyboard_listener,
1097 media_buttons_listener,
1098 touch_buttons_listener,
1099 )
1100}
1101
1102#[cfg(test)]
1103mod test {
1104 use super::*;
1105 use anyhow::anyhow;
1106 use fidl_fuchsia_ui_input::{
1107 MediaButtonsEvent, TouchButton, TouchButtonsEvent, TouchDeviceInfo,
1108 };
1109 use fidl_fuchsia_ui_input3 as fuiinput;
1110 use fuipointer::{
1111 EventPhase, MouseEvent, TouchEvent, TouchInteractionId, TouchPointerSample, TouchResponse,
1112 TouchSourceRequest, TouchSourceRequestStream,
1113 };
1114 use starnix_core::task::CurrentTask;
1115 #[allow(deprecated, reason = "pre-existing usage")]
1116 use starnix_core::testing::create_kernel_task_and_unlocked;
1117 use starnix_core::vfs::{FileHandle, FileObject, VecOutputBuffer};
1118 use starnix_sync::{FileOpsCore, LockEqualOrBefore, Locked, Unlocked};
1119 use starnix_types::time::timeval_from_time;
1120 use starnix_uapi::errors::{EAGAIN, Errno};
1121 use starnix_uapi::input_id;
1122 use starnix_uapi::open_flags::OpenFlags;
1123 use zerocopy::FromBytes as _;
1124
1125 const INPUT_EVENT_SIZE: usize = std::mem::size_of::<uapi::input_event>();
1126
1127 async fn answer_next_touch_watch_request(
1130 request_stream: &mut TouchSourceRequestStream,
1131 touch_events: Vec<TouchEvent>,
1132 ) -> Vec<TouchResponse> {
1133 match request_stream.next().await {
1134 Some(Ok(TouchSourceRequest::Watch { responses, responder })) => {
1135 responder.send(touch_events).expect("failure sending Watch reply");
1136 responses
1137 }
1138 unexpected_request => panic!("unexpected request {:?}", unexpected_request),
1139 }
1140 }
1141
1142 async fn answer_next_mouse_watch_request(
1145 request_stream: &mut fuipointer::MouseSourceRequestStream,
1146 mouse_events: Vec<MouseEvent>,
1147 ) {
1148 match request_stream.next().await {
1149 Some(Ok(fuipointer::MouseSourceRequest::Watch { responder })) => {
1150 responder.send(mouse_events).expect("failure sending Watch reply");
1151 }
1152 unexpected_request => panic!("unexpected request {:?}", unexpected_request),
1153 }
1154 }
1155
1156 fn make_empty_touch_event(device_id: u32) -> TouchEvent {
1157 TouchEvent {
1158 pointer_sample: Some(TouchPointerSample {
1159 interaction: Some(TouchInteractionId {
1160 pointer_id: 0,
1161 device_id,
1162 interaction_id: 0,
1163 }),
1164 ..Default::default()
1165 }),
1166 ..Default::default()
1167 }
1168 }
1169
1170 fn make_touch_event_with_phase_device_id(
1171 phase: EventPhase,
1172 pointer_id: u32,
1173 device_id: u32,
1174 ) -> TouchEvent {
1175 make_touch_event_with_phase_device_id_position(phase, pointer_id, device_id, 0.0, 0.0)
1176 }
1177
1178 fn make_touch_event_with_phase_device_id_position(
1179 phase: EventPhase,
1180 pointer_id: u32,
1181 device_id: u32,
1182 x: f32,
1183 y: f32,
1184 ) -> TouchEvent {
1185 TouchEvent {
1186 timestamp: Some(0),
1187 pointer_sample: Some(TouchPointerSample {
1188 position_in_viewport: Some([x, y]),
1189 phase: Some(phase),
1190 interaction: Some(TouchInteractionId { pointer_id, device_id, interaction_id: 0 }),
1191 ..Default::default()
1192 }),
1193 ..Default::default()
1194 }
1195 }
1196
1197 fn make_mouse_wheel_event(scroll_v_ticks: i64, device_id: u32) -> MouseEvent {
1198 MouseEvent {
1199 timestamp: Some(0),
1200 pointer_sample: Some(MousePointerSample {
1201 device_id: Some(device_id),
1202 scroll_v: Some(scroll_v_ticks),
1203 ..Default::default()
1204 }),
1205 ..Default::default()
1206 }
1207 }
1208
1209 fn read_uapi_events<L>(
1210 locked: &mut Locked<L>,
1211 file: &FileHandle,
1212 current_task: &CurrentTask,
1213 ) -> Vec<uapi::input_event>
1214 where
1215 L: LockEqualOrBefore<FileOpsCore>,
1216 {
1217 std::iter::from_fn(|| {
1218 let locked = locked.cast_locked::<FileOpsCore>();
1219 let mut event_bytes = VecOutputBuffer::new(INPUT_EVENT_SIZE);
1220 match file.read(locked, current_task, &mut event_bytes) {
1221 Ok(INPUT_EVENT_SIZE) => Some(
1222 uapi::input_event::read_from_bytes(Vec::from(event_bytes).as_slice())
1223 .map_err(|_| anyhow!("failed to read input_event from buffer")),
1224 ),
1225 Ok(other_size) => {
1226 Some(Err(anyhow!("got {} bytes (expected {})", other_size, INPUT_EVENT_SIZE)))
1227 }
1228 Err(Errno { code: EAGAIN, .. }) => None,
1229 Err(other_error) => Some(Err(anyhow!("read failed: {:?}", other_error))),
1230 }
1231 })
1232 .enumerate()
1233 .map(|(i, read_res)| match read_res {
1234 Ok(event) => event,
1235 Err(e) => panic!("unexpected result {:?} on iteration {}", e, i),
1236 })
1237 .collect()
1238 }
1239
1240 fn create_test_touch_device(
1241 locked: &mut Locked<Unlocked>,
1242 current_task: &CurrentTask,
1243 input_relay: Arc<InputEventsRelayHandle>,
1244 device_id: u32,
1245 ) -> FileHandle {
1246 let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1247 input_relay.add_touch_device(device_id, open_files.clone(), None);
1248 let device_file = Arc::new(InputFile::new_touch(
1249 input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1250 1000,
1251 1000,
1252 None,
1253 ));
1254 open_files.lock().push(Arc::downgrade(&device_file));
1255
1256 let root_namespace_node = current_task
1257 .lookup_path_from_root(locked, ".".into())
1258 .expect("failed to get namespace node for root");
1259
1260 FileObject::new(
1261 locked,
1262 ¤t_task,
1263 Box::new(device_file),
1264 root_namespace_node,
1265 OpenFlags::empty(),
1266 )
1267 .expect("FileObject::new failed")
1268 }
1269
1270 fn make_uapi_input_event(ty: u32, code: u32, value: i32) -> uapi::input_event {
1271 uapi::input_event {
1272 time: timeval_from_time(zx::MonotonicInstant::from_nanos(0)),
1273 type_: ty as u16,
1274 code: code as u16,
1275 value,
1276 }
1277 }
1278
1279 #[::fuchsia::test]
1280 async fn route_touch_event_by_device_id() {
1281 #[allow(deprecated, reason = "pre-existing usage")]
1283 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1284 let (
1285 input_relay,
1286 _touch_device,
1287 _keyboard_device,
1288 _mouse_device,
1289 input_file,
1290 _keyboard_file,
1291 _mouse_file,
1292 mut touch_source_stream,
1293 _mouse_source_stream,
1294 _keyboard_listener,
1295 _media_buttons_listener,
1296 _touch_buttons_listener,
1297 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1298
1299 const DEVICE_ID: u32 = 10;
1300
1301 answer_next_touch_watch_request(
1302 &mut touch_source_stream,
1303 vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1304 )
1305 .await;
1306
1307 answer_next_touch_watch_request(
1311 &mut touch_source_stream,
1312 vec![make_empty_touch_event(DEVICE_ID)],
1313 )
1314 .await;
1315
1316 let events = read_uapi_events(locked, &input_file, ¤t_task);
1318 assert_ne!(events.len(), 0);
1320
1321 let device_id_10_file =
1323 create_test_touch_device(locked, ¤t_task, input_relay.clone(), DEVICE_ID);
1324
1325 answer_next_touch_watch_request(
1326 &mut touch_source_stream,
1327 vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1328 )
1329 .await;
1330
1331 answer_next_touch_watch_request(
1332 &mut touch_source_stream,
1333 vec![make_empty_touch_event(DEVICE_ID)],
1334 )
1335 .await;
1336
1337 let events = read_uapi_events(locked, &input_file, ¤t_task);
1338 assert_eq!(events.len(), 0);
1340
1341 let events = read_uapi_events(locked, &device_id_10_file, ¤t_task);
1342 assert_ne!(events.len(), 0);
1344 }
1345
1346 #[::fuchsia::test]
1347 async fn route_touch_event_by_device_id_multi_device_events_in_one_sequence() {
1348 #[allow(deprecated, reason = "pre-existing usage")]
1349 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1350 let (
1351 input_relay,
1352 _touch_device,
1353 _keyboard_device,
1354 _mouse_device,
1355 _input_file,
1356 _keyboard_file,
1357 _mouse_file,
1358 mut touch_source_stream,
1359 _mouse_source_stream,
1360 _keyboard_listener,
1361 _media_buttons_listener,
1362 _touch_buttons_listener,
1363 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1364
1365 const DEVICE_ID_10: u32 = 10;
1366 const DEVICE_ID_11: u32 = 11;
1367
1368 let device_id_10_file =
1369 create_test_touch_device(locked, ¤t_task, input_relay.clone(), DEVICE_ID_10);
1370
1371 let device_id_11_file =
1372 create_test_touch_device(locked, ¤t_task, input_relay.clone(), DEVICE_ID_11);
1373
1374 answer_next_touch_watch_request(
1376 &mut touch_source_stream,
1377 vec![
1378 make_touch_event_with_phase_device_id_position(
1379 EventPhase::Add,
1380 1,
1381 DEVICE_ID_10,
1382 10.0,
1383 20.0,
1384 ),
1385 make_touch_event_with_phase_device_id_position(
1386 EventPhase::Add,
1387 2,
1388 DEVICE_ID_11,
1389 30.0,
1390 40.0,
1391 ),
1392 ],
1393 )
1394 .await;
1395
1396 answer_next_touch_watch_request(&mut touch_source_stream, vec![]).await;
1397
1398 let events_10 = read_uapi_events(locked, &device_id_10_file, ¤t_task);
1399 let events_11 = read_uapi_events(locked, &device_id_11_file, ¤t_task);
1400 assert_eq!(events_10.len(), events_11.len());
1401
1402 assert_eq!(
1403 events_10,
1404 vec![
1405 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
1406 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 1),
1407 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 10),
1408 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 20),
1409 make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
1410 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
1411 ]
1412 );
1413
1414 assert_eq!(
1415 events_11,
1416 vec![
1417 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_SLOT, 0),
1418 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_TRACKING_ID, 2),
1419 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_X, 30),
1420 make_uapi_input_event(uapi::EV_ABS, uapi::ABS_MT_POSITION_Y, 40),
1421 make_uapi_input_event(uapi::EV_KEY, uapi::BTN_TOUCH, 1),
1422 make_uapi_input_event(uapi::EV_SYN, uapi::SYN_REPORT, 0),
1423 ]
1424 );
1425 }
1426
1427 #[::fuchsia::test]
1428 async fn route_key_event_by_device_id() {
1429 #[allow(deprecated, reason = "pre-existing usage")]
1431 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1432 let (
1433 input_relay,
1434 _touch_device,
1435 _keyboard_device,
1436 _mouse_device,
1437 _touch_file,
1438 keyboard_file,
1439 _mouse_file,
1440 _touch_source_stream,
1441 _mouse_source_stream,
1442 keyboard_listener,
1443 _media_buttons_listener,
1444 _touch_buttons_listener,
1445 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1446
1447 const DEVICE_ID: u32 = 10;
1448
1449 let key_event = fuiinput::KeyEvent {
1450 timestamp: Some(0),
1451 type_: Some(fuiinput::KeyEventType::Pressed),
1452 key: Some(fidl_fuchsia_input::Key::A),
1453 device_id: Some(DEVICE_ID),
1454 ..Default::default()
1455 };
1456
1457 let _ = keyboard_listener.on_key_event(&key_event).await;
1458
1459 let events = read_uapi_events(locked, &keyboard_file, ¤t_task);
1460 assert_ne!(events.len(), 0);
1462
1463 let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1465 input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
1466 let device_id_10_file = Arc::new(InputFile::new_keyboard(
1467 input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1468 None,
1469 ));
1470 open_files.lock().push(Arc::downgrade(&device_id_10_file));
1471 let root_namespace_node = current_task
1472 .lookup_path_from_root(locked, ".".into())
1473 .expect("failed to get namespace node for root");
1474 let device_id_10_file_object = FileObject::new(
1475 locked,
1476 ¤t_task,
1477 Box::new(device_id_10_file),
1478 root_namespace_node,
1479 OpenFlags::empty(),
1480 )
1481 .expect("FileObject::new failed");
1482
1483 let _ = keyboard_listener.on_key_event(&key_event).await;
1484
1485 let events = read_uapi_events(locked, &keyboard_file, ¤t_task);
1486 assert_eq!(events.len(), 0);
1488
1489 let events = read_uapi_events(locked, &device_id_10_file_object, ¤t_task);
1490 assert_ne!(events.len(), 0);
1492
1493 std::mem::drop(keyboard_listener); }
1495
1496 #[::fuchsia::test]
1497 async fn route_media_button_event_by_device_id() {
1498 #[allow(deprecated, reason = "pre-existing usage")]
1500 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1501 let (
1502 input_relay,
1503 _touch_device,
1504 _keyboard_device,
1505 _mouse_device,
1506 _touch_file,
1507 keyboard_file,
1508 _mouse_file,
1509 _touch_source_stream,
1510 _mouse_source_stream,
1511 _keyboard_listener,
1512 media_buttons_listener,
1513 _touch_buttons_listener,
1514 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1515
1516 const DEVICE_ID: u32 = 10;
1517
1518 let power_pressed_event = MediaButtonsEvent {
1519 volume: Some(0),
1520 mic_mute: Some(false),
1521 pause: Some(false),
1522 camera_disable: Some(false),
1523 power: Some(true),
1524 function: Some(false),
1525 device_id: Some(DEVICE_ID),
1526 ..Default::default()
1527 };
1528
1529 let _ = media_buttons_listener.on_event(power_pressed_event).await;
1530
1531 let events = read_uapi_events(locked, &keyboard_file, ¤t_task);
1532 assert_ne!(events.len(), 0);
1534
1535 let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1537 input_relay.add_keyboard_device(DEVICE_ID, open_files.clone(), None);
1538 let device_id_10_file = Arc::new(InputFile::new_keyboard(
1539 input_id { bustype: 0, vendor: 0, product: 0, version: 0 },
1540 None,
1541 ));
1542 open_files.lock().push(Arc::downgrade(&device_id_10_file));
1543 let root_namespace_node = current_task
1544 .lookup_path_from_root(locked, ".".into())
1545 .expect("failed to get namespace node for root");
1546 let device_id_10_file_object = FileObject::new(
1547 locked,
1548 ¤t_task,
1549 Box::new(device_id_10_file),
1550 root_namespace_node,
1551 OpenFlags::empty(),
1552 )
1553 .expect("FileObject::new failed");
1554
1555 let power_released_event = MediaButtonsEvent {
1556 volume: Some(0),
1557 mic_mute: Some(false),
1558 pause: Some(false),
1559 camera_disable: Some(false),
1560 power: Some(false),
1561 function: Some(false),
1562 device_id: Some(DEVICE_ID),
1563 ..Default::default()
1564 };
1565
1566 let _ = media_buttons_listener.on_event(power_released_event).await;
1567
1568 let events = read_uapi_events(locked, &keyboard_file, ¤t_task);
1569 assert_eq!(events.len(), 0);
1571
1572 let events = read_uapi_events(locked, &device_id_10_file_object, ¤t_task);
1573 assert_ne!(events.len(), 0);
1575
1576 std::mem::drop(media_buttons_listener); }
1578
1579 #[::fuchsia::test]
1580 async fn route_touch_button_event_by_device_id() {
1581 #[allow(deprecated, reason = "pre-existing usage")]
1583 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1584 let (
1585 input_relay,
1586 _touch_device,
1587 _keyboard_device,
1588 _mouse_device,
1589 touch_file,
1590 _keyboard_file,
1591 _mouse_file,
1592 _touch_source_stream,
1593 _mouse_source_stream,
1594 _keyboard_listener,
1595 _media_buttons_listener,
1596 touch_buttons_listener,
1597 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1598
1599 const DEVICE_ID: u32 = 10;
1600
1601 let palm_pressed_event: TouchButtonsEvent = TouchButtonsEvent {
1602 pressed_buttons: Some(vec![TouchButton::Palm]),
1603 device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
1604 ..Default::default()
1605 };
1606
1607 let _ = touch_buttons_listener.on_event(palm_pressed_event).await;
1608
1609 let events = read_uapi_events(locked, &touch_file, ¤t_task);
1610 assert_ne!(events.len(), 0);
1612
1613 let open_files: OpenedFiles = Arc::new(Mutex::new(vec![]));
1615 input_relay.add_touch_device(DEVICE_ID, open_files.clone(), None);
1616 let device_id_10_file =
1617 create_test_touch_device(locked, ¤t_task, input_relay.clone(), DEVICE_ID);
1618
1619 let power_released_event: TouchButtonsEvent = TouchButtonsEvent {
1620 pressed_buttons: Some(vec![]),
1621 device_info: Some(TouchDeviceInfo { id: Some(DEVICE_ID), ..Default::default() }),
1622 ..Default::default()
1623 };
1624
1625 let _ = touch_buttons_listener.on_event(power_released_event).await;
1626
1627 let events = read_uapi_events(locked, &touch_file, ¤t_task);
1628 assert_eq!(events.len(), 0);
1630
1631 let events = read_uapi_events(locked, &device_id_10_file, ¤t_task);
1632 assert_ne!(events.len(), 0);
1634
1635 std::mem::drop(touch_buttons_listener); }
1637
1638 #[::fuchsia::test]
1639 async fn touch_device_multi_reader() {
1640 #[allow(deprecated, reason = "pre-existing usage")]
1642 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1643 let (
1644 _input_relay,
1645 touch_device,
1646 _keyboard_device,
1647 _mouse_device,
1648 touch_reader1,
1649 _keyboard_file,
1650 _mouse_file,
1651 mut touch_source_stream,
1652 _mouse_source_stream,
1653 _keyboard_listener,
1654 _media_buttons_listener,
1655 _touch_buttons_listener,
1656 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1657
1658 let touch_reader2 =
1659 touch_device.open_test(locked, ¤t_task).expect("Failed to create input file");
1660
1661 const DEVICE_ID: u32 = 10;
1662
1663 answer_next_touch_watch_request(
1664 &mut touch_source_stream,
1665 vec![make_touch_event_with_phase_device_id(EventPhase::Add, 1, DEVICE_ID)],
1666 )
1667 .await;
1668
1669 answer_next_touch_watch_request(
1673 &mut touch_source_stream,
1674 vec![make_empty_touch_event(DEVICE_ID)],
1675 )
1676 .await;
1677
1678 let events_from_reader1 = read_uapi_events(locked, &touch_reader1, ¤t_task);
1680 let events_from_reader2 = read_uapi_events(locked, &touch_reader2, ¤t_task);
1681 assert_ne!(events_from_reader1.len(), 0);
1682 assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1683 }
1684
1685 #[::fuchsia::test]
1686 async fn keyboard_device_multi_reader() {
1687 #[allow(deprecated, reason = "pre-existing usage")]
1689 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1690 let (
1691 _input_relay,
1692 _touch_device,
1693 keyboard_device,
1694 _mouse_device,
1695 _touch_file,
1696 keyboard_reader1,
1697 _mouse_file,
1698 _touch_source_stream,
1699 _mouse_source_stream,
1700 keyboard_listener,
1701 _media_buttons_listener,
1702 _touch_buttons_listener,
1703 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1704
1705 let keyboard_reader2 =
1706 keyboard_device.open_test(locked, ¤t_task).expect("Failed to create input file");
1707
1708 const DEVICE_ID: u32 = 10;
1709
1710 let key_event = fuiinput::KeyEvent {
1711 timestamp: Some(0),
1712 type_: Some(fuiinput::KeyEventType::Pressed),
1713 key: Some(fidl_fuchsia_input::Key::A),
1714 device_id: Some(DEVICE_ID),
1715 ..Default::default()
1716 };
1717
1718 let _ = keyboard_listener.on_key_event(&key_event).await;
1719
1720 let events_from_reader1 = read_uapi_events(locked, &keyboard_reader1, ¤t_task);
1722 let events_from_reader2 = read_uapi_events(locked, &keyboard_reader2, ¤t_task);
1723 assert_ne!(events_from_reader1.len(), 0);
1724 assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1725 }
1726
1727 #[::fuchsia::test]
1728 async fn button_device_multi_reader() {
1729 #[allow(deprecated, reason = "pre-existing usage")]
1731 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1732 let (
1733 _input_relay,
1734 _touch_device,
1735 keyboard_device,
1736 _mouse_device,
1737 _touch_file,
1738 keyboard_reader1,
1739 _mouse_file,
1740 _touch_source_stream,
1741 _mouse_source_stream,
1742 _keyboard_listener,
1743 media_buttons_listener,
1744 _touch_buttons_listener,
1745 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1746
1747 let keyboard_reader2 =
1748 keyboard_device.open_test(locked, ¤t_task).expect("Failed to create input file");
1749
1750 const DEVICE_ID: u32 = 10;
1751
1752 let power_pressed_event = MediaButtonsEvent {
1753 volume: Some(0),
1754 mic_mute: Some(false),
1755 pause: Some(false),
1756 camera_disable: Some(false),
1757 power: Some(true),
1758 function: Some(false),
1759 device_id: Some(DEVICE_ID),
1760 ..Default::default()
1761 };
1762
1763 let _ = media_buttons_listener.on_event(power_pressed_event).await;
1764
1765 let events_from_reader1 = read_uapi_events(locked, &keyboard_reader1, ¤t_task);
1767 let events_from_reader2 = read_uapi_events(locked, &keyboard_reader2, ¤t_task);
1768 assert_ne!(events_from_reader1.len(), 0);
1769 assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1770 }
1771
1772 #[::fuchsia::test]
1773 async fn mouse_device_multi_reader() {
1774 #[allow(deprecated, reason = "pre-existing usage")]
1776 let (_kernel, current_task, locked) = create_kernel_task_and_unlocked();
1777 let (
1778 _input_relay,
1779 _touch_device,
1780 _keyboard_device,
1781 mouse_device,
1782 _touch_file,
1783 _keyboard_file,
1784 mouse_reader1,
1785 _touch_stream,
1786 mut mouse_stream,
1787 _keyboard_listener,
1788 _media_buttons_listener,
1789 _touch_buttons_listener,
1790 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::None).await;
1791
1792 let mouse_reader2 =
1793 mouse_device.open_test(locked, ¤t_task).expect("Failed to create input file");
1794
1795 const DEVICE_ID: u32 = 10;
1796
1797 answer_next_mouse_watch_request(
1798 &mut mouse_stream,
1799 vec![make_mouse_wheel_event(1, DEVICE_ID)],
1800 )
1801 .await;
1802
1803 answer_next_mouse_watch_request(
1807 &mut mouse_stream,
1808 vec![make_mouse_wheel_event(0, DEVICE_ID)],
1809 )
1810 .await;
1811
1812 let events_from_reader1 = read_uapi_events(locked, &mouse_reader1, ¤t_task);
1814 let events_from_reader2 = read_uapi_events(locked, &mouse_reader2, ¤t_task);
1815 assert_ne!(events_from_reader1.len(), 0);
1816 assert_eq!(events_from_reader1.len(), events_from_reader2.len());
1817 }
1818
1819 #[::fuchsia::test]
1820 async fn input_message_counters() {
1821 #[allow(deprecated, reason = "pre-existing usage")]
1823 let (kernel, current_task, locked) = create_kernel_task_and_unlocked();
1824 let (
1825 _input_relay,
1826 _touch_device,
1827 _keyboard_device,
1828 _mouse_device,
1829 _touch_file,
1830 keyboard_file,
1831 _mouse_file,
1832 _touch_source_stream,
1833 _mouse_source_stream,
1834 keyboard_listener,
1835 _media_buttons_listener,
1836 _touch_buttons_listener,
1837 ) = start_input_relays_for_test(locked, ¤t_task, EventProxyMode::WakeContainer).await;
1838
1839 const DEVICE_ID: u32 = 10;
1840
1841 let key_event = fuiinput::KeyEvent {
1842 timestamp: Some(0),
1843 type_: Some(fuiinput::KeyEventType::Pressed),
1844 key: Some(fidl_fuchsia_input::Key::A),
1845 device_id: Some(DEVICE_ID),
1846 ..Default::default()
1847 };
1848
1849 let _ = keyboard_listener.on_key_event(&key_event).await;
1850
1851 let events = read_uapi_events(locked, &keyboard_file, ¤t_task);
1852 assert_ne!(events.len(), 0);
1853
1854 assert!(!kernel.suspend_resume_manager.has_nonzero_message_counter());
1855 }
1856}