Skip to main content

hid_types/item/
mod.rs

1//! HID Report Descriptor Items
2//!
3//! This module contains fully populated descriptor items (containing values).
4//! See the [`hid`][crate::hid] module for just the item ID values.
5
6use crate::hid::{CollectionType, InputFlags, OutputFeatureFlags, Unit};
7use crate::id::usage::UsagePage;
8use crate::item::usage::{ExtendedUsage, Usage};
9
10pub mod usage;
11
12/// An HID report descriptor Item.
13#[derive(Clone)]
14#[cfg_attr(feature = "std", derive(Debug))]
15pub enum Item {
16    /// An undecoded "long" item.
17    ///
18    /// According to the spec
19    /// ([Device Class Definition for Human Interface Devices](https://www.usb.org/document-library/device-class-definition-hid-111),
20    /// section 6.2.2.3), there are no standard-defined uses for this encoding.
21    Long(LongItem),
22    /// A __Main__ item.
23    ///
24    /// See [Device Class Definition for Human Interface Devices](https://www.usb.org/document-library/device-class-definition-hid-111),
25    /// section 6.2.2.4.
26    Main(Main),
27    /// A __Global__ item.
28    Global(Global),
29    /// A __Local__ item.
30    Local(Local),
31    /// A reserved item value.
32    ///
33    /// This should not be used; the descriptor cannot be properly decoded.
34    Reserved(u8),
35}
36
37impl Item {
38    #[cfg(feature = "std")]
39    /// A string identifying the type of the item.
40    pub fn type_note(&self) -> &'static str {
41        match self {
42            Item::Long(_) => "[long]",
43            Item::Main(_) => "[main]",
44            Item::Global(_) => "[global]",
45            Item::Local(_) => "[local]",
46            Item::Reserved(_) => "[reserved]",
47        }
48    }
49}
50
51/// A __Main__ item.
52///
53/// See [Device Class Definition for Human Interface Devices](https://www.usb.org/document-library/device-class-definition-hid-111),
54/// section 6.2.2.4.
55#[derive(Clone)]
56#[cfg_attr(feature = "std", derive(Debug))]
57pub enum Main {
58    /// An __Input__ item.
59    Input(InputFlags),
60    /// An __Output__ item.
61    Output(OutputFeatureFlags),
62    /// A __Feature__ item.
63    Feature(OutputFeatureFlags),
64    /// A __Collection__ item.
65    Collection(CollectionType),
66    /// An __End Collection__ item.
67    EndCollection,
68    /// A reserved item type.
69    Reserved(u8),
70}
71
72/// A __Global__ item.
73#[derive(Clone)]
74#[cfg_attr(feature = "std", derive(Debug))]
75pub enum Global {
76    /// A __Usage Page__ item.
77    ///
78    /// The Usage Page is a 16-bit value that identifies a specific table of Usage ID values.
79    /// Future __Usage__ items will select a Usage ID from that Usage Page table.
80    UsagePage(UsagePage),
81    /// A __Logical Minimum__ item.
82    LogicalMinimum(i32),
83    /// A __Logical Maximum__ item.
84    LogicalMaximum(i32),
85    /// A __Physical Minimum__ item.
86    PhysicalMinimum(i32),
87    /// A __Physical Maximum__ item.
88    PhysicalMaximum(i32),
89    /// A __Unit Exponent__ item.
90    UnitExponent(i32),
91    /// A __Unit__ item.
92    Unit(Unit),
93    /// A __Report Size__ item.
94    ReportSize(u32),
95    /// A __Report ID__ item.
96    ReportId(u32),
97    /// A __Report Count__ item.
98    ReportCount(u32),
99    /// A __Push__ item.
100    Push,
101    /// A __Pop__ item.
102    Pop,
103    /// A reserved item type.
104    Reserved(u8),
105}
106
107/// A __Local__ item.
108#[derive(Clone)]
109#[cfg_attr(feature = "std", derive(Debug))]
110pub enum Local {
111    /// A __Usage__ item.
112    Usage(Usage),
113    /// A __Usage__ item, that also contains a __Usage Page__.
114    ExtendedUsage(ExtendedUsage),
115    /// A __Usage Minimum__ item.
116    UsageMinimum(u32),
117    /// A __Usage Maximum__ item.
118    UsageMaximum(u32),
119    /// A __Designator Index__ item.
120    DesignatorIndex(u32),
121    /// A __Designator Minimum__ item.
122    DesignatorMinimum(u32),
123    /// A __Designator Maximum__ item.
124    DesignatorMaximum(u32),
125    /// A __String Index__ item.
126    StringIndex(u32),
127    /// A __String Minimum__ item.
128    StringMinimum(u32),
129    /// A __String Maximum__ item.
130    StringMaximum(u32),
131    /// A __Delimiter__ item.
132    Delimiter(bool),
133    /// A reserved type.
134    Reserved(u8),
135}
136
137/// An item using the "long" encoding.
138///
139/// According to the spec
140/// ([Device Class Definition for Human Interface Devices](https://www.usb.org/document-library/device-class-definition-hid-111),
141/// section 6.2.2.3), there are no standard-defined uses for this encoding.
142#[derive(Clone)]
143#[cfg_attr(feature = "std", derive(Debug))]
144#[expect(missing_docs)]
145pub struct LongItem {
146    pub tag: u8,
147    #[cfg(feature = "std")]
148    pub data: std::vec::Vec<u8>,
149}
150
151#[cfg(feature = "std")]
152mod std_impls {
153    use std::fmt::{self, Display};
154
155    use super::*;
156
157    impl Display for Item {
158        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
159            match self {
160                Item::Long(item) => {
161                    write!(f, "tag {:#04x} [{} bytes]", item.tag, item.data.len())
162                }
163                Item::Main(item) => {
164                    write!(f, "{item}")
165                }
166                Item::Global(item) => {
167                    write!(f, "{item}")
168                }
169                Item::Local(item) => write!(f, "{item}"),
170                Item::Reserved(ty) => write!(f, "reserved type {ty}"),
171            }
172        }
173    }
174
175    impl Display for Main {
176        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
177            match self {
178                Main::Input(flags) => {
179                    write!(f, "Input: {flags:?}")
180                }
181                Main::Output(flags) => {
182                    write!(f, "Output: {flags:?}")
183                }
184                Main::Feature(flags) => {
185                    write!(f, "Feature: {flags:?}")
186                }
187                Main::Collection(coll) => {
188                    write!(f, "Collection: {coll:?}")
189                }
190                Main::EndCollection => {
191                    write!(f, "EndCollection")
192                }
193                Main::Reserved(tag) => {
194                    write!(f, "Reserved tag {tag:#04X}")
195                }
196            }
197        }
198    }
199
200    impl Display for Global {
201        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
202            match self {
203                Global::UsagePage(page) => {
204                    write!(f, "Usage Page: {page:?}")
205                }
206                Global::LogicalMinimum(value) => write!(f, "Logical Minimum: {value}"),
207                Global::LogicalMaximum(value) => write!(f, "Logical Maximum: {value}"),
208                Global::PhysicalMinimum(value) => write!(f, "Physical Minimum: {value}"),
209                Global::PhysicalMaximum(value) => write!(f, "Physical Maximum: {value}"),
210                Global::UnitExponent(value) => write!(f, "Unit Exponent: {value}"),
211                Global::Unit(unit) => write!(f, "Unit: {unit:?}"),
212                Global::Push => write!(f, "Push"),
213                Global::Pop => write!(f, "Pop"),
214                Global::Reserved(tag) => write!(f, "Reserved tag {tag:#04X}"),
215                Global::ReportSize(value) => write!(f, "Report Size: {value}"),
216                Global::ReportId(value) => write!(f, "Report ID: {value}"),
217                Global::ReportCount(value) => write!(f, "Report Count: {value}"),
218            }
219        }
220    }
221
222    impl Display for Local {
223        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
224            match self {
225                Local::Usage(usage) => {
226                    write!(f, "Usage: {usage}")
227                }
228                Local::ExtendedUsage(extended_usage) => {
229                    write!(f, "Extended Usage: {extended_usage:?}")
230                }
231                Local::UsageMinimum(value) => {
232                    write!(f, "Usage Minimum: {value}")
233                }
234                Local::UsageMaximum(value) => {
235                    write!(f, "Usage Maximum: {value}")
236                }
237                Local::DesignatorIndex(value) => write!(f, "Designator Index: {value}"),
238                Local::DesignatorMinimum(value) => write!(f, "Designator Minimum: {value}"),
239                Local::DesignatorMaximum(value) => write!(f, "Designator Maximum: {value}"),
240                Local::StringIndex(value) => write!(f, "String Index: {value}"),
241                Local::StringMinimum(value) => write!(f, "String Minimum: {value}"),
242                Local::StringMaximum(value) => write!(f, "String Maximum: {value}"),
243                Local::Delimiter(value) => write!(f, "Delimiter: {value}"),
244                Local::Reserved(tag) => write!(f, "Reserved tag {tag:#04X}"),
245            }
246        }
247    }
248}