async_hid/backend/hidraw/
descriptor.rs1use std::fs::File;
2use std::io::{Cursor, Read, Seek, SeekFrom};
3use std::path::Path;
4
5use crate::HidResult;
6
7#[derive(Default)]
8pub struct HidrawReportDescriptor(Vec<u8>);
9
10impl HidrawReportDescriptor {
11 pub fn from_syspath(syspath: &Path) -> HidResult<Self> {
13 let path = syspath.join("device/report_descriptor");
14 let mut f = File::open(path)?;
15 let mut buf = Vec::new();
16 f.read_to_end(&mut buf)?;
17
18 Ok(HidrawReportDescriptor(buf))
19 }
20
21 #[cfg_attr(not(test), allow(dead_code))]
26 pub fn from_slice(value: &[u8]) -> HidResult<Self> {
27 Ok(HidrawReportDescriptor(value.to_vec()))
28 }
29
30 pub fn usages(&self) -> impl Iterator<Item = (u16, u16)> + '_ {
31 UsageIterator {
32 usage_page: 0,
33 cursor: Cursor::new(&self.0)
34 }
35 }
36}
37
38struct UsageIterator<'a> {
40 usage_page: u16,
41 cursor: Cursor<&'a Vec<u8>>
42}
43
44impl Iterator for UsageIterator<'_> {
45 type Item = (u16, u16);
46
47 fn next(&mut self) -> Option<Self::Item> {
48 let (usage_page, page) = next_hid_usage(&mut self.cursor, self.usage_page)?;
49
50 self.usage_page = usage_page;
51 Some((usage_page, page))
52 }
53}
54
55fn next_hid_usage(cursor: &mut Cursor<&Vec<u8>>, mut usage_page: u16) -> Option<(u16, u16)> {
58 let mut usage = None;
59 let mut usage_pair = None;
60 let initial = cursor.position() == 0;
61
62 while let Some(Ok(key)) = cursor.bytes().next() {
63 let position = cursor.position() - 1;
66 let key_cmd = key & 0xfc;
67
68 let (data_len, key_size) = hid_item_size(key, cursor)?;
69
70 match key_cmd {
71 0x4 => {
73 usage_page = match hid_report_bytes(cursor, data_len) {
74 Ok(v) => v as u16,
75 Err(_) => break,
76 }
77 }
78 0x8 => {
80 usage = match hid_report_bytes(cursor, data_len) {
81 Ok(v) => Some(v as u16),
82 Err(_) => break,
83 }
84 }
85 0xa0 => {
87 if let Some(u) = usage.take() {
89 usage_pair = Some((usage_page, u))
90 }
91 }
92 0x80 |
94 0x90 |
96 0xb0 |
98 0xc0 => {
100 usage.take();
102 }
103 _ => {}
104 }
105
106 if cursor
107 .seek(SeekFrom::Start(position + (data_len + key_size) as u64))
108 .is_err()
109 {
110 return None;
111 }
112
113 if let Some((usage_page, usage)) = usage_pair {
114 return Some((usage_page, usage));
115 }
116 }
117
118 if let (true, Some(usage)) = (initial, usage) {
119 return Some((usage_page, usage));
120 }
121
122 None
123}
124
125fn hid_item_size(key: u8, cursor: &mut Cursor<&Vec<u8>>) -> Option<(usize, usize)> {
129 if (key & 0xf0) == 0xf0 {
131 if let Some(Ok(len)) = cursor.bytes().next() {
132 return Some((len.into(), 3));
133 }
134
135 return None;
137 }
138
139 match key & 0x03 {
141 v @ 0..=2 => Some((v.into(), 1)),
142 3 => Some((4, 1)),
143 _ => unreachable!() }
145}
146
147fn hid_report_bytes(cursor: &mut Cursor<&Vec<u8>>, num_bytes: usize) -> HidResult<u32> {
151 let mut bytes: [u8; 4] = [0; 4];
152 cursor.read_exact(&mut bytes[..num_bytes])?;
153
154 Ok(u32::from_le_bytes(bytes))
155}