一些试图改进 MacBook 在 Windows 上的触摸板体验的尝试(续)
imbushuo
Please mind the gap
给 Apple Magic Trackpad 2 写的 PTP 驱动基本上成型了。
https://www.zhihu.com/video/888766510372364288
这篇文章是 一些试图改进 MacBook 在 Windows 上的触摸板体验的尝试(更新:MT2 的做好了)的续集。相关代码可在 imbushuo/mac-precision-touchpad 找到。代码写的很乱,还需要好好整整。
Windows DDK 的坑
不知道为什么,32bit Debuggee 上 Visual Studio 调试器集成起不来。只好在不得已的情况下用 Windbg 来调 UMDF 了(去设置没有 User-mode Debugger 时进入 KD 的 Flag)。另外能用 trace 就用 trace,而不是依赖调试。
Windows Precision Touchpad Collection
其实微软的文档已经比较明确:Protocol Implementation,里面定义了各种需要实现的内容。从 Windows 10 开始,鼠标的 HID Collection 是不需要的,为了偷懒,我就没有实现。但是我依旧实现了 Input Configuration Collection (后文会提到为什么)。
PTP Collection 里的 PTPHQA Report 认证散列可以是任意内容,可以是官方提供的那个 256 Bytes 的 Blob,全部填 0 也没什么问题。事实上,官方已经忙不过来了。Windows 10 不会读这个内容,Windows 8.1 在安装了 Win32k.sys update in Windows: October 2015 后也不会检查里面的内容。但是 Windows 8.1 要求实现鼠标的 HID Collection,如果你做设备或者驱动时需要注意这一点。
官方文档规定支持的两种设备总线是 USB 和 I2C,使用 HID 协议通讯。但是实际上只要你实现了额外的 HID minidriver 驱动,就可以支持其他总线连接的触摸板。在这个例子中,因为 Apple 使用自己的 HID 报告结构,并不是 Windows PTP Collection,所以我就需要使用自己写的 HID minidriver 驱动来转换报告。
PTP 使用 X 和 Y Usage 的 Physical Maximum 来报告设备的实际尺寸(记得带上单位和 Exponent,妈耶不会中文了),使用 Logical Maximum 来报告设备可以取到的坐标最大值。Minimum 可以不写。
另外记得写 HID Report Descriptor 要 Byte 对齐(
KMDF or UMDF
这个无所谓。KMDF 的签名麻烦一点(UMDF 不需要 EV,任意代码签名就可以,甚至是自签,让用户信任一下)。注意如果需要使用 UMDF 做 HID miniport 驱动并与 USB 设备通讯的话,你不能使用 WinUSB,否则设备不能工作。正确的姿势是升级到 UMDF 2.15,使用 NativeUSB(由 WUDF 反射弧自己处理)。相关的 INF 片段如下:
; 删掉关于 WinUSB 的引用内容
[MagicTrackpad2PtpDevice\_Install.NT]
CopyFiles=UMDriverCopy
...
; WUDFRd 作为 Filter DO 使用
[MagicTrackpad2PtpDevice\_Install.NT.Services]
AddService=mshidumdf, 0x000001fa, MSHIDUMDF\_ServiceInstall ; flag 0x2 sets this as the service for the device
AddService=WUDFRd,0x000001f8,WUDFRD\_ServiceInstall ; this service is installed because its a filter.
....
; 使用 NativeUSB
[MagicTrackpad2PtpDevice\_Install.NT.Wdf]
UmdfDispatcher=NativeUSB
...
; 记得加注册表加载 WUDFRd 作为 Filter DO
[MagicTrackpad2PtpDevice\_AddReg]
; By default, USBDevice class uses iProduct descriptor to name the device in
; Device Manager on Windows 8 and higher.
; Uncomment for this device to use %DeviceName% on Windows 8 and higher:
HKR,,FriendlyName,,%DeviceName%
HKR,,"LowerFilters",0x00010008,"WUDFRd" ; FLG\_ADDREG\_TYPE\_MULTI\_SZ | FLG\_ADDREG\_APPEND
然后把自己的驱动注册成 Filter DO,然后正常做各种 Routine,处理 IOCTL。相关的 IOCTL 可以在这里查到:WDF HID Minidriver IOCTLs。UMDF HID Minidriver 需要使用一些特定的 IOCTL,比如用 IOCTL_UMDF_HID_GET_FEATURE 代替 IOCTL_HID_GET_FEATURE。然后弄个生产者-消费者模型的 Queue ,在设备来中断时取报告,Fulfill,完成,就可以开始使用了。
Apple "Wellspring" Touchpad
当前在 AppleMac 系列产品上使用的 Touchpad,在开源社区有一个代号叫"Wellspring"(虽然我不知道官方是不是这样)。相关的驱动可以在 Linux 代码树的 https://github.com/torvalds/linux/blob/master/drivers/input/mouse/bcm5974.c 找到。这种触摸板会暴露至少三个 HID Collection,一个标准鼠标,一个触摸板(水果自己的协议),以及一个水果自己定义的专用 Collection。
如果在连接入设备后不写任何 Feature Report,则工作在鼠标模式下;如果写入了 Feature Report 并带入特定的 Bit,则进入触摸板模式。相关代码可以在我的驱动和上面的 bcm5974.c 里找到。Windows Precision Touchpad 里也有类似的东西,所以我的驱动在收到要求进入 PTP 模式的 Feature Report 后,给设备写 Bit 来进入这个模式(我用的裸写 WDF USB 实现)。
坐标系
Windows Precision Touchpad 以左上角为原点,而水果的触摸板以中央为原点。在报告内容时,需要注意进行坐标转换。
怎么在 Apple 的触摸板上判断 Tip Switch 位(手指放下/手指离开)? Force Touch 的压力数据有没有用处?
多个接触点的情况下,压力数据很不可靠,因此 Force Touch 数据在一根手指时意义更大。多根手指时,压力数据只能判断手指是接上来了还是没有,除非你很用力去按。对于 Confidence 位,建议判断接触点面积。另外数据一定要做 Defuzz,不然会死得很难看……
未完待续的问题
这个列表里的问题还在处理中。未来可能会有更新
- Report Time 怎么处理?