0x40a0 · fnInversion
旧版全局 Fn 键翻转——读取或写入当前状态,但不包含默认状态或主机槽位字段。
0x40a0 是最早的 Fn 键翻转 feature。它控制报告这个 feature 的键盘的 F 行按键默认发送 F1–F12,还是执行印在键帽上的媒体和快捷功能。它只含一个全局状态,没有默认状态字段和主机选择器。
**规格:**没有公开的 Logitech 规格。布局从 Logi Options+ 2.8 静态分析逆向得到。**交叉核对:**Solaar。用于:键盘。
函数参考
FnInversionFeature 从 feature version 0 开始实现 feature 0x40a0。
方法
| 函数 | HID++ fn | 签名 | 返回值 |
|---|---|---|---|
get_global_fn_inversion | 0 | () | FnInversionState |
set_global_fn_inversion | 1 | (state: FnInversionState) | () |
两个方法都是 async,并返回 Result<…, Hidpp20Error>。
类型
FnInversionState
这个不可穷举的状态枚举定义了以下值:
| 变体 | 值 | 说明 |
|---|---|---|
Off | 0 | F 行按键默认发送 F1–F12。 |
On | 1 | F 行按键默认执行印在键帽上的媒体或快捷功能。 |
事件
包装器没有为 0x40a0 提供类型化事件或广播识别辅助方法。
线格式
所有请求有效载荷都有 3 个字节。这个 feature 没有多字节字段。
get_global_fn_inversion(fn 0)
请求有效载荷:[0x00, 0x00, 0x00]。
| 字节 | 位 | 字段 | 备注 |
|---|---|---|---|
| 0 | 0–3 | state | 0 = Off;1 = On。Options+ 2.8 |
| 0 | 4–7 | / | 现有证据没有定义这些位。OpenLogi 忽略它们。 |
| 1–15 | / | / | 现有证据没有定义字段。OpenLogi 忽略这些字节。 |
OpenLogi 接受这个 getter 的任意 HID++ 响应长度。它使用 0x0f 掩码读取字节 0,并拒绝结果不是 0 或 1 的值。
set_global_fn_inversion(fn 1)
| 字节 | 值 | 备注 |
|---|---|---|
| 0 | u8::from(state) | 0 = Off;1 = On。Options+ 2.8 |
| 1–2 | 0x00 | OpenLogi 写入固定的零填充。 |
响应是确认消息。OpenLogi 不解码这个函数响应中的字段。调用方如需存储后的状态,必须再次读取。
OpenLogi 的用法
设备报告 0x40a0、0x40a2 或 0x40a3 时,OpenLogi 会声明 Fn 锁能力。它依次打开 0x40a3、0x40a2 和 0x40a0。它只会在较新 feature 不受支持时回退。
设备层把 fn_lock = true 映射为翻转 Off。此时 F 行按键默认发送 F1–F12。它把 fn_lock = false 映射为翻转 On,此时使用印在键帽上的功能。请求包含完整状态值,因此 OpenLogi 不使用读-改-写。
旧版 setter 不返回状态。OpenLogi 会在每次旧版写入后读取状态,并拒绝不匹配的结果。从 v0.8.14 开始,PR #1792 支持这个回退,并把 default_fn_lock 报告为 None。
OpenLogi 没有旧版状态变更广播路径。它会在重连后重放已配置的 fn_lock 值,而不会在会话结束时恢复先前的值。
未确认的细节
- 硬件抓包尚未验证字节 0 的高半字节、其余响应字节和 setter 确认消息。Options+ 2.8 会掩码读取低半字节。OpenLogi 忽略高半字节,并拒绝未知的低半字节值。
- 现有证据没有定义
0x40a0的默认状态或设备端状态变更广播。OpenLogi 不为这个变体提供默认状态,也不返回事件。
Rust 用法
use hidpp::{
device::Device,
feature::fn_inversion::{FnInversionFeature, FnInversionState},
};
async fn inspect(device: &mut Device) -> Result<(), hidpp::protocol::v20::Hidpp20Error> {
let _ = device.enumerate_features().await?;
let Some(feature) = device.get_feature::<FnInversionFeature>() else {
return Ok(());
};
let state = feature.get_global_fn_inversion().await?;
println!("current inversion: {state:?}");
feature
.set_global_fn_inversion(FnInversionState::Off)
.await?;
Ok(())
}