OpenLogi

0x1B04 · specialKeysMSEButtons

枚举可编程控件、修改控件上报状态,并接收已分流按钮、指针、analytics 和原始滚轮事件。

specialKeysMSEButtons(0x1b04)描述鼠标和键盘上的可编程物理控件与虚拟 控件。它枚举按钮、功能键和热键。主机软件可以分流控件、设置持久分流、修改 上报流,或选择重映射目标。

OpenLogi 将这个功能注册为 ReprogControls5。它的类型化 Rust 封装是 ReprogControlsFeature。0x1b04 是 0x1b00 · reprogControls 的较新版本。

**规格:**Logitech HID++ 2.0 —— specialKeysMseButtons(v2)。**交叉核对:**Logi Options+ 2.8(静态分析)、Solaar。用于:按键重映射。

函数参考

ReprogControlsFeature 实现 0x1b04。

方法

函数HID++ fn签名返回值
get_count0()u8
get_cid_info1(index: u8)CidInfo
get_cid_reporting2(cid: ControlId)CidReporting
set_cid_reporting3(cid: ControlId, change: CidReportingChange)CidReportingChangeEcho
get_capabilities4()ReprogControlsCapabilities
reset_all_cid_report_settings5()()
listenevent()async_channel::Receiver<ReprogControlsEvent>

前六个方法都是 async。它们返回 Result<…, Hidpp20Error>。 listen 是同步的 EmittingFeature trait 方法。

类型

ControlId、TaskId 和 GroupMask

类型内部类型说明
ControlIdu16HID++ 控件 ID。
TaskIdu16与控件关联的默认任务。
GroupMasku8get_cid_info 返回的 g1..g8 成员掩码。

CidInfo

字段类型说明
cidControlId控件 ID。
task_idTaskId默认任务 ID。
flagsCidFlags能力和分类标志。
positionu8设备报告的物理位置值。
groupu8设备报告的分组号。
group_maskGroupMask分组成员掩码。

CidFlags

标志位说明
MOUSE1 << 0鼠标或指针控件。
FUNCTION_KEY1 << 1键盘功能键。
HOTKEY1 << 2热键。
FN_TOGGLE1 << 3Fn 切换控件。
REPROGRAMMABLE1 << 4可重编程控件。
DIVERTABLE1 << 5可临时分流控件。
PERSISTENTLY_DIVERTABLE1 << 6可持久分流控件。
VIRTUAL_CONTROL1 << 7虚拟而非物理控件。
RAW_XY1 << 8支持原始 XY 上报。
FORCE_RAW_XY1 << 9支持强制原始 XY 上报。
ANALYTICS_KEY_EVENTS1 << 10支持 analytics 按键事件。
RAW_WHEEL1 << 11支持原始滚轮上报。

CidFlags::raw() 返回组合后的 u16。is_* 和 supports_* 方法公开对应的 具名标志。

CidReporting

字段类型说明
cidControlId已读取状态的控件。
divertedbool临时分流状态。
persistently_divertedbool持久分流状态。
force_raw_xybool强制原始 XY 状态。
raw_xybool原始 XY 状态。
remapOption<ControlId>目标控件;设备报告 0x0000 时为 None。
analytics_key_eventsboolanalytics 按键事件状态。
raw_wheelbool原始滚轮状态。

CidReportingChange

每个 Option<bool> 仅在值为 Some 时修改对应设置。值为 None 时,设备保持 该设置不变。

字段类型说明
divertedOption<bool>临时分流变更。
persistently_divertedOption<bool>持久分流变更。
force_raw_xyOption<bool>强制原始 XY 变更。
raw_xyOption<bool>原始 XY 变更。
remapOption<ControlId>目标控件。None 发送 0x0000 并保持当前重映射。
analytics_key_eventsOption<bool>analytics 按键事件变更。
raw_wheelOption<bool>原始滚轮变更。

如要清除重映射,请为正在写入的控件设置 remap: Some(cid)。不要使用 None: 对于 set_cid_reporting,0x0000 表示保持之前的重映射。

CidReportingChangeEcho

字段类型说明
cidControlId响应中的控件 ID。
divertedOption<bool>回显的临时分流变更。
persistently_divertedOption<bool>回显的持久分流变更。
force_raw_xyOption<bool>回显的强制原始 XY 变更。
raw_xyOption<bool>回显的原始 XY 变更。
remapOption<ControlId>非零时的回显重映射目标。
analytics_key_eventsOption<bool>回显的 analytics 按键事件变更。
raw_wheelOption<bool>回显的原始滚轮变更。

ReprogControlsCapabilities

字段类型说明
reset_all_cid_report_settingsboolreset_all_cid_report_settings 可用。

事件

ReprogControlsFeature 实现 EmittingFeature<ReprogControlsEvent>。

变体Event fn字段说明
DivertedButtons0[ControlId; 4]当前已分流控件。
DivertedRawMouseXy1dx: i16、dy: i16原始指针增量。
AnalyticsKeyEvents2[AnalyticsKeyEvent; 5]五条 packed analytics 条目。
DivertedRawWheel4resolution、periods、delta_vertical原始垂直滚轮增量。

AnalyticsKeyEvent 包含 cid: ControlId 和设备定义的 event: u8。 RawWheelResolution 为 Low = 0 或 High = 1。periods 是无符号四位值 U4。

线格式

表格中的字节是逻辑 HID++ payload 字节。OpenLogi 发送 3 字节短请求,fn 1 和 fn 3 则发送 16 字节长请求。读取方法使用扩展后的 16 字节响应视图,并忽略没有 建模字段的字节。

get_count(fn 0)

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

字节字段备注
0count控件表的条目数。
1–15—OpenLogi 不解析字段。

get_cid_info(fn 1)

请求为长 payload,index 位于字节 0。OpenLogi 在字节 1–15 写入 0x00。

字节字段备注
0–1cidBE u16 的 ControlId。
2–3task_idBE u16 的 TaskId。
4primary flagsCidFlags 的位 0–7。
5position设备报告的位置。
6group设备报告的分组。
7group_maskGroupMask 的 g1..g8 位。
8additional flagsCidFlags 的位 8–11。OpenLogi 将此字节左移 8 位。
9–15—没有已知字段。OpenLogi 忽略这些字节。

get_cid_reporting(fn 2)

请求:[cid_hi, cid_lo, 0x00]。cid_hi,cid_lo 是 BE u16 格式的 ControlId。

字节字段备注
0–1cidBE u16。
2 bit 0diverted1 表示临时分流。
2 bit 2persistently_diverted1 表示持久分流。
2 bit 4raw_xy1 表示原始 XY。
2 bit 6force_raw_xy1 表示强制原始 XY。
3–4remapBE u16 目标。0x0000 表示控件映射到自身,并变为 None。
5 bit 0analytics_key_events1 启用 analytics 事件。
5 bit 2raw_wheel1 启用原始滚轮事件。
6–15—没有已知字段。OpenLogi 忽略这些字节。

set_cid_reporting(fn 3)

OpenLogi 发送 16 字节长请求。它在字节 6–15 写入 0x00。

字节字段备注
0–1cidBE u16。
2 bit 1 / bit 0diverted valid / value仅当 valid 为 1 时修改值。
2 bit 3 / bit 2persistently_diverted valid / value仅当 valid 为 1 时修改值。
2 bit 5 / bit 4raw_xy valid / value仅当 valid 为 1 时修改值。
2 bit 7 / bit 6force_raw_xy valid / value仅当 valid 为 1 时修改值。
3–4remapBE u16。0x0000 保持之前的重映射。写入此 cid 可清除重映射。
5 bit 1 / bit 0analytics_key_events valid / value仅当 valid 为 1 时修改值。
5 bit 3 / bit 2raw_wheel valid / value仅当 valid 为 1 时修改值。
6–15—OpenLogi 写入固定的零填充。

响应具有相同的已建模字节 0–5。CidReportingChangeEcho 仅在 valid 位已设置时 公开布尔值。它将零重映射字段变为 None,并忽略字节 6–15。

get_capabilities(fn 4)

请求:[0x00, 0x00, 0x00]。此函数适用于版本 6 的设备。较旧固件可能返回 InvalidFunctionId。

字节字段备注
0 bit 0reset_all_cid_report_settings1 允许 fn 5。Options+ 2.8。
0 bits 1–7—未知位。OpenLogi 忽略。
1–15—OpenLogi 不解析字段。

reset_all_cid_report_settings(fn 5)

请求:[0x00, 0x00, 0x00]。仅当 fn 4 报告支持时调用它。它重置每个控件的分流 和重映射状态。OpenLogi 返回 (),且不解析响应体。

事件

仅当 software ID 为 0 时,OpenLogi 才接受 unsolicited 消息。OpenLogi 不建模 下表中的未识别字节。

DivertedButtons(event fn 0)

字节字段备注
0–1slot 0BE ControlId;0x0000 表示此 slot 没有控件。
2–3slot 1BE ControlId。
4–5slot 2BE ControlId。
6–7slot 3BE ControlId。
8–15—没有已知字段。OpenLogi 忽略这些字节。

DivertedRawMouseXy(event fn 1)

字节字段备注
0–1dxBE i16 水平增量。
2–3dyBE i16 垂直增量。
4–15—没有已知字段。OpenLogi 忽略这些字节。

AnalyticsKeyEvents(event fn 2)

事件在字节 0–14 中包含五条 3 字节条目。

偏移量字段备注
0–1cidBE ControlId。
2event设备定义的事件代码。

字节 15 没有已知字段。OpenLogi 忽略此字节。

DivertedRawWheel(event fn 4)

字节字段备注
0 bits 7–5—未找到公开含义。OpenLogi 忽略这些位。Options+ 2.8。
0 bit 4resolution0 = Low;1 = High。Options+ 2.8。
0 bits 3–0periodsU4 周期计数。Options+ 2.8。
1–2delta_verticalBE i16 垂直增量。Options+ 2.8。
3–15—没有已知字段。OpenLogi 忽略这些字节。

OpenLogi 的用法

OpenLogi 使用 0x1b04 捕获鼠标控件和切换键盘主机。它在 arm 控件前枚举控件。 它要求对应的 CidFlags,例如 DIVERTABLE、RAW_XY 或 RAW_WHEEL。

每次捕获写入前,OpenLogi 读取并记录 CidReporting。它只写入会话拥有的上报 字段。它将读取到的重映射目标带入变更,因此不会清除已有重映射。

OpenLogi 会在重连后重新 arm 已捕获的控件。它在正常停止时恢复控件,并在 arm 失败后回滚控件。恢复失败会成为待处理的恢复操作,并在当前设备通道上重试。

自 v0.8.15 起,滚轮按住绑定仅会为带 RAW_WHEEL 的控件启用 raw_wheel。它会 在停止、重连失败和 arm 失败时清除该位。它不会恢复已有的 raw_wheel: true 状态。 没有该标志的控件仍是普通分流点击。

原始滚轮报告不包含源 CID。OpenLogi 将报告归属到最早按下的滚轮按住控件。 如果没有按住控件,或者高分辨率倍数无法缩放,OpenLogi 会丢弃该报告。

主机切换会话处理 DivertedButtons 和 AnalyticsKeyEvents。它不会将原始 XY 或 原始滚轮事件视为主机切换。OpenLogi 不调用全局 fn 5 重置,因为该重置可能清除 会话不拥有的设置。

未确认的细节

Logi Options+ 2.8 将带非零 software ID 的未匹配 fn 3 响应作为已分流按键状态 变化处理。OpenLogi 会从事件路径中过滤非零 software ID。因此,它不会发布这类 迟到或外来响应。

静态证据无法显示该响应在硬件上的出现频率。OpenLogi 仍向调用者返回正常匹配的 fn 3 响应,类型为 CidReportingChangeEcho。触发条件和频率需要设备 trace。

Rust 用法

use hidpp::{
    device::Device,
    feature::{
        EmittingFeature,
        reprog_controls::{CidReportingChange, ReprogControlsFeature},
    },
    protocol::v20::Hidpp20Error,
};

async fn divert_first_control(mut device: Device) -> Result<(), Hidpp20Error> {
    device.enumerate_features().await?;
    let Some(feature) = device.get_feature::<ReprogControlsFeature>() else {
        return Ok(());
    };

    for index in 0..feature.get_count().await? {
        let info = feature.get_cid_info(index).await?;
        if !info.flags.is_divertable() {
            continue;
        }

        let before = feature.get_cid_reporting(info.cid).await?;
        let _events = feature.listen();
        feature
            .set_cid_reporting(
                info.cid,
                CidReportingChange {
                    diverted: Some(true),
                    ..Default::default()
                },
            )
            .await?;

        // Restore the reporting bit this example changed before returning.
        feature
            .set_cid_reporting(
                info.cid,
                CidReportingChange {
                    diverted: Some(before.diverted),
                    ..Default::default()
                },
            )
            .await?;
        break;
    }
    Ok(())
}

本页目录