This little driver enables the Griffin PowerMate, a great little device from days gone by. What does PowerMate do? It’s a knob that you can turn or press. That’s it. It also has a blue LED in its base that can change intensity depending on what you’re doing.
When it was released, it was intended to aid video and audio production by adding scrollable knobs to your desktop. Of course, modern controllers exist that offer many more literal bells and whistles, but there’s something… odd… about this early device.
To install, open the DMG and drag powermate agent In your Applications folder. Then, launch powermate agent. Of course, it won’t do anything without the PowerMate, so rummage through your junk USB drawer and clean it out! You’ll see a new item in your top menu to control the behavior of PowerMate.

PowerMate acts as a scroll control, so if the active window or control has a scroll option, turning the dial will scroll the window or increase/decrease the selected value. If you don’t like the default scroll direction you can reverse the scroll direction.
The PowerMate also functions as a mouse button. A momentary push of the button performs the same function as a mouse click. Long pressing the button works like a right-click. You can also change the behavior so that a long press acts as a double-click.
Very simple, right?
A small macOS driver that opens Griffin Powermate (vid 0x077dPID 0x0410) on the USB HID, reads its 6-byte report, and highlights button And ROTATION Events so you can map them to actions (e.g. scroll, click, media keys).
The device reports on the bus but does nothing by default on macOS; this library snatches away The device delivers events to your app.
Report Format (from device)
- byte 0:button position –
0= issued,1= pressed - byte 1:rotation delta – signed; Positive = clockwise, negative = counterclockwise (typically ±1 to ±7 per report). The device does not report speed directly; driver receives rotation rate (delta per second) from the time between reports.
cd /path/to/USB
swift build
swift run PowerMateDemo
With the PowerMate plugged in, turn the knob or press the button; Prints the demo event. Stop with Ctrl+C.
System-Wide Driver (PowerMate Agent)
powermateagent Turns knobs and buttons into keyboard/scroll events any application Receives (browser, editor, etc.):
- ROTATION → vertical scroll, or up/down arrow keys When a menu (or submenu) is focused.
- Click (short press) → left mouse button (on the cursor), or return When a menu is focused (selects the highlighted item).
- long press → right mouse button (on the cursor).
Uses to locate menus and submenus simple use API: When the focused UI element is a menu (including submenus), rotation sends the arrow keys and click returns. Grant simple use In System Settings → Privacy and Security so that the submenus work without “sticking” to scrolling. If accessibility is not enabled, long press also enters fallback “menu mode” (click or arrow keys until 5‑second timeout).
The LED pulses when you turn and dims when idle; Full power on while holding the button.
When run for the first time, macOS will prompt for input monitoring Permission. provide it System Settings → Privacy and Security → Input Monitoring And add (or enable) the terminal or built-in executable, then run the agent again.
To run in background: swift run PowerMateAgent & or run the built binary ./.build/debug/PowerMateAgent and add this login item If you want it to start when you log in.
to make Signed, Notarized App (or installer) so that other people can use it without security warnings, see delivery.md. You will need an Apple developer account; Users will also need to grant input monitoring (or accessibility) once they use the dial for the first time.
in your app Package.swift (or Xcode: File → Add Package Dependencies):
dependencies: [
.package(path: "/path/to/USB"), // or your clone URL
],
targets: [
.target(name: "YourApp", dependencies: ["PowerMateDriver"]),
]
2. Start the driver and map the event
import PowerMateDriver
let driver = PowerMateDriver()
// Optional: use closures for simple mapping
driver.onRotate = { delta, rate in
// delta > 0 = clockwise, delta < 0 = counter-clockwise
// rate = deltas per second (nil on first report); use for speed-dependent mapping
// e.g. scroll: CGEventCreateScrollWheelEvent(..., delta * lineHeight)
}
driver.onButtonDown = { /* e.g. simulate click or toggle */ }
driver.onButtonUp = { }
// Or use the delegate for all events
driver.delegate = self // implement PowerMateDriverDelegate
driver.start()
// Keep run loop running (e.g. main thread in an app)
PowerMateEvent.buttonDown/buttonUp– knob pressed/releasedPowerMateEvent.buttonClick– Brief press and release (under)longPressThreshold).PowerMateEvent.buttonLongPress– Minimal press heldlongPressThresholdThen leave.PowerMateEvent.rotate(delta: Int, rate: Double?)—deltais the signed step number (e.g. +1, -2);rateRotation speed is expressed in deltas per second (zero in first report).
set longPressThreshold (default 0.4 seconds) to tune what counts as a long press. Use onClick And onLongPress (or delegate) to deal with separately.
Use driver.isConnected To see if the device is currently unlocked.
The base has a blue LED that you can use for feedback. Control it only when the device is connected (isConnected == true).
setLEDBrightness(_ value: UInt8)— Static brightness 0-255 (0 = off).setLEDPulseAsleep(_ on: Bool)/setLEDPulseAwake(_ on: Bool)– Turn the built-in pulse on or off when “asleep” or “awake”.setLEDPulseMode(table:op:arg:)– Custom Pulse:table0-2,op0 = slow, 1 = normal, 2 = fast,arg1-255 for op 0/2.
LED commands use USB vendor control requests (same protocol as the Linux driver). they return true If the order was sent successfully. If the USB device is busy (for example another process has it open), LED calls may fail.
mapping of system functions
- scroll: In
onRotatecreate a scroll wheelCGEvent(egCGEventCreateScrollWheelEvent) and post it, or feed the delta into your scroll logic. - Click: In
onButtonDown/onButtonUpCreate and post with a mouse clickCGEventOr call your own click handler. - media/other:map
onRotateAndonButtonDownWhatever you need (e.g. volumes, key equivalents).
May need to post event input monitoring (Or simple use) In System Settings → Privacy & Security For your app.
If the device does not respond
- unplug and plug again PowerMate, then run your app again.
- Close other software He may be using PowerMate (for example older PowerMate apps).
- driver uses
kIOHIDOptionsTypeSeizeDeviceTherefore it takes special access; Only one process can use it at a time.
<a href