AJAZZ AK35i V3 Max 是一把三模机械键盘,带一块 240×135 的屏幕,官方控制程序只有 Windows 版。这个项目把它的功能移植到 macOS,做成原生应用 AK35i Control Center 和命令行工具 ak35i,覆盖灯效、单键颜色、系统设置、改键、宏、屏幕时钟、屏幕图片、电量,以及驱动原版的实时灯效和音乐律动。
整个过程没有 Windows 电脑,也就没有 USB 抓包。协议全部来自对驱动和键盘固件的静态分析,再在 Mac 上靠键盘的应答和实际效果逐项验证。
分析对象
驱动取自 AJAZZ 官网驱动索引里与型号同名的条目 AJAZZ_AK35I MAX V3_Tripe mode RGB with screen_keyboard driver_V1.0.0.zip,下载后先记 SHA-256。归档里是一个 Inno Setup 6.1.0 安装器,用一次性 Alpine 容器里的 innoextract 只读解包,得到 145 个文件。驱动本身从未运行过。
逆向用到的文件如下。
| 文件 | 作用 |
|---|---|
DeviceDriver.exe |
控制程序,32 位 x86 MFC,所有构包和发包逻辑都在这里 |
mui.dll |
界面库,实时灯效动画和 RGB565 转换在这里 |
config.xml |
设备表,USB 为 VID_0C45&PID_8009&MI_00,2.4G 接收器为 0C45:FDFD |
rgb-keyboard.xml |
104 键布局(键码、灯号、行列),发包间隔 cmd_delaytime 35 ms,亮度和速度上限 5,GIF 帧数上限 141 |
| 语言文件 | 界面字符串 ID,用来把控件和处理函数对上 |
| 两个固件升级程序 | 资源里带 256 KB 的主控固件镜像(ARM Cortex-M,SN32F290),只做只读反汇编 |
驱动把配置存在本地 SQLite 里,有 t_light_data、t_key_macro_data、t_macro_data 等十几张表。键盘的改键、宏和屏幕都读不回来,驱动界面上显示的改键和宏完全来自本地数据库。这些建表语句后来用来核对结构体偏移。
方法
静态分析
入口是 HID 调用。DeviceDriver.exe 导入 SetupAPI 和 DeviceIoControl,并动态解析 HidD_SetFeature、HidD_GetFeature。有线下所有设置都经过唯一一处 HidD_SetFeature 包装(0x452010),上一层是单包发送函数 0x44faa0 和实时帧发送函数 0x44fc90。从这几个函数的调用方往上追,借语言 ID 和控件 ID 把每个界面功能对到一个构包函数,再按指令读出每个字节的来源。
结构体字段靠数据库定位。例如灯效构包函数 0x42b400 之前,0x4084e0 执行 SELECT * FROM t_light_data WHERE profile = ? AND mode = ? 填结构体,对照建表列序就能确定 +0x10 是亮度、+0x14 是速度、+0x24 是颜色。
分析分了三轮。
- grok CLI 通过 REA 调 Hopper 6.6 反编译,产出功能拆分初稿。
- Claude 按指令复核传输封装、灯效、音乐律动和时钟。Hopper 的伪代码会把逐字节写入折叠起来,字段偏移一律以指令为准。
- 换用 llvm-objdump,Claude 开两个子代理分头追系统配置、改键、宏、屏幕和实时帧,主会话按地址抽查。
初稿的骨架是对的,但有几处照抄就会发错报文,都在复核时改掉了。
- 改键和宏被合成一条命令。改键是
04 11和04 27,宏是04 19加04 15,格式完全不同。 0x418590被当成屏幕帧提交,它是改键发送函数。0x4346a0被当成用户灯效,它是侧灯模式,本机布局sidelight="0",走不到。驱动里的“用户灯光”就是单键颜色04 23。- 音乐律动被写成不发 HID,有线下它每帧都发一个
04 20。 - 更早的记录把
DeviceIoControl(0xB0192)写成读报告描述符,它是IOCTL_HID_GET_FEATURE,驱动用它读回写入后的应答。
固件镜像套上 ELF 头后用 llvm-objdump 按 Thumb 反汇编。USB 命令阶段的分发在 0x5012,数据阶段在 0x515C,无线命令在 0x67C8。固件分析有两个用处,一是确认写入命令落在哪块闪存,屏幕上传前必须知道这一点,二是和驱动的 2.4G 分支互相印证。驱动包里的固件是 V1.17,实机后来查出是 V1.30,只靠固件得出的结论都要上实机复核。
验证路线
原计划是在 Windows 上用 USBPcap 抓包,逐条对照静态结果。没有 Windows 电脑,改成下面的流程。
- 按驱动逐字节还原报文,先写成测试。
- 在 Mac 上发送,按驱动的方式读回应答。
- 观察效果。灯效和屏幕目测;按键类设置用一次性的只读 IOKit 输入监听,记录键盘实际发出的 HID 用法;能读回的读回核对。
- 拔插数据线、切换连接档位,确认是否持久化。
试验顺序按可恢复性排。基础灯效最先,写错了能用键盘自带的 Fn+\|、Fn+↑/↓、Fn+-/= 恢复。改键、宏、屏幕读不回来,先找好恢复路径再试。改键写回两层全默认就能恢复,驱动的“重置键盘”发的就是这个;宏的恢复是上传空宏表;屏幕则先分析固件,确认上传不会覆盖出厂开机动画。
几条边界始终不变。只发驱动里还原出的序列,不穷举未知命令。不实现固件升级、DFU 和恢复出厂。每次写入都要在界面上确认,命令行要加 --apply。整个项目只破过一次例,见蓝牙一节。
有线传输层
接口
0C45:8009 有两个厂商接口。
| 接口 | 用途页 / 用途 | 报告 | 承载 |
|---|---|---|---|
| 3 | 0xFF13 / 0x01 |
Feature 64 字节 | 所有命令和设置数据 |
| 2 | 0xFF68 / 0x61 |
Output 4096 字节,Input 64 字节 | 屏幕图像 |
报文、会话和应答
驱动的 Feature 缓冲固定 65 字节,第 0 字节是报告 ID 0,后 64 字节是载荷。命令包载荷以 04 <命令号> 开头。一次设置是一个会话,通常是下面的形状,每包前等 35 ms。
04 18 开始,要求应答
04 <命令> 前导包,载荷偏移 8 = 后续数据包个数,要求应答
<数据包> × N 每包 64 字节,不读应答
04 02 提交,要求应答,设置在这一步持久化
04 F0 结束,部分功能没有
要求应答的包写完后再等 35 ms,用 IOCTL_HID_GET_FEATURE 读回。驱动以载荷偏移 3 为 0x01 算成功,但调用方从不检查这个结果,失败了照样往下发。
这条规则在 macOS 上先用已经验证过的时钟序列校准,避免和未验证的灯效报文混在一起。读回结果是命令包的应答为命令字原样回显、偏移 3 为 0x01;数据包的应答是整包回显,偏移 3 是数据本身。最终判定条件是前两字节等于命令字且偏移 3 为 0x01,只用于命令包。
macOS 实现
不需要内核扩展,用户态 IOKit 就够了。
- 用
IOHIDManager按 VID、PID、主用途页和主用途匹配接口。匹配结果不是恰好一个就停止,不猜。 IOHIDDeviceSetReport的报告 ID 是单独参数,缓冲里要去掉驱动那个前导 0,只传 64 字节。IOHIDDeviceGetReport读回的 64 字节同样不含报告 ID,偏移和驱动的载荷偏移一致。- 错误处理比驱动严。
04 18没有应答,一个设置字节都不发;之后某包没有应答,按驱动顺序发完收尾包再报错,避免把键盘留在半截会话里。
// 驱动的 65 字节缓冲去掉报告 ID,剩下 64 字节交给 IOKit
let payload = Array(report.dropFirst())
IOHIDDeviceSetReport(device, kIOHIDReportTypeFeature, 0, payload, payload.count)
// 应答判定,只用于 04 xx 命令包
let acked = response[0] == payload[0] && response[1] == payload[1] && response[3] == 0x01
各功能的协议
| 功能 | 命令 | 驱动函数 | 数据 | 读回 |
|---|---|---|---|---|
| 屏幕时钟 | 04 28 |
0x423ac0 |
1 包 | 无 |
| 基础灯效 | 04 13 |
0x42b400 |
1 包 | 无 |
| 单键颜色 | 04 23,读 04 F5 |
0x44c5f0、0x42b1e0 |
576 字节,9 包 | 有 |
| 系统设置 | 04 17 |
0x413ff0 |
1 包 | 无 |
| 改键 | 04 11 普通层,04 27 Fn 层 |
0x418590 |
576 字节,9 包 | 无 |
| 宏 | 04 19 后接 04 15 |
0x42db70 |
N 包 | 无 |
| 屏幕 | 04 72 |
0x422b00 |
4096 字节 Output 报告 | 无 |
| 实时帧 | 04 20 |
0x428110、0x432e70 |
512 字节,8 包 | 不保存 |
基础灯效 04 13
数据帧前 16 字节有效。
| 偏移 | 内容 |
|---|---|
| 0 | 模式号 0~19 |
| 1~3 | R、G、B |
| 8 | 多彩 |
| 9 | 亮度 0~5 |
| 10 | 速度 0~5 |
| 11 | 方向 |
| 14~15 | AA 55 |
模式表来自驱动首次运行时写库的默认行(0x42b6b0),每个模式带一个 config_func 位掩码,决定界面显示亮度、速度、方向、颜色中的哪些控件。程序只允许驱动界面能发出的取值组合,比如方向值只有带对应位的模式才会变。
验证时发模式 1(静态恒亮)、颜色 00 FF 00、亮度 5、速度 3,三个应答都通过,全键变绿,拔插和切档后保持。之后实测确认亮度 0 为熄灭,速度 0 最慢、5 最快,方向 0 和 1 互为反向。
单键颜色 04 23 和 04 F5
576 字节的块里,每个灯在偏移 4×灯号处占 4 字节 [灯号, R, G, B],没设颜色的槽位全 0,偏移 574~575 为 AA 55。写入前驱动先用一次 04 13 把灯效切到自定义模式 0x80,再走 04 18、04 23(偏移 8 = 9)、9 个数据包、04 02、04 F0 的会话。
04 F5 读回 9 块 64 字节,格式相同。动画模式下连读三次,结果各不相同,非零区域跟着动画移动,说明它读的是键盘此刻点亮的颜色。只有在模式 0x80 下,读回值才等于保存的颜色。读回还会丢精度,写 FF 读回 FC,每通道约 6 位。
命令行据此实现成先切到 0x80,连读两次,不一致就停止,一致再把请求合并进去写入,写完再读一遍,按每通道亮或灭核对。界面上的单键编辑器则按画面所见整块写入,不和键盘里存的合并,避免写进用户看不到的颜色。
系统设置 04 17
会话是 04 18、04 17(偏移 2 = 1,偏移 8 = 1)、数据帧、04 02,没有 04 F0。
| 偏移 | 内容 |
|---|---|
| 0~1 | 00 01,固定 |
| 2 | 禁用 Alt+Tab |
| 3 | 禁用 Alt+F4 |
| 4 | 禁用 Win 键 |
| 5 | Fn 开关 |
| 6 | 休眠,0 不休眠,1/2/3 为 1、5、30 分钟 |
| 8 | 响应时间档位 1~5 |
| 62~63 | AA 55 |
键盘没有读回命令,每次写全部六项,不带参数时写驱动首次运行的默认值。
效果用按键监听验证。键盘背面有 Win/Mac 拨动开关,Mac 档下 Win 键和左 Alt 分别发 Option 和 Command,三个禁用开关只在 Win 档下生效。禁用 Alt+F4、Alt+Tab 都有效,写回 0 就恢复。禁用 Win 单独置 1 时 Win 键照常发出,要和偏移 3 同时为 1 才拦截,复现两次。Windows 驱动只勾这一项时发出的字节相同,所以这是固件行为,程序只给提示,不擅自改别的位。休眠、响应时间和 Fn 开关没观察到可判断的效果,仍标为未验证。
判断按键效果要以 HID 记录为准。拿 Spotlight 是否弹出判断 Win 键、拿大写灯判断 CapsLock 改键都出过错,前者受拨动开关和输入法快捷键干扰,后者是因为 macOS 会忽略短于约 0.55 秒的 CapsLock 点按。
改键 04 11 和 04 27
每次发送整层 576 字节,会话同单键颜色。每键 4 字节记录在偏移 4×key_index,本机 104 键的 key_index 和灯号完全相同。没有记录的键写全 0,即固件默认。
| 类型 | 记录 |
|---|---|
| 默认 | 00 00 00 00 |
| 禁用 | 05 03 00 00 |
| 按键或组合键 | 02 <修饰位> <HID 用法> 00,Ctrl 1、Shift 2、Alt 4、Win 8 |
| 宏 | 06 <宏序号> <播放方式> <次数> |
| 鼠标 | 01 01 <按键位> 00,滚轮 01 03 01 00 / 01 03 FF 00 |
| 多媒体 | 03 <Consumer 用法> 00 00 |
| 多键 | 07 <k1> <k2> <k3> |
打开程序、网址、发送文字三类记录是 05 02 <编号> 00,键盘只上报编号,动作由驱动在电脑上执行,没有移植。
验证结果是 CapsLock 改成 Esc 后从发 0x39 变为 0x29,拔插后保持;Fn 层 F1 改成静音后,Fn+F1 从 Consumer 0x183 变为 0xE2。两层写回全默认后都恢复。
宏 04 19 和 04 15
会话是 04 19、04 15(偏移 8 = 块数 N)、等 30 ms、N 个数据包、等 30 ms、04 02,没有 04 18 和 04 F0。缓冲 3584 字节,布局如下。
- 偏移 0~399 是 100 项索引,每项 4 字节,有内容时为数据块偏移(小端 16 位)加
00 00,空宏为FF FF FF FF。 - 数据块从
0x190开始,8 字节块头的前两字节是条目数,后接 4 字节条目。 - 按下
00 00 <HID> B0,松开00 00 <HID> 30,鼠标按下00 00 <键位> 90、松开10,延时<毫秒低> <毫秒高> 00 50,不足 10 ms 按 10 ms。 - 设数据结束偏移为 E,E 是 64 的倍数时 N = E/64 + 1,否则 N = E/64 + 2,偏移 N×64−2 写
AA 55。
播放方式和次数不在宏表里,在触发它的改键记录里。实测把宏 A 绑到 F12 播放一次、Shift+B 绑到 F11 重复三次,步间隔 20 ms,拔插后仍然有效;上传空宏表并复位改键后恢复原样。
屏幕 04 72
上传前先看固件。0x72 把写地址设到外置闪存 0x950000,之后每收到一个 4096 字节块就写一块、地址加 0x1000。上电播放的出厂开机动画在 0x340000。所以 04 72 写的是可上传的 GIF 页,碰不到出厂动画;USB 协议里也没有读外置闪存的命令,GIF 页原内容覆盖后无法恢复。
图像格式如下。
- 256 字节头,偏移 0 是帧数,偏移 1 起是每帧延时,单位 2 ms,其余填
FF。 - 每帧 240×135,逐行从上到下,RGB565 小端(取 R 高 5 位、G 高 6 位、B 高 5 位)。
- 整体用
FF补齐到 4096 的倍数,帧数上限 141。同方案的 Aula F108 Pro 有人传过 214 帧,141 帧以后覆盖了屏幕菜单图形且无法恢复。
发送顺序是 Feature 接口上的 04 18、04 72(偏移 2 = 槽位 1,偏移 8~9 = 块数),接着在屏幕接口上逐块写 Output 报告,每块键盘回一个 Input 报告 01 5A 02,最后在 Feature 接口发 04 02。
macOS 上 Output 报告同样用 IOHIDDeviceSetReport,类型换成 kIOHIDReportTypeOutput;应答用 IOHIDDeviceRegisterInputReportCallback 注册回调,写完一块后跑 RunLoop 等回复,超时 1 秒。图片用 ImageIO 解码,等比缩放到 240×135 居中,GIF 保留帧延时。
单帧测试图共 16 块,每块约 0.16 秒,方向和颜色顺序正确,拔插后开机动画照常播放。查看 GIF 页要按 Fn+PrtSc(说明书写法)。按 V1.17 固件的 Fn 表,Fn+R 在满足另外两个状态条件时也会切到这个页面,但在 V1.30 实机上按了没有反应。
实时帧 04 20
驱动的实时灯效和音乐律动都由电脑逐帧推送,键盘不保存。每帧是 04 20(偏移 8 = 8)、512 字节分 8 包、04 02,没有 04 18 和 04 F0。数据按顺序写 [灯号, R, G, B],104 键用 416 字节。停止推送,键盘立即回到原来保存的灯效。
时序照 0x44fc90,命令包前后各等 5 ms,读回偏移 3 为 0xFF 表示忙,重发一次;数据包间隔 2 ms;04 20 没有应答就跳过这一帧。普通设置用的 35 ms 间隔在这里不可用,一帧要发 10 包,帧率会低于 3 帧每秒。按驱动时序实测约 14 帧每秒。
2.4G 接收器
驱动在连接模式为 2 时改走另一套短包,固件在 0x67C8 处理。这部分由两个子代理分别追驱动和固件,结论独立得出后逐条比对,完全一致。
接收器在 Mac 上报的是 05AC:024F,产品名 “2.4G Dongle”,这是苹果铝键盘的 ID,和驱动配置里的 0C45:FDFD 不同。它的第 3 个接口用途页 0xFF60、用途 0x61,输入输出都是 32 字节、不带报告 ID,对应驱动写的 33 字节。选接口时先按用途页和用途匹配,再在代码里核对产品名或 VID:PID 和报告长度。只按产品名让 IOHIDManager 过滤没有生效,会把同样带 32 字节厂商接口的罗技接收器也匹配进来,第一次试验就因为出现两个候选接口而在发包前停下。
包格式是 p0 命令、p1 长度、p2 序号、p3~p30 数据(28 字节)、p31 为前面各字节之和。键盘回显 p0~p2 表示收到。没有 04 18 / 04 02 会话,每条命令立即生效。
| 功能 | 报文 |
|---|---|
| 在线探测 | 02 00,应答带固件信息块 |
| 电量 | 20 01,应答字节 3 为百分比 |
| 时钟 | 0C 10 00 + 有线时钟数据帧,整体后移 3 字节 |
| 基础灯效 | 05 10 00 + 有线 04 13 数据帧前 14 字节 + AA 55 |
| 系统设置 | 07 10 00 + 有线 04 17 数据帧前 14 字节 + AA 55 |
| 改键 | 21 包 10(普通层)或 12(Fn 层),每包 28 字节,内容同有线 576 字节块 |
| 宏 | 若干包 09,内容同有线宏表 |
| 单键颜色 | 先 05 10 00 80 … 切模式,再 21 包 14 |
| 音乐律动 | 每帧一包 0B,带前景、背景色号和柱高,驱动发 21 列,固件只读前 18 列 |
| 屏幕 | 7F 03 00 <槽位> <包数 24 位>,之后每包命令字 0x80 + (i >> 16),长度和序号字段放 i 的低两字节 |
设置类数据和有线完全同源,只是切成 28 字节一包,所以有线和 2.4G 共用同一套编码器。
风险集中在固件的写入方式。单包设置命令每条都擦写一个 1 KB 闪存页,不适合跟着滑块连续发。多包流式写入按基址加 28×序号写,到页首就擦,序号没有上限检查。宏表写到第 110 包会进入 Fn 层改键所在的 0xAC00,而驱动自己的宏长度上限比这个还宽。程序在发送前拒绝超过 3,024 字节的宏表,这个边界写进了测试。
发送器的规则是先发 02 00 探测,键盘不应答就一包不发;之后每包等回显,超时 1 秒,没有回显立即停止,不重发,以免同一数据写两次闪存。屏幕数据是唯一的例外。它写在外置闪存,同一包重发只会把同样的字节写到同一地址,跨扇区的包会先重新擦除,结果一致,所以允许最多重发 3 次。第一次 2.4G 上传在 4,639 包中的第 497 包丢了回显,按规则停止;放开重发后,单帧图片 2,325 包、62 秒传完,重发 0 次。
2.4G 下逐项实测了时钟、电量、灯效、系统设置、改键、宏、单键颜色、音乐柱状图和屏幕。键盘在 2.4G 下没有逐键任意颜色的实时帧,也不能读回颜色,这两项只能用数据线。
电量只有 2.4G 能读。驱动的电量函数在非 2.4G 模式下直接返回;固件的电量来自 I2C 电量计,USB 命令处理代码里没有读取它的地方。版本号也从这里拿,探测应答里的信息块按社区项目 dantje/ajazz-ak35i-v3-max 的格式解析为 0C45:8009、V1.30;有线下则直接读 USB 设备描述符里的 bcdDevice,同为 0x0130。
蓝牙
蓝牙下键盘是 0C45:FEFE,HID 报告描述符里没有厂商命令通道,固件在蓝牙模式下也直接丢弃厂商帧,所以设置功能无法经蓝牙使用。程序只用 CoreBluetooth 读标准电池服务(180F / 2A19)。判断键盘是否在蓝牙档,是在 IORegistry 里查 0C45:FEFE 的 HID 服务,不打开设备,因此不需要输入监控权限。
GATT 里还有一个厂商服务 FEE0,特征 FEE1 可读可写。经过确认,往 FEE1 写过一次 2.4G 探测包,写入被接受但没有任何回应。事后查明 FEE0 / FEE1 是沁恒 CH583 系列 BLE OTA 例程的服务和特征,同方案键盘的无线芯片是 CH582F,例程里 0x81 是擦除命令。FEE1 是蓝牙模块的固件升级通道,现在明确禁止写入。这是整个项目里唯一一次发出驱动中没有的数据,正确的顺序应该是先查资料再试。
移植驱动的算法
实时灯效
驱动的 8 种实时灯效在 mui.dll 的 CustomLightMode 里计算。移植方式是逐指令还原更新函数,查找表不手抄。17 张表共 1,730 字节,由脚本从 mui.dll 按地址逐字节导出到 DriverLightTables.swift,每张表注明原地址。
- 计时以 16 ms 为一拍,速度 s 时每 max(15−s, 1) 拍走一步。
- 每一步按驱动顺序调用全部效果的更新函数,与当前用哪个效果无关,各效果的内部状态都在推进。
- 每键输出颜色为 (颜色 × 亮度) >> 8。
驱动的随机取色每次都先 srand(0xE8) 再 rand(),MSVC 下恒为 796,实际取色序号只由一个 1~100 循环的计数器决定。序号能取到 106,而漫天飞舞的配色表只有 106 项,越界读到对齐填充和下一张表的首字节,结果是黑色。这些行为都按原样保留,测试用例直接从反汇编推出期望值。
音乐律动
驱动的音频管线是 WASAPI 环回采集,256 格环形缓冲,前半加 Hann 窗,实数 FFT,按频率加权,取 v = min(1, 0.5·log10(1.1m) + 0.9m),再做 17 点平滑,得到 256 个电平。键(行, 列)的采样点在 x = 11·列、y = 10·行 + 7,电平高于 (64 − y)/64 时显示前景色,否则显示背景色。11 种显示模式的配色和整数 HSV 算法也按地址读出。
Mac 上用 Core Audio 进程 tap 采集系统输出,CATapDescription 建全局立体声 tap,挂到一个私有聚合设备上读取,要求 macOS 14.2 以上并授予系统录音权限。没有用麦克风,它采到的是房间里的声音。
与驱动的差别有三处。输入是混成单声道的最近 512 帧;静音时柱子会落下,驱动是冻结;FFT 按标准实数布局计算,没有逐指令复刻驱动的浮点舍入。驱动默认振幅下样本被乘以 600,FFT 又不归一化,普通音量就会让全部频段饱和,这一点也照原样保留,靠振幅滑块调低。
2.4G 下改发柱高,同一套引擎算出 18 列高度放进 0B 包,由固件按调色板绘制。
工程结构
- Swift 6 + SwiftPM,单个可执行目标。同一个二进制从 Finder 启动时打开 SwiftUI 界面,带参数运行时是命令行工具。
- 和设备、媒体打交道的部分用 IOKit HID、CoreBluetooth、Core Audio 和 ImageIO,整个项目没有第三方依赖。
- 协议编码器都是纯函数,输入设置、输出字节。传输层藏在
FeatureReportDevice、WirelessExchanging这样的协议后面,等待时间也可注入,测试不需要真机。 - 改协议编码器前先写失败的测试。测试断言的字节来自反汇编,或来自实机验证过的序列,比如把全键变绿的那组灯效报文原样写成了测试。目前共 122 个测试。
- 发布包是 Intel 和 Apple Silicon 通用的 DMG,支持 macOS 13 以上,ad-hoc 签名,没有公证。
还没解决的问题
- 禁用 Win 键为什么要同时置 Alt+F4 位才生效。
- Fn+PrtSc 在固件里的出处,以及 Fn+R 在 V1.30 上为什么无效。
- 多帧 GIF 和帧延时没有上过真机。
- 休眠、响应时间、Fn 开关的效果,以及多彩纵横方向 2、3 的含义。
- 换成驱动原版音乐引擎之后的 2.4G 柱状图还没实测。
- 驱动的音乐律动在 Windows 上是否同样饱和,目前只是推断,没有 Windows 机器对照。
项目地址 Ike-li/ak35i-v3-max-macos-control-center。完整的逆向记录在 docs/STATIC_REVERSING.md,安全边界在 docs/SAFETY_MODEL.md。这是独立的社区项目,与 AJAZZ 没有隶属、授权或合作关系。