JoyBridge is a native macOS productivity tool that maps Nintendo Joy-Con, Switch Pro Controller, and compatible Bluetooth controller buttons to keyboard input.
It is not a game utility. The goal is simple: turn controller buttons into customizable macOS keyboard shortcuts.
Latest shared test version: v0.10.0 / 2026-05-11
This version adds a dedicated friend-testing guide, so trusted testers can install, approve, authorize, test, and report issues without reading the full developer README. It is still a local friend-test build, not a notarized public release. See FRIEND_TESTING.md, CHANGELOG.md, and RELEASE_CHECKLIST.md for details.
- Native macOS app built with Swift, SwiftUI, and AppKit
- Controller input through
GameController.framework - Keyboard event simulation through CoreGraphics
CGEvent - Accessibility permission detection and shortcut to System Settings
- Custom button-to-key mappings stored in
UserDefaults - Single-key shortcuts, modifier-only bindings, and modifier combinations such as
Command + CorCommand + Shift + S - Debounced controller input so holding a button does not repeatedly fire
- Target controller selection and locking, so other connected controllers do not trigger mappings
- Menu bar item for checking status, reopening JoyBridge, rescanning controllers, checking Accessibility permission, and quitting the app
- Global pause/resume switch for temporarily disabling all keyboard output
- Readiness check panel for Accessibility, controller connection, target lock, and mapping output status
- Copyable diagnostic summary for easier friend-test feedback
- Custom macOS App icon generated into
Assets.xcassets - Local packaging script for creating friend-test
.zipbuilds - Package source summary with git commit, tag, and clean/dirty status in
READ-ME-FIRST.txt - Dedicated friend-testing guide with install steps and feedback template
- Release-readiness checker for future Developer ID signing and Apple notarization preparation
- Controller status, latest pressed button, and editable mapping list in the UI
- A
- B
- X
- Y
- Left Shoulder
- Right Shoulder
- Left Trigger
- Right Trigger
- DPad Up
- DPad Down
- DPad Left
- DPad Right
Note: these inputs are supported when Apple's GameController.framework exposes them for the connected controller. In current friend testing, connecting both left and right Joy-Cons at the same time allows DPad, A/B/X/Y, and L/R/ZL/ZR to work. When using only a single Joy-Con (L) or single Joy-Con (R), the face/direction buttons work, but L/R/ZL/ZR may not report value changes.
| Controller Button | Keyboard Action |
|---|---|
| A | Space |
| B | Escape |
| X | Command + C |
| Y | Command + V |
| Left Shoulder | Command + Left Arrow |
| Right Shoulder | Command + Right Arrow |
| Left Trigger | Page Up |
| Right Trigger | Page Down |
| DPad Up | Up Arrow |
| DPad Down | Down Arrow |
| DPad Left | Left Arrow |
| DPad Right | Right Arrow |
- macOS 13 or later
- Xcode 16 or later recommended
- Apple Silicon Mac recommended for the current MVP
- A Nintendo Joy-Con, Switch Pro Controller, or compatible Bluetooth controller
- Accessibility permission granted to JoyBridge
- Clone the repository.
- Open
JoyBridge.xcodeprojin Xcode. - Select the
JoyBridgetarget. - In
Signing & Capabilities, choose your Apple Developer team or Personal Team. - Run the app on
My Mac. - In JoyBridge, click
请求授权/打开设置. - Enable JoyBridge in System Settings > Privacy & Security > Accessibility.
- Return to JoyBridge and click
重新检测权限.
For local development, App Sandbox is currently disabled to keep Accessibility and keyboard event testing straightforward.
If macOS still reports that Accessibility is missing after you grant permission, reset the permission record and run the app again:
tccutil reset Accessibility cc.afterlight.JoyBridgeAfter the app works from Xcode, you can create a local friend-test package:
Scripts/package-local-release.sh v0.10.0The script builds the Release app and writes the package to:
dist/JoyBridge-v0.10.0-local-test.zip
Important notes:
- This package is for local friend testing only.
- Start with
FRIEND_TESTING.mdfor the shortest install and testing guide. - It is signed by Xcode for local testing, not with Developer ID for public distribution.
- It is not notarized by Apple yet, so macOS may show a security warning when opening it after download.
- Friends may need to right-click JoyBridge and choose Open, or approve it in System Settings > Privacy & Security.
- Recommended order: unzip the package, move
JoyBridge.appto/Applications, open it, then grant Accessibility permission. - Accessibility permission must be granted to the installed copy of JoyBridge. If an older Xcode build was authorized before, remove and re-add JoyBridge in Accessibility settings.
spctlmay reportrejectedor an internal code-signing error for this local package. That means it is not a notarized public release.READ-ME-FIRST.txtincludes the git commit, tag, and whether the worktree was clean or dirty when packaged.FRIEND_TESTING.mdincludes the friend install guide and feedback template.RELEASE_CHECKLIST.mdis included for future public release preparation notes.Scripts/check-release-readiness.shis included as an optional read-only checker.- The package is not committed to Git.
dist/is ignored on purpose.
JoyBridge includes a read-only checker for the future public release path:
Scripts/check-release-readiness.sh v0.10.0After building or installing an app, you can also check that app bundle:
Scripts/check-release-readiness.sh v0.10.0 /Applications/JoyBridge.appFor the current local friend-test package, some warnings are expected. For example, the app is not signed with Developer ID yet, notarization credentials may not be configured, and there may be no stapled notarization ticket. Those warnings are a reminder that this package is for testing, not public distribution.
If you see a dialog like Apple cannot verify JoyBridge, do not move it to Trash if you trust this local test build.
Recommended path:
- Click Done in the warning dialog.
- Open System Settings > Privacy & Security.
- Scroll to Security.
- Click Open Anyway for JoyBridge.
- Enter your Mac login password if asked.
- Open JoyBridge again.
Apple usually shows the Open Anyway button for about one hour after you try to open the app.
Local tester fallback:
xattr -dr com.apple.quarantine /Applications/JoyBridge.appOnly use this fallback for a JoyBridge build you trust. It removes macOS's download quarantine flag for this app.
- Pair a Joy-Con or Switch Pro Controller in macOS Bluetooth settings.
- Open JoyBridge and click
重新检测控制器. - Confirm that the
运行检查panel shows the current version and the next required step. - Confirm that the controller name appears.
- Click
锁定当前to save the current controller as the target controller. - Press controller buttons and confirm
最近按键updates. - Open TextEdit or another text field.
- Press
Ato test Space. - Select text and press
X/Yto test copy and paste. - Change a mapping in the list and confirm the new action works. Set the Key picker to
None/无when you want a modifier-only binding such asControl. - Hold a controller button and confirm it does not continuously repeat.
- Release and press again to confirm it fires once more.
- Close the main JoyBridge window and confirm JoyBridge remains in the menu bar.
- Use the JoyBridge menu bar item to pause/resume mappings, check status, reopen the window, rescan controllers, check Accessibility permission, or quit the app.
- Click
暂停映射, press controller buttons, and confirm最近按键still updates but no keyboard input is sent. - Click
启用映射and confirm mappings work again. - Click
复制诊断信息and confirm a readable summary is copied for feedback. - Confirm JoyBridge uses the custom icon in Finder, Dock, and the Accessibility permission list.
After a target controller is locked, JoyBridge should only respond to that saved controller. If the target controller is not connected, JoyBridge should not automatically switch to another Bluetooth controller.
For Joy-Con testing, connecting both left and right Joy-Cons at the same time is recommended. Confirm the Xcode console shows Button pressed, Mapping found, and Keyboard event sent. If L/R/ZL/ZR do not print Button pressed when only one Joy-Con is connected, macOS is not exposing those physical buttons through GameController.framework for that single-controller mode.
Menu bar note: menu bar mode only keeps JoyBridge running after the main window is closed. It does not start JoyBridge automatically after a Mac restart yet. Open JoyBridge manually after restart, then quit it from the menu bar item when you are done testing.
Pause note: pausing mappings only stops keyboard output. Controller detection, latest pressed button display, and target controller locking continue to work. The pause state is saved and restored on next launch.
JoyBridge currently focuses only on custom controller-button-to-keyboard mappings, including single keys, modifier-only bindings, and key combinations.
Not included in the first version:
- Motion mouse
- Stick mouse control
- Stick scrolling
- Left/right Joy-Con merging
- Per-app profiles
- Cloud sync or iCloud sync
- Login item support
- Auto update
- App Store packaging
- Plugin system
- Complex shortcut recorder
- Electron, Tauri, Python, or Node.js implementation
JoyBridge/
JoyBridgeApp.swift
ContentView.swift
AppDelegate.swift
Managers/
ControllerManager.swift
MappingManager.swift
AccessibilityPermissionManager.swift
Models/
ControllerButton.swift
KeyboardKey.swift
KeyModifier.swift
KeyMapping.swift
MappingAction.swift
Utilities/
AppInfo.swift
KeyboardEventSender.swift
Views/
ReadinessStatusView.swift
MappingListView.swift
MappingRowView.swift
PermissionStatusView.swift
ControllerStatusView.swift
Scripts/
check-release-readiness.sh
generate-app-icon.swift
package-local-release.sh
FRIEND_TESTING.md
RELEASE_CHECKLIST.md
- JSON import/export for mappings
- Multiple mapping profiles
- Better controller model diagnostics
- Universal build support
- Notarized Developer ID release packaging
JoyBridge 是一个 macOS 原生生产力工具,用于把 Nintendo Joy-Con、Switch Pro Controller 和兼容蓝牙手柄的按钮映射成 macOS 键盘输入。
它不是游戏工具。它的目标很明确:让手柄按钮可以触发自定义键盘按键或快捷键。
最新共享测试版本:v0.10.0 / 2026-05-11
这个版本新增专门的朋友测试说明,让可信测试者不用阅读完整开发 README,也能完成安装、允许打开、授权、测试和反馈。它仍然是本地朋友测试版,不是经过 Apple 公证的正式公开发行版。详细更新请看 FRIEND_TESTING.md、CHANGELOG.md 和 RELEASE_CHECKLIST.md。
- 使用 Swift、SwiftUI、AppKit 构建的 macOS 原生 App
- 使用
GameController.framework监听手柄输入 - 使用 CoreGraphics
CGEvent模拟键盘事件 - 检测 Accessibility 辅助功能权限,并提供跳转系统设置的按钮
- 使用
UserDefaults保存自定义映射 - 支持单键、纯修饰键映射和组合键,例如
Command + C、Command + Shift + S - 防止长按按钮时无限重复触发
- 支持选择并锁定目标控制器,避免其他已连接手柄触发映射
- 支持菜单栏入口,用于查看状态、重新打开 JoyBridge、重新检测控制器、检测辅助功能权限和退出 App
- 支持全局暂停/启用映射,用于临时停止所有键盘输出
- 支持运行检查面板,用于汇总辅助功能、控制器连接、目标锁定和映射输出状态
- 支持复制诊断信息,方便朋友测试时反馈问题
- 支持自定义 macOS App 图标,并生成到
Assets.xcassets - 支持本地打包脚本,用于生成朋友测试版
.zip - 测试包内的
READ-ME-FIRST.txt会显示打包时的 git commit、tag 和工作区 clean/dirty 状态 - 支持专门的朋友测试说明,包含安装步骤和反馈模板
- 支持发布准备检查脚本,用于后续 Developer ID 签名和 Apple 公证准备
- 界面显示控制器状态、最近按下按钮和可编辑映射列表
- A
- B
- X
- Y
- Left Shoulder
- Right Shoulder
- Left Trigger
- Right Trigger
- DPad Up
- DPad Down
- DPad Left
- DPad Right
注意:这些输入的前提是 Apple 的 GameController.framework 能从当前连接的控制器里暴露出对应按钮。当前朋友测试中,同时连接左右 Joy-Con 时,方向键、A/B/X/Y 和 L/R/ZL/ZR 都可以正常工作。只连接单只 Joy-Con (L) 或单只 Joy-Con (R) 时,面键/方向键可用,但 L/R/ZL/ZR 可能不会上报数值变化。
| 手柄按钮 | 键盘动作 |
|---|---|
| A | Space |
| B | Escape |
| X | Command + C |
| Y | Command + V |
| Left Shoulder | Command + Left Arrow |
| Right Shoulder | Command + Right Arrow |
| Left Trigger | Page Up |
| Right Trigger | Page Down |
| DPad Up | Up Arrow |
| DPad Down | Down Arrow |
| DPad Left | Left Arrow |
| DPad Right | Right Arrow |
- macOS 13 或更高版本
- 建议使用 Xcode 16 或更高版本
- 当前 MVP 优先面向 Apple Silicon
- Nintendo Joy-Con、Switch Pro Controller 或兼容蓝牙手柄
- 需要给 JoyBridge 授权 Accessibility 辅助功能权限
- 克隆仓库。
- 用 Xcode 打开
JoyBridge.xcodeproj。 - 选择
JoyBridgeTarget。 - 在
Signing & Capabilities中选择你的 Apple Developer Team 或 Personal Team。 - 选择
My Mac运行。 - 在 JoyBridge 中点击
请求授权/打开设置。 - 在 系统设置 > 隐私与安全性 > 辅助功能 中打开 JoyBridge。
- 回到 JoyBridge,点击
重新检测权限。
本地开发阶段,App Sandbox 当前保持关闭,方便测试 Accessibility 和键盘事件发送。
如果已经授权但 App 仍显示未授权,可以重置 Accessibility 记录后重新运行:
tccutil reset Accessibility cc.afterlight.JoyBridge确认 App 可以从 Xcode 正常运行后,可以生成一个给朋友测试的本地包:
Scripts/package-local-release.sh v0.10.0脚本会构建 Release 版本,并把测试包输出到:
dist/JoyBridge-v0.10.0-local-test.zip
重要提醒:
- 这个包只适合本地朋友测试。
- 请先看
FRIEND_TESTING.md,里面是最短安装和测试说明。 - 它使用 Xcode 本地测试签名,不是用于公开分发的 Developer ID 签名。
- 它还没有经过 Apple 公证,所以下载后打开时 macOS 可能会显示安全提醒。
- 朋友可能需要右键点击 JoyBridge 后选择打开,或在 系统设置 > 隐私与安全性 中手动允许。
- 建议顺序:先解压测试包,把
JoyBridge.app移到“应用程序”,再打开,再授权辅助功能权限。 - 必须给安装后的这个 JoyBridge 授权辅助功能权限。如果以前授权的是 Xcode 构建版本,需要在辅助功能设置里移除并重新添加 JoyBridge。
spctl可能会对这个本地测试包显示rejected或代码签名内部错误。这表示它还不是经过 Apple 公证的正式公开发行版。READ-ME-FIRST.txt会显示打包时的 git commit、tag,以及工作区当时是 clean 还是 dirty。FRIEND_TESTING.md包含朋友安装说明和问题反馈模板。- 测试包内会包含
RELEASE_CHECKLIST.md,用于说明后续公开发布前要注意的事项。 - 测试包内会包含
Scripts/check-release-readiness.sh,作为可选的只读检查工具。 - 测试包不会提交到 Git。
dist/会被故意忽略。
JoyBridge 包含一个只读检查脚本,用于后续公开发布准备:
Scripts/check-release-readiness.sh v0.10.0构建或安装 App 后,也可以检查具体的 App bundle:
Scripts/check-release-readiness.sh v0.10.0 /Applications/JoyBridge.app对当前本地朋友测试包来说,出现一些警告是正常的。例如:App 还不是 Developer ID 签名,还没有配置公证凭证,也没有附加 Apple 公证票据。这些警告是在提醒我们:当前包适合测试,还不适合公开分发。
如果看到类似 Apple 无法验证 JoyBridge 的弹窗,只要你确认这是可信的本地测试包,就不要点击移到废纸篓。
推荐处理方式:
- 在弹窗里点击完成。
- 打开 系统设置 > 隐私与安全性。
- 滚动到安全性区域。
- 找到 JoyBridge,点击仍要打开。
- 如果系统要求,输入你的 Mac 登录密码。
- 再次打开 JoyBridge。
Apple 通常只会在你尝试打开 App 后约一小时内显示仍要打开按钮。
本地测试者备用方式:
xattr -dr com.apple.quarantine /Applications/JoyBridge.app只有在你确认这个 JoyBridge 测试包可信时,才使用这个备用命令。它会移除这个 App 的 macOS 下载隔离标记。
- 在 macOS 蓝牙设置中连接 Joy-Con 或 Switch Pro Controller。
- 打开 JoyBridge,点击
重新检测控制器。 - 确认
运行检查面板显示当前版本和下一步需要处理的状态。 - 确认界面显示控制器名称。
- 点击
锁定当前,把当前控制器保存为目标控制器。 - 按手柄按钮,确认
最近按键更新。 - 打开 TextEdit 或其他输入框。
- 按
A测试 Space。 - 选中文本后按
X/Y测试复制和粘贴。 - 修改映射列表中的按键,确认新的映射生效。需要纯修饰键映射时,可以把 Key 选择器设为
None/无,例如只触发Control。 - 长按手柄按钮,确认不会连续疯狂触发。
- 松开后再次按下,确认可以再次触发。
- 关闭 JoyBridge 主窗口,确认 App 仍然留在菜单栏中。
- 使用菜单栏里的 JoyBridge 暂停/启用映射、查看状态、重新打开窗口、重新检测控制器、检测辅助功能权限或退出 App。
- 点击
暂停映射,按手柄按钮,确认最近按键仍会更新,但不会发送键盘输入。 - 点击
启用映射,确认映射重新生效。 - 点击
复制诊断信息,确认可以复制一段可读的问题反馈摘要。 - 确认 JoyBridge 在 Finder、Dock 和辅助功能权限列表中显示自定义图标。
锁定目标控制器后,JoyBridge 应该只响应这个已保存的控制器。如果目标控制器没有连接,JoyBridge 不应该自动切换到其他蓝牙手柄。
测试 Joy-Con 时,建议同时连接左右两个 Joy-Con。请以 Xcode 控制台中的 Button pressed、Mapping found、Keyboard event sent 为准。如果只连接单只 Joy-Con 时按 L/R/ZL/ZR 没有出现 Button pressed,说明 macOS 当前没有通过 GameController.framework 暴露这些实体按键。
菜单栏说明:菜单栏模式只表示关闭主窗口后 JoyBridge 继续运行。它还不会在 Mac 重启后自动启动。重启后仍需要手动打开 JoyBridge;测试结束时请从菜单栏里的 JoyBridge 选择退出。
暂停说明:暂停映射只会停止键盘输出。控制器检测、最近按键显示和目标控制器锁定仍会继续工作。暂停状态会保存,并在下次启动时恢复。
JoyBridge 第一版只专注于自定义“手柄按钮 -> 键盘单键 / 纯修饰键 / 键盘组合键”。
第一版暂不包含:
- 体感鼠标
- 摇杆控制鼠标
- 摇杆滚动
- 左右 Joy-Con 合并
- 按不同 App 自动切换配置
- 云同步或 iCloud 同步
- 登录项开机自启
- 自动更新
- App Store 打包发布
- 插件系统
- 复杂快捷键录制器
- Electron、Tauri、Python 或 Node.js 方案
JoyBridge/
JoyBridgeApp.swift
ContentView.swift
AppDelegate.swift
Managers/
ControllerManager.swift
MappingManager.swift
AccessibilityPermissionManager.swift
Models/
ControllerButton.swift
KeyboardKey.swift
KeyModifier.swift
KeyMapping.swift
MappingAction.swift
Utilities/
AppInfo.swift
KeyboardEventSender.swift
Views/
ReadinessStatusView.swift
MappingListView.swift
MappingRowView.swift
PermissionStatusView.swift
ControllerStatusView.swift
Scripts/
check-release-readiness.sh
generate-app-icon.swift
package-local-release.sh
FRIEND_TESTING.md
RELEASE_CHECKLIST.md
- 映射 JSON 导入/导出
- 多配置文件
- 更完善的控制器型号诊断
- Universal 构建
- 经过 Apple 公证的 Developer ID 正式发布包