medius 3.4.3

Host control library for the medius transparent mouse passthrough box
Documentation
//! Decoded `RESP(DEVICE_INFO)`: the cloned device's USB identity, kind, and product (§4.3).

use core::fmt;

use crate::protocol::opcode::{DI_HAS_BOS, DI_HAS_SERIAL};

/// Cloned device's primary kind, from its HID report descriptors and Boot declarations (§4.3). One
/// carrying both kinds reads keyboard with a full key bitmap (unless it declares Boot for both) or a
/// Boot keyboard alone, and mouse otherwise.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
pub enum DeviceKind {
    /// Neither a mouse nor a keyboard (a vendor-class pad has no HID interface at all), or nothing cloned
    /// yet: [`DeviceInfo::is_cloned`] tells them apart.
    #[default]
    Unknown,
    Keyboard,
    Mouse,
}

impl DeviceKind {
    pub(crate) fn from_u8(v: u8) -> DeviceKind {
        match v {
            1 => DeviceKind::Keyboard,
            2 => DeviceKind::Mouse,
            _ => DeviceKind::Unknown,
        }
    }
}

impl fmt::Display for DeviceKind {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.write_str(match self {
            DeviceKind::Unknown => "unknown",
            DeviceKind::Keyboard => "keyboard",
            DeviceKind::Mouse => "mouse",
        })
    }
}

/// Cloned device's USB identity, from its descriptors.
#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
pub struct DeviceInfo {
    /// `idVendor`.
    pub vid: u16,
    /// `idProduct`.
    pub pid: u16,
    /// `bcdDevice` (device release).
    pub bcd_device: u16,
    /// `bcdUSB` (e.g. `0x0200`, `0x0201`).
    pub bcd_usb: u16,
    /// The clone serves a serial string.
    pub has_serial: bool,
    /// The clone serves a BOS descriptor (`bcdUSB >= 0x0201`).
    pub has_bos: bool,
    /// Primary kind (§4.3).
    pub kind: DeviceKind,
    /// `iProduct` string as ASCII, `?` for each other character (empty if it serves none).
    pub product: String,
}

impl DeviceInfo {
    /// Whether a device is cloned: with none, the identity reads all-zero (§4.3).
    pub fn is_cloned(&self) -> bool {
        self.vid != 0 || self.pid != 0
    }

    /// Decodes a `RESP(DEVICE_INFO)` payload (§4.3).
    pub(crate) fn from_payload(p: &[u8]) -> Option<Self> {
        if p.len() < 11 {
            return None;
        }
        let flags = p[9];
        Some(DeviceInfo {
            vid: u16::from_le_bytes([p[1], p[2]]),
            pid: u16::from_le_bytes([p[3], p[4]]),
            bcd_device: u16::from_le_bytes([p[5], p[6]]),
            bcd_usb: u16::from_le_bytes([p[7], p[8]]),
            has_serial: flags & DI_HAS_SERIAL != 0,
            has_bos: flags & DI_HAS_BOS != 0,
            kind: DeviceKind::from_u8(p[10]),
            product: String::from_utf8_lossy(&p[11..]).into_owned(),
        })
    }
}

impl fmt::Display for DeviceInfo {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        if self.product.is_empty() {
            write!(f, "{:04X}:{:04X}", self.vid, self.pid)
        } else {
            write!(f, "{:04X}:{:04X} {}", self.vid, self.pid, self.product)
        }
    }
}