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                let tap_location = payload.tap_location.expect("missing 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 touch down 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 touch up input report");
520
521                responder.send().expect("Failed to send SimulateTap response");
522            }
523            Ok(TouchScreenRequest::SimulateSwipe { payload, responder }) => {
524                // Compute the x- and y- displacements between successive touch events.
525                let start_location = payload.start_location.expect("missing start location");
526                let end_location = payload.end_location.expect("missing end location");
527                let move_event_count = payload.move_event_count.expect("missing move event count");
528                assert_ne!(move_event_count, 0);
529                let duration_nanos = payload.duration.unwrap_or(0);
530                let delay_nanos = duration_nanos / ((move_event_count as i64) + 1);
531                let delay = fasync::MonotonicDuration::from_nanos(delay_nanos);
532
533                let start_x_f = start_location.x as f64;
534                let start_y_f = start_location.y as f64;
535                let end_x_f = end_location.x as f64;
536                let end_y_f = end_location.y as f64;
537                let move_event_count_f = move_event_count as f64;
538                let step_size_x = (end_x_f - start_x_f) / move_event_count_f;
539                let step_size_y = (end_y_f - start_y_f) / move_event_count_f;
540
541                // Generate an event at `start_location`, followed by `move_event_count - 1`
542                // evenly-spaced events, followed by an event at `end_location`.
543                for i in 0..move_event_count + 1 {
544                    let i_f = i as f64;
545                    let event_x = start_x_f + (i_f * step_size_x);
546                    let event_y = start_y_f + (i_f * step_size_y);
547
548                    {
549                        fuchsia_trace::duration!(c"input", c"simulate_swipe_move", "idx"=>i);
550                        let trace_id = fuchsia_trace::Id::random();
551                        fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
552
553                        touchscreen_device
554                            .send_input_report(input_report_for_touch_contacts(
555                                vec![(1, math::Vec_ { x: event_x as i32, y: event_y as i32 })],
556                                Some(trace_id.into()),
557                            ))
558                            .expect("Failed to send tap input report");
559                    }
560                    fasync::Timer::new(delay).await;
561                }
562
563                // Send a report with an empty set of touch contacts, so that input
564                // pipeline generates a pointer event with phase == UP.
565                fuchsia_trace::duration!(c"input", c"simulate_swipe_up");
566                let trace_id = fuchsia_trace::Id::random();
567                fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
568                touchscreen_device
569                    .send_input_report(input_report_for_touch_contacts(
570                        vec![],
571                        Some(trace_id.into()),
572                    ))
573                    .expect("failed to send empty input report");
574
575                responder.send().expect("Failed to send SimulateSwipe response");
576            }
577            Ok(TouchScreenRequest::SimulateMultiTap { payload, responder }) => {
578                let tap_locations = payload.tap_locations.expect("missing tap locations");
579
580                {
581                    fuchsia_trace::duration!(c"input", c"simulate_multi_tap_down");
582                    let trace_id = fuchsia_trace::Id::random();
583                    fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
584                    touchscreen_device
585                        .send_input_report(input_report_for_touch_contacts(
586                            tap_locations
587                                .into_iter()
588                                .enumerate()
589                                .map(|(i, it)| (i as u32, it))
590                                .collect(),
591                            Some(trace_id.into()),
592                        ))
593                        .expect("Failed to send tap input report");
594                }
595
596                // Send a report with an empty set of touch contacts, so that input
597                // pipeline generates a pointer event with phase == UP.
598                fuchsia_trace::duration!(c"input", c"simulate_multi_tap_up");
599                let trace_id = fuchsia_trace::Id::random();
600                fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
601                touchscreen_device
602                    .send_input_report(input_report_for_touch_contacts(
603                        vec![],
604                        Some(trace_id.into()),
605                    ))
606                    .expect("failed to send empty input report");
607                responder.send().expect("Failed to send SimulateMultiTap response");
608            }
609            Ok(TouchScreenRequest::SimulateMultiFingerGesture { payload, responder }) => {
610                // Compute the x- and y- displacements between successive touch events.
611                let start_locations = payload.start_locations.expect("missing start locations");
612                let end_locations = payload.end_locations.expect("missing end locations");
613                let move_event_count = payload.move_event_count.expect("missing move event count");
614                let finger_count = payload.finger_count.expect("missing finger count") as usize;
615
616                let move_event_count_f = move_event_count as f32;
617
618                let mut steps: Vec<math::VecF> = vec![];
619
620                for finger in 0..finger_count {
621                    let start_x = start_locations[finger].x as f32;
622                    let start_y = start_locations[finger].y as f32;
623                    let end_x = end_locations[finger].x as f32;
624                    let end_y = end_locations[finger].y as f32;
625                    let step_x = (end_x - start_x) / move_event_count_f;
626                    let step_y = (end_y - start_y) / move_event_count_f;
627                    steps.push(math::VecF { x: step_x, y: step_y });
628                }
629
630                // Generate an event at `start_location`, followed by `move_event_count - 1`
631                // evenly-spaced events, followed by an event at `end_location`.
632                for i in 0..move_event_count {
633                    let i_f = i as f32;
634
635                    let mut contacts: Vec<(u32, math::Vec_)> = vec![];
636
637                    for finger in 0..finger_count {
638                        let start_x = start_locations[finger].x as f32;
639                        let start_y = start_locations[finger].y as f32;
640                        let event_x = (start_x + i_f * steps[finger].x) as i32;
641                        let event_y = (start_y + i_f * steps[finger].y) as i32;
642                        contacts.push((finger as u32, math::Vec_ { x: event_x, y: event_y }));
643                    }
644
645                    fuchsia_trace::duration!(c"input", c"simulate_multi_finger_gesture_move", "idx"=>i);
646                    let trace_id = fuchsia_trace::Id::random();
647                    fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
648
649                    touchscreen_device
650                        .send_input_report(input_report_for_touch_contacts(
651                            contacts,
652                            Some(trace_id.into()),
653                        ))
654                        .expect("Failed to send tap input report");
655                }
656
657                // Send a report with an empty set of touch contacts, so that input
658                // pipeline generates a pointer event with phase == UP.
659                fuchsia_trace::duration!(c"input", c"simulate_multi_finger_gesture_up");
660                let trace_id = fuchsia_trace::Id::random();
661                fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
662                touchscreen_device
663                    .send_input_report(input_report_for_touch_contacts(
664                        vec![],
665                        Some(trace_id.into()),
666                    ))
667                    .expect("failed to send empty input report");
668
669                responder.send().expect("Failed to send SimulateMultiFingerGesture response");
670            }
671            Ok(TouchScreenRequest::SimulateTouchEvent { report, responder }) => {
672                fuchsia_trace::duration!(c"input", c"simulate_touch_event");
673                let trace_id = fuchsia_trace::Id::random();
674                fuchsia_trace::flow_begin!(c"input", c"input_report", trace_id);
675                let input_report = InputReport {
676                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
677                    touch: Some(report),
678                    trace_id: Some(trace_id.into()),
679                    ..Default::default()
680                };
681                touchscreen_device
682                    .send_input_report(input_report)
683                    .expect("failed to send empty input report");
684                responder.send().expect("Failed to send SimulateTouchEvent response");
685            }
686            Err(e) => {
687                error!("Error on touchscreen channel: {}", e);
688                return;
689            }
690        }
691    }
692}
693
694/// Serves `fuchsia.ui.test.input.MediaButtonsDevice`.
695async fn handle_media_buttons_device_request_stream(
696    media_buttons_device: input_device::InputDevice,
697    mut request_stream: MediaButtonsDeviceRequestStream,
698) {
699    while let Some(request) = request_stream.next().await {
700        match request {
701            Ok(MediaButtonsDeviceRequest::SimulateButtonPress { payload, responder }) => {
702                if let Some(button) = payload.button {
703                    let media_buttons_input_report = ConsumerControlInputReport {
704                        pressed_buttons: Some(vec![button]),
705                        ..Default::default()
706                    };
707
708                    let input_report = InputReport {
709                        event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
710                        consumer_control: Some(media_buttons_input_report),
711                        ..Default::default()
712                    };
713
714                    media_buttons_device
715                        .send_input_report(input_report)
716                        .expect("Failed to send button press input report");
717
718                    // Send a report with an empty set of pressed buttons,
719                    // so that input pipeline generates a media buttons
720                    // event with the target button being released.
721                    let empty_report = InputReport {
722                        event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
723                        consumer_control: Some(ConsumerControlInputReport {
724                            pressed_buttons: Some(vec![]),
725                            ..Default::default()
726                        }),
727                        ..Default::default()
728                    };
729
730                    media_buttons_device
731                        .send_input_report(empty_report)
732                        .expect("Failed to send button release input report");
733
734                    responder.send().expect("Failed to send SimulateButtonPress response");
735                } else {
736                    warn!("SimulateButtonPress request missing button");
737                }
738            }
739            Ok(MediaButtonsDeviceRequest::SendButtonsState { payload, responder }) => {
740                let buttons = match payload.buttons {
741                    Some(buttons) => buttons,
742                    None => vec![],
743                };
744                let input_report = InputReport {
745                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
746                    consumer_control: Some(ConsumerControlInputReport {
747                        pressed_buttons: Some(buttons),
748                        ..Default::default()
749                    }),
750                    ..Default::default()
751                };
752
753                media_buttons_device
754                    .send_input_report(input_report)
755                    .expect("Failed to send button press input report");
756
757                responder.send().expect("Failed to send SimulateButtonsPress response");
758            }
759            Err(e) => {
760                error!("Error on media buttons device channel: {}", e);
761                return;
762            }
763        }
764    }
765}
766
767/// Serves `fuchsia.ui.test.input.Keyboard`.
768async fn handle_keyboard_request_stream(
769    keyboard_device: input_device::InputDevice,
770    mut request_stream: KeyboardRequestStream,
771) {
772    while let Some(request) = request_stream.next().await {
773        match request {
774            Ok(KeyboardRequest::SimulateUsAsciiTextEntry { payload, responder }) => {
775                if let Some(text) = payload.text {
776                    let key_sequence = derive_key_sequence(&keymaps::US_QWERTY, &text)
777                        .expect("Failed to derive key sequence");
778
779                    let mut key_iter = key_sequence.into_iter().peekable();
780                    while let Some(keyboard_report) = key_iter.next() {
781                        let input_report = InputReport {
782                            event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
783                            keyboard: Some(KeyboardInputReport {
784                                pressed_keys3: Some(convert_keyboard_report_to_keys(
785                                    &keyboard_report,
786                                )),
787                                ..Default::default()
788                            }),
789                            ..Default::default()
790                        };
791
792                        keyboard_device
793                            .send_input_report(input_report)
794                            .expect("Failed to send key event report");
795
796                        if key_iter.peek().is_some() {
797                            fuchsia_async::Timer::new(Duration::from_millis(100)).await;
798                        }
799                    }
800
801                    responder.send().expect("Failed to send SimulateTextEntry response");
802                } else {
803                    warn!("SimulateTextEntry request missing text");
804                }
805            }
806            Ok(KeyboardRequest::SimulateKeyEvent { payload, responder }) => {
807                let keyboard_report = payload.report.expect("no report");
808                let input_report = InputReport {
809                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
810                    keyboard: Some(keyboard_report),
811                    ..Default::default()
812                };
813
814                keyboard_device
815                    .send_input_report(input_report)
816                    .expect("Failed to send key event report");
817
818                responder.send().expect("Failed to send SimulateKeyEvent response");
819            }
820            Ok(KeyboardRequest::SimulateKeyPress { payload, responder }) => {
821                let key_code = payload.key_code.expect("no key code");
822
823                let down_report = InputReport {
824                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
825                    keyboard: Some(KeyboardInputReport {
826                        pressed_keys3: Some(vec![key_code]),
827                        ..Default::default()
828                    }),
829                    ..Default::default()
830                };
831
832                let up_report = InputReport {
833                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
834                    keyboard: Some(KeyboardInputReport {
835                        pressed_keys3: Some(vec![]),
836                        ..Default::default()
837                    }),
838                    ..Default::default()
839                };
840
841                keyboard_device.send_input_report(down_report).expect("Failed to send key down");
842
843                keyboard_device.send_input_report(up_report).expect("Failed to send key up");
844
845                responder.send().expect("Failed to send SimulateKeyPress response");
846            }
847            Err(e) => {
848                error!("Error on keyboard device channel: {}", e);
849                return;
850            }
851        }
852    }
853}
854
855/// Serves `fuchsia.ui.test.input.Mouse`.
856async fn handle_mouse_request_stream(
857    mouse_device: input_device::InputDevice,
858    mut request_stream: MouseRequestStream,
859) {
860    while let Some(request) = request_stream.next().await {
861        match request {
862            Ok(MouseRequest::SimulateMouseEvent { payload, responder }) => {
863                let mut mouse_input_report = MouseInputReport {
864                    movement_x: payload.movement_x,
865                    movement_y: payload.movement_y,
866                    scroll_v: payload.scroll_v_detent,
867                    scroll_h: payload.scroll_h_detent,
868                    ..Default::default()
869                };
870                if let Some(pressed_buttons) = payload.pressed_buttons {
871                    mouse_input_report.pressed_buttons = Some(
872                        pressed_buttons
873                            .into_iter()
874                            .map(|b| {
875                                b.into_primitive()
876                                    .try_into()
877                                    .expect("failed to convert MouseButton to u8")
878                            })
879                            .collect(),
880                    );
881                }
882
883                let input_report = InputReport {
884                    event_time: Some(fasync::MonotonicInstant::now().into_nanos()),
885                    mouse: Some(mouse_input_report),
886                    ..Default::default()
887                };
888
889                mouse_device
890                    .send_input_report(input_report)
891                    .expect("Failed to send key event report");
892
893                responder.send().expect("Failed to send SimulateMouseEvent response");
894            }
895            Err(e) => {
896                error!("Error on keyboard device channel: {}", e);
897                return;
898            }
899        }
900    }
901}
902
903#[cfg(test)]
904mod tests {
905    // Most of the functions in this file need to bind to FIDL services in
906    // this component's environment to do their work, but a component can't
907    // modify its own environment. Hence, we can't validate those functions.
908    //
909    // However, we can (and do) validate derive_key_sequence().
910
911    use super::{KeyboardReport, Usages, derive_key_sequence};
912    use pretty_assertions::assert_eq;
913
914    // TODO(https://fxbug.dev/42059899): Remove this macro.
915    macro_rules! reports {
916        ( $( [ $( $usages:expr ),* ] ),* $( , )? ) => {
917            Some(vec![
918                $(
919                    KeyboardReport {
920                        pressed_keys: vec![$($usages as u32),*]
921                    }
922                ),*
923            ])
924        }
925    }
926
927    #[test]
928    fn lowercase() {
929        assert_eq!(
930            derive_key_sequence(&keymaps::US_QWERTY, "lowercase"),
931            reports![
932                [Usages::HidUsageKeyL],
933                [Usages::HidUsageKeyO],
934                [Usages::HidUsageKeyW],
935                [Usages::HidUsageKeyE],
936                [Usages::HidUsageKeyR],
937                [Usages::HidUsageKeyC],
938                [Usages::HidUsageKeyA],
939                [Usages::HidUsageKeyS],
940                [Usages::HidUsageKeyE],
941                [],
942            ]
943        );
944    }
945
946    #[test]
947    fn numerics() {
948        assert_eq!(
949            derive_key_sequence(&keymaps::US_QWERTY, "0123456789"),
950            reports![
951                [Usages::HidUsageKey0],
952                [Usages::HidUsageKey1],
953                [Usages::HidUsageKey2],
954                [Usages::HidUsageKey3],
955                [Usages::HidUsageKey4],
956                [Usages::HidUsageKey5],
957                [Usages::HidUsageKey6],
958                [Usages::HidUsageKey7],
959                [Usages::HidUsageKey8],
960                [Usages::HidUsageKey9],
961                [],
962            ]
963        );
964    }
965
966    #[test]
967    fn internet_text_entry() {
968        assert_eq!(
969            derive_key_sequence(&keymaps::US_QWERTY, "http://127.0.0.1:8080"),
970            reports![
971                [Usages::HidUsageKeyH],
972                [Usages::HidUsageKeyT],
973                [],
974                [Usages::HidUsageKeyT],
975                [Usages::HidUsageKeyP],
976                // ':'
977                // Shift is actuated first on its own, then together with
978                // the key.
979                [Usages::HidUsageKeyLeftShift],
980                [Usages::HidUsageKeySemicolon, Usages::HidUsageKeyLeftShift],
981                [],
982                [Usages::HidUsageKeySlash],
983                [],
984                [Usages::HidUsageKeySlash],
985                [Usages::HidUsageKey1],
986                [Usages::HidUsageKey2],
987                [Usages::HidUsageKey7],
988                [Usages::HidUsageKeyDot],
989                [Usages::HidUsageKey0],
990                [Usages::HidUsageKeyDot],
991                [Usages::HidUsageKey0],
992                [Usages::HidUsageKeyDot],
993                [Usages::HidUsageKey1],
994                [Usages::HidUsageKeyLeftShift],
995                [Usages::HidUsageKeySemicolon, Usages::HidUsageKeyLeftShift],
996                [],
997                [Usages::HidUsageKey8],
998                [Usages::HidUsageKey0],
999                [Usages::HidUsageKey8],
1000                [Usages::HidUsageKey0],
1001                [],
1002            ]
1003        );
1004    }
1005
1006    #[test]
1007    fn sentence() {
1008        assert_eq!(
1009            derive_key_sequence(&keymaps::US_QWERTY, "Hello, world!"),
1010            reports![
1011                [Usages::HidUsageKeyLeftShift],
1012                [Usages::HidUsageKeyH, Usages::HidUsageKeyLeftShift],
1013                [],
1014                [Usages::HidUsageKeyE],
1015                [Usages::HidUsageKeyL],
1016                [],
1017                [Usages::HidUsageKeyL],
1018                [Usages::HidUsageKeyO],
1019                [Usages::HidUsageKeyComma],
1020                [Usages::HidUsageKeySpace],
1021                [Usages::HidUsageKeyW],
1022                [Usages::HidUsageKeyO],
1023                [Usages::HidUsageKeyR],
1024                [Usages::HidUsageKeyL],
1025                [Usages::HidUsageKeyD],
1026                [Usages::HidUsageKeyLeftShift],
1027                [Usages::HidUsageKey1, Usages::HidUsageKeyLeftShift],
1028                [],
1029            ]
1030        );
1031    }
1032
1033    #[test]
1034    fn hold_shift() {
1035        assert_eq!(
1036            derive_key_sequence(&keymaps::US_QWERTY, "ALL'S WELL!"),
1037            reports![
1038                [Usages::HidUsageKeyLeftShift],
1039                [Usages::HidUsageKeyA, Usages::HidUsageKeyLeftShift],
1040                [Usages::HidUsageKeyL, Usages::HidUsageKeyLeftShift],
1041                [Usages::HidUsageKeyLeftShift],
1042                [Usages::HidUsageKeyL, Usages::HidUsageKeyLeftShift],
1043                [],
1044                [Usages::HidUsageKeyApostrophe],
1045                [Usages::HidUsageKeyLeftShift],
1046                [Usages::HidUsageKeyS, Usages::HidUsageKeyLeftShift],
1047                [Usages::HidUsageKeySpace, Usages::HidUsageKeyLeftShift],
1048                [Usages::HidUsageKeyW, Usages::HidUsageKeyLeftShift],
1049                [Usages::HidUsageKeyE, Usages::HidUsageKeyLeftShift],
1050                [Usages::HidUsageKeyL, Usages::HidUsageKeyLeftShift],
1051                [Usages::HidUsageKeyLeftShift],
1052                [Usages::HidUsageKeyL, Usages::HidUsageKeyLeftShift],
1053                [Usages::HidUsageKey1, Usages::HidUsageKeyLeftShift],
1054                [],
1055            ]
1056        );
1057    }
1058
1059    #[test]
1060    fn tab_and_newline() {
1061        assert_eq!(
1062            derive_key_sequence(&keymaps::US_QWERTY, "\tHello\n"),
1063            reports![
1064                [Usages::HidUsageKeyTab],
1065                [Usages::HidUsageKeyLeftShift],
1066                [Usages::HidUsageKeyH, Usages::HidUsageKeyLeftShift],
1067                [],
1068                [Usages::HidUsageKeyE],
1069                [Usages::HidUsageKeyL],
1070                [],
1071                [Usages::HidUsageKeyL],
1072                [Usages::HidUsageKeyO],
1073                [Usages::HidUsageKeyEnter],
1074                [],
1075            ]
1076        );
1077    }
1078}