English | 简体中文
Take over an ESP32-S3 keyboard on macOS without changing its firmware. Map physical buttons to shell commands, keyboard events, or text input.
OpenVibeBoard is a native Swift menu bar app. It listens to the keyboard's USB CDC log, dispatches configured actions, and provides a native Settings window. The Swift implementation replaced the archived Python v0.1 client.
- Persistent menu bar utility with optional launch at login via
SMAppService. - Configurable USB CDC serial monitoring through
ORSSerialPort. - Native sidebar-detail Settings for key mappings with a fixed save bar and live reload.
- Three action types:
cmd(shell command),key(keyboard event), andtext(clipboard paste). - Two key modes:
tapandhold. - Chinese-friendly text input through
NSPasteboard+Cmd+V, avoiding input method conversion.
- macOS 15 or later.
- Xcode 16 or later.
- xcodegen:
brew install xcodegen. - The keyboard must expose its ESP-IDF log through a USB serial device.
- The serial device must not be held by another program.
git clone https://github.com/Ethereal49/openvibeboard.git
cd openvibeboard
xcodegen generate
open OpenVibeBoard.xcodeprojRun the OpenVibeBoard scheme with Cmd+R. The menu bar icon appears after launch. On the first run, grant Accessibility permission in System Settings -> Privacy & Security -> Accessibility. The menu bar item includes a direct link to that pane when permission is missing.
You can also build from the command line:
xcodebuild -project OpenVibeBoard.xcodeproj -scheme OpenVibeBoard buildThe keyboard emits lines such as:
button down k1
button up k1
The app parses those events, looks up the matching KeyConfig, and dispatches the action through ActionDispatcher:
MenuBarExtra
-> SerialMonitor
-> ActionDispatcher
-> CmdRunner (cmd)
-> KeyInjector (key)
-> TextInjector (text)
ConfigStore actor ~/Library/Application Support/OpenVibeBoard/config.json
| Type | Behavior | Example |
|---|---|---|
cmd |
Run a shell command without blocking the UI | open -a Codex |
key |
Send a keyboard event through CGEvent |
ctrl+c, option+d, esc |
text |
Paste text through the clipboard | 继续 |
key actions support tap (keydown followed by keyup) and hold (keydown until the physical button is released). Modifier flags are attached to the character key event so they do not leak into later events.
The Settings recorder accepts combinations such as cmd+shift+d; users do not need to type the configuration syntax manually.
For text actions, enter controls whether the app sends Return after pasting. The mode field is only meaningful for key actions.
| Button | Default action |
|---|---|
k1 |
cmd: open -a Codex |
k2 |
text: paste 继续 and press Return |
k3 |
key tap: ctrl+c |
k4 |
key hold: option+d |
Mappings are stored in ~/Library/Application Support/OpenVibeBoard/config.json. The schema remains compatible with the Python v0.1 configuration.
Select the keyboard's serial device under Settings -> Device. OpenVibeBoard remembers an explicit selection and reconnects to it after unplugging or restarting the app. With no saved selection, it prefers the first available /dev/cu.usbmodem* device. The baud rate remains fixed at 115200.
- Accessibility: required for
keyactions and theCmd+Vpart oftextactions. The menu bar action explicitly launches System Settings and opens Privacy & Security -> Accessibility. - Apple Events: shell commands that invoke
osascriptor AppleScript may request Automation permission. - Serial connection fails: select the attached device under Settings -> Device and release it from
screen, Arduino IDE, the Python client, or another serial tool. - A key stops working: check the serial connection first, then inspect the mapping in Settings.
- A hold combination emits only one character or leaves a modifier stuck: verify that the event went through
KeyInjector; modifier flags must be attached to the character keydown.
Trellis stores project conventions in .trellis/spec/. Read the relevant spec before changing the app.
xcodegen generate
xcodebuild test -project OpenVibeBoard.xcodeproj -scheme OpenVibeBoardThe archived Python implementation is under archive/python-v0.1/.
OpenVibeBoard does not include an in-app updater. Updates are delivered manually through GitHub Releases. Until a Developer ID signed and notarized build is published, build the app from source.
Artifacts labeled ad-hoc signed, unnotarized are test builds. macOS Gatekeeper is expected to reject them, so they are not production installers.
- Obtain Developer ID credentials and publish a notarized v0.2.0 build.
- Evaluate automatic updates after the distribution trust chain is established.

