From a2c455be42da108befb116f673bc95d2e6bed555 Mon Sep 17 00:00:00 2001 From: T-vK Date: Thu, 8 Aug 2019 08:00:00 +0000 Subject: [PATCH] Attempt to fix the device descriptor and media keys support --- BleKeyboard.cpp | 129 ++++++++++++--------- BleKeyboard.h | 8 +- README.md | 5 + examples/SendKeyStrokes/SendKeyStrokes.ino | 42 +++++-- 4 files changed, 113 insertions(+), 71 deletions(-) diff --git a/BleKeyboard.cpp b/BleKeyboard.cpp index d35bc40..4a8769f 100644 --- a/BleKeyboard.cpp +++ b/BleKeyboard.cpp @@ -20,59 +20,66 @@ static const char* LOG_TAG = "BLEDevice"; #endif + +// Report IDs: +char KEYBOARD_ID = 0x01; +char MEDIA_KEYS_ID = 0x02; + static const uint8_t _hidReportDescriptor[] = { - USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop Ctrls) - USAGE(1), 0x06, // USAGE (Keyboard) - COLLECTION(1), 0x01, // COLLECTION (Application) - REPORT_ID(1), 0x01, // REPORT_ID (2) - USAGE_PAGE(1), 0x07, // USAGE_PAGE (Kbrd/Keypad) - USAGE_MINIMUM(1), 0xE0, // USAGE_MINIMUM (0xE0) - USAGE_MAXIMUM(1), 0xE7, // USAGE_MAXIMUM (0xE7) - LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) - LOGICAL_MAXIMUM(1), 0x01, // Logical Maximum (1) - REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) - REPORT_COUNT(1), 0x08, // REPORT_COUNT (8) - HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) ; 1 byte (Reserved) - REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) - HIDINPUT(1), 0x01, // INPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - REPORT_COUNT(1), 0x05, // REPORT_COUNT (5) ; 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana) - REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) - USAGE_PAGE(1), 0x08, // USAGE_PAGE (LEDs) - USAGE_MINIMUM(1), 0x01, // USAGE_MINIMUM (0x01) ; Num Lock - USAGE_MAXIMUM(1), 0x05, // USAGE_MAXIMUM (0x05) ; Kana - HIDOUTPUT(1), 0x02, // OUTPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) ; 3 bits (Padding) - REPORT_SIZE(1), 0x03, // REPORT_SIZE (3) - HIDOUTPUT(1), 0x01, // OUTPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) - REPORT_COUNT(1), 0x06, // REPORT_COUNT (6) ; 6 bytes (Keys) - REPORT_SIZE(1), 0x08, // REPORT_SIZE(8) - LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM(0) - LOGICAL_MAXIMUM(1), 0x65, // LOGICAL_MAXIMUM(0x65) ; 101 keys - USAGE_PAGE(1), 0x07, // USAGE_PAGE (Kbrd/Keypad) - USAGE_MINIMUM(1), 0x00, // USAGE_MINIMUM (0) - USAGE_MAXIMUM(1), 0x65, // USAGE_MAXIMUM (0x65) - HIDINPUT(1), 0x00, // INPUT (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) - END_COLLECTION(0), // END_COLLECTION - USAGE_PAGE(1), 0x0C, // USAGE_PAGE (Consumer) - USAGE(1), 0x01, // USAGE (Consumer Control) - COLLECTION(1), 0x01, // COLLECTION (Application) - REPORT_ID(2), 0x02, // REPORT_ID (2) - USAGE_PAGE(1), 0x0C, // USAGE_PAGE (Consumer) - LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) - LOGICAL_MAXIMUM(1), 0x01, // LOGICAL_MAXIMUM (1) - REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) - REPORT_COUNT(1), 0x07, // REPORT_COUNT (7) - USAGE(1), 0xB5, // USAGE (Scan Next Track) - USAGE(1), 0xB6, // USAGE (Scan Previous Track) - USAGE(1), 0xB7, // USAGE (Stop) - USAGE(1), 0xB8, // USAGE (Eject) - USAGE(1), 0xCD, // USAGE (Play/Pause) - USAGE(1), 0xE2, // USAGE (Mute) - USAGE(1), 0xE9, // USAGE (Volume Increment) - USAGE(1), 0xEA, // USAGE (Volume Decrement) - HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) - END_COLLECTION(0) // END_COLLECTION + USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop Ctrls) + USAGE(1), 0x06, // USAGE (Keyboard) + COLLECTION(1), 0x01, // COLLECTION (Application) + // ------------------------------------------------- Keyboard + REPORT_ID(1), KEYBOARD_ID, // REPORT_ID (1) + USAGE_PAGE(1), 0x07, // USAGE_PAGE (Kbrd/Keypad) + USAGE_MINIMUM(1), 0xE0, // USAGE_MINIMUM (0xE0) + USAGE_MAXIMUM(1), 0xE7, // USAGE_MAXIMUM (0xE7) + LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) + LOGICAL_MAXIMUM(1), 0x01, // Logical Maximum (1) + REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) + REPORT_COUNT(1), 0x08, // REPORT_COUNT (8) + HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) ; 1 byte (Reserved) + REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) + HIDINPUT(1), 0x01, // INPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + REPORT_COUNT(1), 0x05, // REPORT_COUNT (5) ; 5 bits (Num lock, Caps lock, Scroll lock, Compose, Kana) + REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) + USAGE_PAGE(1), 0x08, // USAGE_PAGE (LEDs) + USAGE_MINIMUM(1), 0x01, // USAGE_MINIMUM (0x01) ; Num Lock + USAGE_MAXIMUM(1), 0x05, // USAGE_MAXIMUM (0x05) ; Kana + HIDOUTPUT(1), 0x02, // OUTPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) ; 3 bits (Padding) + REPORT_SIZE(1), 0x03, // REPORT_SIZE (3) + HIDOUTPUT(1), 0x01, // OUTPUT (Const,Array,Abs,No Wrap,Linear,Preferred State,No Null Position,Non-volatile) + REPORT_COUNT(1), 0x06, // REPORT_COUNT (6) ; 6 bytes (Keys) + REPORT_SIZE(1), 0x08, // REPORT_SIZE(8) + LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM(0) + LOGICAL_MAXIMUM(1), 0x65, // LOGICAL_MAXIMUM(0x65) ; 101 keys + USAGE_PAGE(1), 0x07, // USAGE_PAGE (Kbrd/Keypad) + USAGE_MINIMUM(1), 0x00, // USAGE_MINIMUM (0) + USAGE_MAXIMUM(1), 0x65, // USAGE_MAXIMUM (0x65) + HIDINPUT(1), 0x00, // INPUT (Data,Array,Abs,No Wrap,Linear,Preferred State,No Null Position) + END_COLLECTION(0), // END_COLLECTION + USAGE_PAGE(1), 0x0C, // USAGE_PAGE (Consumer) + USAGE(1), 0x01, // USAGE (Consumer Control) + COLLECTION(1), 0x01, // COLLECTION (Application) + // ------------------------------------------------- Media Keys + REPORT_ID(1), MEDIA_KEYS_ID, // REPORT_ID (2) + USAGE_PAGE(1), 0x0C, // USAGE_PAGE (Consumer) + LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) + LOGICAL_MAXIMUM(1), 0x01, // LOGICAL_MAXIMUM (1) + REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) + REPORT_COUNT(1), 0x07, // REPORT_COUNT (7) + USAGE(1), 0xB5, // USAGE (Scan Next Track) + USAGE(1), 0xB6, // USAGE (Scan Previous Track) + USAGE(1), 0xB7, // USAGE (Stop) + USAGE(1), 0xB8, // USAGE (Eject) + USAGE(1), 0xCD, // USAGE (Play/Pause) + USAGE(1), 0xE2, // USAGE (Mute) + USAGE(1), 0xE9, // USAGE (Volume Increment) + USAGE(1), 0xEA, // USAGE (Volume Decrement) + HIDINPUT(1), 0x02, // INPUT (Data,Var,Abs,No Wrap,Linear,Preferred State,No Null Position) + END_COLLECTION(0) // END_COLLECTION }; BleKeyboard::BleKeyboard(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) : _buttons(0) @@ -115,12 +122,20 @@ void BleKeyboard::releaseAll(void) } */ -void BleKeyboard::sendReport(KeyReport* keys) +void BleKeyboard::sendReport(KeyReport* keys, char reportId) { if (this->isConnected()) { - this->inputKeyboard->setValue((uint8_t*)keys, sizeof(KeyReport)); - this->inputKeyboard->notify(); + if (reportId == KEYBOARD_ID) + { + this->inputKeyboard->setValue((uint8_t*)keys, sizeof(KeyReport)); + this->inputKeyboard->notify(); + } + else if (reportId == MEDIA_KEYS_ID) + { + this->inputMediaKeys->setValue((uint8_t*)keys, sizeof(MediaKeyReport)); + this->inputMediaKeys->notify(); + } } } @@ -130,7 +145,6 @@ bool BleKeyboard::isConnected(void) { void BleKeyboard::setBatteryLevel(uint8_t level) { this->batteryLevel = level; - this->hid->setBatteryLevel(level); } void BleKeyboard::taskServer(void* pvParameter) { @@ -141,7 +155,8 @@ void BleKeyboard::taskServer(void* pvParameter) { bleKeyboardInstance->hid = new BLEHIDDevice(pServer); bleKeyboardInstance->inputKeyboard = bleKeyboardInstance->hid->inputReport(1); // <-- input REPORTID from report map - bleKeyboardInstance->outputKeyboard = bleKeyboardInstance->hid->outputReport(1); + bleKeyboardInstance->outputKeyboard = bleKeyboardInstance->hid->outputReport(KEYBOARD_ID); + bleKeyboardInstance->inputMediaKeys = bleKeyboardInstance->hid->inputReport(MEDIA_KEYS_ID); bleKeyboardInstance->connectionStatus->inputKeyboard = bleKeyboardInstance->inputKeyboard; bleKeyboardInstance->connectionStatus->outputKeyboard = bleKeyboardInstance->outputKeyboard; diff --git a/BleKeyboard.h b/BleKeyboard.h index 1d93f04..bc130c1 100644 --- a/BleKeyboard.h +++ b/BleKeyboard.h @@ -15,6 +15,8 @@ typedef struct uint8_t keys[6]; } KeyReport; +typedef uint8_t MediaKeyReport[2]; + class BleKeyboard { private: uint8_t _buttons; @@ -22,14 +24,16 @@ private: BLEHIDDevice* hid; BLECharacteristic* inputKeyboard; BLECharacteristic* outputKeyboard; + BLECharacteristic* inputMediaKeys; KeyReport _keyReport; + MediaKeyReport _mediaKeyReport; void buttons(uint8_t b); static void taskServer(void* pvParameter); public: - BleKeyboard(std::string deviceName = "Espressif", std::string deviceManufacturer = "ESP32 Bluetooth Keyboard", uint8_t batteryLevel = 100); + BleKeyboard(std::string deviceName = "ESP32 Bluetooth Keyboard", std::string deviceManufacturer = "Espressif", uint8_t batteryLevel = 100); void begin(void); void end(void); - void sendReport(KeyReport* keys); + void sendReport(KeyReport* keys, char reportId=1); //size_t write(uint8_t k); //size_t write(const uint8_t *buffer, size_t size); //size_t press(uint8_t k); diff --git a/README.md b/README.md index 2afbc4b..a276630 100644 --- a/README.md +++ b/README.md @@ -72,6 +72,11 @@ Just remember that you have to use `bleKeyboard` instead of just `Keyboard` and BleKeyboard bleKeyboard; ``` +There is also Bluetooth specific information that you can set (optional): +Instead of `BleKeyboard bleKeyboard;` you can do `BleKeyboard bleKeyboard("Bluetooth Device Name", "Bluetooth Device Manufacturer", 100);`. +The third parameter is the initial battery level of your device. To adjust the battery level later on you can simply call e.g. `bleKeyboard.setBatteryLevel(50)` (set battery level to 50%). +By default the battery level will be set to 100%, the device name will be `ESP32 Bluetooth Mouse` and the manufacturer will be `Espressif`. + ## Credits Credits to [chegewara](https://github.com/chegewara) as this library is based on [this piece of code](https://github.com/nkolban/esp32-snippets/issues/230#issuecomment-473135679) that he provided. \ No newline at end of file diff --git a/examples/SendKeyStrokes/SendKeyStrokes.ino b/examples/SendKeyStrokes/SendKeyStrokes.ino index aba2499..14b5d97 100644 --- a/examples/SendKeyStrokes/SendKeyStrokes.ino +++ b/examples/SendKeyStrokes/SendKeyStrokes.ino @@ -13,17 +13,17 @@ void setup() { void loop() { if(bleKeyboard.isConnected()) { - Serial.println("Pressing the a-key via the Bluetooth keyboard"); + Serial.println("Pressing the a-key via the Bluetooth keyboard..."); KeyReport keyReport; keyReport.modifiers = 0x00; keyReport.reserved = 0x00; - keyReport.keys[0] = 0x61; // a-key - keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; + keyReport.keys[0] = 0x04; // "a" + keyReport.keys[1] = 0x00; + keyReport.keys[2] = 0x00; + keyReport.keys[3] = 0x00; + keyReport.keys[4] = 0x00; + keyReport.keys[5] = 0x00; bleKeyboard.sendReport(&keyReport); // a-key down @@ -33,14 +33,32 @@ void loop() { keyReport.modifiers = 0x00; keyReport.reserved = 0x00; keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; - keyReport.keys[0] = 0x00; + keyReport.keys[1] = 0x00; + keyReport.keys[2] = 0x00; + keyReport.keys[3] = 0x00; + keyReport.keys[4] = 0x00; + keyReport.keys[5] = 0x00; bleKeyboard.sendReport(&keyReport2); // a-key up + + delay(1000); + + + Serial.println("Pressing the play/pause-key via the Bluetooth keyboard..."); + + MediaKeyReport mediaKeyReport; + mediaKeyReport[0] = 0xcd; // play/pause + mediaKeyReport[1] = 0x00; + bleKeyboard.sendReport(&keyReport); // play/pause-key down + + delay(50); + + MediaKeyReport mediaKeyReport2; + mediaKeyReport2[0] = 0x00; + mediaKeyReport2[1] = 0x00; + bleKeyboard.sendReport(&keyReport2); // play/pause-key up + } delay(5000); } \ No newline at end of file