# How the openlogi-hidpp Fork Extends the Vendored HID++ Protocol Crate

> Explore how the openlogi-hidpp fork enhances the HID++ protocol crate with a type-safe API for 30+ features, ensuring backward compatibility with existing imports.

- Repository: [Xuan Zhang/OpenLogi](https://github.com/AprilNEA/OpenLogi)
- Tags: internals
- Published: 2026-08-30

---

**The `openlogi-hidpp` crate extends the upstream `hidpp` library by adding a registry-driven, type-safe API for 30+ HID++ 2.0 features while maintaining full backward compatibility with existing `hidpp` imports.**

The `openlogi-hidpp` crate is a strategic vendor fork of the `hidpp` protocol library within the AprilNEA/OpenLogi repository. While it preserves the original public API to ensure existing code continues working without modification, it introduces a comprehensive extension layer that models the full HID++ 2.0 feature set used by modern Logitech devices.

## Fork Provenance and Compatibility Strategy

The fork was created from upstream commit `135c5600807845c269b5d5bfa1f33032281fbd86` (version 0.3.0) and maintains close proximity to the original codebase to facilitate future synchronization. This provenance is documented in the crate's README at [`crates/openlogi-hidpp/README.md`](https://github.com/AprilNEA/OpenLogi/blob/main/crates/openlogi-hidpp/README.md) (lines 6-13).

The crate retains the `hidpp::` namespace, allowing existing integrations to continue using identical import paths. The extensions live under `openlogi_hidpp::feature::`, providing a clean separation between the base protocol implementation and OpenLogi-specific enhancements.

## Centralized Feature Registry Architecture

At the heart of the extension lies a **static registry** that maps numeric HID++ feature IDs to their typed implementations. The `KNOWN_FEATURES` map, constructed by the `known_features!` macro in [`src/feature/registry.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/src/feature/registry.rs) (lines 20-70), serves as the central dispatch mechanism for feature discovery.

When a developer calls `device.get_feature::<T>()`, the library queries this registry to locate the appropriate implementation. The registry stores not just the feature ID, but also version metadata and constructor functions, enabling automatic selection of the most capable implementation available on the connected device.

## Versioned Feature Implementations

HID++ features evolve over time, with newer versions superseding older implementations. The `known_features!` macro handles this complexity by recording each implementation's `STARTING_VERSION` (lines 30-48 in [`src/feature/registry.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/src/feature/registry.rs)).

For example, `AdjustableDpi` and `ExtendedAdjustableDpi` represent different generations of the same capability. The registry automatically selects the appropriate version based on the device's reported feature version, ensuring maximum functionality without manual version checking.

## Typed Wrappers for 30+ HID++ 2.0 Features

The fork introduces **strongly-typed wrappers** for more than thirty HID++ 2.0 features, including `UnifiedBattery`, `SmartShiftEnhanced`, `PerKeyLighting`, and `SolarDashboard`. Each wrapper resides in its own module under `src/feature/` and implements the `Feature` trait.

For instance, [`src/feature/adjustable_dpi.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/src/feature/adjustable_dpi.rs) defines `AdjustableDpiFeature`, which implements `CreatableFeature` and exposes methods like `set_dpi()` and `get_dpi()`. This pattern repeats across all added features, providing compile-time guarantees, enumerated types for device states, and bit-flags for capability flags.

## Robust Error Handling and Spec Compliance

The extension layer enforces strict error handling through `Hidpp20Error::UnsupportedResponse`, which is returned when a device reports unknown wire values rather than attempting to guess or coerce invalid data. This policy, documented in the README (lines 39-41), ensures callers receive precise feedback about device capabilities.

Every feature module includes **co-located unit tests** (e.g., [`src/feature/adjustable_dpi/tests.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/src/feature/adjustable_dpi/tests.rs)) that encode and decode official wire format examples, verifying behavior against the HID++ specification. This ensures the typed wrappers accurately represent the underlying protocol.

## Practical API Usage

The fork maintains API compatibility while adding ergonomic discovery methods:

```rust
// Re-exported upstream types work unchanged
let chan = hidpp::HidppChannel::open("/dev/hidraw0")?;
let device = hidpp::Device::new(Arc::new(chan), 0);

// Retrieve typed feature implementations from the registry
let dpi = device.get_feature::<openlogi_hidpp::feature::adjustable_dpi::AdjustableDpiFeature>()?;
let current = dpi.get_dpi()?;
dpi.set_dpi(1200)?;

// Access OpenLogi-specific extensions
let lighting = device.get_feature::<openlogi_hidpp::feature::per_key_lighting::PerKeyLightingFeature>()?;
lighting.set_key_color(key_id, rgb::RGB { r: 0, g: 255, b: 0 })?;

```

The `get_feature` method uses the registry to instantiate the correct type, providing a uniform interface for accessing capabilities ranging from basic DPI adjustment to advanced per-key RGB lighting control.

## Summary

- The `openlogi-hidpp` fork tracks upstream commit `135c5600` (v0.3.0) while adding 30+ HID++ 2.0 feature implementations.
- A **centralized registry** (`KNOWN_FEATURES` in [`src/feature/registry.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/src/feature/registry.rs)) maps feature IDs to versioned implementations using the `known_features!` macro.
- **Type-safe wrappers** provide ergonomic APIs for device capabilities like `AdjustableDpi` and `PerKeyLighting`.
- The original `hidpp::` namespace remains unchanged, ensuring backward compatibility with existing code.
- Strict error handling via `Hidpp20Error::UnsupportedResponse` prevents silent failures when devices lack requested capabilities.

## Frequently Asked Questions

### What is the relationship between openlogi-hidpp and the upstream hidpp crate?

The `openlogi-hidpp` crate is a vendor fork created from upstream commit `135c5600807845c269b5d5bfa1f33032281fbd86` (version 0.3.0). It maintains the original public API under the `hidpp::` namespace for backward compatibility while adding OpenLogi-specific extensions under `openlogi_hidpp::feature::`. The fork stays close to upstream to simplify future synchronization.

### How does the feature registry handle different versions of the same HID++ feature?

The `known_features!` macro in [`src/feature/registry.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/src/feature/registry.rs) records each implementation's `STARTING_VERSION` along with a producer function. When `device.get_feature::<T>()` is called, the registry selects the implementation with the highest version number supported by the connected device, automatically choosing between variants like `AdjustableDpi` and `ExtendedAdjustableDpi` without requiring manual version checks.

### Where are the HID++ feature implementations located in the codebase?

Individual feature implementations reside in separate modules under `crates/openlogi-hidpp/src/feature/`. For example, adjustable DPI functionality lives in [`src/feature/adjustable_dpi.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/src/feature/adjustable_dpi.rs), while per-key lighting controls are in [`src/feature/per_key_lighting.rs`](https://github.com/AprilNEA/OpenLogi/blob/main/src/feature/per_key_lighting.rs). Each module contains the feature struct, trait implementations, unit tests, and wire-format definitions.

### How does the fork handle devices that don't support specific HID++ features?

Rather than returning generic errors or guessing values, the fork returns `Hidpp20Error::UnsupportedResponse` when a device reports unknown or unsupported wire values. This error handling policy, documented in the crate README, ensures applications receive explicit feedback about capability mismatches rather than silent failures or corrupted state.