input_synthesis/modern_backend/
input_device.rs

1// Copyright 2020 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
5#![warn(missing_docs)]
6
7use crate::modern_backend::input_reports_reader::InputReportsReader;
8use crate::synthesizer;
9use crate::usages::hid_usage_to_input3_key;
10use anyhow::{format_err, Context as _, Error};
11use async_trait::async_trait;
12use fidl::endpoints::ServerEnd;
13use fidl::Error as FidlError;
14use fidl_fuchsia_input::Key;
15use fidl_fuchsia_input_report::{
16    ConsumerControlButton, ConsumerControlInputReport, ContactInputReport, DeviceDescriptor,
17    FeatureReport, InputDeviceRequest, InputDeviceRequestStream, InputReport,
18    InputReportsReaderMarker, KeyboardInputReport, MouseInputReport, TouchInputReport,
19    TOUCH_MAX_CONTACTS,
20};
21use fidl_fuchsia_ui_input::{KeyboardReport, Touch};
22use fuchsia_async as fasync;
23use futures::{future, pin_mut, StreamExt, TryFutureExt};
24use std::convert::TryFrom as _;
25
26/// Implements the `synthesizer::InputDevice` trait, and the server side of the
27/// `fuchsia.input.report.InputDevice` FIDL protocol. Used by
28/// `modern_backend::InputDeviceRegistry`.
29///
30/// # Notes
31/// * Some of the methods of `fuchsia.input.report.InputDevice` are not relevant to
32///   input injection, so this implemnentation does not support them:
33///   * `SendOutputReport` provides a way to change keyboard LED state.
34///   If these FIDL methods are invoked, `InputDevice::flush()` will resolve to Err.
35/// * This implementation does not support multiple calls to `GetInputReportsReader`,
36///   since:
37///   * The ideal semantics for multiple calls are not obvious, and
38///   * Each `InputDevice` has a single FIDL client (an input pipeline implementation),
39///     and the current input pipeline implementation is happy to use a single
40///     `InputReportsReader` for the lifetime of the `InputDevice`.
41pub(super) struct InputDevice {
42    /// FIFO queue of reports to be consumed by calls to
43    /// `fuchsia.input.report.InputReportsReader.ReadInputReports()`.
44    /// Populated by calls to `synthesizer::InputDevice` trait methods.
45    report_sender: futures::channel::mpsc::UnboundedSender<InputReport>,
46
47    // `Task` to keep serving the `fuchsia.input.report.InputDevice` protocol.
48    input_device_task: fasync::Task<Result<(), Error>>,
49}
50
51impl std::convert::From<synthesizer::MediaButton> for ConsumerControlButton {
52    fn from(synthesizer_button: synthesizer::MediaButton) -> Self {
53        match synthesizer_button {
54            synthesizer::MediaButton::VolumeUp => Self::VolumeUp,
55            synthesizer::MediaButton::VolumeDown => Self::VolumeDown,
56            synthesizer::MediaButton::MicMute => Self::MicMute,
57            synthesizer::MediaButton::FactoryReset => Self::FactoryReset,
58            synthesizer::MediaButton::Pause => Self::Pause,
59            synthesizer::MediaButton::CameraDisable => Self::CameraDisable,
60        }
61    }
62}
63
64#[async_trait(?Send)]
65impl synthesizer::InputDevice for self::InputDevice {
66    fn media_buttons(
67        &mut self,
68        pressed_buttons: Vec<synthesizer::MediaButton>,
69        time: u64,
70    ) -> Result<(), Error> {
71        self.report_sender
72            .unbounded_send(InputReport {
73                event_time: Some(i64::try_from(time).context("converting time to i64")?),
74                consumer_control: Some(ConsumerControlInputReport {
75                    pressed_buttons: Some(pressed_buttons.into_iter().map(Into::into).collect()),
76                    ..Default::default()
77                }),
78                ..Default::default()
79            })
80            .context("sending media button InputReport")
81    }
82
83    // TODO(https://fxbug.dev/42142533): remove dependency on HID usage codes.
84    fn key_press(&mut self, report: KeyboardReport, time: u64) -> Result<(), Error> {
85        self.key_press_internal(report, time, Self::convert_keyboard_report_to_keys)
86    }
87
88    fn key_press_raw(&mut self, report: KeyboardReport, time: u64) -> Result<(), Error> {
89        self.key_press_internal(report, time, Self::convert_keyboard_report_to_keys_no_transform)
90    }
91
92    // TODO(https://fxbug.dev/42142533): remove reference to HID usage codes.
93    fn key_press_usage(&mut self, usage: Option<u32>, time: u64) -> Result<(), Error> {
94        self.key_press(KeyboardReport { pressed_keys: usage.into_iter().collect() }, time)
95    }
96
97    fn tap(&mut self, pos: Option<(u32, u32)>, time: u64) -> Result<(), Error> {
98        let fingers = pos.and_then(|(x, y)| {
99            Some(vec![Touch { finger_id: 1, x: x as i32, y: y as i32, width: 0, height: 0 }])
100        });
101        self.multi_finger_tap(fingers, time)
102    }
103
104    fn multi_finger_tap(&mut self, fingers: Option<Vec<Touch>>, time: u64) -> Result<(), Error> {
105        let num_fingers = match &fingers {
106            Some(fingers_vec) => fingers_vec.len(),
107            None => 0,
108        };
109        if num_fingers > usize::try_from(TOUCH_MAX_CONTACTS).context("usize is at least 32 bits")? {
110            return Err(format_err!(
111                "Got {} fingers, but max is {}",
112                num_fingers,
113                TOUCH_MAX_CONTACTS
114            ));
115        }
116        self.multi_finger_tap_internal(
117            TouchInputReport {
118                contacts: Some(fingers.map_or_else(Vec::new, |fingers_vec| {
119                    fingers_vec
120                        .into_iter()
121                        .map(|finger| ContactInputReport {
122                            contact_id: Some(finger.finger_id),
123                            position_x: Some(i64::from(finger.x)),
124                            position_y: Some(i64::from(finger.y)),
125                            contact_width: Some(i64::from(finger.width)),
126                            contact_height: Some(i64::from(finger.height)),
127                            ..Default::default()
128                        })
129                        .collect()
130                })),
131                pressed_buttons: Some(vec![]),
132                ..Default::default()
133            },
134            time,
135        )
136    }
137
138    fn mouse(&mut self, report: MouseInputReport, time: u64) -> Result<(), Error> {
139        self.report_sender
140            .unbounded_send(InputReport {
141                event_time: Some(i64::try_from(time).context("converting time to i64")?),
142                mouse: Some(report),
143                ..Default::default()
144            })
145            .context("error sending mouse InputReport")
146    }
147
148    async fn flush(self: Box<Self>) -> Result<(), Error> {
149        let Self { input_device_task, report_sender } = *self;
150        std::mem::drop(report_sender); // Drop `report_sender` to close channel.
151        input_device_task.await
152    }
153}
154
155impl InputDevice {
156    /// Creates a new `InputDevice` that will create a task to:
157    /// a) process requests from `request_stream`, and
158    /// b) respond to `GetDescriptor` calls with the descriptor generated by `descriptor_generator()`
159    pub(super) fn new(
160        request_stream: InputDeviceRequestStream,
161        descriptor: DeviceDescriptor,
162    ) -> Self {
163        let (report_sender, report_receiver) = futures::channel::mpsc::unbounded::<InputReport>();
164
165        // Create a `Task` to keep serving the `fuchsia.input.report.InputDevice` protocol.
166        let input_device_task =
167            fasync::Task::local(Self::serve_reports(request_stream, descriptor, report_receiver));
168
169        Self { report_sender, input_device_task }
170    }
171
172    /// Returns a `Future` which resolves when all `InputReport`s for this device
173    /// have been sent to a `fuchsia.input.InputReportsReader` client, or when
174    /// an error occurs.
175    ///
176    /// # Resolves to
177    /// * `Ok(())` if all reports were written successfully
178    /// * `Err` otherwise. For example:
179    ///   * The `fuchsia.input.InputDevice` client sent an invalid request.
180    ///   * A FIDL error occurred while trying to read a FIDL request.
181    ///   * A FIDL error occurred while trying to write a FIDL response.
182    ///
183    /// # Corner cases
184    /// Resolves to `Err` if the `fuchsia.input.InputDevice` client did not call
185    /// `GetInputReportsReader()`, even if no `InputReport`s were queued.
186    ///
187    /// # Note
188    /// When the `Future` resolves, `InputReports` may still be sitting unread in the
189    /// channel to the `fuchsia.input.InputReportsReader` client. (The client will
190    /// typically be an input pipeline implementation.)
191    async fn serve_reports(
192        request_stream: InputDeviceRequestStream,
193        descriptor: DeviceDescriptor,
194        report_receiver: futures::channel::mpsc::UnboundedReceiver<InputReport>,
195    ) -> Result<(), Error> {
196        // Process `fuchsia.input.report.InputDevice` requests, waiting for the `InputDevice`
197        // client to provide a `ServerEnd<InputReportsReader>` by calling `GetInputReportsReader()`.
198        let mut input_reports_reader_server_end_stream = request_stream
199            .filter_map(|r| future::ready(Self::handle_device_request(r, &descriptor)));
200        let input_reports_reader_fut = {
201            let reader_server_end = input_reports_reader_server_end_stream
202                .next()
203                .await
204                .ok_or_else(|| format_err!("stream ended without a call to GetInputReportsReader"))?
205                .context("handling InputDeviceRequest")?;
206            InputReportsReader { request_stream: reader_server_end.into_stream(), report_receiver }
207                .into_future()
208        };
209        pin_mut!(input_reports_reader_fut);
210
211        // Create a `Future` to keep serving the `fuchsia.input.report.InputDevice` protocol.
212        // This time, receiving a `ServerEnd<InputReportsReaderMarker>` will be an `Err`.
213        let input_device_server_fut = async {
214            match input_reports_reader_server_end_stream.next().await {
215                Some(Ok(_server_end)) => {
216                    // There are no obvious "best" semantics for how to handle multiple
217                    // `GetInputReportsReader` calls, and there is no current need to
218                    // do so. Instead of taking a guess at what the client might want
219                    // in such a case, just return `Err`.
220                    Err(format_err!(
221                        "InputDevice does not support multiple GetInputReportsReader calls"
222                    ))
223                }
224                Some(Err(e)) => Err(e.context("handling InputDeviceRequest")),
225                None => Ok(()),
226            }
227        };
228        pin_mut!(input_device_server_fut);
229
230        // Now, process both `fuchsia.input.report.InputDevice` requests, and
231        // `fuchsia.input.report.InputReportsReader` requests. And keep processing
232        // `InputReportsReader` requests even if the `InputDevice` connection
233        // is severed.
234        future::select(
235            input_device_server_fut.and_then(|_: ()| future::pending()),
236            input_reports_reader_fut,
237        )
238        .await
239        .factor_first()
240        .0
241    }
242
243    /// Converts a [KeyboardReport] into a sequence of key presses, using the supplied
244    /// key-to-HID usage transformation function.
245    fn key_press_internal(
246        &mut self,
247        report: KeyboardReport,
248        time: u64,
249        transform: fn(r: &KeyboardReport) -> Result<Vec<Key>, Error>,
250    ) -> Result<(), Error> {
251        self.report_sender
252            .unbounded_send(InputReport {
253                event_time: Some(i64::try_from(time).context("converting time to i64")?),
254                keyboard: Some(KeyboardInputReport {
255                    pressed_keys3: Some(transform(&report)?),
256                    ..Default::default()
257                }),
258                ..Default::default()
259            })
260            .context("sending key press InputReport")
261    }
262
263    fn multi_finger_tap_internal(
264        &mut self,
265        touch: TouchInputReport,
266        time: u64,
267    ) -> Result<(), Error> {
268        self.report_sender
269            .unbounded_send(InputReport {
270                event_time: Some(i64::try_from(time).context("converting time to i64")?),
271                touch: Some(touch),
272                ..Default::default()
273            })
274            .context("sending touch InputReport")
275    }
276
277    /// Processes a single request from an `InputDeviceRequestStream`
278    ///
279    /// # Returns
280    /// * Some(Ok(ServerEnd<InputReportsReaderMarker>)) if the request yielded an
281    ///   `InputReportsReader`. `InputDevice` should route its `InputReports` to the yielded
282    ///   `InputReportsReader`.
283    /// * Some(Err) if the request yielded an `Error`
284    /// * None if the request was fully processed by `handle_device_request()`
285    fn handle_device_request(
286        request: Result<InputDeviceRequest, FidlError>,
287        descriptor: &DeviceDescriptor,
288    ) -> Option<Result<ServerEnd<InputReportsReaderMarker>, Error>> {
289        match request {
290            Ok(InputDeviceRequest::GetInputReportsReader { reader: reader_server_end, .. }) => {
291                Some(Ok(reader_server_end))
292            }
293            Ok(InputDeviceRequest::GetDescriptor { responder }) => {
294                match responder.send(&descriptor) {
295                    Ok(()) => None,
296                    Err(e) => {
297                        Some(Err(anyhow::Error::from(e).context("sending GetDescriptor response")))
298                    }
299                }
300            }
301            Ok(InputDeviceRequest::GetFeatureReport { responder }) => {
302                match responder.send(Ok(&FeatureReport::default())) {
303                    Ok(()) => None,
304                    Err(e) => Some(Err(
305                        anyhow::Error::from(e).context("sending GetFeatureReport response")
306                    )),
307                }
308            }
309            Err(e) => {
310                // Fail fast.
311                //
312                // Panic here, since we don't have a good way to report an error from a
313                // background task.  InputDevice::flush() exists, but this is unlikely
314                // to be called in tests, and it may get called way too late, after
315                // an error in this background task already caused some other error.
316                panic!("InputDevice got an error while reading request: {:?}", &e);
317            }
318            _ => {
319                // See the previous branch.
320                panic!(
321                    "InputDevice::handle_device_request does not support this request: {:?}",
322                    &request
323                );
324            }
325        }
326    }
327
328    fn convert_keyboard_report_to_keys(report: &KeyboardReport) -> Result<Vec<Key>, Error> {
329        report
330            .pressed_keys
331            .iter()
332            .map(|&usage| {
333                hid_usage_to_input3_key(usage as u16)
334                    .ok_or_else(|| format_err!("no Key for usage {:?}", usage))
335            })
336            .collect()
337    }
338
339    /// Same as convert_keyboard_report_to_keys, but no additional calls to HID usage mapping.
340    ///
341    /// The keyboard report in `convert_keyboard_report_to_keys` assumes USB HID usage page 7.
342    /// This set of keys is narrower than what Fuchsia supports so that function needs to map
343    /// back into Fuchsia USB HID encoding (see [fidl_fuchsia_input::Key]).
344    ///
345    /// This function, in turn, uses the full range of [fidl_fuchsia_input::Key], so does not
346    /// need this conversion.
347    fn convert_keyboard_report_to_keys_no_transform(
348        report: &KeyboardReport,
349    ) -> Result<Vec<Key>, Error> {
350        report
351            .pressed_keys
352            .iter()
353            .map(|&usage| {
354                Key::from_primitive(usage)
355                    .ok_or_else(|| anyhow::anyhow!("could not convert to input::Key: {}", &usage))
356            })
357            .collect()
358    }
359}
360
361#[cfg(test)]
362mod tests {
363    use super::synthesizer::InputDevice as _;
364    use super::*;
365    use fidl::endpoints;
366    use fidl_fuchsia_input_report::{
367        DeviceDescriptor, InputDeviceMarker, KeyboardDescriptor, KeyboardInputDescriptor,
368    };
369    use fuchsia_async as fasync;
370
371    const DEFAULT_REPORT_TIMESTAMP: u64 = 0;
372
373    mod responds_to_get_feature_report_request {
374        use super::*;
375
376        #[fasync::run_until_stalled(test)]
377        async fn single_request_before_call_to_get_feature_report() -> Result<(), Error> {
378            let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
379            let input_device_server_fut =
380                Box::new(InputDevice::new(request_stream, DeviceDescriptor::default())).flush();
381            let get_feature_report_fut = proxy.get_feature_report();
382            std::mem::drop(proxy); // Drop `proxy` to terminate `request_stream`.
383
384            let (_, get_feature_report_result) =
385                future::join(input_device_server_fut, get_feature_report_fut).await;
386            assert_eq!(
387                get_feature_report_result.context("fidl error")?,
388                Ok(FeatureReport::default())
389            );
390            Ok(())
391        }
392    }
393
394    mod responds_to_get_descriptor_request {
395        use super::utils::{make_input_device_proxy_and_struct, make_keyboard_descriptor};
396        use super::*;
397        use assert_matches::assert_matches;
398        use futures::task::Poll;
399
400        #[fasync::run_until_stalled(test)]
401        async fn single_request_before_call_to_get_input_reports_reader() -> Result<(), Error> {
402            let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
403            let input_device_server_fut =
404                Box::new(InputDevice::new(request_stream, make_keyboard_descriptor(vec![Key::A])))
405                    .flush();
406            let get_descriptor_fut = proxy.get_descriptor();
407            std::mem::drop(proxy); // Drop `proxy` to terminate `request_stream`.
408
409            let (_, get_descriptor_result) =
410                future::join(input_device_server_fut, get_descriptor_fut).await;
411            assert_eq!(
412                get_descriptor_result.context("fidl error")?,
413                make_keyboard_descriptor(vec![Key::A])
414            );
415            Ok(())
416        }
417
418        #[test]
419        fn multiple_requests_before_call_to_get_input_reports_reader() -> Result<(), Error> {
420            let mut executor = fasync::TestExecutor::new();
421            let (proxy, request_stream) = endpoints::create_proxy_and_stream::<InputDeviceMarker>();
422            let mut input_device_server_fut =
423                Box::new(InputDevice::new(request_stream, make_keyboard_descriptor(vec![Key::A])))
424                    .flush();
425
426            let mut get_descriptor_fut = proxy.get_descriptor();
427            assert_matches!(
428                executor.run_until_stalled(&mut input_device_server_fut),
429                Poll::Pending
430            );
431            std::mem::drop(executor.run_until_stalled(&mut get_descriptor_fut));
432
433            let mut get_descriptor_fut = proxy.get_descriptor();
434            let _ = executor.run_until_stalled(&mut input_device_server_fut);
435            assert_matches!(
436                executor.run_until_stalled(&mut get_descriptor_fut),
437                Poll::Ready(Ok(_))
438            );
439
440            Ok(())
441        }
442
443        #[test]
444        fn after_call_to_get_input_reports_reader_with_report_pending() -> Result<(), Error> {
445            let mut executor = fasync::TestExecutor::new();
446            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
447            input_device
448                .key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
449                .context("internal error queuing input event")?;
450
451            let input_device_server_fut = input_device.flush();
452            pin_mut!(input_device_server_fut);
453
454            let (_input_reports_reader_proxy, input_reports_reader_server_end) =
455                endpoints::create_proxy::<InputReportsReaderMarker>();
456            input_device_proxy
457                .get_input_reports_reader(input_reports_reader_server_end)
458                .context("sending get_input_reports_reader request")?;
459            assert_matches!(
460                executor.run_until_stalled(&mut input_device_server_fut),
461                Poll::Pending
462            );
463
464            let mut get_descriptor_fut = input_device_proxy.get_descriptor();
465            assert_matches!(
466                executor.run_until_stalled(&mut input_device_server_fut),
467                Poll::Pending
468            );
469            assert_matches!(executor.run_until_stalled(&mut get_descriptor_fut), Poll::Ready(_));
470            Ok(())
471        }
472    }
473
474    mod report_contents {
475        use super::utils::{get_input_reports, make_input_device_proxy_and_struct};
476        use super::*;
477        use crate::usages::Usages;
478        use assert_matches::assert_matches;
479        use std::convert::TryInto as _;
480
481        #[fasync::run_until_stalled(test)]
482        async fn media_buttons_generates_empty_consumer_controls_input_report() -> Result<(), Error>
483        {
484            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
485            input_device.media_buttons(vec![], DEFAULT_REPORT_TIMESTAMP)?;
486
487            let input_reports = get_input_reports(input_device, input_device_proxy).await;
488            assert_eq!(
489                input_reports.as_slice(),
490                [InputReport {
491                    event_time: Some(
492                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
493                    ),
494                    consumer_control: Some(ConsumerControlInputReport {
495                        pressed_buttons: Some(vec![]),
496                        ..Default::default()
497                    }),
498                    ..Default::default()
499                }]
500            );
501            Ok(())
502        }
503
504        #[fasync::run_until_stalled(test)]
505        async fn media_buttons_generates_full_consumer_controls_input_report() -> Result<(), Error>
506        {
507            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
508            input_device.media_buttons(
509                vec![
510                    synthesizer::MediaButton::VolumeUp,
511                    synthesizer::MediaButton::VolumeDown,
512                    synthesizer::MediaButton::MicMute,
513                    synthesizer::MediaButton::FactoryReset,
514                    synthesizer::MediaButton::Pause,
515                    synthesizer::MediaButton::CameraDisable,
516                ],
517                DEFAULT_REPORT_TIMESTAMP,
518            )?;
519
520            let input_reports = get_input_reports(input_device, input_device_proxy).await;
521            assert_eq!(
522                input_reports.as_slice(),
523                [InputReport {
524                    event_time: Some(
525                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
526                    ),
527                    consumer_control: Some(ConsumerControlInputReport {
528                        pressed_buttons: Some(vec![
529                            ConsumerControlButton::VolumeUp,
530                            ConsumerControlButton::VolumeDown,
531                            ConsumerControlButton::MicMute,
532                            ConsumerControlButton::FactoryReset,
533                            ConsumerControlButton::Pause,
534                            ConsumerControlButton::CameraDisable,
535                        ]),
536                        ..Default::default()
537                    }),
538                    ..Default::default()
539                }]
540            );
541            Ok(())
542        }
543
544        #[fasync::run_until_stalled(test)]
545        async fn media_buttons_generates_partial_consumer_controls_input_report(
546        ) -> Result<(), Error> {
547            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
548            input_device.media_buttons(
549                vec![
550                    synthesizer::MediaButton::VolumeUp,
551                    synthesizer::MediaButton::MicMute,
552                    synthesizer::MediaButton::Pause,
553                ],
554                DEFAULT_REPORT_TIMESTAMP,
555            )?;
556
557            let input_reports = get_input_reports(input_device, input_device_proxy).await;
558            assert_eq!(
559                input_reports.as_slice(),
560                [InputReport {
561                    event_time: Some(
562                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
563                    ),
564                    consumer_control: Some(ConsumerControlInputReport {
565                        pressed_buttons: Some(vec![
566                            ConsumerControlButton::VolumeUp,
567                            ConsumerControlButton::MicMute,
568                            ConsumerControlButton::Pause,
569                        ]),
570                        ..Default::default()
571                    }),
572                    ..Default::default()
573                }]
574            );
575            Ok(())
576        }
577
578        #[fasync::run_until_stalled(test)]
579        async fn key_press_generates_expected_keyboard_input_report() -> Result<(), Error> {
580            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
581            input_device.key_press(
582                KeyboardReport {
583                    pressed_keys: vec![Usages::HidUsageKeyA as u32, Usages::HidUsageKeyB as u32],
584                },
585                DEFAULT_REPORT_TIMESTAMP,
586            )?;
587
588            let input_reports = get_input_reports(input_device, input_device_proxy).await;
589            assert_eq!(
590                input_reports.as_slice(),
591                [InputReport {
592                    event_time: Some(
593                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
594                    ),
595                    keyboard: Some(KeyboardInputReport {
596                        pressed_keys3: Some(vec![Key::A, Key::B]),
597                        ..Default::default()
598                    }),
599                    ..Default::default()
600                }]
601            );
602            Ok(())
603        }
604
605        #[fasync::run_until_stalled(test)]
606        async fn key_press_usage_generates_expected_keyboard_input_report_for_some(
607        ) -> Result<(), Error> {
608            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
609            input_device
610                .key_press_usage(Some(Usages::HidUsageKeyA as u32), DEFAULT_REPORT_TIMESTAMP)?;
611
612            let input_reports = get_input_reports(input_device, input_device_proxy).await;
613            assert_eq!(
614                input_reports.as_slice(),
615                [InputReport {
616                    event_time: Some(
617                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
618                    ),
619                    keyboard: Some(KeyboardInputReport {
620                        pressed_keys3: Some(vec![Key::A]),
621                        ..Default::default()
622                    }),
623                    ..Default::default()
624                }]
625            );
626            Ok(())
627        }
628
629        #[fasync::run_until_stalled(test)]
630        async fn key_press_usage_generates_expected_keyboard_input_report_for_none(
631        ) -> Result<(), Error> {
632            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
633            input_device.key_press_usage(None, DEFAULT_REPORT_TIMESTAMP)?;
634
635            let input_reports = get_input_reports(input_device, input_device_proxy).await;
636            assert_eq!(
637                input_reports.as_slice(),
638                [InputReport {
639                    event_time: Some(
640                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
641                    ),
642                    keyboard: Some(KeyboardInputReport {
643                        pressed_keys3: Some(vec![]),
644                        ..Default::default()
645                    }),
646                    ..Default::default()
647                }]
648            );
649            Ok(())
650        }
651
652        #[fasync::run_until_stalled(test)]
653        async fn key_press_returns_error_if_usage_cannot_be_mapped_to_key() {
654            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
655            assert_matches!(
656                input_device.key_press(
657                    KeyboardReport { pressed_keys: vec![0xffff_ffff] },
658                    DEFAULT_REPORT_TIMESTAMP
659                ),
660                Err(_)
661            );
662        }
663
664        #[fasync::run_until_stalled(test)]
665        async fn key_press_usage_returns_error_if_usage_cannot_be_mapped_to_key() {
666            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
667            assert_matches!(
668                input_device.key_press_usage(Some(0xffff_ffff), DEFAULT_REPORT_TIMESTAMP),
669                Err(_)
670            );
671        }
672
673        #[fasync::run_until_stalled(test)]
674        async fn key_events_generates_expected_keyboard_response() -> Result<(), Error> {
675            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
676            input_device.key_press_raw(
677                KeyboardReport {
678                    pressed_keys: vec![Key::A.into_primitive(), Key::B.into_primitive()],
679                },
680                DEFAULT_REPORT_TIMESTAMP,
681            )?;
682
683            let input_reports = get_input_reports(input_device, _input_device_proxy).await;
684            assert_eq!(
685                input_reports.as_slice(),
686                [InputReport {
687                    event_time: Some(
688                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
689                    ),
690                    keyboard: Some(KeyboardInputReport {
691                        pressed_keys3: Some(vec![Key::A, Key::B]),
692                        ..Default::default()
693                    }),
694                    ..Default::default()
695                }]
696            );
697            Ok(())
698        }
699
700        #[fasync::run_until_stalled(test)]
701        async fn tap_generates_expected_report_for_some() -> Result<(), Error> {
702            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
703            input_device.tap(Some((10, 20)), DEFAULT_REPORT_TIMESTAMP)?;
704
705            let input_reports = get_input_reports(input_device, _input_device_proxy).await;
706            assert_eq!(
707                input_reports.as_slice(),
708                [InputReport {
709                    event_time: Some(
710                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
711                    ),
712                    touch: Some(TouchInputReport {
713                        contacts: Some(vec![ContactInputReport {
714                            contact_id: Some(1),
715                            position_x: Some(10),
716                            position_y: Some(20),
717                            pressure: None,
718                            contact_width: Some(0),
719                            contact_height: Some(0),
720                            ..Default::default()
721                        }]),
722                        pressed_buttons: Some(vec![]),
723                        ..Default::default()
724                    }),
725                    ..Default::default()
726                }]
727            );
728            Ok(())
729        }
730
731        #[fasync::run_until_stalled(test)]
732        async fn tap_generates_expected_report_for_none() -> Result<(), Error> {
733            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
734            input_device.tap(None, DEFAULT_REPORT_TIMESTAMP)?;
735
736            let input_reports = get_input_reports(input_device, _input_device_proxy).await;
737            assert_eq!(
738                input_reports.as_slice(),
739                [InputReport {
740                    event_time: Some(
741                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
742                    ),
743                    touch: Some(TouchInputReport {
744                        contacts: Some(vec![]),
745                        pressed_buttons: Some(vec![]),
746                        ..Default::default()
747                    }),
748                    ..Default::default()
749                }]
750            );
751            Ok(())
752        }
753
754        #[fasync::run_until_stalled(test)]
755        async fn multi_finger_tap_generates_report_for_single_finger() -> Result<(), Error> {
756            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
757            input_device.multi_finger_tap(
758                Some(vec![Touch { finger_id: 5, x: 10, y: 20, width: 100, height: 200 }]),
759                DEFAULT_REPORT_TIMESTAMP,
760            )?;
761
762            let input_reports = get_input_reports(input_device, _input_device_proxy).await;
763            assert_eq!(
764                input_reports.as_slice(),
765                [InputReport {
766                    event_time: Some(
767                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
768                    ),
769                    touch: Some(TouchInputReport {
770                        contacts: Some(vec![ContactInputReport {
771                            contact_id: Some(5),
772                            position_x: Some(10),
773                            position_y: Some(20),
774                            pressure: None,
775                            contact_width: Some(100),
776                            contact_height: Some(200),
777                            ..Default::default()
778                        }]),
779                        pressed_buttons: Some(vec![]),
780                        ..Default::default()
781                    }),
782                    ..Default::default()
783                }]
784            );
785            Ok(())
786        }
787
788        #[fasync::run_until_stalled(test)]
789        async fn multi_finger_tap_generates_expected_report_for_two_fingers() -> Result<(), Error> {
790            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
791            input_device.multi_finger_tap(
792                Some(vec![
793                    Touch { finger_id: 5, x: 10, y: 20, width: 100, height: 200 },
794                    Touch { finger_id: 0, x: 30, y: 40, width: 300, height: 400 },
795                ]),
796                DEFAULT_REPORT_TIMESTAMP,
797            )?;
798
799            let input_reports = get_input_reports(input_device, _input_device_proxy).await;
800            assert_eq!(
801                input_reports.as_slice(),
802                [InputReport {
803                    event_time: Some(
804                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
805                    ),
806                    touch: Some(TouchInputReport {
807                        contacts: Some(vec![
808                            ContactInputReport {
809                                contact_id: Some(5),
810                                position_x: Some(10),
811                                position_y: Some(20),
812                                pressure: None,
813                                contact_width: Some(100),
814                                contact_height: Some(200),
815                                ..Default::default()
816                            },
817                            ContactInputReport {
818                                contact_id: Some(0),
819                                position_x: Some(30),
820                                position_y: Some(40),
821                                pressure: None,
822                                contact_width: Some(300),
823                                contact_height: Some(400),
824                                ..Default::default()
825                            }
826                        ]),
827                        pressed_buttons: Some(vec![]),
828                        ..Default::default()
829                    }),
830                    ..Default::default()
831                }]
832            );
833            Ok(())
834        }
835
836        #[fasync::run_until_stalled(test)]
837        async fn multi_finger_tap_generates_expected_report_for_zero_fingers() -> Result<(), Error>
838        {
839            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
840            input_device.multi_finger_tap(Some(vec![]), DEFAULT_REPORT_TIMESTAMP)?;
841
842            let input_reports = get_input_reports(input_device, _input_device_proxy).await;
843            assert_eq!(
844                input_reports.as_slice(),
845                [InputReport {
846                    event_time: Some(
847                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
848                    ),
849                    touch: Some(TouchInputReport {
850                        contacts: Some(vec![]),
851                        pressed_buttons: Some(vec![]),
852                        ..Default::default()
853                    }),
854                    ..Default::default()
855                }]
856            );
857            Ok(())
858        }
859
860        #[fasync::run_until_stalled(test)]
861        async fn multi_finger_tap_generates_expected_report_for_none() -> Result<(), Error> {
862            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
863            input_device.multi_finger_tap(None, DEFAULT_REPORT_TIMESTAMP)?;
864
865            let input_reports = get_input_reports(input_device, _input_device_proxy).await;
866            assert_eq!(
867                input_reports.as_slice(),
868                [InputReport {
869                    event_time: Some(
870                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
871                    ),
872                    touch: Some(TouchInputReport {
873                        contacts: Some(vec![]),
874                        pressed_buttons: Some(vec![]),
875                        ..Default::default()
876                    }),
877                    ..Default::default()
878                }]
879            );
880            Ok(())
881        }
882
883        #[fasync::run_until_stalled(test)]
884        async fn multi_finger_tap_returns_error_when_num_fingers_is_to_large() {
885            let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
886            assert_matches!(
887                input_device.multi_finger_tap(
888                    Some(
889                        (0..=TOUCH_MAX_CONTACTS)
890                            .map(|i| Touch {
891                                finger_id: i,
892                                x: i as i32,
893                                y: i as i32,
894                                width: i,
895                                height: i
896                            })
897                            .collect(),
898                    ),
899                    DEFAULT_REPORT_TIMESTAMP,
900                ),
901                Err(_)
902            );
903        }
904
905        #[fasync::run_until_stalled(test)]
906        async fn mouse_generates_empty_mouse_input_report() -> Result<(), Error> {
907            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
908            input_device.mouse(MouseInputReport::default(), DEFAULT_REPORT_TIMESTAMP)?;
909
910            let input_reports = get_input_reports(input_device, input_device_proxy).await;
911            assert_eq!(
912                input_reports.as_slice(),
913                [InputReport {
914                    event_time: Some(
915                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
916                    ),
917                    mouse: Some(MouseInputReport::default()),
918                    ..Default::default()
919                }]
920            );
921            Ok(())
922        }
923
924        #[fasync::run_until_stalled(test)]
925        async fn mouse_generates_full_mouse_input_report() -> Result<(), Error> {
926            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
927            input_device.mouse(
928                MouseInputReport {
929                    movement_x: Some(10),
930                    movement_y: Some(15),
931                    pressed_buttons: Some(vec![1, 2, 3]),
932                    scroll_v: Some(1),
933                    scroll_h: Some(-1),
934                    ..Default::default()
935                },
936                DEFAULT_REPORT_TIMESTAMP,
937            )?;
938
939            let input_reports = get_input_reports(input_device, input_device_proxy).await;
940            assert_eq!(
941                input_reports.as_slice(),
942                [InputReport {
943                    event_time: Some(
944                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
945                    ),
946                    mouse: Some(MouseInputReport {
947                        movement_x: Some(10),
948                        movement_y: Some(15),
949                        pressed_buttons: Some(vec![1, 2, 3]),
950                        scroll_v: Some(1),
951                        scroll_h: Some(-1),
952                        ..Default::default()
953                    }),
954                    ..Default::default()
955                }]
956            );
957            Ok(())
958        }
959
960        #[fasync::run_until_stalled(test)]
961        async fn mouse_generates_partial_mouse_input_report() -> Result<(), Error> {
962            let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
963            input_device.mouse(
964                MouseInputReport {
965                    movement_x: Some(10),
966                    movement_y: Some(15),
967                    pressed_buttons: Some(vec![]),
968                    ..Default::default()
969                },
970                DEFAULT_REPORT_TIMESTAMP,
971            )?;
972
973            let input_reports = get_input_reports(input_device, input_device_proxy).await;
974            assert_eq!(
975                input_reports.as_slice(),
976                [InputReport {
977                    event_time: Some(
978                        DEFAULT_REPORT_TIMESTAMP.try_into().expect("converting to i64")
979                    ),
980                    mouse: Some(MouseInputReport {
981                        movement_x: Some(10),
982                        movement_y: Some(15),
983                        pressed_buttons: Some(vec![]),
984                        ..Default::default()
985                    }),
986                    ..Default::default()
987                }]
988            );
989            Ok(())
990        }
991    }
992
993    mod future_resolution {
994        use super::utils::{make_input_device_proxy_and_struct, make_input_reports_reader_proxy};
995        use super::*;
996        use futures::task::Poll;
997
998        mod yields_ok_after_all_reports_are_sent_to_input_reports_reader {
999            use super::*;
1000            use assert_matches::assert_matches;
1001
1002            #[test]
1003            fn if_device_request_channel_was_closed() {
1004                let mut executor = fasync::TestExecutor::new();
1005                let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
1006                let input_reports_reader_proxy =
1007                    make_input_reports_reader_proxy(&input_device_proxy);
1008                input_device
1009                    .key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
1010                    .expect("queuing input report");
1011
1012                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
1013                let mut input_device_fut = input_device.flush();
1014                std::mem::drop(input_device_proxy); // Close device request channel.
1015                assert_matches!(
1016                    executor.run_until_stalled(&mut input_device_fut),
1017                    Poll::Ready(Ok(()))
1018                );
1019            }
1020
1021            #[test]
1022            fn even_if_device_request_channel_is_open() {
1023                let mut executor = fasync::TestExecutor::new();
1024                let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
1025                let input_reports_reader_proxy =
1026                    make_input_reports_reader_proxy(&input_device_proxy);
1027                input_device
1028                    .key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
1029                    .expect("queuing input report");
1030
1031                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
1032                let mut input_device_fut = input_device.flush();
1033                assert_matches!(
1034                    executor.run_until_stalled(&mut input_device_fut),
1035                    Poll::Ready(Ok(()))
1036                );
1037            }
1038
1039            #[test]
1040            fn even_if_reports_was_empty_and_device_request_channel_is_open() {
1041                let mut executor = fasync::TestExecutor::new();
1042                let (input_device_proxy, input_device) = make_input_device_proxy_and_struct();
1043                let input_reports_reader_proxy =
1044                    make_input_reports_reader_proxy(&input_device_proxy);
1045                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
1046                let mut input_device_fut = input_device.flush();
1047                assert_matches!(
1048                    executor.run_until_stalled(&mut input_device_fut),
1049                    Poll::Ready(Ok(()))
1050                );
1051            }
1052        }
1053
1054        mod yields_err_if_peer_closed_device_channel_without_calling_get_input_reports_reader {
1055            use super::*;
1056            use assert_matches::assert_matches;
1057
1058            #[test]
1059            fn if_reports_were_available() {
1060                let mut executor = fasync::TestExecutor::new();
1061                let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
1062                input_device
1063                    .key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
1064                    .expect("queuing input report");
1065
1066                let mut input_device_fut = input_device.flush();
1067                std::mem::drop(input_device_proxy);
1068                assert_matches!(
1069                    executor.run_until_stalled(&mut input_device_fut),
1070                    Poll::Ready(Err(_))
1071                )
1072            }
1073
1074            #[test]
1075            fn even_if_no_reports_were_available() {
1076                let mut executor = fasync::TestExecutor::new();
1077                let (input_device_proxy, input_device) = make_input_device_proxy_and_struct();
1078                let mut input_device_fut = input_device.flush();
1079                std::mem::drop(input_device_proxy);
1080                assert_matches!(
1081                    executor.run_until_stalled(&mut input_device_fut),
1082                    Poll::Ready(Err(_))
1083                )
1084            }
1085        }
1086
1087        mod is_pending_if_peer_has_device_channel_open_and_has_not_called_get_input_reports_reader {
1088            use super::*;
1089            use assert_matches::assert_matches;
1090
1091            #[test]
1092            fn if_reports_were_available() {
1093                let mut executor = fasync::TestExecutor::new();
1094                let (_input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
1095                input_device
1096                    .key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
1097                    .expect("queuing input report");
1098
1099                let mut input_device_fut = input_device.flush();
1100                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
1101            }
1102
1103            #[test]
1104            fn even_if_no_reports_were_available() {
1105                let mut executor = fasync::TestExecutor::new();
1106                let (_input_device_proxy, input_device) = make_input_device_proxy_and_struct();
1107                let mut input_device_fut = input_device.flush();
1108                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
1109            }
1110
1111            #[test]
1112            fn even_if_get_device_descriptor_has_been_called() {
1113                let mut executor = fasync::TestExecutor::new();
1114                let (input_device_proxy, input_device) = make_input_device_proxy_and_struct();
1115                let mut input_device_fut = input_device.flush();
1116                let _get_descriptor_fut = input_device_proxy.get_descriptor();
1117                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
1118            }
1119        }
1120
1121        mod is_pending_if_peer_has_not_read_any_reports_when_a_report_is_available {
1122            use super::*;
1123            use assert_matches::assert_matches;
1124
1125            #[test]
1126            fn if_device_request_channel_is_open() {
1127                let mut executor = fasync::TestExecutor::new();
1128                let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
1129                let _input_reports_reader_proxy =
1130                    make_input_reports_reader_proxy(&input_device_proxy);
1131                input_device
1132                    .key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
1133                    .expect("queuing input report");
1134
1135                let mut input_device_fut = input_device.flush();
1136                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
1137            }
1138
1139            #[test]
1140            fn even_if_device_channel_is_closed() {
1141                let mut executor = fasync::TestExecutor::new();
1142                let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
1143                let _input_reports_reader_proxy =
1144                    make_input_reports_reader_proxy(&input_device_proxy);
1145                input_device
1146                    .key_press(KeyboardReport { pressed_keys: vec![] }, DEFAULT_REPORT_TIMESTAMP)
1147                    .expect("queuing input report");
1148
1149                let mut input_device_fut = input_device.flush();
1150                std::mem::drop(input_device_proxy); // Terminate `InputDeviceRequestStream`.
1151                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
1152            }
1153        }
1154
1155        mod is_pending_if_peer_did_not_read_all_reports {
1156            use super::*;
1157            use assert_matches::assert_matches;
1158            use fidl_fuchsia_input_report::MAX_DEVICE_REPORT_COUNT;
1159
1160            #[test]
1161            fn if_device_request_channel_is_open() {
1162                let mut executor = fasync::TestExecutor::new();
1163                let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
1164                let input_reports_reader_proxy =
1165                    make_input_reports_reader_proxy(&input_device_proxy);
1166                (0..=MAX_DEVICE_REPORT_COUNT).for_each(|_| {
1167                    input_device
1168                        .key_press(
1169                            KeyboardReport { pressed_keys: vec![] },
1170                            DEFAULT_REPORT_TIMESTAMP,
1171                        )
1172                        .expect("queuing input report");
1173                });
1174
1175                // One query isn't enough to consume all of the reports queued above.
1176                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
1177                let mut input_device_fut = input_device.flush();
1178                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
1179            }
1180
1181            #[test]
1182            fn even_if_device_request_channel_is_closed() {
1183                let mut executor = fasync::TestExecutor::new();
1184                let (input_device_proxy, mut input_device) = make_input_device_proxy_and_struct();
1185                let input_reports_reader_proxy =
1186                    make_input_reports_reader_proxy(&input_device_proxy);
1187                (0..=MAX_DEVICE_REPORT_COUNT).for_each(|_| {
1188                    input_device
1189                        .key_press(
1190                            KeyboardReport { pressed_keys: vec![] },
1191                            DEFAULT_REPORT_TIMESTAMP,
1192                        )
1193                        .expect("queuing input report");
1194                });
1195
1196                // One query isn't enough to consume all of the reports queued above.
1197                let _input_reports_fut = input_reports_reader_proxy.read_input_reports();
1198                let mut input_device_fut = input_device.flush();
1199                std::mem::drop(input_device_proxy); // Terminate `InputDeviceRequestStream`.
1200                assert_matches!(executor.run_until_stalled(&mut input_device_fut), Poll::Pending)
1201            }
1202        }
1203    }
1204
1205    // Because `input_synthesis` is a library, unsupported use cases should yield `Error`s,
1206    // rather than panic!()-ing.
1207    mod unsupported_use_cases {
1208        use super::utils::make_input_device_proxy_and_struct;
1209        use super::*;
1210        use assert_matches::assert_matches;
1211
1212        #[fasync::run_until_stalled(test)]
1213        async fn multiple_get_input_reports_reader_requests_yield_error() -> Result<(), Error> {
1214            let (input_device_proxy, input_device) = make_input_device_proxy_and_struct();
1215
1216            let (_input_reports_reader_proxy, input_reports_reader_server_end) =
1217                endpoints::create_proxy::<InputReportsReaderMarker>();
1218            input_device_proxy
1219                .get_input_reports_reader(input_reports_reader_server_end)
1220                .expect("sending first get_input_reports_reader request");
1221
1222            let (_input_reports_reader_proxy, input_reports_reader_server_end) =
1223                endpoints::create_proxy::<InputReportsReaderMarker>();
1224            input_device_proxy
1225                .get_input_reports_reader(input_reports_reader_server_end)
1226                .expect("sending second get_input_reports_reader request");
1227
1228            let input_device_fut = input_device.flush();
1229            assert_matches!(input_device_fut.await, Err(_));
1230            Ok(())
1231        }
1232    }
1233
1234    mod utils {
1235        use super::*;
1236        use fidl_fuchsia_input_report::{InputDeviceProxy, InputReportsReaderProxy};
1237
1238        /// Creates a `DeviceDescriptor` for a keyboard which has the keys enumerated
1239        /// in `keys`.
1240        pub(super) fn make_keyboard_descriptor(keys: Vec<Key>) -> DeviceDescriptor {
1241            DeviceDescriptor {
1242                keyboard: Some(KeyboardDescriptor {
1243                    input: Some(KeyboardInputDescriptor {
1244                        keys3: Some(keys),
1245                        ..Default::default()
1246                    }),
1247                    ..Default::default()
1248                }),
1249                ..Default::default()
1250            }
1251        }
1252
1253        /// Creates an `InputDeviceProxy`, for sending `fuchsia.input.report.InputDevice`
1254        /// requests, and an `InputDevice` struct that will receive the FIDL requests
1255        /// from the `InputDeviceProxy`.
1256        ///
1257        /// # Returns
1258        /// A tuple of the proxy and struct. The struct is `Box`-ed so that the caller
1259        /// can easily invoke `flush()`.
1260        pub(super) fn make_input_device_proxy_and_struct() -> (InputDeviceProxy, Box<InputDevice>) {
1261            let (input_device_proxy, input_device_request_stream) =
1262                endpoints::create_proxy_and_stream::<InputDeviceMarker>();
1263            let input_device = Box::new(InputDevice::new(
1264                input_device_request_stream,
1265                DeviceDescriptor::default(),
1266            ));
1267            (input_device_proxy, input_device)
1268        }
1269
1270        /// Creates an `InputReportsReaderProxy`, for sending
1271        /// `fuchsia.input.report.InputReportsReader` reqests, and registers that
1272        /// `InputReportsReader` with the `InputDevice` bound to `InputDeviceProxy`.
1273        ///
1274        /// # Returns
1275        /// The newly created `InputReportsReaderProxy`.
1276        pub(super) fn make_input_reports_reader_proxy(
1277            input_device_proxy: &InputDeviceProxy,
1278        ) -> InputReportsReaderProxy {
1279            let (input_reports_reader_proxy, input_reports_reader_server_end) =
1280                endpoints::create_proxy::<InputReportsReaderMarker>();
1281            input_device_proxy
1282                .get_input_reports_reader(input_reports_reader_server_end)
1283                .expect("sending get_input_reports_reader request");
1284            input_reports_reader_proxy
1285        }
1286
1287        /// Serves `fuchsia.input.report.InputDevice` and `fuchsia.input.report.InputReportsReader`
1288        /// protocols using `input_device`, and reads `InputReport`s with one call to
1289        /// `input_device_proxy.read_input_reports()`. Then drops the connections to
1290        /// `fuchsia.input.report.InputDevice` and `fuchsia.input.report.InputReportsReader`.
1291        ///
1292        /// # Returns
1293        /// The reports provided by the `InputDevice`.
1294        pub(super) async fn get_input_reports(
1295            input_device: Box<InputDevice>,
1296            input_device_proxy: InputDeviceProxy,
1297        ) -> Vec<InputReport> {
1298            let input_reports_reader_proxy = make_input_reports_reader_proxy(&input_device_proxy);
1299            let input_device_server_fut = input_device.flush();
1300            let input_reports_fut = input_reports_reader_proxy.read_input_reports();
1301            std::mem::drop(input_reports_reader_proxy); // Close channel to `input_reports_reader_server_end`
1302            std::mem::drop(input_device_proxy); // Terminate `input_device_request_stream`.
1303            future::join(input_device_server_fut, input_reports_fut)
1304                .await
1305                .1
1306                .expect("fidl error")
1307                .map_err(zx::Status::from_raw)
1308                .expect("service error")
1309        }
1310    }
1311}