OpenLogi

0x2121 · hiResWheel

读取并保留高分辨率滚轮状态,接收转发的移动和棘轮事件,并支持 OpenLogi 的按设备平滑滚轮。

hiResWheel 配置高分辨率滚轮报告及其原生或转发路由。它还报告滚轮移动和棘轮切换。OpenLogi v0.8.15 修改已定义设置时会保留完整的三字节模式。

**规格:**Logitech HID++ 2.0 —— x2121 hiResWheel(v1)。**交叉核对:**Logi Options+ 2.8(静态分析)、Solaar。用于:滚动。

函数参考

HiResWheelFeature(0x2121)支持 feature 版本 0,并提供以下方法。

方法

函数HID++ fn签名返回值
get_wheel_capabilities0()Result<WheelCapabilities, Hidpp20Error>
get_wheel_mode1()Result<WheelMode, Hidpp20Error>
set_wheel_mode2(mode: WheelMode)Result<WheelMode, Hidpp20Error>
get_ratchet_switch_state3()Result<WheelRatchetState, Hidpp20Error>
listenevent()async_channel::Receiver<HiResWheelEvent>

前四个方法是 async。listen 是 EmittingFeature trait 的方法。OpenLogi 没有对应 function 4 的 get_analytics_data 方法。

类型

WheelCapabilities

字段类型说明
multiplieru8每个棘齿距离对应的高分辨率移动单位数。
has_prioritybool模式包含字节 1。Options+ 2.8 将其命名为 priority。
has_ratebool模式包含字节 2。Options+ 2.8 将其命名为 rate。
has_switchbool滚轮具有物理棘轮模式切换开关。
has_invertbool设备支持原生 HID 方向反转。它不适用于转发报告。
has_analytics_databoolfeature 报告 analytics 数据。OpenLogi 不读取此数据。
ratches_per_rotationu8一整圈中的棘齿数。
wheel_diameteru8标称滚轮直径,单位为毫米。

WheelMode

字段类型说明
targetWheelEventTarget原生 HID 或转发 HID++ 移动路由。
resolutionWheelResolution当前报告分辨率。
invertedbool原生 HID 方向反转。
private extensionprivate字节 0 中 0~2 以外的位,以及字节 1~2。OpenLogi 会逐字节保留这些由固件管理的数据。

WheelMode 没有公开构造函数。你必须使用 get_wheel_mode 读取它,只修改其公开字段,然后传给 set_wheel_mode。

WheelResolution

变体值说明
Low0低分辨率报告。
High1高分辨率报告。

WheelEventTarget

变体值说明
Native0移动发送到原生 HID 路径。
Diverted1移动作为 HID++ 事件到达。

WheelRatchetState

变体值说明
Freespin0滚轮处于自由滚动模式。
Ratchet1滚轮处于棘轮模式。

事件

HiResWheelEvent

变体载荷说明
WheelMovementWheelMovementData转发的滚轮移动。
RatchetSwitchWheelRatchetState棘轮模式变化。

WheelMovementData

字段类型说明
resolutionWheelResolution此移动事件报告的分辨率。
periodsU4采样周期计数,范围为 0~15。
delta_verticali16BE 有符号垂直增量。远离用户时为正。
delta_horizontali16BE 有符号水平增量。仅能垂直移动的滚轮报告零。Options+ 2.8。

线格式

所有 OpenLogi function 请求均使用三字节载荷。OpenLogi 会在解码前将回复和事件扩展为 16 字节缓冲区。多字节移动增量为 BE 有符号 i16 值。

get_wheel_capabilities(fn 0)

请求:[0x00, 0x00, 0x00]。

回复:

字节字段说明
0multiplier原始 u8。
1 bit 0has_priorityOptions+ 2.8。
1 bit 1has_rateOptions+ 2.8。
1 bit 2has_switch棘轮切换能力。
1 bit 3has_invert原生反转能力。
1 bit 4has_analytics_dataOptions+ 2.8。
1 bits 5~7保留或未知OpenLogi 忽略这些位。
2ratches_per_rotation原始 u8。
3wheel_diameter原始 u8 毫米值。

get_wheel_mode(fn 1)

请求:[0x00, 0x00, 0x00]。

回复:

字节字段说明
0 bit 0target0 为 Native;1 为 Diverted。
0 bit 1resolution0 为 Low;1 为 High。
0 bit 2inverted适用于原生 HID 报告。
0 bit 3analyticsOptions+ 2.8。OpenLogi 保留此位,但不公开它。
0 bits 4~7保留或未知OpenLogi 在私有模式扩展中逐字节保留这些位。
1priorityOptions+ 2.8。OpenLogi 保留此字节,但不公开或验证它。
2rateOptions+ 2.8。OpenLogi 保留此字节,但不公开或验证它。

set_wheel_mode(fn 2)

**请求:**已读取 WheelMode 中的三个字节。

字节写入字段说明
0target、resolution、inverted 和扩展标志OpenLogi 用公开字段替换位 0~2。它保留 bit 3 和位 4~7。
1priority从已读取模式中逐字节保留。Options+ 2.8。
2rate从已读取模式中逐字节保留。Options+ 2.8。

**回复:**与 get_wheel_mode 相同的三字节模式布局。

get_ratchet_switch_state(fn 3)

请求:[0x00, 0x00, 0x00]。

回复:

字节字段说明
0 bit 0WheelRatchetState0 为 Freespin;1 为 Ratchet。
0 bits 1~7保留OpenLogi 忽略这些位。

get_analytics_data(fn 4)

OpenLogi 未实现此 function。Options+ 2.8 仅在 analytics 数据可用时读取 function 4,并接受至少 16 个原始字节的回复。请求布局和这 16 个字节的含义仍未确认。

事件

WheelMovement(event fn 0)

字节字段说明
0 bit 4resolution0 为 Low;1 为 High。
0 bits 3~0periodsU4,范围为 0~15。
1~2delta_verticalBE 有符号 i16。
3~4delta_horizontalBE 有符号 i16。Options+ 2.8 要求五字节移动载荷。

RatchetSwitch(event fn 1)

字节字段说明
0 bit 0WheelRatchetState0 为 Freespin;1 为 Ratchet。

OpenLogi 的用法

OpenLogi 将 0x2121 记录为 hires_wheel 能力。它会单独读取 has_invert,再公开原生滚轮反转。常规分辨率和反转写入会先读取完整模式。它们只修改 target、resolution 或 inverted,发送原始扩展字节,检查 setter 回显,然后读回并检查已定义字段。原生反转写入需要 has_invert。

每台设备的 smooth_wheel 选项默认值为 false。仅当设备具有 0x2121、设备已启用、鼠标捕获已启用且操作系统鼠标钩子可以发送输入时,此选项才会 arm。在 macOS 上,最后一个条件需要辅助功能访问权限。捕获会话读取能力和模式,然后以读-改-写方式写入 target = Diverted,并在可用时写入已配置的分辨率或反转值。该会话拥有滚轮期间,常规原生模式重放路径会停止写入。

会话将垂直 WheelMovement 报告路由给 agent。高分辨率移动会除以 multiplier,低分辨率移动每个棘齿使用一个单位。agent 应用已配置的反转和 macOS 自然滚动方向。即使全局平滑滚动选项关闭,agent 也会发送缓动滚动。如果滚动运行时无法接受输入,agent 会直接发送已缩放的垂直增量。OpenLogi 当前会丢弃 delta_horizontal,且只记录 RatchetSwitch;两者均不会成为用户可见事件。

正常停止、断开连接、捕获计划变化或 arm 失败时,OpenLogi 只以读-改-写方式写入 target = Native。此操作会保留分辨率、反转、analytics、priority、rate 和未知模式位。恢复失败会保持为待处理状态,并通过当前通道重试。如果 agent 异常退出,滚轮可能保持转发状态,直到 OpenLogi 重新连接或再次运行。

未确认的细节

Options+ 2.8 将字节 0 bit 3 命名为 analytics,并将字节 1~2 命名为 priority 和 rate。其静态分析未确定这些字段的合法范围或设备行为。OpenLogi 保留这三个字段,但不将其公开为设置。

Options+ 2.8 要求五字节 WheelMovement 载荷。OpenLogi 会解码扩展后的 16 字节缓冲区,且不会拒绝原始长度较短的载荷。截断事件的硬件行为仍未确认。

Options+ 2.8 从 function 4 接受至少 16 个字节。请求载荷及其字节含义仍未确认。OpenLogi 公开 analytics 能力标志,但没有 function 4 的原始 API。

Rust 用法

use std::sync::Arc;

use hidpp::{
    channel::HidppChannel,
    device::Device,
    feature::{
        EmittingFeature,
        hires_wheel::{HiResWheelFeature, WheelEventTarget, WheelResolution},
    },
};

async fn read_one_diverted_event(
    channel: Arc<HidppChannel>,
    device_index: u8,
) -> Result<(), Box<dyn std::error::Error>> {
    let mut device = Device::new(channel, device_index).await?;
    device.enumerate_features().await?;

    let Some(feature) = device.get_feature::<HiResWheelFeature>() else {
        return Ok(());
    };
    let mut mode = feature.get_wheel_mode().await?;
    let original_target = mode.target;
    mode.target = WheelEventTarget::Diverted;
    mode.resolution = WheelResolution::High;
    feature.set_wheel_mode(mode).await?;

    let events = feature.listen();
    if let Ok(event) = events.recv().await {
        println!("{event:?}");
    }

    let mut restore = feature.get_wheel_mode().await?;
    restore.target = original_target;
    feature.set_wheel_mode(restore).await?;
    Ok(())
}

本页目录