A macOS app that bridges Nintendo Switch 2 controllers to a virtual HID gamepad, so games and other apps can use them as standard controllers. Tested with Apple Game Controller framework apps, SDL-based apps (Steam, Dolphin), and the web Gamepad API.
Switch 2 controllers don't pair via the standard Bluetooth Security Manager Protocol and don't expose HID over GATT — they speak Nintendo's proprietary profile over a vendor BLE service. macOS therefore can't pair or use them natively. WaveBird connects via CoreBluetooth, parses the proprietary report format into a canonical state, and re-publishes each controller as a virtual HID gamepad through CoreHID.
Early. Currently supports:
- Nintendo Switch 2 GameCube Controller (NSO) over Bluetooth LE — analog sticks, all face/shoulder buttons, D-pad, Rumble and Motion
- Nintendo Switch 2 Pro Controller over Bluetooth LE — analog sticks, all buttons including Home and Capture, Rumble and Motion
- Nintendo Switch 2 Joy-Con (L / R) over Bluetooth LE — used as a merged L + R pair that presents as a single gamepad, or each side on its own. Sticks, all buttons, Rumble and Motion. Attach the second side and WaveBird forms the pair automatically; split them back into solo controllers anytime.
- Bluetooth pairing — WaveBird remembers controllers across launches, so after the first pair you reconnect by pressing any button instead of holding SYNC. Remembered controllers stay visible (offline) in the list.
Not yet supported: Charging Grip and USB connections.
- Download the latest
WaveBird-<version>.dmgfrom the Releases page. - Open the DMG and drag WaveBird.app to Applications.
The app is signed and notarized by Apple, so it launches without a Gatekeeper warning. You can also check for updates from within the app (WaveBird → Check for Updates…).
Each release DMG carries a SLSA build-provenance attestation. To verify it was built by this repo's release workflow before installing:
gh attestation verify --repo murphyjt/wavebird WaveBird-<version>.dmgEach connected controller can present as a different virtual gamepad. Open the controller card and use the "Use profile" picker on the General tab to switch:
| Profile | Rumble | Motion | Notes |
|---|---|---|---|
| Switch Pro Controller | ✅ | ✅ | Recommended |
| DualShock 4 | ✅ | ❌ | |
| DualSense | ✅ | ❌ | |
| Xbox Wireless Controller | ✅ | — | Recommended |
The selection persists per-controller (by serial) across reconnects, and can be changed while the controller is offline.
The General tab also has a Sticks section for inverting the left and/or right stick Y-axis. Per-controller rumble tuning (intensity, preset, per-band frequency and amplitude) lives on the Haptics tab. All controller settings persist per controller (by serial), so each physical controller carries its own configuration across re-pairings.
These profiles appear in System Settings → Game Controllers, where they can be remapped and customized.
- macOS 26.0 or newer
- Xcode 26 or newer (Swift 6.2)
xcodebuild -project WaveBird.xcodeproj -scheme WaveBird -configuration Debug buildOr open WaveBird.xcodeproj in Xcode and run.
WaveBird needs two privacy permissions the first time it runs. macOS may prompt for them automatically, or you can grant them manually:
System Settings → Privacy & Security → Accessibility — required to publish a virtual HID gamepad.
System Settings → Privacy & Security → Bluetooth — required to scan for and connect to controllers.
If a permission prompt appears, click Allow. If WaveBird is listed but unchecked, check it and relaunch.
Note: If you granted permissions for a previous version and the virtual gamepad stopped appearing after updating, open Privacy & Security → Accessibility, remove WaveBird, and re-add it — macOS sometimes doesn't re-validate an existing entry after a binary update.
- Launch the app — it begins scanning automatically.
- Hold the SYNC button on your controller until the LEDs flash. (If you've paired it before, just press any button.)
- WaveBird discovers and connects; the controller appears in the device list once it's ready.
- On the first connect of a new controller, WaveBird asks whether to pair it. Accepting writes a long-term key to both sides so future reconnects don't need SYNC. Pairing overwrites the controller's Nintendo Switch 2 console pairing — to use it on the console again you'll need to hold SYNC there.
- Click the controller card to open its settings — pick a virtual gamepad profile, invert stick axes (General), or tune rumble (Haptics). Use the "Forget This Device…" button to drop WaveBird's record of a pairing; the controller keeps its stored key until you pair it with something else.
The virtual gamepad is visible to apps that use the Game Controller framework or the WebHID / Gamepad APIs (Chrome / Safari gamepad testers like lizardbyte gamepad-tester).
- BlueRetro by darthcloud — protocol reference for Switch 2 controllers (Apache 2.0).
- switch2_controller_research by ndeadly — detailed write-ups of the Switch 2 BLE / HID protocol.
- SDL —
SDL_hidapi_switch2.cfor the factory trigger-calibration flash layout and the NS2 LRAEncodeHDRumblebit packing;SDL_hidapi_switch.cfor the Switch 1 Pro Controller subcommand handshake the Switch Pro presentation emulates, and the NS1 HD Rumble amplitude table we invert to decode the presentation's incoming rumble (zlib). - dekuNukem/Nintendo_Switch_Reverse_Engineering
— write-up of the Switch 1 Bluetooth HID protocol (subcommand IDs, report
0x30 button/stick layout) used by the Switch Pro presentation, and the
rumble_data_table.mdamplitude curve we use to decode NS1 HD Rumble bytes back into 16-bit amplitudes before re-encoding for NS2 LRA.
MIT — see LICENSE.