OpenLogi
Features

0x19b0 · hapticFeedback

Device haptic actuator control — capabilities, enable state and intensity, and playing a typed waveform, as used by the MX Master 4's Actions Ring.

Controls a device's haptic actuator: which waveforms it can play, whether haptics are enabled and at what intensity, and playing one waveform immediately.

OpenLogi uses it for the Actions Ring on the MX Master 4, a subtle pulse when the highlighted slot changes, and a firmer one when an action runs.

Logitech has not published this feature in the public HID++ spec. The function and payload layouts here were cross-checked against Solaar and an MX Master 4; additions must be verified against hardware rather than guessed.

Spec: reverse-engineered — x19b0 hapticFeedback. Used by: Actions Ring hover and activation feedback.

Function reference

The HapticFeedbackFeature wrapper (0x19b0) exposes:

Methods

FunctionHID++ fnSignatureReturns
get_capabilities0()HapticCapabilities
get_configuration1()HapticConfiguration
set_configuration2(enabled: bool, intensity: HapticIntensity)()
play4(waveform: HapticWaveform)()

All are async and return Result<…, Hidpp20Error>.

Types

HapticCapabilities

FieldTypeDescription
unknown_prefix[u8; 4]Bytes whose meaning has not yet been verified.
waveformsSupportedWaveformsSupported waveform mask.

SupportedWaveforms

A bitflags mask; unknown bits are retained so newer firmware doesn't silently lose capability information.

FlagBitDescription
DAMP_STATE_CHANGE1A damp state-change pulse, used after activating a ring action.
SUBTLE_COLLISION4A subtle collision pulse, used when the highlighted ring slot changes.

HapticWaveform

VariantValueDescription
DampStateChange1Confirmation pulse used when an action runs.
SubtleCollision4Light boundary pulse used for hover transitions.

HapticConfiguration

FieldTypeDescription
enabledboolWhether firmware haptic playback is enabled.
intensityHapticIntensityCurrent intensity percentage.
level_countu8Number of discrete levels advertised by the firmware.
level_stepu8Percentage step between discrete levels.

HapticIntensity

A validated 0100 percentage: HapticIntensity::new(value) returns None above HapticIntensity::MAX (100), so an out-of-range intensity can never reach the wire.

Wire format

FunctionRequestResponse
0 get_capabilities[0x00, 0x00, 0x00]bytes 0–3 unverified prefix; bytes 4–7 big-endian u32 waveform mask
1 get_configuration[0x00, 0x00, 0x00]byte 0 enabled (0/1); byte 1 intensity percent; byte 2 high nibble = level step, low nibble = level count
2 set_configuration[enabled, intensity, 0x00]
4 play[waveform, 0x00, 0x00]

An enabled byte other than 0/1, or an intensity above 100, fails as Hidpp20Error::UnsupportedResponse rather than being coerced.

Usage (Rust)

use hidpp::{
    device::Device,
    feature::haptic_feedback::{HapticFeedbackFeature, HapticIntensity, HapticWaveform},
};

// device: &mut Device, already created via Device::new(channel, index)
device.enumerate_features().await?;

if let Some(feat) = device.get_feature::<HapticFeedbackFeature>() {
    let caps = feat.get_capabilities().await?;
    println!("waveforms: {:?}", caps.waveforms);

    if let Some(intensity) = HapticIntensity::new(60) {
        feat.set_configuration(true, intensity).await?;
    }
    feat.play(HapticWaveform::SubtleCollision).await?;
}

On this page