hid-types 0.1.1

Rust types for working with USB HID report descriptors
Documentation
//! Types that contain all the information in Usage tags.

use crate::Ident;
use crate::id::usage::{
    KnownUsagePage, UsagePage, arcade, auxiliary_display, barcode_scanner, battery_system,
    braille_display, camera_control, consumer, digitizers, eye_head_trackers, fido_alliance,
    game_controls, generic_desktop, generic_device_controls, haptics, keyboard_keypad, led_page,
    lighting_illumination, magnetic_stripe_reader, medical_instrument, monitor,
    physical_input_device, power, scales, sensors, simulation_controls, soc, sport_controls,
    telephony_device, vesa_virtual_controls, vr_controls,
};

/// A __Usage ID__, that includes its parent __Usage Page__.
#[derive(Clone, Copy, PartialEq)]
pub struct ExtendedUsage {
    /// The Usage Page.
    pub page: UsagePage,
    /// The Usage ID.
    pub id: u16,
}

impl ExtendedUsage {
    /// Create a new `ExtendedUsage` value.
    pub fn new(page: UsagePage, id: u16) -> Self {
        Self { page, id }
    }

    /// Construct a usage page/id from a single integer
    pub fn from_u32(value: u32) -> Self {
        let lsb = (value & 0xFFFF) as u16;
        let msb = (value >> 16) as u16;
        let page = UsagePage::from_integer(msb);
        Self { page, id: lsb }
    }

    /// Extract the usage value if it is a known value.
    ///
    /// If this returns `None` it could be for multiple reasons:
    ///
    /// 1. The Usage Page does not contain distinct IDs (e.g. Button)
    /// 2. The Usage Page is unknown or reserved.
    /// 3. The Usage Page is known but the Usage value is unknown or reserved.
    pub fn get_known(&self) -> Option<KnownUsage> {
        let Ident::Known(known_page) = self.page else {
            return None;
        };
        match known_page {
            KnownUsagePage::Undefined => None,
            KnownUsagePage::GenericDesktop => generic_desktop::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::GenericDesktop),
            KnownUsagePage::SimulationControls => {
                simulation_controls::KnownUsage::try_from(self.id)
                    .ok()
                    .map(KnownUsage::SimulationControls)
            }
            KnownUsagePage::VrControls => vr_controls::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::VrControls),
            KnownUsagePage::SportControls => sport_controls::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::SportControls),
            KnownUsagePage::GameControls => game_controls::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::GameControls),
            KnownUsagePage::GenericDeviceControls => {
                generic_device_controls::KnownUsage::try_from(self.id)
                    .ok()
                    .map(KnownUsage::GenericDeviceControls)
            }
            KnownUsagePage::KeyboardKeypad => keyboard_keypad::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::KeyboardKeypad),
            KnownUsagePage::Led => led_page::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Led),
            KnownUsagePage::Button => Some(KnownUsage::Button(self.id)),
            KnownUsagePage::Ordinal => Some(KnownUsage::Ordinal(self.id)),
            KnownUsagePage::TelephonyDevice => telephony_device::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::TelephonyDevice),
            KnownUsagePage::Consumer => consumer::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Consumer),
            KnownUsagePage::Digitizers => digitizers::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Digitizers),
            KnownUsagePage::Haptics => haptics::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Haptics),
            KnownUsagePage::PhysicalInputDevice => {
                physical_input_device::KnownUsage::try_from(self.id)
                    .ok()
                    .map(KnownUsage::PhysicalInputDevice)
            }
            KnownUsagePage::Unicode => Some(KnownUsage::Unicode(self.id)),
            KnownUsagePage::Soc => soc::KnownUsage::try_from(self.id).ok().map(KnownUsage::Soc),
            KnownUsagePage::EyeAndHeadTrackers => eye_head_trackers::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::EyeAndHeadTrackers),
            KnownUsagePage::AuxiliaryDisplay => auxiliary_display::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::AuxiliaryDisplay),
            KnownUsagePage::Sensors => sensors::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Sensors),
            KnownUsagePage::MedicalInstrument => medical_instrument::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::MedicalInstrument),
            KnownUsagePage::BrailleDisplay => braille_display::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::BrailleDisplay),
            KnownUsagePage::LightingAndIllumination => {
                lighting_illumination::KnownUsage::try_from(self.id)
                    .ok()
                    .map(KnownUsage::LightingAndIllumination)
            }
            KnownUsagePage::Monitor => monitor::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Monitor),
            KnownUsagePage::MonitorEnumerated => Some(KnownUsage::MonitorEnumerated(self.id)),
            KnownUsagePage::VesaVirtualControls => {
                vesa_virtual_controls::KnownUsage::try_from(self.id)
                    .ok()
                    .map(KnownUsage::VesaVirtualControls)
            }
            KnownUsagePage::Power => power::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Power),
            KnownUsagePage::BatterySystem => battery_system::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::BatterySystem),
            KnownUsagePage::BarcodeScanner => barcode_scanner::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::BarcodeScanner),
            KnownUsagePage::Scales => scales::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Scales),
            KnownUsagePage::MagneticStripeReader => {
                magnetic_stripe_reader::KnownUsage::try_from(self.id)
                    .ok()
                    .map(KnownUsage::MagneticStripeReader)
            }
            KnownUsagePage::CameraControl => camera_control::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::CameraControl),
            KnownUsagePage::Arcade => arcade::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::Arcade),
            KnownUsagePage::GamingDevice => Some(KnownUsage::GamingDevice(self.id)),
            KnownUsagePage::FidoAlliance => fido_alliance::KnownUsage::try_from(self.id)
                .ok()
                .map(KnownUsage::FidoAlliance),
        }
    }
}

/// A __Usage ID__, that does not encode its parent page.
#[derive(Clone, PartialEq)]
pub enum Usage {
    /// A Usage value that remembers its parent page.
    Known(KnownUsage),
    /// A standalone Usage value that cannot be decoded without page context.
    Unknown(u16),
}

impl Usage {
    /// Create a new `Usage` value, in the context of a known Usage Page.
    pub fn new(page: UsagePage, id: u16) -> Self {
        match ExtendedUsage::new(page, id).get_known() {
            Some(known) => Usage::Known(known),
            None => Usage::Unknown(id),
        }
    }

    /// Construct a usage without `UsagePage` context.
    pub fn without_page(id: u16) -> Self {
        Usage::Unknown(id)
    }
}

/// A well-known usage id.
#[expect(missing_docs)]
#[derive(Clone, PartialEq)]
pub enum KnownUsage {
    GenericDesktop(generic_desktop::KnownUsage),
    SimulationControls(simulation_controls::KnownUsage),
    VrControls(vr_controls::KnownUsage),
    SportControls(sport_controls::KnownUsage),
    GameControls(game_controls::KnownUsage),
    GenericDeviceControls(generic_device_controls::KnownUsage),
    KeyboardKeypad(keyboard_keypad::KnownUsage),
    Led(led_page::KnownUsage),
    Button(u16),
    Ordinal(u16),
    TelephonyDevice(telephony_device::KnownUsage),
    Consumer(consumer::KnownUsage),
    Digitizers(digitizers::KnownUsage),
    Haptics(haptics::KnownUsage),
    PhysicalInputDevice(physical_input_device::KnownUsage),
    Unicode(u16),
    Soc(soc::KnownUsage),
    EyeAndHeadTrackers(eye_head_trackers::KnownUsage),
    AuxiliaryDisplay(auxiliary_display::KnownUsage),
    Sensors(sensors::KnownUsage),
    MedicalInstrument(medical_instrument::KnownUsage),
    BrailleDisplay(braille_display::KnownUsage),
    LightingAndIllumination(lighting_illumination::KnownUsage),
    Monitor(monitor::KnownUsage),
    MonitorEnumerated(u16),
    VesaVirtualControls(vesa_virtual_controls::KnownUsage),
    Power(power::KnownUsage),
    BatterySystem(battery_system::KnownUsage),
    BarcodeScanner(barcode_scanner::KnownUsage),
    Scales(scales::KnownUsage),
    MagneticStripeReader(magnetic_stripe_reader::KnownUsage),
    CameraControl(camera_control::KnownUsage),
    Arcade(arcade::KnownUsage),
    GamingDevice(u16),
    FidoAlliance(fido_alliance::KnownUsage),
}

#[cfg(feature = "std")]
mod std_impls {
    use std::fmt::{self, Debug, Display};

    use super::*;

    impl Debug for ExtendedUsage {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            let mut debug_struct = f.debug_struct("Usage");
            debug_struct.field("page", &self.page);

            if let Some(known) = self.get_known() {
                debug_struct.field("id", &known);
            } else {
                debug_struct.field("id", &format_args!("{:#04x}", self.id));
            }
            debug_struct.finish()
        }
    }

    impl Debug for Usage {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            let mut debug_struct = f.debug_struct("Usage");

            // Note: we don't print the `page` value, since it was
            // not meant to be encoded in this item.

            match self {
                Usage::Known(usage) => {
                    debug_struct.field("id", &usage);
                }
                Usage::Unknown(id) => {
                    debug_struct.field("id", &id);
                }
            }
            debug_struct.finish()
        }
    }

    impl Debug for KnownUsage {
        // Only prints the inner value.
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            match self {
                Self::Button(value)
                | Self::Ordinal(value)
                | Self::Unicode(value)
                | Self::MonitorEnumerated(value)
                | Self::GamingDevice(value) => {
                    // 16-bit usage ID without a unique name.
                    Debug::fmt(&value, f)
                }
                Self::GenericDesktop(value) => value.fmt(f),
                Self::SimulationControls(value) => value.fmt(f),
                Self::VrControls(value) => value.fmt(f),
                Self::SportControls(value) => value.fmt(f),
                Self::GameControls(value) => value.fmt(f),
                Self::GenericDeviceControls(value) => value.fmt(f),
                Self::KeyboardKeypad(value) => value.fmt(f),
                Self::Led(value) => value.fmt(f),
                Self::TelephonyDevice(value) => value.fmt(f),
                Self::Consumer(value) => value.fmt(f),
                Self::Digitizers(value) => value.fmt(f),
                Self::Haptics(value) => value.fmt(f),
                Self::PhysicalInputDevice(value) => value.fmt(f),
                Self::Soc(value) => value.fmt(f),
                Self::EyeAndHeadTrackers(value) => value.fmt(f),
                Self::AuxiliaryDisplay(value) => value.fmt(f),
                Self::Sensors(value) => value.fmt(f),
                Self::MedicalInstrument(value) => value.fmt(f),
                Self::BrailleDisplay(value) => value.fmt(f),
                Self::LightingAndIllumination(value) => value.fmt(f),
                Self::Monitor(value) => value.fmt(f),
                Self::VesaVirtualControls(value) => value.fmt(f),
                Self::Power(value) => value.fmt(f),
                Self::BatterySystem(value) => value.fmt(f),
                Self::BarcodeScanner(value) => value.fmt(f),
                Self::Scales(value) => value.fmt(f),
                Self::MagneticStripeReader(value) => value.fmt(f),
                Self::CameraControl(value) => value.fmt(f),
                Self::Arcade(value) => value.fmt(f),
                Self::FidoAlliance(value) => value.fmt(f),
            }
        }
    }

    impl Display for KnownUsage {
        // Only prints the inner value.
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            match self {
                Self::Button(value)
                | Self::Ordinal(value)
                | Self::Unicode(value)
                | Self::MonitorEnumerated(value)
                | Self::GamingDevice(value) => {
                    // 16-bit usage ID without a unique name.
                    Display::fmt(&value, f)
                }
                Self::GenericDesktop(value) => value.fmt(f),
                Self::SimulationControls(value) => value.fmt(f),
                Self::VrControls(value) => value.fmt(f),
                Self::SportControls(value) => value.fmt(f),
                Self::GameControls(value) => value.fmt(f),
                Self::GenericDeviceControls(value) => value.fmt(f),
                Self::KeyboardKeypad(value) => value.fmt(f),
                Self::Led(value) => value.fmt(f),
                Self::TelephonyDevice(value) => value.fmt(f),
                Self::Consumer(value) => value.fmt(f),
                Self::Digitizers(value) => value.fmt(f),
                Self::Haptics(value) => value.fmt(f),
                Self::PhysicalInputDevice(value) => value.fmt(f),
                Self::Soc(value) => value.fmt(f),
                Self::EyeAndHeadTrackers(value) => value.fmt(f),
                Self::AuxiliaryDisplay(value) => value.fmt(f),
                Self::Sensors(value) => value.fmt(f),
                Self::MedicalInstrument(value) => value.fmt(f),
                Self::BrailleDisplay(value) => value.fmt(f),
                Self::LightingAndIllumination(value) => value.fmt(f),
                Self::Monitor(value) => value.fmt(f),
                Self::VesaVirtualControls(value) => value.fmt(f),
                Self::Power(value) => value.fmt(f),
                Self::BatterySystem(value) => value.fmt(f),
                Self::BarcodeScanner(value) => value.fmt(f),
                Self::Scales(value) => value.fmt(f),
                Self::MagneticStripeReader(value) => value.fmt(f),
                Self::CameraControl(value) => value.fmt(f),
                Self::Arcade(value) => value.fmt(f),
                Self::FidoAlliance(value) => value.fmt(f),
            }
        }
    }

    impl Display for Usage {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            // Note: we don't print the `page` value, since it was
            // not meant to be encoded in this item.

            match self {
                Usage::Known(usage) => Display::fmt(&usage, f),
                Usage::Unknown(id) => Display::fmt(&format_args!("{id:#04x}"), f),
            }
        }
    }
}