async_hidg/
lib.rs

1#![forbid(future_incompatible)]
2#![deny(bad_style, missing_docs)]
3#![doc = include_str!("../README.md")]
4
5use hidg_core::{check_read, check_write, AsDevicePath};
6
7pub use hidg_core::{Class, Error, Result, StateChange, ValueChange};
8
9#[cfg(feature = "keyboard")]
10pub use hidg_core::{
11    Key, KeyStateChanges, Keyboard, KeyboardInput, KeyboardOutput, Led, LedStateChanges, Leds,
12    Modifiers,
13};
14
15#[cfg(feature = "mouse")]
16pub use hidg_core::{
17    Button, Buttons, Mouse, MouseInput, MouseInputChange, MouseInputChanges, MouseOutput,
18};
19
20use core::marker::PhantomData;
21use std::{
22    fs::{File, OpenOptions},
23    io::{Read, Write},
24};
25
26use async_io::Async;
27use blocking::unblock as asyncify;
28
29/// HID Gadget Device
30pub struct Device<C: Class> {
31    file: Async<File>,
32    _class: PhantomData<C>,
33}
34
35impl<C: Class> Device<C> {
36    /// Open device by path or name or number
37    pub async fn open(device: impl AsDevicePath) -> Result<Self> {
38        let path = device.as_device_path();
39        let file = Async::new(
40            asyncify(move || OpenOptions::new().read(true).write(true).open(path)).await?,
41        )?;
42        Ok(Self {
43            file,
44            _class: PhantomData,
45        })
46    }
47
48    /// Send input report
49    pub async fn input(&mut self, input: &C::Input) -> Result<()>
50    where
51        C::Input: AsRef<[u8]>,
52    {
53        self.file.writable().await?;
54        let raw = input.as_ref();
55        let len = self.file.get_ref().write(raw)?;
56
57        check_write(len, raw.len())
58    }
59
60    /// Receive output report
61    pub async fn output(&mut self, output: &mut C::Output) -> Result<()>
62    where
63        C::Output: AsMut<[u8]>,
64    {
65        self.file.readable().await?;
66        let raw = output.as_mut();
67        let len = self.file.get_ref().read(raw)?;
68
69        check_read(len, raw.len())?;
70
71        Ok(())
72    }
73}