Turn a leftover Fire TV remote into a Mac controller (OpenAI sells this idea for $230)
OpenAI's Codex Micro validated the demand for a physical AI trigger. A Fire TV remote from your drawer does the job for $0: D-pad mouse, one-button push-to-talk dictation, lock screen. Full Karabiner config included.
OpenAI just shipped its first hardware product: Codex Micro, a $230 macropad for talking to AI agents.
The demand is real. The $230 is optional.
The day before that launch, I turned the Fire TV remote that had been sleeping in my drawer for six months into exactly this — a wireless controller for my Mac. D-pad moves the cursor. Center clicks. Hold the Alexa button and talk; release, and your words land as text. Power key locks the screen. Total cost: $0 and about 15 minutes, if you skip the mistakes I made for you.
Here’s the whole thing, including the three fights the remote put up.
What you get
| Remote key | What it does on the Mac |
|---|---|
| Ring ▲▼◀▶ | Move the mouse cursor |
| Select (center) | Left click |
| Menu ☰ | Right click |
| Alexa button — quick tap | Enter |
| Alexa button — hold | Push-to-talk: hold = record, release = transcribe |
| Power | Lock screen |
| Play/Pause, volume, mute | Normal media keys (unchanged) |
| Back, Prime/Netflix app keys | ⚠️ Nothing — not fixable (see limits below) |
Dictation flow: hold Alexa → speak → release → tap Alexa to send. One button does it all.
The interesting part (before the steps)
There is no “click” anywhere in this remote. It pairs as a pure BLE keyboard — the center Select button is literally an Enter key. The mouse doesn’t exist until you synthesize it: arrow keys become cursor deltas, Enter becomes button1. You’re not remapping a mouse; you’re conjuring one out of a keyboard.
That’s also why this works at all — and why the same trick applies to almost any leftover BLE remote with buttons.
Prerequisites
- A Mac with Bluetooth
- A Fire TV Alexa Voice Remote (2nd gen or newer)
- A dictation app with a hold-fn-to-record mode (I use Wisp)
- Homebrew
⚠️ The remote bonds to ONE device. Pairing it to your Mac disconnects it from your Fire TV. To go back, re-pair it to the Fire TV later.
Step 1 — Install Karabiner-Elements
brew install --cask karabiner-elements
Open Karabiner-Elements once, then grant permissions: System Settings → Privacy & Security → Input Monitoring → enable karabiner_grabber (and karabiner_observer if listed). Approve the driver extension if prompted.
Step 2 — Pair the remote
- Mac: System Settings → Bluetooth
- Remote: hold the Home button ~10 seconds until the LED flashes
- Click Connect when “Amazon Remote” appears
Step 3 — Set your dictation app to push-to-talk
Wisp has a built-in “hold fn to record, release to transcribe” mode:
defaults write com.wisp.app "wisp.activationMethod" -string "fnHold"
osascript -e 'quit app "Wisp"'; sleep 2; open -a Wisp
(Or set it in Wisp’s settings UI. Note: your keyboard’s real fn key now also triggers Wisp — that’s native behavior.)
Step 4 — Install the key mappings
Replace ~/.config/karabiner/karabiner.json with the config below. The file hot-reloads — no restart needed. Already have your own rules? Copy the two rule objects from "rules" into your existing profile instead.
{
"global": {
"check_for_updates_on_startup": true,
"show_in_menu_bar": true,
"show_profile_name_in_menu_bar": false
},
"profiles": [
{
"name": "Default profile",
"selected": true,
"complex_modifications": {
"rules": [
{
"description": "Fire TV remote: D-pad ring -> mouse cursor, Select -> left click (remote only, vendor 0x0171)",
"manipulators": [
{
"type": "basic",
"from": { "key_code": "up_arrow" },
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "mouse_key": { "y": -1536 } } ]
},
{
"type": "basic",
"from": { "key_code": "down_arrow" },
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "mouse_key": { "y": 1536 } } ]
},
{
"type": "basic",
"from": { "key_code": "left_arrow" },
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "mouse_key": { "x": -1536 } } ]
},
{
"type": "basic",
"from": { "key_code": "right_arrow" },
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "mouse_key": { "x": 1536 } } ]
},
{
"type": "basic",
"from": { "key_code": "return_or_enter" },
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "pointing_button": "button1" } ]
},
{
"type": "basic",
"from": { "key_code": "keypad_enter" },
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "pointing_button": "button1" } ]
},
{
"type": "basic",
"from": { "consumer_key_code": "menu" },
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "pointing_button": "button2" } ]
},
{
"type": "basic",
"from": {
"consumer_key_code": "power",
"modifiers": { "optional": ["any"] }
},
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "key_code": "q", "modifiers": ["left_control", "left_command"] } ]
},
{
"type": "basic",
"from": {
"key_code": "power",
"modifiers": { "optional": ["any"] }
},
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "key_code": "q", "modifiers": ["left_control", "left_command"] } ]
},
{
"type": "basic",
"from": {
"key_code": "tab",
"modifiers": { "optional": ["any"] }
},
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "key_code": "q", "modifiers": ["left_control", "left_command"] } ]
},
{
"type": "basic",
"from": {
"key_code": "left_command",
"modifiers": { "optional": ["any"] }
},
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "key_code": "vk_none" } ]
}
]
},
{
"description": "Fire TV remote: Alexa button — tap = Enter, hold = fn (push-to-talk)",
"manipulators": [
{
"type": "basic",
"from": { "consumer_key_code": "ac_search" },
"to": [ { "key_code": "fn" } ],
"to_if_alone": [ { "key_code": "return_or_enter" } ],
"parameters": { "basic.to_if_alone_timeout_milliseconds": 300 }
},
{
"type": "basic",
"from": { "key_code": "f4" },
"conditions": [ { "type": "device_if", "identifiers": [ { "vendor_id": 369 } ] } ],
"to": [ { "key_code": "fn" } ],
"to_if_alone": [ { "key_code": "return_or_enter" } ],
"parameters": { "basic.to_if_alone_timeout_milliseconds": 300 }
}
]
}
]
},
"virtual_hid_keyboard": {
"country_code": 0,
"keyboard_type_v2": "ansi"
}
}
]
}
The three fights
1. The power key kept opening the app switcher instead of locking the screen. macOS silently translates the remote’s raw power signal into ⌘Tab for normal apps. The config above catches it at three layers (consumer power, key power, and tab) so it reliably locks instead.
2. Different remote generations send different Enter variants. The config maps both return_or_enter and keypad_enter to left click. If your Select key types Enter instead of clicking, open Karabiner-EventViewer, press the key, and add whatever variant yours sends.
3. Quick Alexa taps triggered phantom recordings. Fixed with a hold threshold:
defaults write com.wisp.app wisp.fnHoldMinimumDuration -float 0.4
Honest limits
Two things I couldn’t fix, and you won’t either:
- Back and the Prime/Netflix app keys do nothing. They don’t go through the Bluetooth keyboard interface at all — they use an Amazon-proprietary channel only Fire TV devices understand. The remote exposes exactly one HID service to macOS.
- The remote’s microphone can’t be your Mac’s mic. Same proprietary channel. Your Mac’s built-in mic does the listening — the remote is just the push-to-talk trigger.
The $230 version has neither limitation. It’s the 100-point answer; this is the $0, 85-point one. On my couch, 85 is plenty.
Troubleshooting
| Symptom | Fix |
|---|---|
| Nothing works at all | Check Input Monitoring permissions; confirm the remote is connected in Bluetooth settings |
| A key does the wrong thing | Karabiner-EventViewer → press the key → edit that rule’s "from" |
| Select types Enter instead of clicking | Your remote sends another Enter variant — add it (mine sends keypad_enter) |
| Tap-Alexa Enter doesn’t fire | Increase to_if_alone_timeout_milliseconds to 400–500 |
| Cursor too slow/fast | Change the 1536 values (bigger = faster) |
| Stopped working after a macOS update | Re-check Input Monitoring permissions |
The takeaway
What stays with me isn’t the $230 I didn’t spend. It’s that the remote sat in a drawer for six months because I’d filed it under “TV accessory.” It had Bluetooth, buttons, and a perfect push-to-talk key the whole time. It wasn’t missing features. It was missing someone asking: what else can you do?
The cheapest dividend of the AI era might be exactly that — re-asking that question about the things you already own.
If you resurrect a drawer gadget with this, I’d like to hear which one.
关注公众号
扫码关注公众号「老迈的朋友们」——AI 求职、招聘内幕、AI 落地,新文第一时间推给你。
手机可长按识别