Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
59 changes: 53 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,10 +6,34 @@
[![macOS](https://img.shields.io/badge/macOS-Apple%20Silicon-black.svg)](#requirements)
[![Windows](https://img.shields.io/badge/Windows-11%20x64-0078D4.svg)](#requirements)

Turn a MacBook's built-in trackpad into a native Windows Precision Touchpad over a trusted wired
LAN. macOS captures raw contacts; Windows exposes them through KMDF and Virtual HID Framework (VHF),
so scrolling, pinch zoom, and system gestures are handled by the Windows touchpad stack rather than
mouse-event emulation.
## Why?

Many programmers already work with both hands:

- the right hand uses a mouse for precise pointing, selection, drawing, or CAD;
- the left hand scrolls documents, papers, browsers, and code, and performs pinch zoom.

Great standalone Windows touchpads are uncommon, but many desks already have a MacBook sitting next
to the Windows PC. Instead of buying another touchpad, this project turns the MacBook's built-in
trackpad into a native Windows Precision Touchpad.

```text
┌─────────────────────────────┐
│ Windows PC │
└─────────────────────────────┘

⌨ Keyboard

MacBook trackpad Mouse
left hand right hand
scroll / zoom precise operation
```

> **Don't buy another touchpad. Reuse the best one you already have.**

macOS captures raw contacts over a trusted wired LAN; Windows exposes them through KMDF and Virtual
HID Framework (VHF), so scrolling, pinch zoom, and system gestures are handled by the native Windows
touchpad stack rather than mouse-event emulation.

> **Experimental:** the end-to-end prototype moves the Windows pointer and supports native
> two-finger scrolling and pinch zoom. It currently requires a test-signed Windows driver and a
Expand Down Expand Up @@ -77,6 +101,9 @@ make
python3 tools/analyze_capture.py touches.jsonl
```

See the [complete macOS operation guide](docs/MAC_SETUP.md) and
[macOS development notes](docs/MAC_DEVELOPMENT.md).

### 2. Prepare Windows

Build and install the KMDF/VHF driver and receiver first. The current bring-up and restart procedure
Expand Down Expand Up @@ -104,8 +131,13 @@ nc -vz WINDOWS_IP 39871

Stop with `Ctrl-C`. On disconnect or a 200 ms active-contact timeout, Windows releases all contacts.

The agent does not intercept local macOS input. If desired, configure macOS to ignore the built-in
trackpad while an external mouse is present under Accessibility → Pointer Control.
The agent does not intercept local macOS input. To dedicate the built-in trackpad to Windows while
an external mouse controls the Mac, enable:

```text
System Settings → Accessibility → Pointer Control → Mouse & Trackpad
→ Ignore built-in trackpad when mouse or wireless trackpad is present
```

## Repository layout

Expand Down Expand Up @@ -152,6 +184,21 @@ ctest --test-dir out\windows -C Release --output-on-failure
Contributions should keep networking out of kernel mode, preserve complete-frame semantics, and add
tests for protocol or contact-lifecycle changes. See [CONTRIBUTING.md](CONTRIBUTING.md).

## Development process

This prototype was developed end to end through **vibe coding with GPT-5.6 Sol (Light)**, from the
macOS feasibility probe and MTP1 protocol to the Windows VHF driver and documentation. It used
approximately 50% of one weekly model allowance.

The work was completed in two main development sessions of roughly three hours each. When the
Windows driver showed the Device Manager yellow warning icon, a web high-reasoning mode briefly
joined the investigation to isolate the `VhfCreate` startup failure and its missing `vhf` lower
filter.

Physical-device actions, installation, risk decisions, and end-to-end acceptance tests were
performed by the project owner. AI-generated code was compiled and tested on the actual Mac and
Windows machines before being merged.

## Roadmap

- Validate three- and four-finger gestures with multiple MacBook generations
Expand Down
52 changes: 47 additions & 5 deletions README.zh-CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,33 @@
[![macOS](https://img.shields.io/badge/macOS-Apple%20Silicon-black.svg)](#环境要求)
[![Windows](https://img.shields.io/badge/Windows-11%20x64-0078D4.svg)](#环境要求)

通过可信的有线局域网,把 MacBook 内建触控板变成 Windows 原生精确式触控板。macOS
负责采集原始触点,Windows 通过 KMDF 和 Virtual HID Framework(VHF)将其呈现为触控板,
滚动、双指缩放和系统手势均由 Windows 触控板栈处理,而不是模拟鼠标事件。
## 为什么做这个项目?

很多程序员已经习惯双手分工:

- 右手使用鼠标,负责精确指向、选择、绘图或 CAD;
- 左手负责滚动论文、文档、浏览器和代码,并进行双指缩放。

Windows 上优秀的独立触控板并不多,但很多人的 Windows 主机旁边其实已经放着一台 MacBook。
与其再买一块触控板,不如直接把 MacBook 的内建触控板变成 Windows 原生精确式触控板。

```text
┌─────────────────────────────┐
│ Windows PC │
└─────────────────────────────┘

⌨ 键盘

MacBook 触控板 鼠标
左手 右手
滚动 / 缩放 精确操作
```

> **不用再买 Windows 触控板,把你已有的 MacBook 利用起来。**

macOS 通过可信的有线局域网发送原始触点;Windows 使用 KMDF 和 Virtual HID Framework
(VHF)将其呈现为原生触控板。滚动、双指缩放和系统手势由 Windows 触控板栈处理,而不是
模拟鼠标事件。

> **实验性项目:** 当前端到端原型已经能使用真实 Mac 输入移动 Windows 指针,并支持原生
> 双指滚动和双指缩放。现阶段仍需要 Windows 测试签名驱动和 macOS 私有框架,不适合无人值守
Expand Down Expand Up @@ -75,6 +99,9 @@ make
python3 tools/analyze_capture.py touches.jsonl
```

完整说明见 [macOS 安装与操作指南](docs/MAC_SETUP.zh-CN.md) 和
[macOS 端开发记录](docs/MAC_DEVELOPMENT.zh-CN.md)。

### 2. 准备 Windows

先构建并安装 KMDF/VHF 驱动和 Receiver。当前启动与重启流程见:
Expand All @@ -100,8 +127,12 @@ nc -vz WINDOWS_IP 39871

使用 `Ctrl-C` 停止。连接断开或活跃触点超过 200ms 没有更新时,Windows 会释放全部触点。

Agent 不拦截 macOS 本机输入。如果希望外接鼠标存在时禁用内建触控板,请使用 macOS 的
“辅助功能 → 指针控制”系统设置。
Agent 不拦截 macOS 本机输入。如果希望外接鼠标控制 Mac、内建触控板专门控制 Windows,请开启:

```text
系统设置 → 辅助功能 → 指针控制 → 鼠标与触控板
→ 有鼠标或无线触控板时忽略内建触控板
```

## 仓库结构

Expand Down Expand Up @@ -146,6 +177,17 @@ ctest --test-dir out\windows -C Release --output-on-failure
贡献代码时应保持网络逻辑位于用户态、保持完整帧语义,并为协议或触点生命周期变化增加测试。
详见 [CONTRIBUTING.md](CONTRIBUTING.md)。

## 开发方式

本原型从 macOS 可行性探针、MTP1 协议、Windows VHF 驱动到文档,**全程采用 GPT-5.6 Sol
(Light)进行 vibe coding**,大约使用了一个周额度的 50%。

主要开发分为两个时段,每次约三小时。Windows 驱动曾在设备管理器中出现黄色感叹号;排查
`VhfCreate` 启动失败和缺失的 `vhf` lower filter 时,短暂让网页端高思考模式介入协助定位。

真实设备操作、安装、风险决策和端到端验收由项目作者完成。AI 生成的代码在合并前均在实际
Mac 和 Windows 机器上完成编译与测试。

## 路线图

- 在更多 MacBook 机型上验证三指和四指手势
Expand Down
115 changes: 115 additions & 0 deletions docs/MAC_DEVELOPMENT.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
# macOS development notes

[简体中文](MAC_DEVELOPMENT.zh-CN.md)

The macOS implementation is intentionally small. Windows owns gesture recognition and the native
Precision Touchpad contract; the Mac has three responsibilities: capture raw contacts faithfully,
encode complete MTP1 frames, and deliver current state with safe reconnect behavior.

## 1. The original feasibility risk

The project depended on whether macOS could expose stable raw contacts rather than only high-level
scroll and gesture events. Public `NSTouch` can report normalized positions in an application event
path, but it was not assumed to provide the required global, background, and geometry behavior.

The feasibility probe therefore dynamically loads Apple's private:

```text
/System/Library/PrivateFrameworks/MultitouchSupport.framework
```

Required symbols are resolved with `dlopen`/`dlsym`, so the binary does not directly link against an
undocumented SDK interface. All inferred structures and function types are isolated in
`mac/Probe/MultitouchSupportABI.h`, including a compile-time size assertion for `MTTouch`.

## 2. What the probe established

Real capture testing established:

- one built-in device is discoverable on the tested Apple Silicon MacBook;
- five simultaneous contacts are available;
- contact IDs remain stable through a touch lifecycle;
- active hardware cadence has an 8 ms median interval, approximately 125 Hz;
- position, velocity, size, ellipse axes, angle, and density fields contain usable values;
- no invalid frames or duplicate IDs were observed in the recorded test sessions.

The probe writes JSON Lines to stdout and diagnostics to stderr. A private-framework hardware banner
initially polluted stdout; startup output is now redirected so capture files remain valid JSONL.

## 3. Why the Mac sends contacts, not gestures

Recognizing scroll, pinch, and multi-finger gestures on macOS would turn the project into remote
mouse emulation and lose native Windows settings. MTP1 therefore carries the complete current
contact set:

```text
identifier + state + flags + x/y + geometry + monotonic timestamp
```

Windows maps those contacts to HID slots and lets its Precision Touchpad stack recognize gestures.
This is why native two-finger scrolling and pinch zoom work without Mac-side gesture code.

## 4. Real-time and reconnect design

The private callback must not block on TCP. `mac-touch-agent` encodes on the callback path, places
bounded messages into a 256-frame queue, and performs socket writes on a sender thread with
`TCP_NODELAY`.

Every connection starts:

```text
HELLO(sequence=N)
RESET(sequence=N+1)
FRAME(sequence=N+2)
```

An early prototype reused sequence numbers for control messages. The strict Windows receiver
correctly rejected that stream after restart. Sequence allocation was fixed to advance for every
message. If the bounded queue overflows, the agent reconnects and starts a new `HELLO`/`RESET` epoch
instead of continuing with an invalid gap.

## 5. Coordinate orientation

The wire protocol preserves raw normalized Mac coordinates. Real end-to-end testing showed that the
Mac Y axis and Windows Precision Touchpad surface grow in opposite directions. The correction belongs
in the Windows mapping layer:

```text
hid_y = 1 - mac_y
```

Keeping this out of the wire format preserves raw sensor meaning and allows other receivers to make
their own coordinate choices.

## 6. Local macOS input policy

A CGEventTap-based suppression experiment was considered, but rejected:

- it requires Accessibility/Input Monitoring privileges;
- it cannot reliably distinguish the built-in trackpad from an external mouse;
- global interception creates unnecessary safety and usability risk.

The final design does not suppress macOS input. Users who dedicate the built-in trackpad to Windows
use macOS's own “Ignore built-in trackpad when mouse or wireless trackpad is present” setting.

## 7. Why there is relatively little Mac code

The implementation is small because responsibility is deliberately narrow:

- no gesture recognizer;
- no virtual device or kernel extension on macOS;
- no UI, pairing, installer, or background daemon yet;
- no direct USB device-mode path;
- shared protocol codec instead of a second serialization implementation.

The difficult work was validating the private sensor path and defining failure-safe boundaries, not
writing a large application. Keeping this side small reduces breakage when macOS private ABI changes.

## Remaining macOS work

- test additional Apple Silicon generations and macOS releases;
- package a signed menu-bar/background agent;
- add discovery, pairing, authentication, and encrypted transport;
- handle sleep/wake and interface changes;
- investigate a reduced-function public-API backend;
- add calibrated device metadata only after cross-model measurement.
108 changes: 108 additions & 0 deletions docs/MAC_DEVELOPMENT.zh-CN.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
# macOS 端开发记录

[English](MAC_DEVELOPMENT.md)

macOS 端代码有意保持精简。手势识别和原生精确式触控板协议由 Windows 负责;Mac 只有三个
职责:忠实采集原始触点、编码完整 MTP1 帧、在重连和异常情况下安全地传递当前状态。

## 1. 最初真正的技术风险

项目能否成立,取决于 macOS 能不能提供稳定的原始触点,而不只是滚动和手势事件。公开的
`NSTouch` 可以在应用事件路径中提供标准化坐标,但不能预先假定它满足全局、后台和完整几何
数据需求。

因此第一步探针动态加载 Apple 私有框架:

```text
/System/Library/PrivateFrameworks/MultitouchSupport.framework
```

程序通过 `dlopen`/`dlsym` 解析所需符号,不直接链接未公开的 SDK 接口。所有推断出的结构和
函数类型集中隔离在 `mac/Probe/MultitouchSupportABI.h`,并对 `MTTouch` 大小进行编译期断言。

## 2. 探针验证了什么

真实采集验证结果:

- 在测试的 Apple Silicon MacBook 上可以找到一个内建触控设备;
- 支持五指同时接触;
- Contact ID 在一次触点生命周期内保持稳定;
- 活动状态下中位帧间隔为 8ms,约 125Hz;
- 坐标、速度、面积、椭圆轴、角度和密度字段都有有效数据;
- 已记录测试中没有非法帧和重复 ID。

探针把 JSON Lines 写到 stdout,把诊断写到 stderr。私有框架最初会向 stdout 输出一行硬件
信息,污染采集文件;后来把启动阶段输出重定向,保证 JSONL 可以直接分析。

## 3. 为什么 Mac 不识别手势

如果在 macOS 识别滚动、缩放和多指手势,项目就会退化成远程鼠标模拟,并失去 Windows 原生
设置。MTP1 因此发送完整的当前触点集合:

```text
identifier + state + flags + x/y + geometry + monotonic timestamp
```

Windows 将触点映射到 HID slot,并交给精确式触控板栈识别手势。因此双指滚动和双指缩放能
原生工作,而不需要 Mac 端手势代码。

## 4. 实时性与重连

私有框架回调不能阻塞在 TCP 上。`mac-touch-agent` 在回调路径编码数据,写入 256 帧有界队列,
由独立发送线程配合 `TCP_NODELAY` 执行 Socket 写入。

每次连接严格从以下序列开始:

```text
HELLO(sequence=N)
RESET(sequence=N+1)
FRAME(sequence=N+2)
```

早期原型曾让控制消息复用 sequence,严格的 Windows Receiver 在重启后正确拒绝了该数据流。
修复后,每条消息都会递增 sequence。队列溢出时不会带着非法缺口继续发送,而是重新连接并
建立新的 `HELLO`/`RESET` 会话。

## 5. 坐标方向

网络协议保留 Mac 原始标准化坐标。真实端到端测试发现,Mac Y 轴与 Windows 精确式触控板表面
方向相反,因此在 Windows 映射层修正:

```text
hid_y = 1 - mac_y
```

不在网络协议中反转坐标,可以保留原始传感器含义,也允许未来其他 Receiver 自行选择方向。

## 6. macOS 本机输入策略

开发过程中考虑过使用 CGEventTap 拦截本机输入,但最终放弃:

- 需要“辅助功能”和“输入监控”权限;
- 无法可靠区分内建触控板与外接鼠标;
- 全局拦截会增加不必要的安全和可用性风险。

最终 Agent 不拦截 macOS 输入。需要把内建触控板专用于 Windows 的用户,使用 macOS 自带的
“有鼠标或无线触控板时忽略内建触控板”设置。

## 7. 为什么 Mac 端代码看起来不多

这是有意的职责收敛:

- 不实现手势识别器;
- 不在 macOS 创建虚拟设备或内核扩展;
- 暂时没有 UI、配对、安装器和后台守护进程;
- 不尝试普通 USB-C Device Mode;
- 复用共享协议编码器,不创建第二套序列化实现。

困难部分是验证私有传感器路径和建立异常安全边界,而不是写一个庞大的应用。Mac 端越小,
未来 macOS 私有 ABI 发生变化时需要维护的范围越小。

## 后续 macOS 工作

- 测试更多 Apple Silicon 代际和 macOS 版本;
- 封装签名的菜单栏/后台 Agent;
- 增加发现、配对、认证和加密;
- 处理睡眠唤醒和网络接口变化;
- 研究功能受限的公开 API 后端;
- 在跨机型测量后增加校准过的设备元数据。
Loading
Loading