Skip to main content

hid_types/
hid.rs

1//! HID descriptor items.
2
3use bitfield_struct::bitfield;
4use num_enum::{IntoPrimitive, TryFromPrimitive};
5
6use crate::Ident;
7
8/// A one-byte tag+type+size value
9#[bitfield(u32, debug = false)]
10#[derive(PartialEq)]
11pub struct IoFlags {
12    #[bits(1)]
13    data_or_constant: bool,
14    #[bits(1)]
15    array_or_variable: bool,
16    #[bits(1)]
17    absolute_or_relative: bool,
18    #[bits(1)]
19    wrap: bool,
20    #[bits(1)]
21    non_linear: bool,
22    #[bits(1)]
23    no_preferred: bool,
24    #[bits(1)]
25    null_state: bool,
26    // Note: `volatile` is only valid for Output and Feature (not Input)
27    #[bits(1)]
28    volatile: bool,
29    #[bits(1)]
30    bitfield_or_buffered: bool,
31    #[bits(23)]
32    reserved: u32,
33}
34
35impl IoFlags {
36    /// Construct a new `IoFlags` for a data field.
37    pub const fn data() -> Self {
38        Self::new()
39    }
40
41    /// Construct a new `IoFlags` for a constant field.
42    pub const fn constant() -> Self {
43        Self::new().with_data_or_constant(true)
44    }
45
46    /// The field stores a variable (otherwise it will store an array)
47    pub const fn variable(self) -> Self {
48        self.with_array_or_variable(true)
49    }
50
51    /// The field holds a relative value (by default values are absolute)
52    pub const fn relative(self) -> Self {
53        self.with_absolute_or_relative(true)
54    }
55}
56
57/// A collection of shorthand types for specifying input/output/feature item flags.
58///
59/// These are not required ([`IoFlags`] may be used instead) but because it may not
60/// be clear what the default flags are, these values may improve readability.
61pub mod ioflags {
62    use super::IoFlags;
63
64    /// Input/Output/Feature flags, using the terminology common in USB HID standards.
65    ///
66    /// This is shorthand for `IoFlags::data().variable()`.
67    pub const DATA_VARIABLE_ABSOLUTE: IoFlags = IoFlags::data().variable();
68
69    /// Input/Output/Feature flags for a constant, using the terminology common in USB HID standards.
70    ///
71    /// This is shorthand for `IoFlags::constant()`. It is commonly used to declare padding bits or bytes.
72    pub const CONSTANT: IoFlags = IoFlags::constant();
73
74    /// Input/Output/Feature flags for a data array, using the terminology common in USB HID standards.
75    ///
76    /// This is shorthand for `IoFlags::data()` (Note: the flag defaults to "array").
77    pub const ARRAY: IoFlags = IoFlags::data();
78}
79
80/// A wrapper indicating `IoFlags` that should be interpreted as Input flags.
81#[derive(Clone, Copy, PartialEq)]
82pub struct InputFlags(pub IoFlags);
83
84/// A wrapper indicating `IoFlags` that should be interpreted as Output or Feature flags.
85#[derive(Clone, Copy, PartialEq)]
86pub struct OutputFeatureFlags(pub IoFlags);
87
88/// A known __Collection__ type.
89#[expect(missing_docs)]
90#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive, IntoPrimitive)]
91#[repr(u8)]
92pub enum KnownCollectionType {
93    Physical = 0,
94    Application = 1,
95    Logical = 2,
96    Report = 3,
97    NamedArray = 4,
98    UsageSwitch = 5,
99    UsageModifier = 6,
100}
101
102/// A __Collection__ type.
103pub type CollectionType = Ident<KnownCollectionType, u8>;
104
105/// Some known unit values.
106///
107/// Note: this type is incomplete, and does not represent all
108/// the possible unit values.
109#[expect(missing_docs)]
110#[derive(Clone, Copy, Debug, PartialEq, TryFromPrimitive)]
111#[repr(u32)]
112#[non_exhaustive]
113pub enum KnownUnit {
114    // Length^1 in SI Linear (1)
115    Centimeter = 0x11,
116    // Length^1 in SI Rotation (2)
117    Radian = 0x12,
118    // Length^1 in English Linear (3)
119    Inch = 0x13,
120    // Length^1 in English Rotation(4)
121    Degree = 0x14,
122}
123
124/// A __Unit__ value.
125pub type Unit = Ident<KnownUnit, u32>;
126
127#[cfg(feature = "std")]
128mod std_impls {
129    use super::*;
130
131    use std::fmt::{self, Debug};
132
133    fn debug_flags(is_input: bool, flags: IoFlags, f: &mut fmt::Formatter<'_>) -> fmt::Result {
134        if flags.data_or_constant() {
135            f.write_str("Constant ")?;
136        } else {
137            f.write_str("Data ")?;
138        }
139        if flags.array_or_variable() {
140            f.write_str("Variable ")?;
141        } else {
142            f.write_str("Array ")?;
143        }
144        if flags.absolute_or_relative() {
145            f.write_str("Relative ")?;
146        } else {
147            f.write_str("Absolute ")?;
148        }
149        if flags.wrap() {
150            f.write_str("Wrap ")?;
151        } else {
152            f.write_str("No-Wrap ")?;
153        }
154        if flags.non_linear() {
155            f.write_str("Non-Linear ")?;
156        } else {
157            f.write_str("Linear ")?;
158        }
159        if flags.no_preferred() {
160            f.write_str("No-Preferred ")?;
161        } else {
162            f.write_str("Preferred-State ")?;
163        }
164        if flags.null_state() {
165            f.write_str("Null-State ")?
166        } else {
167            f.write_str("No-Null-Position ")?;
168        }
169
170        // The `volatile` field is only valid for Output and Feature tags.
171        if flags.volatile() {
172            f.write_str("Volatile ")?;
173        } else {
174            if !is_input {
175                f.write_str("Non-Volatile ")?;
176            }
177        }
178
179        if flags.bitfield_or_buffered() {
180            f.write_str("Buffered-Bytes")?;
181        } else {
182            f.write_str("Bit-Field")?;
183        }
184        Ok(())
185    }
186
187    impl Debug for InputFlags {
188        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
189            debug_flags(true, self.0, f)
190        }
191    }
192
193    impl Debug for OutputFeatureFlags {
194        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
195            debug_flags(false, self.0, f)
196        }
197    }
198}