Skip to content

Instantly share code, notes, and snippets.

@delfer
Last active October 27, 2025 18:22
Show Gist options
  • Select an option

  • Save delfer/57ce2fddcc467fabafd079b927459854 to your computer and use it in GitHub Desktop.

Select an option

Save delfer/57ce2fddcc467fabafd079b927459854 to your computer and use it in GitHub Desktop.
ESP32-C3 6 buttons BLE Keyboard
// Make sure you can use the ESP32 with the Arduino IDE (Installed esp32 by Espressif in Board Manager).
// Install Lib https://github.com/delfer/ESP32-BLE-Keyboard
// Download the latest release of this library from the release page (Source code (zip)).
// In the Arduino IDE go to "Sketch" -> "Include Library" -> "Add .ZIP Library..." and select the file you just downloaded.
//#define DEBUG_MODE // Uncomment to disable debug output
#ifdef DEBUG_MODE
#define DEBUG_PRINTF(...) Serial.printf(__VA_ARGS__)
#else
#define DEBUG_PRINTF(...)
#endif
#include <BleKeyboard.h>
// Create a BleKeyboard object.
BleKeyboard bleKeyboard("ESP32C3-6Keypad", "Delfer", 100);
// --- BUTTON CONFIGURATION ---
// Uncomment the following line to use numpad key codes (KEY_NUM_0..KEY_NUM_5)
// If commented, regular digit keys ('0'..'5') will be used
//#define USE_NUMPAD_KEYS
const int BUTTON_PINS[] = {0, 3, 4, 5, 7, 10};
#ifdef USE_NUMPAD_KEYS
const uint8_t KEY_CODES[] = {
KEY_NUM_0,
KEY_NUM_1,
KEY_NUM_2,
KEY_NUM_3,
KEY_NUM_4,
KEY_NUM_5};
#else
const uint8_t KEY_CODES[] = {
'0',
'1',
'2',
'3',
'4',
'5'};
#endif
const int NUM_BUTTONS = sizeof(BUTTON_PINS) / sizeof(BUTTON_PINS[0]);
// --- DEBOUNCE PARAMETERS ---
// Debounce delay in milliseconds.
const unsigned long DEBOUNCE_DELAY_MS = 50;
// --- STATE VARIABLES FOR POLLING ---
// Last stable (steady) button state
int buttonState[NUM_BUTTONS];
// Last read button state (may be debounced)
int lastButtonState[NUM_BUTTONS];
// Time of last button state change (for debouncing)
unsigned long lastDebounceTime[NUM_BUTTONS] = {0};
void setup() {
#ifdef DEBUG_MODE
Serial.begin(115200);
#endif
// Initialize pins
for (int i = 0; i < NUM_BUTTONS; i++) {
pinMode(BUTTON_PINS[i], INPUT_PULLUP);
// Read initial state
int initialState = digitalRead(BUTTON_PINS[i]);
buttonState[i] = initialState;
lastButtonState[i] = initialState;
}
bleKeyboard.begin();
Serial.println("BLE Keyboard started. Waiting for connection...");
}
// -----------------------------------------------------------------
// MAIN LOOP() - BUTTON POLLING WITH DEBOUNCING
// -----------------------------------------------------------------
void loop() {
// Iterate through all buttons in each cycle
for (int i = 0; i < NUM_BUTTONS; i++) {
// 1. Read the current pin state
int reading = digitalRead(BUTTON_PINS[i]);
// 2. If the state has changed compared to the previous reading,
// reset the debounce timer.
if (reading != lastButtonState[i]) {
lastDebounceTime[i] = millis();
}
// 3. Check if enough time has passed since the last change.
if ((millis() - lastDebounceTime[i]) > DEBOUNCE_DELAY_MS) {
// If enough time has passed, the state can be considered stable.
// Check if this stable state differs from the previously
// recorded one.
if (reading != buttonState[i]) {
buttonState[i] = reading; // Update stable state
// 4. Handle press or release event
if (buttonState[i] == LOW) {
// EVENT: PRESS (LOW, because INPUT_PULLUP is used)
DEBUG_PRINTF("✅ Button %d (GPIO%d) PRESSED.\n", i + 1,
BUTTON_PINS[i]);
if (bleKeyboard.isConnected()) {
bleKeyboard.press(KEY_CODES[i]);
}
} else {
// EVENT: RELEASE (HIGH)
DEBUG_PRINTF("❌ Button %d (GPIO%d) RELEASED.\n", i + 1,
BUTTON_PINS[i]);
if (bleKeyboard.isConnected()) {
bleKeyboard.release(KEY_CODES[i]);
}
}
}
}
// 5. Save the current read state for the next iteration
lastButtonState[i] = reading;
}
// No delay() in the loop to ensure fast polling and reaction.
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment