Hi haideralipunjabi,
If your KVM switch doesn't respond to the hotkey from the ESP32, the issue is most likely how Ctrl is being sent – it must go in the modifier byte, not as a regular key. You also need to follow the correct press and release sequence.
Here's a working example for the hotkey Ctrl + Ctrl + 2 that should be recognized even by picky KVM switches:
Code: Select all
#include "freertos/FreeRTOS.h"
#include "freertos/task.h"
#include "tinyusb.h"
#include "class/hid/hid_device.h"
#include "esp_log.h"
#define TAG "KVM_Trigger"
// --- HID Report descriptor ---
const uint8_t hid_report_descriptor[] = {
TUD_HID_REPORT_DESC_KEYBOARD(HID_REPORT_ID(HID_ITF_PROTOCOL_KEYBOARD)),
};
// --- String descriptors ---
const char *hid_string_descriptor[] = {
(char[]){0x09, 0x04}, // Language: English (0x0409)
"ESP32-S3", // Manufacturer
"Virtual Keyboard", // Product name
"123456", // Serial number
"Keyboard Interface", // Interface description
};
// --- USB Configuration descriptor ---
#define TUSB_DESC_TOTAL_LEN (TUD_CONFIG_DESC_LEN + TUD_HID_DESC_LEN)
const uint8_t hid_configuration_descriptor[] = {
TUD_CONFIG_DESCRIPTOR(1, 1, 0, TUSB_DESC_TOTAL_LEN, TUSB_DESC_CONFIG_ATT_REMOTE_WAKEUP, 100),
TUD_HID_DESCRIPTOR(0, 4, true, sizeof(hid_report_descriptor), 0x81, 8, 10),
};
// --- USB Device descriptor ---
const tusb_desc_device_t device_descriptor = {
.bLength = sizeof(tusb_desc_device_t),
.bDescriptorType = TUSB_DESC_DEVICE,
.bcdUSB = 0x0200,
.bDeviceClass = 0x00,
.bDeviceSubClass = 0x00,
.bDeviceProtocol = 0x00,
.bMaxPacketSize0 = CFG_TUD_ENDPOINT0_SIZE,
.idVendor = 0xCafe,
.idProduct = 0x4020,
.bcdDevice = 0x0100,
.iManufacturer = 0x01,
.iProduct = 0x02,
.iSerialNumber = 0x03,
.bNumConfigurations = 0x01};
// --- TinyUSB HID callbacks ---
uint8_t const *tud_hid_descriptor_report_cb(uint8_t instance)
{
return hid_report_descriptor;
}
uint16_t tud_hid_get_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t *buffer, uint16_t reqlen)
{
return 0;
}
void tud_hid_set_report_cb(uint8_t instance, uint8_t report_id, hid_report_type_t report_type, uint8_t const *buffer, uint16_t bufsize)
{
// Not used
}
// --- Helper functions to send key combos ---
// Send only Ctrl (without any other key)
void send_ctrl_only()
{
tud_hid_keyboard_report(HID_ITF_PROTOCOL_KEYBOARD, KEYBOARD_MODIFIER_LEFTCTRL, NULL);
vTaskDelay(pdMS_TO_TICKS(100));
tud_hid_keyboard_report(HID_ITF_PROTOCOL_KEYBOARD, 0, NULL);
vTaskDelay(pdMS_TO_TICKS(100));
}
// Send Ctrl + a specific key
void send_ctrl_plus_key(uint8_t key)
{
uint8_t keycode[6] = {0};
keycode[0] = key;
tud_hid_keyboard_report(HID_ITF_PROTOCOL_KEYBOARD, KEYBOARD_MODIFIER_LEFTCTRL, keycode);
vTaskDelay(pdMS_TO_TICKS(100));
tud_hid_keyboard_report(HID_ITF_PROTOCOL_KEYBOARD, 0, NULL);
vTaskDelay(pdMS_TO_TICKS(100));
}
// --- Main application ---
void app_main(void)
{
// Configure and install TinyUSB driver
const tinyusb_config_t tusb_cfg = {
.device_descriptor = &device_descriptor,
.string_descriptor = hid_string_descriptor,
.string_descriptor_count = sizeof(hid_string_descriptor) / sizeof(hid_string_descriptor[0]),
.external_phy = false,
#if TUD_OPT_HIGH_SPEED
.fs_configuration_descriptor = hid_configuration_descriptor,
.hs_configuration_descriptor = hid_configuration_descriptor,
#else
.configuration_descriptor = hid_configuration_descriptor,
#endif
};
tinyusb_driver_install(&tusb_cfg);
ESP_LOGI(TAG, "USB HID keyboard ready");
// Wait until the USB host has mounted the device
while (!tud_mounted())
{
vTaskDelay(pdMS_TO_TICKS(100));
}
// Send KVM hotkey: Ctrl + Ctrl + 2
send_ctrl_only();
send_ctrl_only();
send_ctrl_plus_key(HID_KEY_2);
ESP_LOGI(TAG, "KVM hotkey sent");
}
Recommendations:
Make sure your descriptor has boot_protocol = true
Right after USB mounts, send tud_hid_keyboard_report(..., 0, NULL); as an "idle" state
If it still doesn't work, try another VID/PID, but the most important thing is comparing lsusb -v with a working keyboard