← All posts

MacroDeck: Five Buttons and a Potentiometer Is Sometimes All You Need

2024Hardware · Arduino

Keyboard shortcuts are fast until you need to look them up. I wanted something I could reach for without thinking. A physical button for the actions I use most. A knob for volume.

MacroDeck is an Arduino with five push buttons and a potentiometer connected to a Python script on my computer. Press a button and it launches VSCode, toggles fullscreen, or adjusts volume. Turn the knob and the brightness value changes. It is not complicated. That is the point.

The Split

The Arduino handles the hardware layer. It monitors each button with edge detection so one press sends one message. It reads the potentiometer and only sends an update when the value changes by more than ten, which filters out analog noise.

The Python script receives those messages over serial and routes them to actions. pyautogui handles keyboard simulation. os.system launches applications. The two sides communicate through formatted strings. BUTTON_3 triggers volume up. POT_128 adjusts the brightness level.

This separation is the only architectural decision that matters. The Arduino does not know what actions its buttons trigger. The Python script does not care how the buttons are wired. Reassigning a button means changing a few lines in one file, not both.

The Difference Between a Button That Works and One That Does Not

A physical button bounces. The contact makes and breaks several times before settling. Without debouncing, one press registers as five.

I used software debouncing through state tracking. The Arduino stores the previous state of each button and only sends a message on the transition from high to low. A rising edge is ignored. A falling edge fires once. That logic is about ten lines. It is the difference between a tool that works and one that is annoying to use.

The same thinking applied to the potentiometer. Noise from the analog reading would flood the serial line with tiny fluctuations. A threshold of ten on the mapped value eliminated that without introducing noticeable lag.

Where the Pipeline Stopped

The brightness knob controls an LED on the Arduino. It does not actually adjust the screen brightness because I never wired that integration. The value gets sent to the Python script and printed to the console. That is where the pipeline ends.

The serial port is hardcoded to COM5. The "start brave" command is Windows-specific. There is no configuration file for button mappings. Every change requires editing the source code. For 93 lines of code, these are acceptable gaps. They are also the exact things I would fix in a version two.

This was one of the first projects where the software I wrote controlled something physical that I built. The boundary between code and the real world felt thinner. A button press on a breadboard triggered an action on my screen. That connection is the reason hardware projects are worth doing even when they are small.

Five buttons and a potentiometer is not a product. It is enough to learn something.

View all projects →View on GitHub ↗