diff --git a/ESP32-BLE-Mouse-S3/BleConnectionStatus.cpp b/ESP32-BLE-Mouse-S3/BleConnectionStatus.cpp new file mode 100644 index 0000000..f01183b --- /dev/null +++ b/ESP32-BLE-Mouse-S3/BleConnectionStatus.cpp @@ -0,0 +1,18 @@ +#include "BleConnectionStatus.h" + +BleConnectionStatus::BleConnectionStatus(void) { +} + +void BleConnectionStatus::onConnect(BLEServer* pServer) +{ + this->connected = true; + BLE2902* desc = (BLE2902*)this->inputMouse->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); + desc->setNotifications(true); +} + +void BleConnectionStatus::onDisconnect(BLEServer* pServer) +{ + this->connected = false; + BLE2902* desc = (BLE2902*)this->inputMouse->getDescriptorByUUID(BLEUUID((uint16_t)0x2902)); + desc->setNotifications(false); +} diff --git a/ESP32-BLE-Mouse-S3/BleConnectionStatus.h b/ESP32-BLE-Mouse-S3/BleConnectionStatus.h new file mode 100644 index 0000000..b703150 --- /dev/null +++ b/ESP32-BLE-Mouse-S3/BleConnectionStatus.h @@ -0,0 +1,21 @@ +#ifndef ESP32_BLE_CONNECTION_STATUS_H +#define ESP32_BLE_CONNECTION_STATUS_H +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) + +#include +#include "BLE2902.h" +#include "BLECharacteristic.h" + +class BleConnectionStatus : public BLEServerCallbacks +{ +public: + BleConnectionStatus(void); + bool connected = false; + void onConnect(BLEServer* pServer); + void onDisconnect(BLEServer* pServer); + BLECharacteristic* inputMouse; +}; + +#endif // CONFIG_BT_ENABLED +#endif // ESP32_BLE_CONNECTION_STATUS_H diff --git a/ESP32-BLE-Mouse-S3/BleMouse.cpp b/ESP32-BLE-Mouse-S3/BleMouse.cpp new file mode 100644 index 0000000..7c49355 --- /dev/null +++ b/ESP32-BLE-Mouse-S3/BleMouse.cpp @@ -0,0 +1,161 @@ +#include +#include +#include +#include "BLE2902.h" +#include "BLEHIDDevice.h" +#include "HIDTypes.h" +#include "HIDKeyboardTypes.h" +#include +#include "sdkconfig.h" +#include "BleConnectionStatus.h" +#include "BleMouse.h" +#if defined(CONFIG_ARDUHAL_ESP_LOG) + #include "esp32-hal-log.h" + #define LOG_TAG "" +#else + #include "esp_log.h" + static const char* LOG_TAG = "BLEDevice"; +#endif +static const uint8_t _hidReportDescriptor[] = { + USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop) + USAGE(1), 0x02, // USAGE (Mouse) + COLLECTION(1), 0x01, // COLLECTION (Application) + USAGE(1), 0x01, // USAGE (Pointer) + COLLECTION(1), 0x00, // COLLECTION (Physical) + // ------------------------------------------------- Buttons (Left, Right, Middle, Back, Forward) + USAGE_PAGE(1), 0x09, // USAGE_PAGE (Button) + USAGE_MINIMUM(1), 0x01, // USAGE_MINIMUM (Button 1) + USAGE_MAXIMUM(1), 0x05, // USAGE_MAXIMUM (Button 5) + LOGICAL_MINIMUM(1), 0x00, // LOGICAL_MINIMUM (0) + LOGICAL_MAXIMUM(1), 0x01, // LOGICAL_MAXIMUM (1) + REPORT_SIZE(1), 0x01, // REPORT_SIZE (1) + REPORT_COUNT(1), 0x05, // REPORT_COUNT (5) + HIDINPUT(1), 0x02, // INPUT (Data, Variable, Absolute) ;5 button bits + // ------------------------------------------------- Padding + REPORT_SIZE(1), 0x03, // REPORT_SIZE (3) + REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) + HIDINPUT(1), 0x03, // INPUT (Constant, Variable, Absolute) ;3 bit padding + // ------------------------------------------------- X/Y position, Wheel + USAGE_PAGE(1), 0x01, // USAGE_PAGE (Generic Desktop) + USAGE(1), 0x30, // USAGE (X) + USAGE(1), 0x31, // USAGE (Y) + USAGE(1), 0x38, // USAGE (Wheel) + LOGICAL_MINIMUM(1), 0x81, // LOGICAL_MINIMUM (-127) + LOGICAL_MAXIMUM(1), 0x7f, // LOGICAL_MAXIMUM (127) + REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) + REPORT_COUNT(1), 0x03, // REPORT_COUNT (3) + HIDINPUT(1), 0x06, // INPUT (Data, Variable, Relative) ;3 bytes (X,Y,Wheel) + // ------------------------------------------------- Horizontal wheel + USAGE_PAGE(1), 0x0c, // USAGE PAGE (Consumer Devices) + USAGE(2), 0x38, 0x02, // USAGE (AC Pan) + LOGICAL_MINIMUM(1), 0x81, // LOGICAL_MINIMUM (-127) + LOGICAL_MAXIMUM(1), 0x7f, // LOGICAL_MAXIMUM (127) + REPORT_SIZE(1), 0x08, // REPORT_SIZE (8) + REPORT_COUNT(1), 0x01, // REPORT_COUNT (1) + HIDINPUT(1), 0x06, // INPUT (Data, Var, Rel) + END_COLLECTION(0), // END_COLLECTION + END_COLLECTION(0) // END_COLLECTION +}; + +BleMouse::BleMouse(std::string deviceName, std::string deviceManufacturer, uint8_t batteryLevel) : + _buttons(0), + hid(0) +{ + this->deviceName = deviceName; + this->deviceManufacturer = deviceManufacturer; + this->batteryLevel = batteryLevel; + this->connectionStatus = new BleConnectionStatus(); +} +void BleMouse::begin(void) +{ + xTaskCreate(this->taskServer, "server", 20000, (void *)this, 5, NULL); +} + +void BleMouse::end(void) +{ +} + +void BleMouse::click(uint8_t b) +{ + _buttons = b; + move(0,0,0,0); + _buttons = 0; + move(0,0,0,0); +} + +void BleMouse::move(signed char x, signed char y, signed char wheel, signed char hWheel) +{ + if (this->isConnected()) + { + uint8_t m[5]; + m[0] = _buttons; + m[1] = x; + m[2] = y; + m[3] = wheel; + m[4] = hWheel; + this->inputMouse->setValue(m, 5); + this->inputMouse->notify(); + } +} + +void BleMouse::buttons(uint8_t b) +{ + if (b != _buttons) + { + _buttons = b; + move(0,0,0,0); + } +} + +void BleMouse::press(uint8_t b) +{ + buttons(_buttons | b); +} + +void BleMouse::release(uint8_t b) +{ + buttons(_buttons & ~b); +} + +bool BleMouse::isPressed(uint8_t b) +{ + if ((b & _buttons) > 0) + return true; + return false; +} + +bool BleMouse::isConnected(void) { + return this->connectionStatus->connected; +} + +void BleMouse::setBatteryLevel(uint8_t level) { + this->batteryLevel = level; + if (hid != 0) + this->hid->setBatteryLevel(this->batteryLevel); +} + +void BleMouse::taskServer(void* pvParameter) { + BleMouse* bleMouseInstance = (BleMouse *) pvParameter; //static_cast(pvParameter); + BLEDevice::init(bleMouseInstance->deviceName); + BLEServer *pServer = BLEDevice::createServer(); + pServer->setCallbacks(bleMouseInstance->connectionStatus); + bleMouseInstance->hid = new BLEHIDDevice(pServer); + bleMouseInstance->inputMouse = bleMouseInstance->hid->inputReport(0); // <-- input REPORTID from report map + bleMouseInstance->connectionStatus->inputMouse = bleMouseInstance->inputMouse; + bleMouseInstance->hid->manufacturer()->setValue(bleMouseInstance->deviceManufacturer); + bleMouseInstance->hid->pnp(0x02, 0xe502, 0xa111, 0x0210); + bleMouseInstance->hid->hidInfo(0x00,0x02); + BLESecurity *pSecurity = new BLESecurity(); + pSecurity->setAuthenticationMode(ESP_LE_AUTH_BOND); + bleMouseInstance->hid->reportMap((uint8_t*)_hidReportDescriptor, sizeof(_hidReportDescriptor)); + bleMouseInstance->hid->startServices(); + bleMouseInstance->onStarted(pServer); + BLEAdvertising *pAdvertising = pServer->getAdvertising(); + pAdvertising->setAppearance(HID_MOUSE); + pAdvertising->addServiceUUID(bleMouseInstance->hid->hidService()->getUUID()); + pAdvertising->start(); + bleMouseInstance->hid->setBatteryLevel(bleMouseInstance->batteryLevel); + ESP_LOGD(LOG_TAG, "Advertising started!"); + vTaskDelay(portMAX_DELAY); //delay(portMAX_DELAY); +} + diff --git a/ESP32-BLE-Mouse-S3/BleMouse.h b/ESP32-BLE-Mouse-S3/BleMouse.h new file mode 100644 index 0000000..76def87 --- /dev/null +++ b/ESP32-BLE-Mouse-S3/BleMouse.h @@ -0,0 +1,43 @@ +#ifndef ESP32_BLE_MOUSE_H +#define ESP32_BLE_MOUSE_H +#include "sdkconfig.h" +#if defined(CONFIG_BT_ENABLED) +#include "BleConnectionStatus.h" +#include "BLEHIDDevice.h" +#include "BLECharacteristic.h" +#define MOUSE_LEFT 1 +#define MOUSE_RIGHT 2 +#define MOUSE_MIDDLE 4 +#define MOUSE_BACK 8 +#define MOUSE_FORWARD 16 +#define MOUSE_ALL (MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE) // For compatibility with the Mouse library + +class BleMouse { +private: + uint8_t _buttons; + BleConnectionStatus* connectionStatus; + BLEHIDDevice* hid; + BLECharacteristic* inputMouse; + void buttons(uint8_t b); + void rawAction(uint8_t msg[], char msgSize); + static void taskServer(void* pvParameter); +public: + BleMouse(std::string deviceName = "ESP32 Bluetooth Mouse", std::string deviceManufacturer = "Espressif", uint8_t batteryLevel = 100); + void begin(void); + void end(void); + void click(uint8_t b = MOUSE_LEFT); + void move(signed char x, signed char y, signed char wheel = 0, signed char hWheel = 0); + void press(uint8_t b = MOUSE_LEFT); // press LEFT by default + void release(uint8_t b = MOUSE_LEFT); // release LEFT by default + bool isPressed(uint8_t b = MOUSE_LEFT); // check LEFT by default + bool isConnected(void); + void setBatteryLevel(uint8_t level); + uint8_t batteryLevel; + std::string deviceManufacturer; + std::string deviceName; +protected: + virtual void onStarted(BLEServer *pServer) { }; +}; + +#endif // CONFIG_BT_ENABLED +#endif // ESP32_BLE_MOUSE_H diff --git a/ESP32-BLE-Mouse-S3/README.md b/ESP32-BLE-Mouse-S3/README.md new file mode 100644 index 0000000..ab03117 --- /dev/null +++ b/ESP32-BLE-Mouse-S3/README.md @@ -0,0 +1,83 @@ +# ESP32 BLE Mouse library + +This library allows you to make the ESP32 act as a Bluetooth Mouse and control what it does. E.g. move the mouse, scroll, make a click etc. + +You might also be interested in: +- [ESP32-BLE-Abs-Mouse](https://github.com/sobrinho/ESP32-BLE-Abs-Mouse) +- [ESP32-BLE-Keyboard](https://github.com/T-vK/ESP32-BLE-Keyboard) +- [ESP32-BLE-Gamepad](https://github.com/lemmingDev/ESP32-BLE-Gamepad) + +## Features + + - [x] Left click + - [x] Right click + - [x] Middle click + - [x] Back/Forwards click + - [x] Move mouse pointer left/right + - [x] Move mouse pointer up/down + - [x] Scroll up/down + - [x] Scroll left/right + - [x] Report optional battery level to host (basically works, but it doesn't show up in Android's status bar) + - [x] Customize Bluetooth device name/manufacturer + - [x] Compatible with Android + - [x] Compatible with Windows + - [x] Compatible with Linux + - [x] Compatible with MacOS X (not stable, some people have issues, doesn't work with old devices) + - [x] Compatible with iOS (not stable, some people have issues, doesn't work with old devices) + +## Installation +- (Make sure you can use the ESP32 with the Arduino IDE. [Instructions can be found here.](https://github.com/espressif/arduino-esp32#installation-instructions)) +- [Download the latest release of this library from the release page.](https://github.com/T-vK/ESP32-BLE-Mouse/releases) +- In the Arduino IDE go to "Sketch" -> "Include Library" -> "Add .ZIP Library..." and select the file you just downloaded. +- You can now go to "File" -> "Examples" -> "ESP32 BLE Mouse" and select any of the examples to get started. + +## Example + +``` C++ +/** + * This example turns the ESP32 into a Bluetooth LE mouse that scrolls down every 2 seconds. + */ +#include + +BleMouse bleMouse; + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + bleMouse.begin(); +} + +void loop() { + if(bleMouse.isConnected()) { + Serial.println("Scroll Down"); + bleMouse.move(0,0,-1); + } + delay(2000); +} +``` + +## API docs +The BleMouse interface is almost identical to the Mouse Interface, so you can use documentation right here: +https://www.arduino.cc/reference/en/language/functions/usb/mouse/ + +Just remember that you have to use `bleMouse` instead of just `Mouse` and you need these two lines at the top of your script: +``` +#include +BleMouse bleMouse; +``` + +This library supports a few additional features that the Mouse library does not support at the time of writing: + +- Scrolling left/right E.g.: `bleMouse.move(0,0,0,1)` (Scroll left) and `bleMouse.move(0,0,0,-1)` (Scroll right) +- Using the back and forward buttons E.g.: `bleMouse.click(MOUSE_BACK)` and `bleMouse.click(MOUSE_FORWARD)` + +There is also Bluetooth specific information that you can use (optional): + +Instead of `BleMouse bleMouse;` you can do `BleMouse bleMouse("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. `bleMouse.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. diff --git a/ESP32-BLE-Mouse-S3/examples/MouseButtons/MouseButtons.ino b/ESP32-BLE-Mouse-S3/examples/MouseButtons/MouseButtons.ino new file mode 100644 index 0000000..2859377 --- /dev/null +++ b/ESP32-BLE-Mouse-S3/examples/MouseButtons/MouseButtons.ino @@ -0,0 +1,45 @@ +/** + * This example turns the ESP32 into a Bluetooth LE mouse that continuously moves the mouse. + */ +#include + +BleMouse bleMouse; + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + bleMouse.begin(); +} + +void loop() { + if(bleMouse.isConnected()) { + Serial.println("Left click"); + bleMouse.click(MOUSE_LEFT); + delay(500); + + Serial.println("Right click"); + bleMouse.click(MOUSE_RIGHT); + delay(500); + + Serial.println("Scroll wheel click"); + bleMouse.click(MOUSE_MIDDLE); + delay(500); + + Serial.println("Back button click"); + bleMouse.click(MOUSE_BACK); + delay(500); + + Serial.println("Forward button click"); + bleMouse.click(MOUSE_FORWARD); + delay(500); + + Serial.println("Click left+right mouse button at the same time"); + bleMouse.click(MOUSE_LEFT | MOUSE_RIGHT); + delay(500); + + Serial.println("Click left+right mouse button and scroll wheel at the same time"); + bleMouse.click(MOUSE_LEFT | MOUSE_RIGHT | MOUSE_MIDDLE); + delay(500); + + } +} \ No newline at end of file diff --git a/ESP32-BLE-Mouse-S3/examples/ScrollAndMoveMouse/ScrollAndMoveMouse.ino b/ESP32-BLE-Mouse-S3/examples/ScrollAndMoveMouse/ScrollAndMoveMouse.ino new file mode 100644 index 0000000..492beb5 --- /dev/null +++ b/ESP32-BLE-Mouse-S3/examples/ScrollAndMoveMouse/ScrollAndMoveMouse.ino @@ -0,0 +1,84 @@ +/** + * This example turns the ESP32 into a Bluetooth LE mouse that continuously moves the mouse. + */ +#include + +BleMouse bleMouse; + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + bleMouse.begin(); +} + +void loop() { + if(bleMouse.isConnected()) { + + unsigned long startTime; + + Serial.println("Scroll up"); + startTime = millis(); + while(millis() + +BleMouse bleMouse; + +void setup() { + Serial.begin(115200); + Serial.println("Starting BLE work!"); + bleMouse.begin(); +} + +void loop() { + if(bleMouse.isConnected()) { + Serial.println("Scroll Down"); + bleMouse.move(0,0,-1); + } + delay(2000); +} diff --git a/ESP32-BLE-Mouse-S3/keywords.txt b/ESP32-BLE-Mouse-S3/keywords.txt new file mode 100644 index 0000000..0f21a55 --- /dev/null +++ b/ESP32-BLE-Mouse-S3/keywords.txt @@ -0,0 +1,30 @@ +####################################### +# Syntax Coloring Map For ESP32 BLE Mouse +####################################### +# Class +####################################### + +BleMouse KEYWORD1 + +####################################### +# Methods and Functions +####################################### + +begin KEYWORD2 +end KEYWORD2 +click KEYWORD2 +move KEYWORD2 +press KEYWORD2 +release KEYWORD2 +isPressed KEYWORD2 +isConnected KEYWORD2 + +####################################### +# Constants +####################################### + +MOUSE_LEFT LITERAL1 +MOUSE_RIGHT LITERAL1 +MOUSE_MIDDLE LITERAL1 +MOUSE_BACK LITERAL1 +MOUSE_FORWARD LITERAL1 \ No newline at end of file diff --git a/ESP32-BLE-Mouse-S3/library.properties b/ESP32-BLE-Mouse-S3/library.properties new file mode 100644 index 0000000..0e278fe --- /dev/null +++ b/ESP32-BLE-Mouse-S3/library.properties @@ -0,0 +1,9 @@ +name=ESP32-s3 BLE Mouse +version=0.3.1 +author=T-vK +maintainer=T-vK +sentence=Bluetooth LE Mouse library for the ESP32. +paragraph=Bluetooth LE Mouse library for the ESP32. +category=Communication +url=https://github.com/T-vK/ESP32-BLE-Mouse +architectures=esp32