WARNING这篇文章没有任何实操教程,纯粹是我的个人研究记录
CAUTION实用派用户请关闭本文,在我看来研究和折腾的乐趣比做出这个产品更重要
前言
首先我是一个很多年的 Hackintosh 用户 (马上就不是了)
众所周知,macOS 对触控板的优化非常好,甚至好过鼠标
@Apple 什么时候改一下你那个反人类的鼠标滚轮方向
而且鼠标还有一个问题:它必须工作在一个平整的平面上,还要给鼠标移动和手腕留出空间,非常的不适合冬天在被窝里玩电脑 。
我想到了苹果的 Magic TrackPad,然后一看价格,告辞
不过呢也不是完全没有希望,因为我发现 Macbook 的拆机触控板模块极其便宜,大概十几块钱一个,用的是 USB 和 SPI 协议。于是我想到一个思路是:通过一个单片机,将触控板的 SPI 报文实时翻译为 HID 报文传递给 Host。
在此不得不感谢 Apple 的设计理念,给一块触控板加入了极其逆天的硬件配置,但是又在系统里处处限制
(这就不得不提新款 Macbook 拿角度传感器检测屏幕开合的设计了)
选型
我准备用 Macbook 2017 15寸的原装拆机触控板为基础进行改造,原因如下:
- 这块触控板的面积是真的大,差不多
- Macbook 2017 是最后一代没有 T2 芯片的 Macbook Pro,系统是直接和触控板交互的,而不需要去跟 T2 芯片掰扯一堆加密协议
- 它的硬件配置极其逆天:四个高精度压力传感器,一组 Tapic Engine,大面积玻璃触控面
- 它只要 15 块钱还包邮
CAUTION不要试图研究 2018 年后的触控板,T2 芯片的水很深的。Apple Silicon 系列的 MacBook 更是想都别想,苹果真的往死里加密的。
研究方向
基于其硬件功能,我提出三个研究方向
- 将触控板模拟为 Magic TrackPad,并在 macOS(原生驱动)和 Windows(使用PTP驱动)中完美工作
- 将触控板模拟为标准 HID 协议的数位板,低成本实现压感和倾斜感应,甚至还能做出绘画时的力度反馈
什么?你说一块触控板面积太小不适合画画,那我们就多来几块组阵列(这点是我在做白日梦,忽略就好)
目前难点
总体
- Apple 是不会告诉我任何协议内容的
- 触控板模块用的是不常见的 电平,需要加转换芯片
- Tapic Engine 瞬时启动电流较大,可能干扰 MCU 运行
- 我真的很菜
数位板模式
- 不会有人拿手指画画的,所以需要配无源电容笔
- 手指和电容笔是完全不同的力学模型,触控板自己算出来的压力和倾极大概率是不准的
- 面积太小
- 误触
优势
- 15 块钱的东西你要什么自行车,觉得不准右转 Apple Pencil
- 数位板只认专用的数位笔,这玩意可是能认手指的
- 原生压力感应+倾斜感应
- 能做出绘画时的力反馈
协议研究
得益于 Linux 内核已经完整支持了 Macbook 系列的内建触控板,我们很容易从 Linux 源码树中得到其 SPI 报文格式
drivers/input/keyboard/applespi.c:
/** * struct tp_finger - single trackpad finger structure, le16-aligned * * @origin: zero when switching track finger * @abs_x: absolute x coordinate * @abs_y: absolute y coordinate * @rel_x: relative x coordinate * @rel_y: relative y coordinate * @tool_major: tool area, major axis * @tool_minor: tool area, minor axis * @orientation: 16384 when point, else 15 bit angle * @touch_major: touch area, major axis * @touch_minor: touch area, minor axis * @unused: zeros * @pressure: pressure on forcetouch touchpad * @multi: one finger: varies, more fingers: constant * @crc16: on last finger: crc over the whole message struct * (i.e. message header + this struct) minus the last * @crc16 field; unknown on all other fingers. */struct tp_finger { __le16 origin; __le16 abs_x; __le16 abs_y; __le16 rel_x; __le16 rel_y; __le16 tool_major; __le16 tool_minor; __le16 orientation; __le16 touch_major; __le16 touch_minor; __le16 unused[2]; __le16 pressure; __le16 multi; __le16 crc16;};
/** * struct touchpad_protocol - touchpad message. * message.type = 0x0210 * * @unknown1: unknown * @clicked: 1 if a button-click was detected, 0 otherwise * @unknown2: unknown * @number_of_fingers: the number of fingers being reported in @fingers * @clicked2: same as @clicked * @unknown3: unknown * @fingers: the data for each finger */struct touchpad_protocol { u8 unknown1[1]; u8 clicked; u8 unknown2[28]; u8 number_of_fingers; u8 clicked2; u8 unknown3[16]; struct tp_finger fingers[];};代码告诉我们,触控板会直接返回按压力度,手指倾斜角度等信息
注意到了吗,struct tp_finger中pressure的数据类型是__le16
也就是手指的压力等级是 16 位无符号整数,意味着压力的取值范围是
而主流的 Wacom 数位板也才 8192 级压感!(当然,这只是理论精度,实际上一定是有不可忽略的误差,但只要做好滤波,精度不会比 Wacom 差多少)
更重要的是,触控板内部为我们解决了手指角度问题@orientation: 16384 when point, else 15 bit angle,我们甚至不需要自己实现算法
硬件设计
略微分析了一下 A1707 的原理图,画了一张驱动板,用 ESP32-S3 做 MCU 来翻译数据包和包装 HID 报文
正在等年后嘉立创发货…
开什么玩笑,第一次正儿八经画板子就要我画这么难吗
To be continued
这其实是我一个不成熟的前期想法,这个项目可能会在我大学四年中慢慢研究,也可能成为一个废案,不要抱太大希望,万一是 ADHD 的三分钟热度呢。
但研究的过程总是很有趣的,于是我选择记录下来。