Skip to content
Kiln Forged
All projects
ConceptBluetooth · Keyboard · ESP32-S3

Bluetooth Macro Pad

A wireless keypad with nine mechanical keys and a knob. Each key sends a shortcut or media control over Bluetooth to a laptop, tablet or phone.

“I want a small wireless keypad with a few programmable keys and a volume knob.”
Loading 3D view…
Stage 1

Spec

Spec
Qty 1

Bluetooth Macro Pad

Nine hot-swap mechanical keys and a rotary knob that act as a Bluetooth keyboard.

Power
USB-C powered, optional 600 mAh battery
Size
84 × 90 × 16 mm (keys add 6 mm)
Inputs
9 mechanical keys (hot-swap), Rotary encoder with push
Outputs
Status LED, Bluetooth keyboard reports
Connectivity
Bluetooth LE, USB-C
Budget
Under $35 in parts

Constraints

  • Works with macOS, Windows, iPadOS and Android
  • Keys swap without soldering
  • Why

    Hot-swap sockets

    You can try different switches without soldering, and replace one that wears out.

Stage 2

Circuit board

Top view of the Bluetooth Macro Pad board74 mm80 mmSW1SW2SW3SW4SW5SW6SW7SW8SW9ENC1J1LED1U2
ESP32-S3-MINI-128 components2-layer, 74 × 80 mm≈ $13.73 in parts
  • Why

    One pin per key, no matrix

    The ESP32-S3 has plenty of pins, so each key gets its own. That avoids diodes and ghosting, and the firmware stays simple.

  • Why

    Module under the keys

    The ESP32-S3 module sits on the back of the board with its antenna past the edge, so the keys keep a clean grid.

Stage 3

Firmware

src/main.cppArduino (PlatformIO) + ESP32 BLE Keyboard
// Bluetooth Macro Pad — nine keys and a knob that act as a wireless
// keyboard. Edit the MACROS table to change what each key does.

#include <Arduino.h>
#include <BleKeyboard.h>
#include "pins.h"

BleKeyboard keyboard("Kiln Forged Macro Pad", "Kiln Forged", 100);

struct Macro {
  uint8_t modifier;   // KEY_LEFT_CTRL, KEY_LEFT_GUI, ... or 0
  uint8_t key;
};

// Default layout: copy, paste, undo / screenshot, mute, lock / prev, play, next
const Macro MACROS[9] = {
  {KEY_LEFT_GUI, 'c'}, {KEY_LEFT_GUI, 'v'}, {KEY_LEFT_GUI, 'z'},
  {KEY_LEFT_GUI | KEY_LEFT_SHIFT, '4'}, {0, 0}, {KEY_LEFT_GUI | KEY_LEFT_CTRL, 'q'},
  {0, 0}, {0, 0}, {0, 0},
};
// Keys that send media controls instead of a shortcut (nullptr = shortcut).
const uint8_t *MEDIA[9] = {
  nullptr, nullptr, nullptr, nullptr, KEY_MEDIA_MUTE, nullptr,
  KEY_MEDIA_PREVIOUS_TRACK, KEY_MEDIA_PLAY_PAUSE, KEY_MEDIA_NEXT_TRACK,
};

bool lastState[9] = {};
int lastEncoderA = HIGH;

3 files: src/main.cpp, include/pins.h, platformio.ini

  • Why

    Shortcuts live in one table

    Edit the MACROS table to change any key. A future app will do this for you.

Stage 4

Enclosure

Outer size
84 × 90 × 16 mm
Material
PLA, 0.2 mm layers
Print time
3 h 20 min, no supports
  • Why

    Tilted 6°

    A slight tilt makes the keys easier to reach without a stand.

Stage 5

Assembly

  1. 1Press the switches into the sockets.
  2. 2Screw the board to the base.
  3. 3Add the knob cap.
  • Why

    Fit check passed

    Switch plate sits 5 mm above the board, as MX switches expect.

See every stage run, step by step

The workspace shows each engine working, with approval checkpoints in between.

Open in workspace