Here's a Python script to automatically mute your microphone when you are typing on your noisy keyboard. Designed for and tested with Gnome Wayland, but should be good for any Linux desktop environment.
Just in case it isn't obvious, AI helped with the code and also made this cute depiction of our use case:
I love mechanical keyboards like my beloved IBM Model M, but they are loud and can disrupt video calls. It's easy to forget to mute yourself while typing notes or multitasking during meetings.
Magic Mute monitors your keyboard device and automatically:
- 🔇 Auto-mutes your microphone as soon as you start typing
- 🔊 Auto-unmutes your microphone just after you stop typing
- 🔘 Manual toggle mode via Scroll Lock key (or any key you choose)
- 💡 LED feedback lights up Scroll Lock LED when muted
Works directly with kernel input devices and PipeWire/PulseAudio, so it's desktop-environment agnostic and it even works with annoying Wayland.
- 🎯 Device-specific: Monitor only your mechanical keyboard, not your laptop's built-in keyboard
- 🎤 Microphone-specific: Mute only your headset mic, not your laptop's internal microphone
- ⚡ Low latency: Instant muting when you press a key
- 🔘 Manual toggle mode: Press Scroll Lock to stay muted until you press it again
- 💡 Visual feedback: Scroll Lock LED shows mute status at a glance
- 🔧 Configurable: Adjust the unmute delay and toggle key to your preference
- 🪶 Lightweight: Python daemon is simple and with minimal dependencies
- ✨ Graceful: Automatically unmutes after you exit with Ctrl-C
- Linux with PipeWire or PulseAudio
- Python 3.7+
- Read access to input devices (udev rule or running as appropriate user)
- Clone or download this repository to your desired location:
git clone https://github.com/swapdisk/magic-mute.git- Install Python dependencies:
cd magic-mute
pip install -r requirements.txtList all available keyboard devices:
./magic_mute.py --list-keyboardsLook for your mechanical keyboard and note its name, for example, "IBM Model M" or "HID 04d9:1400". You can use the full name or any substring that uniquely identifies it.
List all available microphone sources:
./magic_mute.py --list-micsLook for your headset or desired microphone and note its name or description.
./magic_mute.py --keyboard "Model M" --mic "Headset"Or using short options:
./magic_mute.py -k "HID 04d9" -m "Headset"Wait 3 seconds after typing stops before unmuting:
./magic_mute.py -k "Model M" -m "Headset" -d 3.0See what's happening in real-time:
./magic_mute.py -k "Model M" -m "Headset" -vUse a different key instead of Scroll Lock for manual toggle:
./magic_mute.py -k "Model M" -m "Headset" -t KEY_PAUSE./magic_mute.py \
--keyboard "Model M" \
--mic "USB Audio Device Mono" \
--delay 2.5 \
--toggle-key KEY_SCROLLLOCK \
--verbose-k, --keyboard NAME Keyboard device name or substring (e.g., "Model M", "HID 04d9")
-m, --mic NAME Microphone source name or substring (e.g., "Headset")
-d, --delay SECONDS Seconds to wait before unmuting (default: 1.0)
-r, --retry-interval SEC Seconds between retries when devices not found (default: 60.0)
-t, --toggle-key KEY Key to toggle manual mute mode (default: KEY_SCROLLLOCK)
--no-retry Exit if devices not found instead of retrying
-v, --verbose Enable verbose output
--list-keyboards List all available keyboard devices
--list-mics List all available microphone sources
Configuration can also be provided via environment variables. Command-line arguments take precedence.
MAGIC_MUTE_KEYBOARD Keyboard device name (same as --keyboard)
MAGIC_MUTE_MIC Microphone source name (same as --mic)
MAGIC_MUTE_DELAY Unmute delay in seconds (same as --delay)
MAGIC_MUTE_RETRY_INTERVAL Retry interval in seconds (same as --retry-interval)
MAGIC_MUTE_TOGGLE_KEY Toggle key name (same as --toggle-key)
Press the toggle key (default: Scroll Lock) to enter manual mute mode:
- Your microphone will mute and stay muted even when you stop typing
- The Scroll Lock LED will light up to show you're muted
- Press the toggle key again to exit manual mode and unmute
- While in manual mode, typing won't trigger the auto-unmute timer
This is perfect for when you need to stay muted for an extended period (listening to a presentation, etc.) but still want visual confirmation of your mute status.
Note: LED feedback requires a keyboard with a Scroll Lock LED. If your keyboard doesn't have one, manual toggle mode still works - you just won't get the visual indicator.
Your user needs read access to the keyboard device file. Typically, this is achieved with input group membership. For example:
sudo usermod -aG input $USERIf you're using Gnome on Wayland, there's a security gotcha: Gnome deliberately drops the input group from your desktop session processes to prevent applications from keylogging via raw input device access. This is intentional security hardening.
Symptoms:
/etc/groupshows you're in theinputgroup- Running
idin a terminal window doesn't show theinputgroup --list-keyboardsworks withsudobut not without it- SSH sessions show the
inputgroup, but desktop terminals don't
To get around this annoyance, the script automatically handles it by re-executing itself via sg input when needed.
The script should work under a regular user service on all desktop environments including Gnome Wayland.
Step 1: Create a configuration file at INSTALL_PATH/magic-mute.conf:
MAGIC_MUTE_KEYBOARD="Model M"
MAGIC_MUTE_MIC="Headset"
MAGIC_MUTE_DELAY=1.0
MAGIC_MUTE_RETRY_INTERVAL=60.0
MAGIC_MUTE_TOGGLE_KEY=KEY_SCROLLLOCKReplace the values with your actual device names (use --list-keyboards and --list-mics to find them).
Step 2: Create ~/.config/systemd/user/magic-mute.service:
[Unit]
Description=Magic Mute - Auto-mute mic while typing
After=pipewire.service
[Service]
Type=simple
Environment=PYTHONUNBUFFERED=1
EnvironmentFile=-INSTALL_PATH/magic-mute.conf
ExecStart=INSTALL_PATH/magic_mute.py
Restart=on-failure
RestartSec=5
KillSignal=SIGINT
[Install]
WantedBy=default.targetReplace INSTALL_PATH with the full path to where you installed magic-mute.
The - prefix before the path makes the config file optional - the service will work with command-line args if the file doesn't exist.
Step 3: Enable and start:
systemctl --user daemon-reload
systemctl --user enable magic-mute.service
systemctl --user start magic-mute.serviceChanging configuration:
To change keyboard or microphone settings, just edit magic-mute.conf and restart:
systemctl --user restart magic-mute.serviceNo need to run daemon-reload when only the config file changes!
Check status:
systemctl --user status magic-mute.serviceView logs:
journalctl --user -u magic-mute.service -fAlternative: Command-line arguments
You can also configure via command-line arguments in the service file instead of using a config file:
ExecStart=INSTALL_PATH/magic_mute.py --keyboard "Model M" --mic "Headset"Command-line arguments take precedence over environment variables, so you can mix both approaches.
-
Keyboard Discovery: Searches for your keyboard by name across all input devices, so it works even if the device path changes between reboots
-
Device Retry Logic: If devices aren't found (e.g., laptop undocked), waits and retries every 60 seconds instead of failing. Perfect for dock/undock scenarios - no systemd restart spam!
-
Keyboard Monitoring: Uses the
evdevlibrary to read events directly from the keyboard device at the kernel level (/dev/input/eventX) -
Manual Toggle Mode: Detects toggle key (default Scroll Lock) to enter/exit manual mute mode. In manual mode, you stay muted until you press the toggle key again.
-
LED Feedback: Controls the keyboard's Scroll Lock LED to show mute status - on when muted, off when unmuted. Works for both auto-mute and manual mode.
-
Microphone Control: Uses
pulsectlto interface with PipeWire/PulseAudio's API for muting/unmuting audio sources -
Smart Timing: When a key is pressed (in auto mode):
- Immediately mutes the microphone
- Starts/resets a countdown timer
- When the timer expires (no keys pressed for N seconds), unmutes the microphone
-
Desktop Environment Agnostic: Works on Wayland, Xorg, or even headless systems because it operates at the kernel device level
- By default, the script will retry every 60 seconds if devices aren't found
- This is normal when your laptop is undocked or devices are unplugged
- The script will automatically start working when you reconnect the devices
- Use
--no-retryif you want it to exit immediately instead of waiting - Check available keyboards with
--list-keyboards - Verify permissions (see Device Permissions section)
- Make sure you're using a substring that uniquely identifies your keyboard
- Check available sources with
--list-mics - Try using a substring of the microphone name (e.g., "Headset" instead of full name)
- Make sure PipeWire/PulseAudio is running
- Verify the mic name matches with
--list-mics - Run with
--verboseto see what's happening - Check that PipeWire/PulseAudio is controlling the correct device
- Use
--list-keyboardsto see all available keyboards - Make your search string more specific to match only your mechanical keyboard
- Check the "Name" and "Physical" fields to identify your mechanical keyboard uniquely
- Check that your keyboard has a Scroll Lock LED (laptop keyboards often don't)
- The script will detect and log if LED control is not supported
- Manual toggle mode still works without LED feedback
- If you need write access to the keyboard device, ensure your udev rule uses
MODE="0660"notMODE="0640"
- Make sure you're using a valid evdev key name (e.g.,
KEY_SCROLLLOCK,KEY_PAUSE,KEY_NUMLOCK) - Run with
--verboseto see if the key press is detected - Check that the key exists on your keyboard with
evtestor similar tools
MIT
