Keyboard Switch is an experimental, native macOS menu-bar app for coordinating a pre-paired Apple Magic Keyboard between up to three Macs on the same LAN. It uses local peer discovery and asks macOS to disconnect or connect the real Bluetooth HID device; it does not forward keystrokes.
The software builds and its switching, networking, security, and simulated Bluetooth paths are testable. The legacy public IOBluetooth framework can inventory the local paired Magic Keyboard and exposes connection operations. A reliable physical A→B→A transfer has not yet been demonstrated. macOS may decline or delay connection requests, and Touch ID association is not portable. Do not treat this repository as a production replacement until the hardware acceptance matrix passes on every intended Mac and OS version.
Normal switching never deletes Bluetooth pairing information. Cable-pair the keyboard with every Mac before testing. Keep another input device available during feasibility tests.
- Apple-silicon Mac with macOS 15 or later
- Xcode 16 or later and Swift 6
- USB-C rechargeable Apple Magic Keyboard
- All Macs awake and reachable on the same local network
swift test
swift run KeyboardSwitchApp
swift run keyboard-switch-diagnosticsInventory is safe and redacts most of the Bluetooth identifier. Explicit diagnostics can interrupt keyboard input:
swift run keyboard-switch-diagnostics --disconnect FULL_DEVICE_ID
swift run keyboard-switch-diagnostics --connect FULL_DEVICE_IDRun those commands only with a fallback mouse/keyboard available. A successful API return is not proof of usable HID input; verify by typing on the target.
./Scripts/build-app.sh creates dist/KeyboardSwitch.app. By default it is ad-hoc signed. Set CODE_SIGN_IDENTITY to a Developer ID Application identity for distribution; ./Scripts/sign-app.sh can re-sign an existing bundle. ./Scripts/install.sh installs to ~/Applications; ./Scripts/uninstall.sh removes that copy and local preferences.
For notarization, export NOTARY_PROFILE created with xcrun notarytool store-credentials, then run ./Scripts/notarize.sh. See comments in each script for overrides.
./Scripts/package-release.sh verifies the bundle and creates a versioned ZIP plus SHA-256 checksum. CI builds twice and compares every non-signature file, enables complete Swift concurrency checking and warnings-as-errors, and runs license, secret-pattern, and undeclared-dependency checks. An ad-hoc archive is for local testing only; it is not notarized or Gatekeeper-ready.
On each supported macOS release, cable-pair once on Macs A, B, and C, unplug the cable, then demonstrate three consecutive A→B→C→A cycles. Record hardware metadata and verify actual typed input after every handoff. Repeat after sleep/wake, Bluetooth restart, app restart, Wi-Fi interruption, and keyboard power-cycle. Pairing must remain intact and recovery must restore the source or report manual action accurately.
No release should claim physical compatibility until those tests pass on real hardware. Touch ID, FileVault pre-login, wake-from-shutdown, iPad, Windows, pointing devices, and App Store distribution are outside v1.
Run ./Scripts/hardware-acceptance.sh for a structured JSON Lines record. See Tests/ACCEPTANCE.md. A human must verify actual typed input; the harness never treats an API return as proof.
The app works locally, captures no keystrokes, and does not request Accessibility or Input Monitoring permission. Peer trust secrets belong in Keychain. Diagnostic identifiers and network addresses must remain redacted in exported logs.
MIT. The project uses original branding and UI rather than copying Magic Switch assets.
./Scripts/uninstall.sh preserves Keychain identity and peer trust by default. The explicit --remove-keychain flag performs a full reset and removes only the two documented Keybridge generic-password services.