input_testing/
lib.rs

1// Copyright 2022 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use async_utils::event::Event as AsyncEvent;
6use fidl_fuchsia_input::Key;
7use fidl_fuchsia_input_injection::InputDeviceRegistryMarker;
8use fidl_fuchsia_input_report::{
9    ConsumerControlInputReport, ContactInputReport, DeviceInformation, InputReport,
10    KeyboardInputReport, MouseInputReport, TouchInputReport,
11};
12use fidl_fuchsia_ui_input::KeyboardReport;
13use fidl_fuchsia_ui_test_input::{
14    CoordinateUnit, KeyboardMarker, KeyboardRequest, KeyboardRequestStream,
15    MediaButtonsDeviceMarker, MediaButtonsDeviceRequest, MediaButtonsDeviceRequestStream,
16    MouseMarker, MouseRequest, MouseRequestStream,
17    RegistryRegisterKeyboardAndGetDeviceInfoResponse,
18    RegistryRegisterMediaButtonsDeviceAndGetDeviceInfoResponse,
19    RegistryRegisterMouseAndGetDeviceInfoResponse,
20    RegistryRegisterTouchScreenAndGetDeviceInfoResponse, RegistryRequest, RegistryRequestStream,
21    TouchScreenMarker, TouchScreenRequest, TouchScreenRequestStream,
22};
23use fuchsia_component::client::connect_to_protocol;
24use futures::{StreamExt, TryStreamExt};
25use keymaps::inverse_keymap::{InverseKeymap, Shift};
26use keymaps::usages::{Usages, hid_usage_to_input3_key};
27use log::{error, info, warn};
28use std::time::Duration;
29use {
30    fidl_fuchsia_math as math, fidl_fuchsia_ui_display_singleton as display_info,
31    fuchsia_async as fasync,
32};
33
34mod input_device;
35mod input_device_registry;
36mod input_reports_reader;
37
38/// Use this to place required DeviceInformation into DeviceDescriptor.
39fn new_fake_device_info() -> DeviceInformation {
40    DeviceInformation {
41        product_id: Some(42),
42        vendor_id: Some(43),
43        version: Some(u32::MAX),
44        polling_rate: Some(1000),
45        ..Default::default()
46    }
47}
48
49/// Converts the `input` string into a key sequence under the `InverseKeymap` derived from `keymap`.
50///
51/// This is intended for end-to-end and input testing only; for production use cases and general
52/// testing, IME injection should be used instead.
53///
54/// A translation from `input` to a sequence of keystrokes is not guaranteed to exist. If a
55/// translation does not exist, `None` is returned.
56///
57/// The sequence does not contain pauses except between repeated keys or to clear a shift state,
58/// though the sequence does terminate with an empty report (no keys pressed). A shift key
59/// transition is sent in advance of each series of keys that needs it.
60///
61/// Note that there is currently no way to distinguish between particular key releases. As such,
62/// only one key release report is generated even in combinations, e.g. Shift + A.
63///
64/// # Example
65///
66/// ```
67/// let key_sequence = derive_key_sequence(&keymaps::US_QWERTY, "A").unwrap();
68///
69/// // [shift, A, clear]
70/// assert_eq!(key_sequence.len(), 3);
71/// ```
72///
73/// TODO(https://fxbug.dev/42059899): Simplify the logic in this test.
74fn derive_key_sequence(keymap: &keymaps::Keymap<'_>, input: &str) -> Option<Vec<KeyboardReport>> {
75    let inverse_keymap = InverseKeymap::new(keymap);
76    let mut reports = vec![];
77    let mut shift_pressed = false;
78    let mut last_usage = None;
79
80    for ch in input.chars() {
81        let key_stroke = inverse_keymap.get(&ch)?;
82
83        match key_stroke.shift {
84            Shift::Yes if !shift_pressed => {
85                shift_pressed = true;
86                last_usage = Some(0);
87            }
88            Shift::No if shift_pressed => {
89                shift_pressed = false;
90                last_usage = Some(0);
91            }
92            _ => {
93                if last_usage == Some(key_stroke.usage) {
94                    last_usage = Some(0);
95                }
96            }
97        }
98
99        if let Some(0) = last_usage {
100            reports.push(KeyboardReport {
101                pressed_keys: if shift_pressed {
102                    vec![Usages::HidUsageKeyLeftShift as u32]
103                } else {
104                    vec![]
105                },
106            });
107        }
108
109        last_usage = Some(key_stroke.usage);
110
111        reports.push(KeyboardReport {
112            pressed_keys: if shift_pressed {
113                vec![key_stroke.usage, Usages::HidUsageKeyLeftShift as u32]
114            } else {
115                vec![key_stroke.usage]
116            },
117        });
118    }
119
120    reports.push(KeyboardReport { pressed_keys: vec![] });
121
122    Some(reports)
123}
124
125fn convert_keyboard_report_to_keys(report: &KeyboardReport) -> Vec<Key> {
126    report
127        .pressed_keys
128        .iter()
129        .map(|&usage| {
130            hid_usage_to_input3_key(usage.try_into().expect("failed to convert usage to u16"))
131                .unwrap_or_else(|| panic!("no Key for usage {:?}", usage))
132        })
133        .collect()
134}
135
136async fn register_touch_screen(
137    mut registry: input_device_registry::InputDeviceRegistry,
138    task_group: &mut fasync::TaskGroup,
139    device_server_end: fidl::endpoints::ServerEnd<TouchScreenMarker>,
140    got_input_reports_reader: AsyncEvent,
141    min_x: i64,
142    max_x: i64,
143    min_y: i64,
144    max_y: i64,
145) -> input_device::DeviceId {
146    let device = registry
147        .add_touchscreen_device(min_x, max_x, min_y, max_y)
148        .await
149        .expect("failed to create fake touchscreen device");
150    let device_id = device.device_id;
151
152    task_group.spawn(async move {
153        handle_touchscreen_request_stream(device, device_server_end.into_stream()).await;
154    });
155
156    info!("wait for input-pipeline setup input-reader");
157    let _ = got_input_reports_reader.wait().await;
158    info!("input-pipeline setup input-reader.");
159
160    device_id
161}
162
163async fn register_media_button(
164    mut registry: input_device_registry::InputDeviceRegistry,
165    task_group: &mut fasync::TaskGroup,
166    device_server_end: fidl::endpoints::ServerEnd<MediaButtonsDeviceMarker>,
167    got_input_reports_reader: AsyncEvent,
168) -> input_device::DeviceId {
169    let device = registry
170        .add_media_buttons_device()
171        .await
172        .expect("failed to create fake media buttons device");
173    let device_id = device.device_id;
174
175    task_group.spawn(async move {
176        handle_media_buttons_device_request_stream(device, device_server_end.into_stream()).await;
177    });
178
179    info!("wait for input-pipeline setup input-reader");
180    let _ = got_input_reports_reader.wait().await;
181    info!("input-pipeline setup input-reader.");
182
183    device_id
184}
185
186async fn register_keyboard(
187    mut registry: input_device_registry::InputDeviceRegistry,
188    task_group: &mut fasync::TaskGroup,
189    device_server_end: fidl::endpoints::ServerEnd<KeyboardMarker>,
190    got_input_reports_reader: AsyncEvent,
191) -> input_device::DeviceId {
192    let device = registry.add_keyboard_device().await.expect("failed to create fake keyboard");
193    let device_id = device.device_id;
194
195    task_group.spawn(async move {
196        handle_keyboard_request_stream(device, device_server_end.into_stream()).await;
197    });
198
199    info!("wait for input-pipeline setup input-reader");
200    let _ = got_input_reports_reader.wait().await;
201    info!("input-pipeline setup input-reader.");
202
203    device_id
204}
205
206async fn register_mouse(
207    mut registry: input_device_registry::InputDeviceRegistry,
208    task_group: &mut fasync::TaskGroup,
209    device_server_end: fidl::endpoints::ServerEnd<MouseMarker>,
210    got_input_reports_reader: AsyncEvent,
211) -> input_device::DeviceId {
212    let device = registry.add_mouse_device().await.expect("failed to create fake mouse");
213    let device_id = device.device_id;
214
215    task_group.spawn(async move {
216        handle_mouse_request_stream(device, device_server_end.into_stream()).await;
217    });
218
219    info!("wait for input-pipeline setup input-reader");
220    let _ = got_input_reports_reader.wait().await;
221    info!("input-pipeline setup input-reader.");
222
223    device_id
224}
225
226/// Serves `fuchsia.ui.test.input.Registry`.
227pub async fn handle_registry_request_stream(request_stream: RegistryRequestStream) {
228    request_stream
229        .try_for_each_concurrent(None, |request| async {
230            let input_device_registry = connect_to_protocol::<InputDeviceRegistryMarker>()
231                .expect("connect to input_device_registry");
232            let got_input_reports_reader = AsyncEvent::new();
233
234            let registry = input_device_registry::InputDeviceRegistry::new(
235                input_device_registry,
236                got_input_reports_reader.clone(),
237            );
238            let mut task_group = fasync::TaskGroup::new();
239
240            match request {
241                RegistryRequest::RegisterTouchScreen { payload, responder, .. } => {
242                    info!("register touchscreen");
243                    let device = payload
244                        .device
245                        .expect("no touchscreen device provided in registration request");
246                    let (min_x, max_x, min_y, max_y) = match payload.coordinate_unit {
247                        Some(CoordinateUnit::PhysicalPixels) => {
248                            let display_info_proxy =
249                                connect_to_protocol::<display_info::InfoMarker>()
250                                    .expect("failed to connect to display info service");
251                            let display_dimensions = display_info_proxy
252                                .get_metrics()
253                                .await
254                                .expect("failed to get display metrics")
255                                .extent_in_px
256                                .expect("display metrics missing extent in px");
257                            (
258                                0,
259                                display_dimensions.width as i64,
260                                0,
261                                display_dimensions.height as i64,
262                            )
263                        }
264                        Some(CoordinateUnit::RegisteredDimensions) => {
265                            let dimensions =
266                                payload.display_dimensions.expect("missing dimensions");
267                            if dimensions.min_x >= dimensions.max_x
268                                || dimensions.min_y >= dimensions.max_y
269                            {
270                                panic!("invalid dimensions");
271                            }
272                            (dimensions.min_x, dimensions.max_x, dimensions.min_y, dimensions.max_y)
273                        }
274                        _ => (-1000, 1000, -1000, 1000),
275                    };
276
277                    register_touch_screen(
278                        registry,
279                        &mut task_group,
280                        device,
281                        got_input_reports_reader,
282                        min_x,
283                        max_x,
284                        min_y,
285                        max_y,
286                    )
287                    .await;
288
289                    responder.send().expect("Failed to respond to RegisterTouchScreen request");
290                }
291                RegistryRequest::RegisterTouchScreenAndGetDeviceInfo {
292                    payload, responder, ..
293                } => {
294                    info!("register touchscreen");
295                    let device = payload
296                        .device
297                        .expect("no touchscreen device provided in registration request");
298                    let (min_x, max_x, min_y, max_y) = match payload.coordinate_unit {
299                        Some(CoordinateUnit::PhysicalPixels) => {
300                            let display_info_proxy =
301                                connect_to_protocol::<display_info::InfoMarker>()
302                                    .expect("failed to connect to display info service");
303                            let display_dimensions = display_info_proxy
304                                .get_metrics()
305                                .await
306                                .expect("failed to get display metrics")
307                                .extent_in_px
308                                .expect("display metrics missing extent in px");
309                            (
310                                0,
311                                display_dimensions.width as i64,
312                                0,
313                                display_dimensions.height as i64,
314                            )
315                        }
316                        Some(CoordinateUnit::RegisteredDimensions) => {
317                            let dimensions =
318                                payload.display_dimensions.expect("missing dimensions");
319                            if dimensions.min_x >= dimensions.max_x
320                                || dimensions.min_y >= dimensions.max_y
321                            {
322                                panic!("invalid dimensions");
323                            }
324                            (dimensions.min_x, dimensions.max_x, dimensions.min_y, dimensions.max_y)
325                        }
326                        _ => (-1000, 1000, -1000, 1000),
327                    };
328
329                    let device_id = register_touch_screen(
330                        registry,
331                        &mut task_group,
332                        device,
333                        got_input_reports_reader,
334                        min_x,
335                        max_x,
336                        min_y,
337                        max_y,
338                    )
339                    .await;
340
341                    responder
342                        .send(RegistryRegisterTouchScreenAndGetDeviceInfoResponse {
343                            device_id: Some(device_id),
344                            ..Default::default()
345                        })
346                        .expect("Failed to respond to RegisterTouchScreenAndGetDeviceInfo request");
347                }
348                RegistryRequest::RegisterMediaButtonsDevice { payload, responder, .. } => {
349                    info!("register media buttons device");
350                    let device = payload
351                        .device
352                        .expect("no media buttons device provided in registration request");
353
354                    register_media_button(
355                        registry,
356                        &mut task_group,
357                        device,
358                        got_input_reports_reader,
359                    )
360                    .await;
361
362                    responder
363                        .send()
364                        .expect("Failed to respond to RegisterMediaButtonsDevice request");
365                }
366                RegistryRequest::RegisterMediaButtonsDeviceAndGetDeviceInfo {
367                    payload,
368                    responder,
369                    ..
370                } => {
371                    info!("register media buttons device");
372                    let device = payload
373                        .device
374                        .expect("no media buttons device provided in registration request");
375
376                    let device_id = register_media_button(
377                        registry,
378                        &mut task_group,
379                        device,
380                        got_input_reports_reader,
381                    )
382                    .await;
383
384                    responder.send(RegistryRegisterMediaButtonsDeviceAndGetDeviceInfoResponse {
385                        device_id: Some(device_id),
386                        ..Default::default()
387                    }).expect(
388                        "Failed to respond to RegisterMediaButtonsDeviceAndGetDeviceInfo request",
389                    );
390                }
391                RegistryRequest::RegisterKeyboard { payload, responder, .. } => {
392                    info!("register keyboard device");
393                    let device = payload
394                        .device
395                        .expect("no keyboard device provided in registration request");
396
397                    register_keyboard(registry, &mut task_group, device, got_input_reports_reader)
398                        .await;
399
400                    responder.send().expect("Failed to respond to RegisterKeyboard request");
401                }
402                RegistryRequest::RegisterKeyboardAndGetDeviceInfo {
403                    payload, responder, ..
404                } => {
405                    info!("register keyboard device");
406                    let device = payload
407                        .device
408                        .expect("no keyboard device provided in registration request");
409
410                    let device_id = register_keyboard(
411                        registry,
412                        &mut task_group,
413                        device,
414                        got_input_reports_reader,
415                    )
416                    .await;
417
418                    responder
419                        .send(RegistryRegisterKeyboardAndGetDeviceInfoResponse {
420                            device_id: Some(device_id),
421                            ..Default::default()
422                        })
423                        .expect("Failed to respond to RegisterKeyboardAndGetDeviceInfo request");
424                }
425                RegistryRequest::RegisterMouse { payload, responder } => {
426                    info!("register mouse device");
427                    let device = payload.device.expect("no mouse provided in registration request");
428
429                    register_mouse(registry, &mut task_group, device, got_input_reports_reader)
430                        .await;
431
432                    responder.send().expect("Failed to respond to RegisterMouse request");
433                }
434                RegistryRequest::RegisterMouseAndGetDeviceInfo { payload, responder } => {
435                    info!("register mouse device");
436                    let device = payload.device.expect("no mouse provided in registration request");
437
438                    let device_id =
439                        register_mouse(registry, &mut task_group, device, got_input_reports_reader)
440                            .await;
441
442                    responder
443                        .send(RegistryRegisterMouseAndGetDeviceInfoResponse {
444                            device_id: Some(device_id),
445                            ..Default::default()
446                        })
447                        .expect("Failed to respond to RegisterMouse request");
448                }
449            }
450
451            task_group.join().await;
452            Ok(())
453        })
454        .await
455        .expect("failed to serve test realm factory request stream");
456}
457
458fn input_report_for_touch_contacts(
459    contacts: Vec<(u32, math::Vec_)>,
460    trace_id: Option<u64>,
461) -> InputReport {
462    let contact_input_reports = contacts
463        .into_iter()
464        .map(|(contact_id, location)| ContactInputReport {
465            contact_id: Some(contact_id),
466            position_x: Some(location.x as i64),
467            position_y: Some(location.y as i64),
468            contact_width: Some(0),
469            contact_height: Some(0),
470            ..Default::default()
471        })
472        .collect();
473
474    let touch_input_report = TouchInputReport {
475        contacts: Some(contact_input_reports),
476        pressed_buttons: Some(vec![]),
477        ..Default::default()
478    };
479
480    InputReport {
481        event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
482        touch: Some(touch_input_report),
483        trace_id,
484        ..Default::default()
485    }
486}
487
488/// Serves `fuchsia.ui.test.input.TouchScreen`.
489async fn handle_touchscreen_request_stream(
490    touchscreen_device: input_device::InputDevice,
491    mut request_stream: TouchScreenRequestStream,
492) {
493    while let Some(request) = request_stream.next().await {
494        match request {
495            Ok(TouchScreenRequest::SimulateTap { payload, responder }) => {
496                if let Some(tap_location) = payload.tap_location {
497                    {
498                        fuchsia_trace::duration!(c"input", c"simulate_tap_down");
499                        let trace_id = fuchsia_trace::Id::random();
500                        fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
501                        touchscreen_device
502                            .send_input_report(input_report_for_touch_contacts(
503                                vec![(1, tap_location)],
504                                Some(trace_id.into()),
505                            ))
506                            .expect("Failed to send tap input report");
507                    }
508
509                    // Send a report with an empty set of touch contacts, so that input
510                    // pipeline generates a pointer event with phase == UP.
511                    fuchsia_trace::duration!(c"input", c"simulate_tap_up");
512                    let trace_id = fuchsia_trace::Id::random();
513                    fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
514                    touchscreen_device
515                        .send_input_report(input_report_for_touch_contacts(
516                            vec![],
517                            Some(trace_id.into()),
518                        ))
519                        .expect("failed to send empty input report");
520
521                    responder.send().expect("Failed to send SimulateTap response");
522                } else {
523                    warn!("SimulateTap request missing tap location");
524                }
525            }
526            Ok(TouchScreenRequest::SimulateSwipe { payload, responder }) => {
527                // Compute the x- and y- displacements between successive touch events.
528                let start_location = payload.start_location.expect("missing start location");
529                let end_location = payload.end_location.expect("missing end location");
530                let move_event_count = payload.move_event_count.expect("missing move event count");
531                assert_ne!(move_event_count, 0);
532                let duration_nanos = payload.duration.unwrap_or(0);
533                let delay_nanos = duration_nanos / ((move_event_count as i64) + 1);
534                let delay = fasync::MonotonicDuration::from_nanos(delay_nanos);
535
536                let start_x_f = start_location.x as f64;
537                let start_y_f = start_location.y as f64;
538                let end_x_f = end_location.x as f64;
539                let end_y_f = end_location.y as f64;
540                let move_event_count_f = move_event_count as f64;
541                let step_size_x = (end_x_f - start_x_f) / move_event_count_f;
542                let step_size_y = (end_y_f - start_y_f) / move_event_count_f;
543
544                // Generate an event at `start_location`, followed by `move_event_count - 1`
545                // evenly-spaced events, followed by an event at `end_location`.
546                for i in 0..move_event_count + 1 {
547                    let i_f = i as f64;
548                    let event_x = start_x_f + (i_f * step_size_x);
549                    let event_y = start_y_f + (i_f * step_size_y);
550
551                    fuchsia_trace::duration!(c"input", c"simulate_swipe_move", "idx"=>i);
552                    let trace_id = fuchsia_trace::Id::random();
553                    fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
554
555                    touchscreen_device
556                        .send_input_report(input_report_for_touch_contacts(
557                            vec![(1, math::Vec_ { x: event_x as i32, y: event_y as i32 })],
558                            Some(trace_id.into()),
559                        ))
560                        .expect("Failed to send tap input report");
561                    delay.sleep();
562                }
563
564                // Send a report with an empty set of touch contacts, so that input
565                // pipeline generates a pointer event with phase == UP.
566                fuchsia_trace::duration!(c"input", c"simulate_swipe_up");
567                let trace_id = fuchsia_trace::Id::random();
568                fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
569                touchscreen_device
570                    .send_input_report(input_report_for_touch_contacts(
571                        vec![],
572                        Some(trace_id.into()),
573                    ))
574                    .expect("failed to send empty input report");
575
576                responder.send().expect("Failed to send SimulateSwipe response");
577            }
578            Ok(TouchScreenRequest::SimulateMultiTap { payload, responder }) => {
579                let tap_locations = payload.tap_locations.expect("missing tap locations");
580
581                {
582                    fuchsia_trace::duration!(c"input", c"simulate_multi_tap_down");
583                    let trace_id = fuchsia_trace::Id::random();
584                    fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
585                    touchscreen_device
586                        .send_input_report(input_report_for_touch_contacts(
587                            tap_locations
588                                .into_iter()
589                                .enumerate()
590                                .map(|(i, it)| (i as u32, it))
591                                .collect(),
592                            Some(trace_id.into()),
593                        ))
594                        .expect("Failed to send tap input report");
595                }
596
597                // Send a report with an empty set of touch contacts, so that input
598                // pipeline generates a pointer event with phase == UP.
599                fuchsia_trace::duration!(c"input", c"simulate_multi_tap_up");
600                let trace_id = fuchsia_trace::Id::random();
601                fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
602                touchscreen_device
603                    .send_input_report(input_report_for_touch_contacts(
604                        vec![],
605                        Some(trace_id.into()),
606                    ))
607                    .expect("failed to send empty input report");
608                responder.send().expect("Failed to send SimulateMultiTap response");
609            }
610            Ok(TouchScreenRequest::SimulateMultiFingerGesture { payload, responder }) => {
611                // Compute the x- and y- displacements between successive touch events.
612                let start_locations = payload.start_locations.expect("missing start locations");
613                let end_locations = payload.end_locations.expect("missing end locations");
614                let move_event_count = payload.move_event_count.expect("missing move event count");
615                let finger_count = payload.finger_count.expect("missing finger count") as usize;
616
617                let move_event_count_f = move_event_count as f32;
618
619                let mut steps: Vec<math::VecF> = vec![];
620
621                for finger in 0..finger_count {
622                    let start_x = start_locations[finger].x as f32;
623                    let start_y = start_locations[finger].y as f32;
624                    let end_x = end_locations[finger].x as f32;
625                    let end_y = end_locations[finger].y as f32;
626                    let step_x = (end_x - start_x) / move_event_count_f;
627                    let step_y = (end_y - start_y) / move_event_count_f;
628                    steps.push(math::VecF { x: step_x, y: step_y });
629                }
630
631                // Generate an event at `start_location`, followed by `move_event_count - 1`
632                // evenly-spaced events, followed by an event at `end_location`.
633                for i in 0..move_event_count {
634                    let i_f = i as f32;
635
636                    let mut contacts: Vec<(u32, math::Vec_)> = vec![];
637
638                    for finger in 0..finger_count {
639                        let start_x = start_locations[finger].x as f32;
640                        let start_y = start_locations[finger].y as f32;
641                        let event_x = (start_x + i_f * steps[finger].x) as i32;
642                        let event_y = (start_y + i_f * steps[finger].y) as i32;
643                        contacts.push((finger as u32, math::Vec_ { x: event_x, y: event_y }));
644                    }
645
646                    fuchsia_trace::duration!(c"input", c"simulate_multi_finger_gesture_move", "idx"=>i);
647                    let trace_id = fuchsia_trace::Id::random();
648                    fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
649
650                    touchscreen_device
651                        .send_input_report(input_report_for_touch_contacts(
652                            contacts,
653                            Some(trace_id.into()),
654                        ))
655                        .expect("Failed to send tap input report");
656                }
657
658                // Send a report with an empty set of touch contacts, so that input
659                // pipeline generates a pointer event with phase == UP.
660                fuchsia_trace::duration!(c"input", c"simulate_multi_finger_gesture_up");
661                let trace_id = fuchsia_trace::Id::random();
662                fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
663                touchscreen_device
664                    .send_input_report(input_report_for_touch_contacts(
665                        vec![],
666                        Some(trace_id.into()),
667                    ))
668                    .expect("failed to send empty input report");
669
670                responder.send().expect("Failed to send SimulateMultiFingerGesture response");
671            }
672            Ok(TouchScreenRequest::SimulateTouchEvent { report, responder }) => {
673                fuchsia_trace::duration!(c"input", c"simulate_touch_event");
674                let trace_id = fuchsia_trace::Id::random();
675                fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
676                let input_report = InputReport {
677                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
678                    touch: Some(report),
679                    trace_id: Some(trace_id.into()),
680                    ..Default::default()
681                };
682                touchscreen_device
683                    .send_input_report(input_report)
684                    .expect("failed to send empty input report");
685                responder.send().expect("Failed to send SimulateTouchEvent response");
686            }
687            Err(e) => {
688                error!("Error on touchscreen channel: {}", e);
689                return;
690            }
691        }
692    }
693}
694
695/// Serves `fuchsia.ui.test.input.MediaButtonsDevice`.
696async fn handle_media_buttons_device_request_stream(
697    media_buttons_device: input_device::InputDevice,
698    mut request_stream: MediaButtonsDeviceRequestStream,
699) {
700    while let Some(request) = request_stream.next().await {
701        match request {
702            Ok(MediaButtonsDeviceRequest::SimulateButtonPress { payload, responder }) => {
703                if let Some(button) = payload.button {
704                    let media_buttons_input_report = ConsumerControlInputReport {
705                        pressed_buttons: Some(vec![button]),
706                        ..Default::default()
707                    };
708
709                    let input_report = InputReport {
710                        event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
711                        consumer_control: Some(media_buttons_input_report),
712                        ..Default::default()
713                    };
714
715                    media_buttons_device
716                        .send_input_report(input_report)
717                        .expect("Failed to send button press input report");
718
719                    // Send a report with an empty set of pressed buttons,
720                    // so that input pipeline generates a media buttons
721                    // event with the target button being released.
722                    let empty_report = InputReport {
723                        event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
724                        consumer_control: Some(ConsumerControlInputReport {
725                            pressed_buttons: Some(vec![]),
726                            ..Default::default()
727                        }),
728                        ..Default::default()
729                    };
730
731                    media_buttons_device
732                        .send_input_report(empty_report)
733                        .expect("Failed to send button release input report");
734
735                    responder.send().expect("Failed to send SimulateButtonPress response");
736                } else {
737                    warn!("SimulateButtonPress request missing button");
738                }
739            }
740            Ok(MediaButtonsDeviceRequest::SendButtonsState { payload, responder }) => {
741                let buttons = match payload.buttons {
742                    Some(buttons) => buttons,
743                    None => vec![],
744                };
745                let input_report = InputReport {
746                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
747                    consumer_control: Some(ConsumerControlInputReport {
748                        pressed_buttons: Some(buttons),
749                        ..Default::default()
750                    }),
751                    ..Default::default()
752                };
753
754                media_buttons_device
755                    .send_input_report(input_report)
756                    .expect("Failed to send button press input report");
757
758                responder.send().expect("Failed to send SimulateButtonsPress response");
759            }
760            Err(e) => {
761                error!("Error on media buttons device channel: {}", e);
762                return;
763            }
764        }
765    }
766}
767
768/// Serves `fuchsia.ui.test.input.Keyboard`.
769async fn handle_keyboard_request_stream(
770    keyboard_device: input_device::InputDevice,
771    mut request_stream: KeyboardRequestStream,
772) {
773    while let Some(request) = request_stream.next().await {
774        match request {
775            Ok(KeyboardRequest::SimulateUsAsciiTextEntry { payload, responder }) => {
776                if let Some(text) = payload.text {
777                    let key_sequence = derive_key_sequence(&keymaps::US_QWERTY, &text)
778                        .expect("Failed to derive key sequence");
779
780                    let mut key_iter = key_sequence.into_iter().peekable();
781                    while let Some(keyboard_report) = key_iter.next() {
782                        let input_report = InputReport {
783                            event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
784                            keyboard: Some(KeyboardInputReport {
785                                pressed_keys3: Some(convert_keyboard_report_to_keys(
786                                    &keyboard_report,
787                                )),
788                                ..Default::default()
789                            }),
790                            ..Default::default()
791                        };
792
793                        keyboard_device
794                            .send_input_report(input_report)
795                            .expect("Failed to send key event report");
796
797                        if key_iter.peek().is_some() {
798                            fuchsia_async::Timer::new(Duration::from_millis(100)).await;
799                        }
800                    }
801
802                    responder.send().expect("Failed to send SimulateTextEntry response");
803                } else {
804                    warn!("SimulateTextEntry request missing text");
805                }
806            }
807            Ok(KeyboardRequest::SimulateKeyEvent { payload, responder }) => {
808                let keyboard_report = payload.report.expect("no report");
809                let input_report = InputReport {
810                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
811                    keyboard: Some(keyboard_report),
812                    ..Default::default()
813                };
814
815                keyboard_device
816                    .send_input_report(input_report)
817                    .expect("Failed to send key event report");
818
819                responder.send().expect("Failed to send SimulateKeyEvent response");
820            }
821            Ok(KeyboardRequest::SimulateKeyPress { payload, responder }) => {
822                let key_code = payload.key_code.expect("no key code");
823
824                let down_report = InputReport {
825                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
826                    keyboard: Some(KeyboardInputReport {
827                        pressed_keys3: Some(vec![key_code]),
828                        ..Default::default()
829                    }),
830                    ..Default::default()
831                };
832
833                let up_report = InputReport {
834                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
835                    keyboard: Some(KeyboardInputReport {
836                        pressed_keys3: Some(vec![]),
837                        ..Default::default()
838                    }),
839                    ..Default::default()
840                };
841
842                keyboard_device.send_input_report(down_report).expect("Failed to send key down");
843
844                keyboard_device.send_input_report(up_report).expect("Failed to send key up");
845
846                responder.send().expect("Failed to send SimulateKeyPress response");
847            }
848            Err(e) => {
849                error!("Error on keyboard device channel: {}", e);
850                return;
851            }
852        }
853    }
854}
855
856/// Serves `fuchsia.ui.test.input.Mouse`.
857async fn handle_mouse_request_stream(
858    mouse_device: input_device::InputDevice,
859    mut request_stream: MouseRequestStream,
860) {
861    while let Some(request) = request_stream.next().await {
862        match request {
863            Ok(MouseRequest::SimulateMouseEvent { payload, responder }) => {
864                let mut mouse_input_report = MouseInputReport {
865                    movement_x: payload.movement_x,
866                    movement_y: payload.movement_y,
867                    scroll_v: payload.scroll_v_detent,
868                    scroll_h: payload.scroll_h_detent,
869                    ..Default::default()
870                };
871                if let Some(pressed_buttons) = payload.pressed_buttons {
872                    mouse_input_report.pressed_buttons = Some(
873                        pressed_buttons
874                            .into_iter()
875                            .map(|b| {
876                                b.into_primitive()
877                                    .try_into()
878                                    .expect("failed to convert MouseButton to u8")
879                            })
880                            .collect(),
881                    );
882                }
883
884                let input_report = InputReport {
885                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
886                    mouse: Some(mouse_input_report),
887                    ..Default::default()
888                };
889
890                mouse_device
891                    .send_input_report(input_report)
892                    .expect("Failed to send key event report");
893
894                responder.send().expect("Failed to send SimulateMouseEvent response");
895            }
896            Err(e) => {
897                error!("Error on keyboard device channel: {}", e);
898                return;
899            }
900        }
901    }
902}
903
904#[cfg(test)]
905mod tests {
906    // Most of the functions in this file need to bind to FIDL services in
907    // this component's environment to do their work, but a component can't
908    // modify its own environment. Hence, we can't validate those functions.
909    //
910    // However, we can (and do) validate derive_key_sequence().
911
912    use super::{KeyboardReport, Usages, derive_key_sequence};
913    use pretty_assertions::assert_eq;
914
915    // TODO(https://fxbug.dev/42059899): Remove this macro.
916    macro_rules! reports {
917        ( $( [ $( $usages:expr ),* ] ),* $( , )? ) => {
918            Some(vec![
919                $(
920                    KeyboardReport {
921                        pressed_keys: vec![$($usages as u32),*]
922                    }
923                ),*
924            ])
925        }
926    }
927
928    #[test]
929    fn lowercase() {
930        assert_eq!(
931            derive_key_sequence(&keymaps::US_QWERTY, "lowercase"),
932            reports![
933                [Usages::HidUsageKeyL],
934                [Usages::HidUsageKeyO],
935                [Usages::HidUsageKeyW],
936                [Usages::HidUsageKeyE],
937                [Usages::HidUsageKeyR],
938                [Usages::HidUsageKeyC],
939                [Usages::HidUsageKeyA],
940                [Usages::HidUsageKeyS],
941                [Usages::HidUsageKeyE],
942                [],
943            ]
944        );
945    }
946
947    #[test]
948    fn numerics() {
949        assert_eq!(
950            derive_key_sequence(&keymaps::US_QWERTY, "0123456789"),
951            reports![
952                [Usages::HidUsageKey0],
953                [Usages::HidUsageKey1],
954                [Usages::HidUsageKey2],
955                [Usages::HidUsageKey3],
956                [Usages::HidUsageKey4],
957                [Usages::HidUsageKey5],
958                [Usages::HidUsageKey6],
959                [Usages::HidUsageKey7],
960                [Usages::HidUsageKey8],
961                [Usages::HidUsageKey9],
962                [],
963            ]
964        );
965    }
966
967    #[test]
968    fn internet_text_entry() {
969        assert_eq!(
970            derive_key_sequence(&keymaps::US_QWERTY, "http://127.0.0.1:8080"),
971            reports![
972                [Usages::HidUsageKeyH],
973                [Usages::HidUsageKeyT],
974                [],
975                [Usages::HidUsageKeyT],
976                [Usages::HidUsageKeyP],
977                // ':'
978                // Shift is actuated first on its own, then together with
979                // the key.
980                [Usages::HidUsageKeyLeftShift],
981                [Usages::HidUsageKeySemicolon, Usages::HidUsageKeyLeftShift],
982                [],
983                [Usages::HidUsageKeySlash],
984                [],
985                [Usages::HidUsageKeySlash],
986                [Usages::HidUsageKey1],
987                [Usages::HidUsageKey2],
988                [Usages::HidUsageKey7],
989                [Usages::HidUsageKeyDot],
990                [Usages::HidUsageKey0],
991                [Usages::HidUsageKeyDot],
992                [Usages::HidUsageKey0],
993                [Usages::HidUsageKeyDot],
994                [Usages::HidUsageKey1],
995                [Usages::HidUsageKeyLeftShift],
996                [Usages::HidUsageKeySemicolon, Usages::HidUsageKeyLeftShift],
997                [],
998                [Usages::HidUsageKey8],
999                [Usages::HidUsageKey0],
1000                [Usages::HidUsageKey8],
1001                [Usages::HidUsageKey0],
1002                [],
1003            ]
1004        );
1005    }
1006
1007    #[test]
1008    fn sentence() {
1009        assert_eq!(
1010            derive_key_sequence(&keymaps::US_QWERTY, "Hello, world!"),
1011            reports![
1012                [Usages::HidUsageKeyLeftShift],
1013                [Usages::HidUsageKeyH, Usages::HidUsageKeyLeftShift],
1014                [],
1015                [Usages::HidUsageKeyE],
1016                [Usages::HidUsageKeyL],
1017                [],
1018                [Usages::HidUsageKeyL],
1019                [Usages::HidUsageKeyO],
1020                [Usages::HidUsageKeyComma],
1021                [Usages::HidUsageKeySpace],
1022                [Usages::HidUsageKeyW],
1023                [Usages::HidUsageKeyO],
1024                [Usages::HidUsageKeyR],
1025                [Usages::HidUsageKeyL],
1026                [Usages::HidUsageKeyD],
1027                [Usages::HidUsageKeyLeftShift],
1028                [Usages::HidUsageKey1, Usages::HidUsageKeyLeftShift],
1029                [],
1030            ]
1031        );
1032    }
1033
1034    #[test]
1035    fn hold_shift() {
1036        assert_eq!(
1037            derive_key_sequence(&keymaps::US_QWERTY, "ALL'S WELL!"),
1038            reports![
1039                [Usages::HidUsageKeyLeftShift],
1040                [Usages::HidUsageKeyA, Usages::HidUsageKeyLeftShift],
1041                [Usages::HidUsageKeyL, Usages::HidUsageKeyLeftShift],
1042                [Usages::HidUsageKeyLeftShift],
1043                [Usages::HidUsageKeyL, Usages::HidUsageKeyLeftShift],
1044                [],
1045                [Usages::HidUsageKeyApostrophe],
1046                [Usages::HidUsageKeyLeftShift],
1047                [Usages::HidUsageKeyS, Usages::HidUsageKeyLeftShift],
1048                [Usages::HidUsageKeySpace, Usages::HidUsageKeyLeftShift],
1049                [Usages::HidUsageKeyW, Usages::HidUsageKeyLeftShift],
1050                [Usages::HidUsageKeyE, Usages::HidUsageKeyLeftShift],
1051                [Usages::HidUsageKeyL, Usages::HidUsageKeyLeftShift],
1052                [Usages::HidUsageKeyLeftShift],
1053                [Usages::HidUsageKeyL, Usages::HidUsageKeyLeftShift],
1054                [Usages::HidUsageKey1, Usages::HidUsageKeyLeftShift],
1055                [],
1056            ]
1057        );
1058    }
1059
1060    #[test]
1061    fn tab_and_newline() {
1062        assert_eq!(
1063            derive_key_sequence(&keymaps::US_QWERTY, "\tHello\n"),
1064            reports![
1065                [Usages::HidUsageKeyTab],
1066                [Usages::HidUsageKeyLeftShift],
1067                [Usages::HidUsageKeyH, Usages::HidUsageKeyLeftShift],
1068                [],
1069                [Usages::HidUsageKeyE],
1070                [Usages::HidUsageKeyL],
1071                [],
1072                [Usages::HidUsageKeyL],
1073                [Usages::HidUsageKeyO],
1074                [Usages::HidUsageKeyEnter],
1075                [],
1076            ]
1077        );
1078    }
1079}