← Home Few Bits
Cover image for MuteKey: A Minimal Hardware Microphone Kill Switch (USB HID) with Raspberry Pi Pico

MuteKey: A Minimal Hardware Microphone Kill Switch (USB HID) with Raspberry Pi Pico

Alex Solis Alex Solis ·

What this is

MuteKey is a tiny desktop button that mutes your microphone by emulating a USB keyboard. It's cheap, local, and intentionally simple: no cloud, no drivers, no complicated audio routing. Plug it into your workstation and press a button to send a mute/unmute shortcut. Works well for video calls, voice recording sessions, or the occasional panicked scramble when you realize your mic was open.

Why this approach

Software mute buttons are convenient but fragile: apps update, hotkeys change, and OS privacy nudges can get in the way. A hardware button that acts as a USB HID keyboard is robust and cross-platform. Instead of trying to present as an audio device (tricky), we send a keyboard shortcut that most meeting apps respect. It's low-footprint and privacy-friendly because it does one, clearly-auditable thing.

Parts

  • Raspberry Pi Pico or Pico W (you just need USB HID support)
  • Momentary tactile switch (or a small illuminated switch if you like)
  • NeoPixel or simple LED (optional, for status)
  • A few jumper wires and a small project enclosure or hot-glue mount
  • CircuitPython installed on the Pico (see steps)

Wiring (trivial)

  1. Connect one leg of the switch to a GPIO pin (example GP14) and the other leg to a ground pin.
  2. If using an LED, wire its data pin to another GPIO (example GP15) and ground to a resistor then ground. If using a NeoPixel, power to 3V3, ground to GND, data to GP15.
  3. Plug the Pico into USB — that'll be the host connection.

Software: CircuitPython HID snippet

Install CircuitPython on your Pico if you haven’t already (get the UF2 from circuitpython.org and drop it on the RPI-RP2 drive). Copy a single file code.py to the CIRCUITPY drive. The code below is intentionally tiny and uses the Consumer Control/media key for microphone mute where supported; we also include a fallback sequence for apps that expect Ctrl+Shift+M (common in Zoom/Teams/Chrome). Tweak shortcuts for your environment.

import time import board import digitalio from adafruit_hid.keyboard import Keyboard from adafruit_hid.keycode import Keycode from adafruit_hid.consumer_control import ConsumerControl from adafruit_hid.consumer_control_code import ConsumerControlCode btn = digitalio.DigitalInOut(board.GP14) btn.switch_to_input(pull=digitalio.Pull.UP) kb = Keyboard() cc = ConsumerControl() last = True while True: cur = btn.value if cur and not last: # button released -> treat as a press try: # Try a standard mic mute media key cc.send(ConsumerControlCode.MUTE) except Exception: # Fallback: send Ctrl+Shift+M kb.press(Keycode.CONTROL, Keycode.SHIFT, Keycode.M) kb.release_all() time.sleep(0.1) last = cur time.sleep(0.01)

How it behaves

When you press the button the Pico will attempt to send a consumer media MUTE key. Many operating systems and apps map that to microphone or input mute. If the media key isn't handled, the code falls back to a common application shortcut (Ctrl+Shift+M), so it works with Zoom and similar apps. You can edit the fallback to suit your favorite app or platform.

Packaging and ergonomics

  • Mount the switch in a small plastic or 3D-printed enclosure. Keep the Pico accessible so you can update the code later.
  • If you use a non-illuminated switch, consider adding a small LED as a mute indicator. You can toggle it in software whenever you send a mute command.
  • Label the switch clearly. A dramatic red cap is aesthetically pleasing and functional.

Troubleshooting

  1. If the button does nothing, confirm the Pico is mounted as a USB device and CircuitPython is running (the CIRCUITPY drive should be visible).
  2. Open the Pico's REPL if needed to debug. Add a print statement on button press to confirm detection.
  3. Some OSes don't map the consumer MUTE code to microphone mute. If that happens, pick the per-app shortcut and replace the fallback in the code. For macOS you might use Command+Shift+A (example) depending on app settings.
  4. If a target app grabs global hotkeys or runs sandboxed, bind the app's configured hotkey instead of relying on the media key.

Privacy and safety notes

This device intentionally acts as an input device to your host. Treat it like any keyboard: don't plug it into machines you don't control. The code is simple and auditable — if you want to be paranoid, review code.py before running. No network stacks, no telemetry, no cloud access.

Tip: keep a spare MuteKey on your desk. Panic mutes are a real thing.

Next steps and variations

  • Make a latching LED so the indicator reflects mute state. You can attempt to query host apps via USB HID reports, but that's complex; a manual toggle (press-on = mute LED on) is often pragmatic.
  • Use a rotary encoder to switch between mute modes or to send different hotkeys for different apps.
  • Port the code to TinyUSB/C if you want a compiled firmware with lower latency and smaller runtime.

Wrap-up

MuteKey is a small, pragmatic hardware tool that solves a common privacy problem with minimal fuss. It leans on CircuitPython and the USB HID profile to keep complexity low and the device auditable. Build it in an afternoon, customize the shortcut the next, and enjoy fewer accidental broadcasts.