ESPHome 2026.11.0-dev
Loading...
Searching...
No Matches
keyboard.cpp
Go to the documentation of this file.
1#if defined(USE_ESP32_VARIANT_ESP32P4) || defined(USE_ESP32_VARIANT_ESP32S2) || defined(USE_ESP32_VARIANT_ESP32S3) || \
2 defined(USE_ESP32_VARIANT_ESP32S31) || defined(USE_ESP32_VARIANT_ESP32H4)
3
4#include "keyboard.h"
5#include "esphome/core/log.h"
6
8
9ESPHOME_LOG_TAG(TAG, "tinyusb_keyboard");
10
11void TinyUSBKeyboard::dump_config() { ESP_LOGCONFIG(TAG, "TinyUSB Keyboard"); }
12
13void TinyUSBKeyboard::set_keyboard_(uint8_t keycode, uint8_t modifiers) {
14 this->keycode_ = keycode;
15 this->modifiers_ = modifiers;
16 this->keyboard_pending_ = true;
17 this->flush_();
18}
19
20void TinyUSBKeyboard::set_consumer_(uint16_t usage) {
21 this->usage_ = usage;
22 this->consumer_pending_ = true;
23 this->flush_();
24}
25
27 if (!tud_mounted()) {
28 // No host is listening, and a key held from before it attached would be wrong, so drop the state
29 ESP_LOGV(TAG, "No host, dropping report");
30 this->keyboard_pending_ = false;
31 this->consumer_pending_ = false;
32 this->wakeup_requested_ = false;
33 this->disable_loop();
34 return;
35 }
36 if (tud_suspended()) {
37 // A key press wakes a sleeping host, like a real keyboard; the report goes out once the bus resumes.
38 // Signal once per suspend: a host that did not arm remote wakeup will not answer, and one that did
39 // must not be signalled on every pass.
40 if (!this->wakeup_requested_) {
41 this->wakeup_requested_ = true;
42 if (!tud_remote_wakeup()) {
43 ESP_LOGV(TAG, "Host did not allow remote wakeup");
44 }
45 }
46 this->enable_loop();
47 return;
48 }
49 this->wakeup_requested_ = false;
50 // tud_hid_*_report() returns false while the endpoint still holds the previous report, which is
51 // what happens for a press and a release in one action list. Keep retrying so the release gets out.
52 if (this->keyboard_pending_) {
53 uint8_t keycodes[6] = {this->keycode_};
54 if (tud_hid_keyboard_report(REPORT_ID_KEYBOARD, this->modifiers_, keycodes)) {
55 this->keyboard_pending_ = false;
56 }
57 }
58 if (this->consumer_pending_ && !this->keyboard_pending_ &&
59 tud_hid_report(REPORT_ID_CONSUMER, &this->usage_, sizeof(this->usage_))) {
60 this->consumer_pending_ = false;
61 }
62 if (this->keyboard_pending_ || this->consumer_pending_) {
63 this->enable_loop();
64 } else {
65 this->disable_loop();
66 }
67}
68
69void TinyUSBKeyboard::loop() { this->flush_(); }
70
71} // namespace esphome::tinyusb_keyboard
72
73// TinyUSB resolves these at link time when HID is enabled
74extern "C" {
75const uint8_t *tud_hid_descriptor_report_cb(uint8_t /*instance*/) {
77}
78
79uint16_t tud_hid_get_report_cb(uint8_t /*instance*/, uint8_t /*report_id*/, hid_report_type_t /*report_type*/,
80 uint8_t * /*buffer*/, uint16_t /*reqlen*/) {
81 return 0;
82}
83
84// Keyboard LED state from the host; nothing consumes it yet
85void tud_hid_set_report_cb(uint8_t /*instance*/, uint8_t /*report_id*/, hid_report_type_t /*report_type*/,
86 const uint8_t * /*buffer*/, uint16_t /*bufsize*/) {}
87}
88
89#endif // USE_ESP32_VARIANT_ESP32P4 || USE_ESP32_VARIANT_ESP32S2 || USE_ESP32_VARIANT_ESP32S3 ||
90 // USE_ESP32_VARIANT_ESP32S31 || USE_ESP32_VARIANT_ESP32H4
void enable_loop()
Enable this component's loop.
Definition component.h:248
void disable_loop()
Disable this component's loop.
void flush_()
Sends whatever changed; a report the endpoint cannot take yet is retried from loop()
Definition keyboard.cpp:26
void set_keyboard_(uint8_t keycode, uint8_t modifiers)
Definition keyboard.cpp:13
uint16_t tud_hid_get_report_cb(uint8_t, uint8_t, hid_report_type_t, uint8_t *, uint16_t)
Definition keyboard.cpp:79
const uint8_t * tud_hid_descriptor_report_cb(uint8_t)
Definition keyboard.cpp:75
void tud_hid_set_report_cb(uint8_t, uint8_t, hid_report_type_t, const uint8_t *, uint16_t)
Definition keyboard.cpp:85
ESPHOME_LOG_TAG(TAG, "tinyusb_keyboard")
constexpr uint8_t HID_REPORT_DESCRIPTOR[]
Definition keyboard.h:22