Contributions are very welcome — this project exists because a handful of community projects each solved a piece of the puzzle, and it tries to give back by documenting everything it learned. Protocol findings are as valuable as code here.
The CLI (works on any Mac, no special signing):
swift build -c release
cp .build/release/procon2 /opt/homebrew/bin/ # or anywhere on PATHThe driver (needed only for wireless play; requires a paid Apple Developer membership for DriverKit signing — the HID family capabilities auto-provision, no Apple approval needed):
brew install xcodegen
cd VirtualPad
xcodegen generate
# open VirtualPad.xcodeproj once to pick your signing team for both targets
xcodebuild -project VirtualPad.xcodeproj -target ProCon2VirtualPad \
-configuration Release -allowProvisioningUpdates build
cp -R build/Release/ProCon2VirtualPad.app /Applications/
open /Applications/ProCon2VirtualPad.app # then approve in System SettingsChange the bundle identifiers in VirtualPad/project.yml,
VirtualPad/Dext/Info.plist, and VirtualPad/HostApp/main.swift to your own
prefix before signing.
You need real hardware — a Nintendo Switch 2 Pro Controller (other Switch 2 controllers likely work for the USB path; reports welcome). Useful tools that ship in the CLI:
procon2 monitor --raw— hex view of USB input reports, changed bytes highlighted. This is how the button table in the README was measured.procon2 learn— interactive wizard that maps buttons to report bits and writesprocon2-mapping.json.procon2 ble --raw— the same for Bluetooth LE notifications.procon2 ledtest— sends command candidates over BLE while logging every notify characteristic; the pattern for safe protocol experiments.
- Never send bytes whose semantics you don't understand to a write
characteristic — we learned this the hard way (an undocumented command
changed controller power behavior). Derive commands from a trustworthy
source first: BlueRetro's
sw2.c/sw2.his the authoritative BLE reference; HandheldLegend's captures are ground truth for USB. - When you discover something new (a command, a report field, a quirk), document it in the README's protocol notes section in the same style — byte offsets, exact frames, and how you verified it.
- The BLE and USB command sets share IDs and the
0x91request marker but differ in the interface byte (0x00USB /0x01BLE) and transport channels. See the README channel map before adding commands.
See the README roadmap. Currently: gyro/IMU forwarding over the wireless bridge, battery level reporting, and Joy-Con 2 / NSO GameCube controller support (the USB enabler already matches their PIDs; the rest is untested).
Follow the existing code: small single-purpose files, comments only where the code can't speak for itself (protocol byte offsets, macOS API gotchas). The dext is intentionally minimal — prefer putting logic in the CLI where it can be iterated without driver re-approval.