ForceCursor is a macOS and watchOS prototype that turns an Apple Watch into a short-session air mouse. Wrist rotation produces relative pointer movement, and explicit Watch controls produce clicks.
The physical Watch uses high-level URLSession HTTP requests. It does not use gRPC, Network.framework, Bluetooth LE, or a manually managed Bluetooth connection. This transport is compatible with the networking policy enforced on physical Apple Watch hardware.
The custom single-tap classifier comes after transport and motion have been proven. The temporary click buttons exercise the exact leftClick() and rightClick() command path that a gesture detector will call later.
Apple Watch Mac
Core Motion HTTP server on TCP 8787
motion and button intent == URLSession ==> ordered command handler
protobuf request bodies CGEvent cursor control
The Watch determines what the wrist did. It sends motion, leftClick, rightClick, mouseDown, mouseUp, scroll, and stop commands as serialized Protocol Buffer messages. The Mac owns the actual pointer location because another mouse, HomeRow, a display change, or macOS can move it independently.
Motion is sampled at 50 Hz and transmitted at no more than about 30 Hz. Gyroscope velocity is integrated using the actual sample interval, a small dead zone removes drift, and nonlinear acceleration lets fast wrist turns cross a large display without making slow aiming overly sensitive. Displacement is accumulated while an HTTP request is in flight, so coalescing does not lose travel. The Mac eases each received displacement across 60 Hz cursor updates. Button commands preserve their order and are not discarded.
The Protocol Buffer contract is in Protocol/force_cursor.proto. Xcode's SwiftProtobufPlugin build tool plugin generates the Swift message types when either target builds.
- Xcode 27 beta with the macOS 27 and watchOS 27 SDKs
- macOS 15 or newer
- watchOS 11 or newer
- A physical Apple Watch for meaningful networking and motion testing
- The Mac and Watch on the same trusted local network
- XcodeGen 2.45.4 or newer
ForceCursor currently uses plaintext HTTP because this is a LAN prototype. Do not use it on an untrusted network. Authentication and TLS belong in a later milestone.
project.yml is the source of truth. From the repository root, run:
xcodegen generateRegenerate after changing packages, targets, build settings, capabilities, or adding source files. Normal edits to an existing Swift file do not require regeneration.
-
Install Xcode 27 beta from Apple Developer Downloads.
-
Open Xcode once and let it install requested platform components.
-
If command-line tools still point to Command Line Tools, either select the beta globally:
sudo xcode-select --switch /Applications/Xcode-beta.app/Contents/Developer
Or prefix commands with
DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer. -
Run
xcodegen generate, then openForceCursor.xcodeproj. -
Wait for Xcode to resolve the Swift Protobuf package.
-
If Xcode asks whether to trust and enable
SwiftProtobufPlugin, approve it. It is supplied by Apple'sswift-protobufpackage. -
Select
ForceCursorMac, open Signing & Capabilities, and choose your Apple Developer team. -
Repeat that signing step for
ForceCursorWatchContainerandForceCursorWatch. The container is the iOS packaging stub for the Watch app. -
If a bundle identifier is unavailable, change it in Xcode and make the same change in
project.ymlso regeneration keeps it.
Free personal-team signing is enough for your own devices, although its provisioning expires periodically.
- Pair the Watch normally with your iPhone.
- Connect the paired iPhone to the Mac by cable for initial setup.
- Enable Developer Mode on the iPhone and Watch when Xcode requests it.
- In Xcode, open Window > Devices and Simulators.
- Select the iPhone and wait for its paired Watch to appear.
- Accept trust prompts and keep the iPhone and Watch unlocked while Xcode prepares developer support.
- Confirm that the Watch appears as a run destination for the
ForceCursorWatchscheme.
- Select the
ForceCursorMacscheme and My Mac destination. - Press Run.
- If macOS asks whether ForceCursor may accept incoming connections, allow it.
- Click Request Permission in ForceCursor.
- Open System Settings > Privacy & Security > Accessibility and enable ForceCursor.
- Return to ForceCursor and click Move right 80 px. The pointer should move.
- Copy the
Mac addressshown in the app, such as192.168.1.42:8787. Enter only the IP portion on the Watch.
If the Mac has multiple active network interfaces, use the IPv4 address for the Wi-Fi interface shown under System Settings > Network > Wi-Fi > Details > TCP/IP.
- Leave the Mac app running.
- Select the
ForceCursorWatchscheme and your physical Apple Watch destination. - Press Run and wait for installation.
- Grant Motion and Local Network permission if prompted.
- Enter the Mac's IPv4 address in the Watch app. Do not include
:8787. - Tap Connect. The Watch performs
GET /healthand should show Connected to Mac. - Tap Start Cursor, then rotate your wrist gently.
- Use the temporary buttons to test left and right click.
- Tap Stop Cursor before leaving the app.
There is no Bluetooth pairing step beyond the normal Apple Watch and iPhone pairing. Reconnecting means opening both ForceCursor apps and tapping Connect after the Mac server is ready.
GET /healthreturns HTTP 200 when the Mac server is ready.POST /controlaccepts one serializedForceCursorInputand returns HTTP 204.- The server keeps HTTP connections alive so
URLSessioncan reuse the connection. - The Watch sets its maximum connection count to one, preserving request order.
- Plaintext HTTP has no authentication or encryption.
- The first version uses a manually entered Mac IP address.
- Cursor axes, dead zone, acceleration, and sensitivity need physical-device tuning.
URLSessionlatency on watchOS can vary with the Watch's current network route.- There is no automatic reconnection yet.
Build the Mac target without signing:
DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer \
xcodebuild -project ForceCursor.xcodeproj \
-scheme ForceCursorMac \
-destination 'platform=macOS' \
CODE_SIGNING_ALLOWED=NO buildBuild the Watch target for a generic physical device without signing:
DEVELOPER_DIR=/Applications/Xcode-beta.app/Contents/Developer \
xcodebuild -project ForceCursor.xcodeproj \
-scheme ForceCursorWatch \
-destination 'generic/platform=watchOS' \
CODE_SIGNING_ALLOWED=NO build- Measure HTTP request latency and loss on a physical Watch.
- Tune wrist axes, dead zone, acceleration, and motion coalescing.
- Add automatic reconnection and clearer network diagnostics.
- Add authenticated pairing and TLS.
- Record labeled tap and non-tap IMU windows.
- Implement a conservative personal tap detector.