medius/types/
device_info.rs1use core::fmt;
4
5use crate::protocol::opcode::{DI_HAS_BOS, DI_HAS_SERIAL};
6
7#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
12pub enum DeviceKind {
13 #[default]
16 Unknown,
17 Keyboard,
18 Mouse,
19}
20
21impl DeviceKind {
22 pub(crate) fn from_u8(v: u8) -> DeviceKind {
23 match v {
24 1 => DeviceKind::Keyboard,
25 2 => DeviceKind::Mouse,
26 _ => DeviceKind::Unknown,
27 }
28 }
29}
30
31impl fmt::Display for DeviceKind {
32 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33 f.write_str(match self {
34 DeviceKind::Unknown => "unknown",
35 DeviceKind::Keyboard => "keyboard",
36 DeviceKind::Mouse => "mouse",
37 })
38 }
39}
40
41#[derive(Debug, Clone, PartialEq, Eq, Hash, Default)]
43pub struct DeviceInfo {
44 pub vid: u16,
46 pub pid: u16,
48 pub bcd_device: u16,
50 pub bcd_usb: u16,
52 pub has_serial: bool,
54 pub has_bos: bool,
56 pub kind: DeviceKind,
58 pub product: String,
61}
62
63impl DeviceInfo {
64 pub fn is_cloned(&self) -> bool {
66 self.vid != 0 || self.pid != 0
67 }
68
69 pub(crate) fn from_payload(p: &[u8]) -> Option<Self> {
71 if p.len() < 11 {
72 return None;
73 }
74 let flags = p[9];
75 Some(DeviceInfo {
76 vid: u16::from_le_bytes([p[1], p[2]]),
77 pid: u16::from_le_bytes([p[3], p[4]]),
78 bcd_device: u16::from_le_bytes([p[5], p[6]]),
79 bcd_usb: u16::from_le_bytes([p[7], p[8]]),
80 has_serial: flags & DI_HAS_SERIAL != 0,
81 has_bos: flags & DI_HAS_BOS != 0,
82 kind: DeviceKind::from_u8(p[10]),
83 product: String::from_utf8_lossy(&p[11..]).into_owned(),
84 })
85 }
86}
87
88impl fmt::Display for DeviceInfo {
89 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
90 if self.product.is_empty() {
91 write!(f, "{:04X}:{:04X}", self.vid, self.pid)
92 } else {
93 write!(f, "{:04X}:{:04X} {}", self.vid, self.pid, self.product)
94 }
95 }
96}