pub struct ReportDescriptorBuilder<S: ReportDescriptorBuilderState> { /* private fields */ }Expand description
A struct for programatically building a HID Report Descriptor.
use hut::{self, AsUsage};
let mut builder = ReportDescriptorBuilder::new();
let rdesc: Vec<u8> = builder
.usage_page(hut::UsagePage::GenericDesktop)
.usage_id(hut::GenericDesktop::Mouse)
.open_collection(CollectionItem::Application)
.open_collection(CollectionItem::Physical)
.push()
.append(LogicalMinimum::from(0).into())
.append(LogicalMaximum::from(128).into())
.pop()
.append(ReportCount::from(2).into())
.append(ReportSize::from(8).into())
.usage_id(hut::GenericDesktop::X)
.usage_id(hut::GenericDesktop::Y)
.input(ItemBuilder::new()
.variable()
.absolute()
.input())
.close_collection()
.close_collection()
.build();Implementations§
Source§impl<S: ReportDescriptorBuilderState> ReportDescriptorBuilder<S>
impl<S: ReportDescriptorBuilderState> ReportDescriptorBuilder<S>
Sourcepub fn append(self, item: ItemType) -> Self
pub fn append(self, item: ItemType) -> Self
Append an item to this builder. This will append the necesssary bytes once ReportDescriptorBuilder::build() is called.
Sourcepub fn usage_page(self, usage_page: impl AsUsagePage) -> Self
pub fn usage_page(self, usage_page: impl AsUsagePage) -> Self
Append the given UsagePage to the report descriptor.
However, since most report descriptors seen in the wild use the LocalItem::Usage for the Usage ID only, this wrapper is provided to make the code more obvious.
In this buggy example code the actual usage used in the report descriptor will be
GenericDesktop Mouse.
use hidreport::types::*;
use hidreport::{Field, ReportDescriptor, Report, VariableField, Usage};
use hut::{self, AsUsagePage, AsUsage};
let rdesc = ReportDescriptorBuilder::new()
.usage_page(hut::GenericDesktop::X) // sets Usage Page to GenericDesktop
.usage_id(hut::Arcade::CoinDoor) // BUG: sets Usage ID to 0x2
.append(LogicalMinimum::from(0).into())
.append(LogicalMaximum::from(128).into())
.append(ReportCount::from(1).into())
.append(ReportSize::from(8).into())
.input(ItemBuilder::new()
.variable()
.absolute()
.input())
.build();
let rdesc: ReportDescriptor = ReportDescriptor::try_from(&rdesc).unwrap();
let input = rdesc.input_reports().first().unwrap();
let item = input.fields().first().unwrap();
let usage: Usage = match item {
Field::Variable(VariableField {
usage, ..
}) => *usage,
_ => panic!("Invalid field type"),
};
let expected_buggy_usage: Usage = hut::GenericDesktop::Mouse.usage().into();
assert_eq!(usage, expected_buggy_usage);This is a convenience wrapper for Self::append().
Sourcepub fn usage_id(self, usage: impl AsUsage) -> Self
pub fn usage_id(self, usage: impl AsUsage) -> Self
Append the given Usage ID to the report descriptor.
However, since most report descriptors seen in the wild use the LocalItem::Usage for the Usage ID only, this wrapper is provided to make the code more obvious.
In this buggy example code the actual usage used in the report descriptor will be
Button 0x30.
use hidreport::types::*;
use hut::{self, AsUsagePage, AsUsage};
let rdesc = ReportDescriptorBuilder::new()
.usage_page(hut::UsagePage::Button) // sets Usage Page to Button
.usage_id(hut::GenericDesktop::X) // BUG: sets Usage ID to 0x30
.build();See Self::usage_page() for an more detailed example on a Usage Page and Usage ID mismatch.
This is a convenience wrapper for Self::append().
Sourcepub fn input(self, item: InputItem) -> Self
pub fn input(self, item: InputItem) -> Self
Append the InputItem. Use the ItemBuilder with ItemBuilder::input() to create this item.
This is a convenience wrapper for Self::append().
Sourcepub fn output(self, item: OutputItem) -> Self
pub fn output(self, item: OutputItem) -> Self
Append the OutputItem. Use the ItemBuilder with ItemBuilder::output() to create this item.
This is a convenience wrapper for Self::append().
Sourcepub fn feature(self, item: FeatureItem) -> Self
pub fn feature(self, item: FeatureItem) -> Self
Append the FeatureItem. Use the ItemBuilder with ItemBuilder::feature() to create this item.
This is a convenience wrapper for Self::append().
Source§impl ReportDescriptorBuilder<ReportDescriptorBuilderToplevel>
impl ReportDescriptorBuilder<ReportDescriptorBuilderToplevel>
Sourcepub fn new() -> ReportDescriptorBuilder<ReportDescriptorBuilderToplevel>
pub fn new() -> ReportDescriptorBuilder<ReportDescriptorBuilderToplevel>
Create a new builder
Sourcepub fn open_collection(
self,
item: CollectionItem,
) -> ReportDescriptorBuilder<ReportDescriptorBuilderC1>
pub fn open_collection( self, item: CollectionItem, ) -> ReportDescriptorBuilder<ReportDescriptorBuilderC1>
Open a new collection for the builder. This collection must be closed with a call to close_collection().
This is a convenience function and identical to append() with a CollectionItem. However it enforces that all collections are correctly closed before build() can be called.
Sourcepub fn push(
self,
) -> ReportDescriptorBuilder<ReportDescriptorBuilderToplevelPush>
pub fn push( self, ) -> ReportDescriptorBuilder<ReportDescriptorBuilderToplevelPush>
Pushes the current builder stack (use pop() to return to the current state).
This is a convenience wrapper for
append() with a GlobalItem::Push. However
it enforces that a Push is followed by a Pop before
build() can be called or another collection
can be opened.
It is not possible to open_collection() while
in the logical Pushed state. This is a restriction by this crate, use
append() directly where this is required.
Sourcepub fn build(&self) -> Vec<u8> ⓘ
pub fn build(&self) -> Vec<u8> ⓘ
Build the report descriptor bytes based on the current builder state.
This optimizes each HID Items to be of the minimum required, i.e. a value that fits into a u8 will be encoded as HID Item with a data length of 1, etc.
This does not optimize potentially duplicate fields added by the caller,
e.g. adding two consecutive ReportSize() in the builder will result
in both of these showing up in the resulting report descriptor byte array.
Source§impl ReportDescriptorBuilder<ReportDescriptorBuilderToplevelPush>
impl ReportDescriptorBuilder<ReportDescriptorBuilderToplevelPush>
Sourcepub fn pop(self) -> ReportDescriptorBuilder<ReportDescriptorBuilderToplevel>
pub fn pop(self) -> ReportDescriptorBuilder<ReportDescriptorBuilderToplevel>
Pops the current builder stack, see push().
This is a convenience wrapper for
append() with a GlobalItem::Pop. However
it enforces that a Push is followed by a Pop before
build() can be called or another collection
can be opened.
It is not possible to open_collection() while
in the logical Pushed state. This is a restriction by this crate, use
append() directly where this is required.
Source§impl ReportDescriptorBuilder<ReportDescriptorBuilderC1>
impl ReportDescriptorBuilder<ReportDescriptorBuilderC1>
Sourcepub fn close_collection(
self,
) -> ReportDescriptorBuilder<ReportDescriptorBuilderToplevel>
pub fn close_collection( self, ) -> ReportDescriptorBuilder<ReportDescriptorBuilderToplevel>
Close the current collection.
This function is only available after open_collection().