Skip to main content

hid_descriptor/
encode.rs

1use hid_types::encoding::{TagTypeSize, TypeBits, encode_signed, encode_unsigned};
2use hid_types::id::{GlobalItem, IntoTagType, LocalItem, MainItem};
3use hid_types::item::{Global, Item, Local, LongItem, Main};
4
5use crate::DescriptorBytes;
6
7/// A trait for items that can be encoded into the HID report descriptor binary format.
8pub trait EncodeItem {
9    /// Encode the item into a sequence of bytes.
10    fn encode(&self) -> DescriptorBytes;
11}
12
13impl EncodeItem for LongItem {
14    fn encode(&self) -> DescriptorBytes {
15        long_encode(self.tag, &self.data)
16    }
17}
18
19impl EncodeItem for Main {
20    fn encode(&self) -> DescriptorBytes {
21        match self {
22            Main::Input(input_flags) => {
23                let data: u32 = input_flags.0.into();
24                short_encode_unsigned(MainItem::Input, &data.to_le_bytes())
25            }
26            Main::Output(output_flags) => {
27                let data: u32 = output_flags.0.into();
28                short_encode_unsigned(MainItem::Output, &data.to_le_bytes())
29            }
30            Main::Feature(feature_flags) => {
31                let data: u32 = feature_flags.0.into();
32                short_encode_unsigned(MainItem::Feature, &data.to_le_bytes())
33            }
34            Main::Collection(ty) => {
35                let data: u8 = ty.to_integer();
36                short_encode_unsigned(MainItem::Collection, &data.to_le_bytes())
37            }
38            Main::EndCollection => short_encode_unsigned(MainItem::EndCollection, &[]),
39            Main::Reserved(tag, data) => reserved_encode(*tag, TypeBits::Main, *data),
40        }
41    }
42}
43
44impl EncodeItem for Global {
45    fn encode(&self) -> DescriptorBytes {
46        match self {
47            Global::UsagePage(usage_page) => {
48                let data = usage_page.to_integer().to_le_bytes();
49                short_encode_unsigned(GlobalItem::UsagePage, &data)
50            }
51            Global::LogicalMinimum(value) => {
52                short_encode_signed(GlobalItem::LogicalMinimum, &value.to_le_bytes())
53            }
54            Global::LogicalMaximum(value) => {
55                short_encode_signed(GlobalItem::LogicalMaximum, &value.to_le_bytes())
56            }
57            Global::PhysicalMinimum(value) => {
58                short_encode_signed(GlobalItem::PhysicalMinimum, &value.to_le_bytes())
59            }
60            Global::PhysicalMaximum(value) => {
61                short_encode_signed(GlobalItem::PhysicalMaximum, &value.to_le_bytes())
62            }
63            Global::UnitExponent(value) => {
64                short_encode_signed(GlobalItem::UnitExponent, &value.to_le_bytes())
65            }
66            Global::Unit(unit) => {
67                let data = unit.to_integer().to_le_bytes();
68                short_encode_unsigned(GlobalItem::Unit, &data)
69            }
70            Global::ReportSize(value) => {
71                short_encode_unsigned(GlobalItem::ReportSize, &value.to_le_bytes())
72            }
73            Global::ReportId(value) => {
74                short_encode_unsigned(GlobalItem::ReportId, &value.to_le_bytes())
75            }
76            Global::ReportCount(value) => {
77                short_encode_unsigned(GlobalItem::ReportCount, &value.to_le_bytes())
78            }
79            Global::Push => short_encode_unsigned(GlobalItem::Push, &[]),
80            Global::Pop => short_encode_unsigned(GlobalItem::Pop, &[]),
81            Global::Reserved(tag, data) => reserved_encode(*tag, TypeBits::Global, *data),
82        }
83    }
84}
85
86impl EncodeItem for Local {
87    fn encode(&self) -> DescriptorBytes {
88        match self {
89            Local::Usage(usage) => {
90                let data = usage.to_integer().to_le_bytes();
91                short_encode_unsigned(LocalItem::Usage, &data)
92            }
93            Local::ExtendedUsage(extended_usage) => {
94                let data = extended_usage.to_integer().to_le_bytes();
95                short_encode_unsigned(LocalItem::Usage, &data)
96            }
97            Local::UsageMinimum(value) => {
98                short_encode_unsigned(LocalItem::UsageMinimum, &value.to_le_bytes())
99            }
100            Local::UsageMaximum(value) => {
101                short_encode_unsigned(LocalItem::UsageMaximum, &value.to_le_bytes())
102            }
103            Local::DesignatorIndex(value) => {
104                short_encode_unsigned(LocalItem::DesignatorIndex, &value.to_le_bytes())
105            }
106            Local::DesignatorMinimum(value) => {
107                short_encode_unsigned(LocalItem::DesignatorMinimum, &value.to_le_bytes())
108            }
109            Local::DesignatorMaximum(value) => {
110                short_encode_unsigned(LocalItem::DesignatorMaximum, &value.to_le_bytes())
111            }
112            Local::StringIndex(value) => {
113                short_encode_unsigned(LocalItem::StringIndex, &value.to_le_bytes())
114            }
115            Local::StringMinimum(value) => {
116                short_encode_unsigned(LocalItem::StringMinimum, &value.to_le_bytes())
117            }
118            Local::StringMaximum(value) => {
119                short_encode_unsigned(LocalItem::StringMaximum, &value.to_le_bytes())
120            }
121            Local::Delimiter(value) => {
122                let data = u8::from(*value);
123                short_encode_unsigned(LocalItem::Delimiter, &data.to_le_bytes())
124            }
125            Local::Reserved(tag, data) => reserved_encode(*tag, TypeBits::Local, *data),
126        }
127    }
128}
129
130impl EncodeItem for Item {
131    fn encode(&self) -> DescriptorBytes {
132        match self {
133            Item::Long(long_item) => long_item.encode(),
134            Item::Main(main) => main.encode(),
135            Item::Global(global) => global.encode(),
136            Item::Local(local) => local.encode(),
137            Item::Reserved(tag, data) => reserved_encode(*tag, TypeBits::Reserved, *data),
138        }
139    }
140}
141
142fn long_encode(tag: u8, data: &[u8]) -> DescriptorBytes {
143    // bSize=2, bType=Reserved, bTag=0b1111. This is hardcoded in the HID spec.
144    const LONG_TAG_BYTE: u8 = 0xFE;
145
146    let data_size: u8 = data
147        .len()
148        .try_into()
149        .expect("long encoding can only store 255 bytes");
150
151    [LONG_TAG_BYTE, data_size, tag]
152        .into_iter()
153        .chain(data.iter().copied())
154        .collect()
155}
156
157fn reserved_encode(tag: u8, ty: TypeBits, data: Option<i32>) -> DescriptorBytes {
158    let tts = TagTypeSize::new().with_tag(tag).with_ty(ty);
159
160    let data: &[u8] = match data {
161        None => &[],
162        Some(bytes) => &bytes.to_le_bytes(),
163    };
164
165    short_encode_signed(tts, data)
166}
167
168fn short_encode_unsigned<T: IntoTagType>(tag: T, data: &[u8]) -> DescriptorBytes {
169    let data = encode_unsigned(data);
170    let tag = TagTypeSize::from_tag(tag, data.len());
171
172    [tag.into_bits()]
173        .into_iter()
174        .chain(data.iter().copied())
175        .collect()
176}
177
178fn short_encode_signed<T: IntoTagType>(tag: T, data: &[u8]) -> DescriptorBytes {
179    let data = encode_signed(data);
180    let tag = TagTypeSize::from_tag(tag, data.len());
181
182    [tag.into_bits()]
183        .into_iter()
184        .chain(data.iter().copied())
185        .collect()
186}