Skip to content

Instantly share code, notes, and snippets.

@manuelbl
Created August 3, 2019 09:12
Show Gist options
  • Save manuelbl/66f059effc8a7be148adb1f104666467 to your computer and use it in GitHub Desktop.
Save manuelbl/66f059effc8a7be148adb1f104666467 to your computer and use it in GitHub Desktop.
ESP32 as Bluetooth Keyboard

ESP32 as Bluetooth Keyboard

With its built-in Bluetooth capabilities, the ESP32 can act as a Bluetooth keyboard. The below code is a minimal example of how to achieve it. It will generate the key strokes for a message whenever a button attached to the ESP32 is pressed.

For the example setup, a momentary button should be connected to pin 2 and to ground. Pin 2 will be configured as an input with pull-up.

In order to receive the message, add the ESP32 as a Bluetooth keyboard of your computer or mobile phone:

  1. Go to your computers/phones settings
  2. Ensure Bluetooth is turned on
  3. Scan for Bluetooth devices
  4. Connect to the device called "ESP32 Keyboard"
  5. Open an empty document in a text editor
  6. Press the button attached to the ESP32

The code has been written for the Arduino framework. I recommend using PlatformIO for development as it is far superior to the Arduino IDE while still taking full advantage of the Arduino ecosystem (libraries, support etc.)

/*
* Sample program for ESP32 acting as a Bluetooth keyboard
*
* Copyright (c) 2019 Manuel Bl
*
* Licensed under MIT License
* https://opensource.org/licenses/MIT
*/
//
// This program lets an ESP32 act as a keyboard connected via Bluetooth.
// When a button attached to the ESP32 is pressed, it will generate the key strokes for a message.
//
// For the setup, a momentary button should be connected to pin 2 and to ground.
// Pin 2 will be configured as an input with pull-up.
//
// In order to receive the message, add the ESP32 as a Bluetooth keyboard of your computer
// or mobile phone:
//
// 1. Go to your computers/phones settings
// 2. Ensure Bluetooth is turned on
// 3. Scan for Bluetooth devices
// 4. Connect to the device called "ESP32 Keyboard"
// 5. Open an empty document in a text editor
// 6. Press the button attached to the ESP32
#define US_KEYBOARD 1
#include <Arduino.h>
#include "BLEDevice.h"
#include "BLEHIDDevice.h"
#include "HIDTypes.h"
#include "HIDKeyboardTypes.h"
// Change the below values if desired
#define BUTTON_PIN 2
#define MESSAGE "Hello from ESP32\n"
#define DEVICE_NAME "ESP32 Keyboard"
// Forward declarations
void bluetoothTask(void*);
void typeText(const char* text);
bool isBleConnected = false;
void setup() {
Serial.begin(115200);
// configure pin for button
pinMode(BUTTON_PIN, INPUT_PULLUP);
// start Bluetooth task
xTaskCreate(bluetoothTask, "bluetooth", 20000, NULL, 5, NULL);
}
void loop() {
if (isBleConnected && digitalRead(BUTTON_PIN) == LOW) {
// button has been pressed: type message
Serial.println(MESSAGE);
typeText(MESSAGE);
}
delay(100);
}
// Message (report) sent when a key is pressed or released
struct InputReport {
uint8_t modifiers; // bitmask: CTRL = 1, SHIFT = 2, ALT = 4
uint8_t reserved; // must be 0
uint8_t pressedKeys[6]; // up to six concurrenlty pressed keys
};
// Message (report) received when an LED's state changed
struct OutputReport {
uint8_t leds; // bitmask: num lock = 1, caps lock = 2, scroll lock = 4, compose = 8, kana = 16
};
// The report map describes the HID device (a keyboard in this case) and
// the messages (reports in HID terms) sent and received.
static const uint8_t REPORT_MAP[] = {
USAGE_PAGE(1), 0x01, // Generic Desktop Controls
USAGE(1), 0x06, // Keyboard
COLLECTION(1), 0x01, // Application
REPORT_ID(1), 0x01, // Report ID (1)
USAGE_PAGE(1), 0x07, // Keyboard/Keypad
USAGE_MINIMUM(1), 0xE0, // Keyboard Left Control
USAGE_MAXIMUM(1), 0xE7, // Keyboard Right Control
LOGICAL_MINIMUM(1), 0x00, // Each bit is either 0 or 1
LOGICAL_MAXIMUM(1), 0x01,
REPORT_COUNT(1), 0x08, // 8 bits for the modifier keys
REPORT_SIZE(1), 0x01,
HIDINPUT(1), 0x02, // Data, Var, Abs
REPORT_COUNT(1), 0x01, // 1 byte (unused)
REPORT_SIZE(1), 0x08,
HIDINPUT(1), 0x01, // Const, Array, Abs
REPORT_COUNT(1), 0x06, // 6 bytes (for up to 6 concurrently pressed keys)
REPORT_SIZE(1), 0x08,
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x65, // 101 keys
USAGE_MINIMUM(1), 0x00,
USAGE_MAXIMUM(1), 0x65,
HIDINPUT(1), 0x00, // Data, Array, Abs
REPORT_COUNT(1), 0x05, // 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana)
REPORT_SIZE(1), 0x01,
USAGE_PAGE(1), 0x08, // LEDs
USAGE_MINIMUM(1), 0x01, // Num Lock
USAGE_MAXIMUM(1), 0x05, // Kana
LOGICAL_MINIMUM(1), 0x00,
LOGICAL_MAXIMUM(1), 0x01,
HIDOUTPUT(1), 0x02, // Data, Var, Abs
REPORT_COUNT(1), 0x01, // 3 bits (Padding)
REPORT_SIZE(1), 0x03,
HIDOUTPUT(1), 0x01, // Const, Array, Abs
END_COLLECTION(0) // End application collection
};
BLEHIDDevice* hid;
BLECharacteristic* input;
BLECharacteristic* output;
const InputReport NO_KEY_PRESSED = { };
/*
* Callbacks related to BLE connection
*/
class BleKeyboardCallbacks : public BLEServerCallbacks {
void onConnect(BLEServer* server) {
isBleConnected = true;
// Allow notifications for characteristics
BLE2902* cccDesc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
cccDesc->setNotifications(true);
Serial.println("Client has connected");
}
void onDisconnect(BLEServer* server) {
isBleConnected = false;
// Disallow notifications for characteristics
BLE2902* cccDesc = (BLE2902*)input->getDescriptorByUUID(BLEUUID((uint16_t)0x2902));
cccDesc->setNotifications(false);
Serial.println("Client has disconnected");
}
};
/*
* Called when the client (computer, smart phone) wants to turn on or off
* the LEDs in the keyboard.
*
* bit 0 - NUM LOCK
* bit 1 - CAPS LOCK
* bit 2 - SCROLL LOCK
*/
class OutputCallbacks : public BLECharacteristicCallbacks {
void onWrite(BLECharacteristic* characteristic) {
OutputReport* report = (OutputReport*) characteristic->getData();
Serial.print("LED state: ");
Serial.print((int) report->leds);
Serial.println();
}
};
void bluetoothTask(void*) {
// initialize the device
BLEDevice::init(DEVICE_NAME);
BLEServer* server = BLEDevice::createServer();
server->setCallbacks(new BleKeyboardCallbacks());
// create an HID device
hid = new BLEHIDDevice(server);
input = hid->inputReport(1); // report ID
output = hid->outputReport(1); // report ID
output->setCallbacks(new OutputCallbacks());
// set manufacturer name
hid->manufacturer()->setValue("Maker Community");
// set USB vendor and product ID
hid->pnp(0x02, 0xe502, 0xa111, 0x0210);
// information about HID device: device is not localized, device can be connected
hid->hidInfo(0x00, 0x02);
// Security: device requires bonding
BLESecurity* security = new BLESecurity();
security->setAuthenticationMode(ESP_LE_AUTH_BOND);
// set report map
hid->reportMap((uint8_t*)REPORT_MAP, sizeof(REPORT_MAP));
hid->startServices();
// set battery level to 100%
hid->setBatteryLevel(100);
// advertise the services
BLEAdvertising* advertising = server->getAdvertising();
advertising->setAppearance(HID_KEYBOARD);
advertising->addServiceUUID(hid->hidService()->getUUID());
advertising->addServiceUUID(hid->deviceInfo()->getUUID());
advertising->addServiceUUID(hid->batteryService()->getUUID());
advertising->start();
Serial.println("BLE ready");
delay(portMAX_DELAY);
};
void typeText(const char* text) {
int len = strlen(text);
for (int i = 0; i < len; i++) {
// translate character to key combination
uint8_t val = (uint8_t)text[i];
if (val > KEYMAP_SIZE)
continue; // character not available on keyboard - skip
KEYMAP map = keymap[val];
// create input report
InputReport report = {
.modifiers = map.modifier,
.reserved = 0,
.pressedKeys = {
map.usage,
0, 0, 0, 0, 0
}
};
// send the input report
input->setValue((uint8_t*)&report, sizeof(report));
input->notify();
delay(5);
// release all keys between two characters; otherwise two identical
// consecutive characters are treated as just one key press
input->setValue((uint8_t*)&NO_KEY_PRESSED, sizeof(NO_KEY_PRESSED));
input->notify();
delay(5);
}
}
@Dreamcazman
Copy link

hello I'm not sure of what problem you are having but if you need help with the coding I would say that you might want to find someone who can help off of the website called fiverr when I have trouble with my coding I would always go to that website to find someone who can help me so you can try there

I think I explained my problem above well enough, who better to ask than the author. @manuelbl, can you assist please?

I want the Arduino to send a 'special key' (eg ESCAPE) when I press a button and not type ESCAPE instead, I hope that makes sense.

@legitlee
Copy link

legitlee commented Oct 15, 2023 via email

@manuelbl
Copy link
Author

@Dreamcazman If you want to send special keys, use the code at the beginning of this thread and combine it with the code for the special keys (see this post).

Then you need to modify loop(). The original code sends an entire string whenever the button is pressed (and Bluetooth is connected). It needs to be replaced with testing for your buttons and sending the correct key code. Assuming that Up and Down are the Arduino GPIO numbers for your buttons, the code will look something like this:

void loop() {  
    if (isBleConnected) {
        if (digitalRead(Up) == LOW) {
            sendKeyCode(KEY_UP);
        } else if (digitalRead(Down) == LOW) {
            sendKeyCode(KEY_DOWN);
        }
    }
    delay(50);
}

@Dreamcazman
Copy link

Dreamcazman commented Oct 15, 2023

@Dreamcazman If you want to send special keys, use the code at the beginning of this thread and combine it with the code for the special keys (see this post).

Then you need to modify loop(). The original code sends an entire string whenever the button is pressed (and Bluetooth is connected). It needs to be replaced with testing for your buttons and sending the correct key code. Assuming that Up and Down are the Arduino GPIO numbers for your buttons, the code will look something like this:

void loop() {  
    if (isBleConnected) {
        if (digitalRead(Up) == LOW) {
            sendKeyCode(KEY_UP);
        } else if (digitalRead(Down) == LOW) {
            sendKeyCode(KEY_DOWN);
        }
    }
    delay(50);
}

Thanks, however after seemingly getting nowhere I scrapped what I was doing, reinstalled and redownloaded the libraries. I found an adaptation of the BLEkeyboard code and actually got it working. It already had some keys set up, but after a lot of trial and error I realised I could use some decimal codes for the special keys.

Also added some debounce code

See my code below, it may help someone else out too.

#define USE_NIMBLE
#include <BleKeyboard.h>

BleKeyboard bleKeyboard;

#define Up 26
#define Down 27
#define Left 14
#define Right 12
#define Coin 13
#define Start 15
#define Spacebar 2
#define Enter 0
#define Escape 4

bool keyStates[9] = {false, false, false, false, false, false, false, false, false};
int keyPins[9] = {Up, Down, Left, Right, Coin, Start, Spacebar, Enter, Escape};
uint8_t keyCodes[9] = {(218), (217), (216), (215), '5', '1', (180), (176), (177)};


void setup() {
  Serial.begin(115200);
  Serial.println("Code running...");
  setInputs();
  bleKeyboard.begin();
}

bool connectNotificationSent = false;

void loop() {
  int counter;
  if(bleKeyboard.isConnected()) {
    if (!connectNotificationSent) {
      Serial.println("Code connected...");
      connectNotificationSent = true;
    }
    for(counter = 0; counter < 9; counter ++){
      handleButton(counter);
    }
  }
}

void setInputs() {
    pinMode(Up, INPUT_PULLUP);
    pinMode(Down, INPUT_PULLUP);
    pinMode(Left, INPUT_PULLUP);
    pinMode(Right, INPUT_PULLUP);
    pinMode(Coin, INPUT_PULLUP);
    pinMode(Start, INPUT_PULLUP);
    pinMode(Spacebar, INPUT_PULLUP);
    pinMode(Enter, INPUT_PULLUP);
    pinMode(Escape, INPUT_PULLUP);
}

unsigned long debounceButtons[9];
int intervalDebounce = 50;

void handleButton(int keyIndex){
  // handle the button press
 if (millis()- debounceButtons[keyIndex]>=intervalDebounce){ 
  if (!digitalRead(keyPins[keyIndex])){
    // button pressed
    if (!keyStates[keyIndex]){
      debounceButtons[keyIndex]= millis();
      // key not currently pressed
      keyStates[keyIndex] = true;
      bleKeyboard.press(keyCodes[keyIndex]);
    }
  }
  else {
    // button not pressed
    if (keyStates[keyIndex]){
      debounceButtons[keyIndex]= millis();
      // key currently pressed
      keyStates[keyIndex] = false;
      bleKeyboard.release(keyCodes[keyIndex]);
    }
  }
}
} 

@legitlee
Copy link

legitlee commented Oct 15, 2023 via email

@simplyrohan
Copy link

Are there any parts I can cut out to make the program size smaller? I don't have a lot of memory, and this uses up a lot of it. I don't need any special characters, numbers, or control keys. Just the basic, English, character set. I have a rough idea of how to do this, but I'm not sure... Thanks for any help, and this is a great example code!

@Dreamcazman
Copy link

Dreamcazman commented Dec 3, 2023

Are there any parts I can cut out to make the program size smaller? I don't have a lot of memory, and this uses up a lot of it. I don't need any special characters, numbers, or control keys. Just the basic, English, character set. I have a rough idea of how to do this, but I'm not sure... Thanks for any help, and this is a great example code!

I'm not sure, it's already fairly compact as it uses Nimble. You may be able to reduce the number of inputs or the debounce code could be removed but without it can cause phantom or unwanted button presses.

Other than that, maybe invest in an Arduino device with more available memory.

@simplyrohan
Copy link

simplyrohan commented Dec 3, 2023

You may be able to reduce the number of inputs

Any idea how I would do this? I see the InputReport struct and REPORT_MAP array, but I'm not sure what I would need to change...

@Dreamcazman
Copy link

Any idea how I would do this? I see the InputReport struct and REPORT_MAP array, but I'm not sure what I would need to change...

For example, if you want to remove the 'Spacebar' input, remove the following:

'#define Spacebar 2' and 'pinMode(Spacebar, INPUT_PULLUP);' lines

This part, remove one of the 'false' entries so there are only eight left, then remove 'Spacebar', it's corresponding key code and change the number from 9 to 8, so it looks like this:

bool keyStates[8] = {false, false, false, false, false, false, false, false};
int keyPins[8] = {Up, Down, Left, Right, Coin, Start, Enter, Escape};
uint8_t keyCodes[8] = {(218), (217), (216), (215), '5', '1', (176), (177)};

Then any other place in the code where it mentions '9' (like above), change it to how many inputs there are, ie. it's now 8.

Hope that makes sense.

@legitlee
Copy link

legitlee commented Dec 3, 2023 via email

@manuelbl
Copy link
Author

manuelbl commented Dec 3, 2023

@simplyrohan The code on this page is quite small. I doubt that any optimizations will make a relevant difference.

The major contributor to the code and RAM size is Bluetooth itself. It's a non-trivial protocol. The moment a single Bluetooth function is used, a large library is pulled in.

So if you need to shrink the code, focus on the Bluetooth library:

  • ESP-NimBLE is supposedly smaller than ESP-Bluedroid
  • Test if certain configuration options reduce flash and memory size, e.g. by turning of unnecessary features (e.g. no central role, reduced logging to get rid of logging messages in the code)

@sundarv74
Copy link

Hello,
Can we connect to two Android phones at the same time and send keys to both from the ESP32? May I request what modifications are needed and any possible code sample for the purpose?
Regards, Sundar.

@TechRelief
Copy link

Trying to make it work with an Espressif ESP32-S3-USB-OTG board it connects to bluetooth (windows 10) and responds when a button is pressed on the board and reaches the typeText() function which does its thing, but there is no ouput at all.
I put a Serial.print() statement to monitor what it is trying to output and for a typeText("abc") it outputs "456", but I am confused about the fact it has references to input->setValue should it not Output? Any thoughts?
Also where is the best way to read up on what it is actually trying to send (i.e. via bluetooth so I can perhaps try to debug this?

@TechRelief
Copy link

Ok so I seem to finally have it working; but I do not know why exactly but I did have to create a new board definition for ESP32-S3-USB-OTG and PlatformIO does not publish what the settings in the board JSON file are for, they tell you to look at existing board definitions for clues. So I copied some settings from other ESP32-S3 boards and somehow it started to work. I do have a question though:
At the end of the bluetoothTask() function it has: delay(portMAX_DELAY);
How does this work exactly? portMAX_DELAY is an unsigned 0xFFFFFFFF value which equates to a delay of 49 days in milliseconds? Is this a kludge to halt code execution here? If anyone knows please enlighten me, thanks...

@wvsbsp
Copy link

wvsbsp commented Dec 17, 2023

Works like a charm! Many thanks! I've been watching this project for a while.
Now i need a bit of hardware to scroll in a PDF file while playing an instrument. I needed only 3 control-keys KEY_PAGE_UP, KEY_PAGE_DOWN and KEY_F11. The longest it took me to find the names for the control keys. It would be a good idea to insert a link in the comment to
~\Arduino15\packages\esp32\hardware\esp32\2.0.14\libraries\BLE\src\HIDKeyboardTypes.h
That's all i had to program: ;-)
`bool bTaster0, bTaster2, bTaster4, oldTaster0, oldTaster2, oldTaster4;
void loop() {
bTaster0 = digitalRead(Taster0);
bTaster2 = digitalRead(Taster2);
bTaster4 = digitalRead(Taster4);

if (isBleConnected && bTaster2 == false && oldTaster2 == true) {
// button has been pressed: type message
//Serial.println(MESSAGE);
//typeText(MESSAGE);
char NewMessage[] = { KEY_PAGE_UP, 0 };
typeText(NewMessage);
}
if (isBleConnected && bTaster4 == false && oldTaster4 == true) {
// button has been pressed: type message
char NewMessage[] = { KEY_PAGE_DOWN, 0 };
typeText(NewMessage);
}
if (isBleConnected && bTaster0 == false && oldTaster0 == true) {
// button has been pressed: type message
char NewMessage[] = { KEY_F11, 0 };
typeText(NewMessage);
}
oldTaster0 = bTaster0;
oldTaster2 = bTaster2;
oldTaster4 = bTaster4;

delay(100);
}`

@HectorFraguas
Copy link

I'm trying to connect it with an Android device and it connects correctly but I can't get the volume up and volume down keys to work, has anyone got something like that?

@arvebjoe
Copy link

arvebjoe commented Mar 5, 2024

I can't get the media play/pause keys to work. Other keys like arrow up or down work fine. I've tried 0x48 (KEY_PAUSE) and 0xB3 (after searching online). Any suggestions?

Example:
sendKeyCode(KEY_PAUSE); // doesn't work
sendKeyCode(0xB3); // doesn't work
sendKeyCode(KEY_DOWN); // works fine

@intg76
Copy link

intg76 commented May 25, 2024

Great example, but i can't understand, can this library send combo like "win+shift+KEY_RIGHT"? How to do it?

@drowe
Copy link

drowe commented Jun 4, 2024

This example works great! One bit I'd add for future folks that find this - I had the issue where if my phone/device disconnected, it would leave the ESP32 in a stuck state - unable to reconnect for anything. Found in a related issue about restarting the advertising on client disconnected - so, I added

Serial.println("Restarting advertising...");
server->getAdvertising()->start();

in the onDisconnect method (line 154) - and if my device disconnected (turned off) it would auto-reconnect because the ESP32 would start advertising again.

@OneDuckyBoy
Copy link

Is it possible to use it as media controls?(play/pause, volume up and down, previous and next song)
I tryed unsuccessfully to use

void sendKeyCode(uint8_t keyCode) {
    // create input report
    InputReport report = {
        .modifiers = 0,
        .reserved = 0,
        .pressedKeys = { keyCode, 0, 0, 0, 0, 0 }
    };

    // send the input report
    input->setValue((uint8_t*)&report, sizeof(report));
    input->notify();
    delay(5);

    // release all keys
    input->setValue((uint8_t*)&NO_KEY_PRESSED, sizeof(NO_KEY_PRESSED));
    input->notify();
    delay(5);
}

and 
sendKeyCode(playpause);
#define playpause 0xCD 

I asked chatGPT for help and it gave me

struct ConsumerReport {
    uint16_t usage;
};

const ConsumerReport NO_CONSUMER_KEY_PRESSED = { 0x0000 };

void sendConsumerKey(uint16_t usage) {
    // Create consumer control report
    ConsumerReport report = { usage };

    // Send the consumer control report
    input->setValue((uint8_t*)&report, sizeof(report));
    input->notify();
    delay(5);

    // Release all keys
    input->setValue((uint8_t*)&NO_CONSUMER_KEY_PRESSED, sizeof(NO_CONSUMER_KEY_PRESSED));
    input->notify();
    delay(5);
}

whitch didn`t work either

I may be the problem, because I don't entirely understand the code and don't know how to fix it

I would be super grateful if there is somebody who would be able to help!

@alanmiller
Copy link

alanmiller commented Jul 7, 2024

@manuelbl You got me right. Your short example is very good, because now I really understand that function more. Thank You! Maybe this is interesting: With some AI help I modified the function so that it accepts this format:
.....
This allows to read in commands with variable modifiers. Thank you for your elegant code! I would also like to publish my project on github and I would add your license. Could I do so? All the Best!

@ctc-nick
I'd like to implement the same but net well versed in cpp, could you share how you are storing your mappings in Json? ie what library are you using for that? Does you code actually load a json file? Does that file get copied to the ESP32 device or just compiled into the image?

@legitlee
Copy link

legitlee commented Jul 8, 2024 via email

@alanmiller
Copy link

Thanks @legitlee but I was asking @ctc-nick how/which json library he was using for the mapping buttons to pins.
I figured out my own solution in plain C using an array of structs. I am creating a control box for my golf simulator and have 13 buttons.

I defined the pins and keycodes in a header file

#define CLUB_UP_PIN      13 // gpio 13
#define CLUB_DOWN_PIN    12 // gpio 12
#define KEY_CLUB_UP      0x0c // letter i
#define KEY_CLUB_DOWN    0x0e // letter k

then in main I have

typedef struct {
    std::string name;
    int pin;
    uint8_t keycode;
    uint8_t modifier;
    bool state;
} Button;

Button buttons[BUTTONS] = {
    {"Club-Up",      CLUB_UP_PIN,     KEY_CLUB_UP,     KEY_NONE,  false},
    {"Club-Down",    CLUB_DOWN_PIN,   KEY_CLUB_DOWN,   KEY_NONE,  false},
    {"Fly-Over",     FLYOVER_PIN,     KEY_FLYOVER,     KEY_NONE,  false},
    {"Scorecard",    SCORECARD_PIN,   KEY_SCORECARD,   KEY_NONE,  false},
    {"Range-Finder", RANGE_FINDER_PIN,KEY_RANGE_FINDER,KEY_NONE,  false},
    {"Next-Hole",    HOLE_UP_PIN,     KEY_HOLE_UP,     KEY_NONE,  false},
    {"Previous-Hole",HOLE_DOWN_PIN,   KEY_HOLE_DOWN,   KEY_NONE,  false},
    {"Aim-Left",     AIM_LEFT_PIN,    KEY_AIM_LEFT,    KEY_NONE,  false},
    {"Aim-Right",    AIM_RIGHT_PIN,   KEY_AIM_RIGHT,   KEY_NONE,  false},
    {"Aim-Down",     AIM_DOWN_PIN,    KEY_AIM_DOWN,    KEY_NONE,  false},
    {"Aim-Up",       AIM_UP_PIN,      KEY_AIM_UP,      KEY_NONE,  false},
    {"Mulligan",     MULLIGAN_PIN,    KEY_MULLIGAN,    KEY_LCTRL, false},
    {"Aimpoint",     AIMPOINT_PIN,    KEY_AIMPOINT,    KEY_NONE,  false}
};

then in setup()

int i;
    for(i = 0; i < BUTTONS; i ++) {
        pinMode(buttons[i].pin,INPUT_PULLUP);
    }

and in loop() I call

sendKeyCode(buttons[keyIndex].keycode,buttons[keyIndex].modifier);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment