ESP32-S3实现远程虚拟的USB有线鼠标键盘
想要用ESP32-S3实现远程虚拟USB有线鼠标键盘,让ESP32-S3同时具备两个关键能力:一是模拟成电脑可识别的USB有线HID设备(鼠标+键盘),二是通过远程通信(WiFi/BLE)接收控制指令,最终让电脑像接了真实USB键鼠一样,响应远程的操作。这个方案无需额外USB转串口模块,直接利用ESP32-S3的USB-OTG功能实现“有线键鼠模拟”,远程端通过WiFi(推荐,传输距离远)或BLE控制。
一、核心实现原理
ESP32-S3的USB-OTG接口支持USB Device模式,可配置为HID(人机接口设备)类,向电脑发送标准的鼠标/键盘HID报告,电脑会自动识别为“USB有线键鼠”;同时ESP32-S3通过WiFi建立TCP/UDP连接,接收远程端(比如手机/另一台电脑)的控制指令,解析后转换成HID报告发送给电脑,完成远程操作。
简单来说:远程控制端→WiFi(TCP)→ESP32-S3(解析指令)→USB HID模拟→电脑(识别为有线键鼠)
二、硬件准备(极简,新手友好)
| 组件 | 规格/要求 | 作用说明 |
|---|---|---|
| ESP32-S3开发板 | 带USB-OTG口(如ESP32-S3-DevKitC-1) | 核心,同时实现WiFi通信和USB HID模拟 |
| USB Type-C数据线 | 数据款(非仅充电) | 连接ESP32-S3的USB-OTG口到电脑 |
| 电脑(Windows/Linux) | 任意版本 | 识别ESP32-S3为USB键鼠并响应操作 |
| 远程控制端 | 手机/另一台电脑(带网络调试助手) | 发送键鼠控制指令(如“移动鼠标”“按键盘A”) |
三、软件环境准备
- Arduino IDE配置(新手首选,无需复杂编译):
- 安装Arduino IDE,在「文件→首选项」中添加ESP32开发板地址:
https://dl.espressif.com/dl/package_esp32_index.json; - 在「工具→开发板→ESP32 Arduino」中选择
ESP32-S3 Dev Module; - 关键配置:
USB Mode选USB-OTG (HID),CPU Frequency选80MHz(降频降功耗),Flash Size选4MB。
- 安装Arduino IDE,在「文件→首选项」中添加ESP32开发板地址:
四、完整实现代码(WiFi+USB HID键鼠,开箱即用)
以下代码实现核心功能:
- ESP32-S3连接指定WiFi,作为TCP服务器等待远程指令;
- 模拟USB有线鼠标(移动、左键点击)+ 键盘(单键、组合键);
- 自定义简单指令协议,远程端发送指令即可控制。
#include<Arduino.h>#include<WiFi.h>#include<USBHID.h>#include<HIDReports.h>#include<HIDTypes.h>// ===================== 配置项(修改为你的信息)=====================#defineWIFI_SSID"你的WiFi名称"#defineWIFI_PWD"你的WiFi密码"#defineTCP_PORT8888// TCP通信端口#defineBAUD_RATE115200// 串口波特率(调试用)// ===================== USB HID 配置(鼠标+键盘)=====================USBHID hid;// 鼠标HID报告描述符(标准格式:X/Y移动、滚轮、按键)uint8_tmouseReportDesc[]={0x05,0x01,// USAGE_PAGE (Generic Desktop)0x09,0x02,// USAGE (Mouse)0xA1,0x01,// COLLECTION (Application)0x09,0x01,// USAGE (Pointer)0xA1,0x00,// COLLECTION (Physical)0x05,0x09,// USAGE_PAGE (Button)0x19,0x01,// USAGE_MINIMUM (Button 1)0x29,0x03,// USAGE_MAXIMUM (Button 3)0x15,0x00,// LOGICAL_MINIMUM (0)0x25,0x01,// LOGICAL_MAXIMUM (1)0x95,0x03,// REPORT_COUNT (3)0x75,0x01,// REPORT_SIZE (1)0x81,0x02,// INPUT (Data,Var,Abs)0x95,0x01,// REPORT_COUNT (1)0x75,0x05,// REPORT_SIZE (5)0x81,0x01,// INPUT (Cnst,Var,Abs)0x05,0x01,// USAGE_PAGE (Generic Desktop)0x09,0x30,// USAGE (X)0x09,0x31,// USAGE (Y)0x09,0x38,// USAGE (Wheel)0x15,0x81,// LOGICAL_MINIMUM (-127)0x25,0x7F,// LOGICAL_MAXIMUM (127)0x75,0x08,// REPORT_SIZE (8)0x95,0x03,// REPORT_COUNT (3)0x81,0x06,// INPUT (Data,Var,Rel)0xC0,// END_COLLECTION0xC0// END_COLLECTION};// 键盘HID报告描述符(标准104键+修饰键)uint8_tkeyboardReportDesc[]={0x05,0x01,// USAGE_PAGE (Generic Desktop)0x09,0x06,// USAGE (Keyboard)0xA1,0x01,// COLLECTION (Application)0x05,0x07,// USAGE_PAGE (Keyboard/Keypad)0x19,0xE0,// USAGE_MINIMUM (Keyboard Left Control)0x29,0xE7,// USAGE_MAXIMUM (Keyboard Right GUI)0x15,0x00,// LOGICAL_MINIMUM (0)0x25,0x01,// LOGICAL_MAXIMUM (1)0x95,0x08,// REPORT_COUNT (8)0x75,0x01,// REPORT_SIZE (1)0x81,0x02,// INPUT (Data,Var,Abs)0x95,0x01,// REPORT_COUNT (1)0x75,0x08,// REPORT_SIZE (8)0x81,0x03,// INPUT (Cnst,Var,Abs)0x95,0x06,// REPORT_COUNT (6)0x75,0x08,// REPORT_SIZE (8)0x15,0x00,// LOGICAL_MINIMUM (0)0x25,0x65,// LOGICAL_MAXIMUM (101)0x05,0x07,// USAGE_PAGE (Keyboard/Keypad)0x19,0x00,// USAGE_MINIMUM (Reserved)0x29,0x65,// USAGE_MAXIMUM (Keyboard Application)0x81,0x00,// INPUT (Data,Array)0xC0// END_COLLECTION};// 定义HID报告结构HIDReport mouseReport={mouseReportDesc,sizeof(mouseReportDesc)};HIDReport keyboardReport={keyboardReportDesc,sizeof(keyboardReportDesc)};// ===================== TCP通信相关 =====================WiFiServertcpServer(TCP_PORT);WiFiClient tcpClient;String recvData="";// ===================== 键鼠控制函数(核心)=====================// 鼠标控制:x/y为移动偏移(-127~127),btn为按键(1=左键,2=右键,4=中键),wheel为滚轮(-127~127)voidmouseControl(int8_tx,int8_ty,uint8_tbtn,int8_twheel=0){uint8_treport[4]={btn,x,y,wheel};// 鼠标报告:按键、X、Y、滚轮hid.sendReport(&mouseReport,report,sizeof(report));}// 键盘控制:modifier为修饰键(如0x01=左Ctrl,0x02=左Shift),key为按键(如0x04=A,0x05=B)voidkeyboardControl(uint8_tmodifier,uint8_tkey){uint8_treport[8]={modifier,0,key,0,0,0,0,0};// 键盘报告格式hid.sendReport(&keyboardReport,report,sizeof(report));delay(50);// 按键保持时间// 释放按键(避免长按)memset(report,0,sizeof(report));hid.sendReport(&keyboardReport,report,sizeof(report));}// ===================== 指令解析(自定义简单协议)=====================// 指令格式示例:// 鼠标移动:M|x|y (如M|10|5 → 鼠标右移10,下移5)// 鼠标左键点击:MB|1 (MB|0=释放,MB|1=按下)// 键盘按键:K|mod|key (如K|0|4 → 按A键;K|1|4 → 按Ctrl+A)voidparseCmd(String cmd){cmd.trim();// 去除空格if(cmd.startsWith("M|")){// 鼠标移动cmd=cmd.substring(2);intx=cmd.substring(0,cmd.indexOf("|")).toInt();inty=cmd.substring(cmd.indexOf("|")+1).toInt();mouseControl((int8_t)x,(int8_t)y,0);Serial.printf("鼠标移动:X=%d, Y=%d\n",x,y);}elseif(cmd.startsWith("MB|")){// 鼠标按键intbtn=cmd.substring(3).toInt();mouseControl(0,0,btn);Serial.printf("鼠标按键:%d\n",btn);}elseif(cmd.startsWith("K|")){// 键盘按键cmd=cmd.substring(2);intmod=cmd.substring(0,cmd.indexOf("|")).toInt();intkey=cmd.substring(cmd.indexOf("|")+1).toInt();keyboardControl((uint8_t)mod,(uint8_t)key);Serial.printf("键盘按键:修饰键=%d, 按键=%d\n",mod,key);}}// ===================== WiFi连接 =====================voidconnectWiFi(){WiFi.begin(WIFI_SSID,WIFI_PWD);Serial.print("连接WiFi...");while(WiFi.status()!=WL_CONNECTED){delay(500);Serial.print(".");}Serial.println("\nWiFi连接成功!");Serial.print("ESP32-S3 IP地址:");Serial.println(WiFi.localIP());tcpServer.begin();// 启动TCP服务器Serial.printf("TCP服务器已启动,端口:%d\n",TCP_PORT);}// ===================== 初始化 =====================voidsetup(){Serial.begin(BAUD_RATE);delay(1000);// 初始化USB HIDhid.addReport(&mouseReport);hid.addReport(&keyboardReport);hid.begin();while(!hid.ready()){// 等待HID初始化完成delay(100);Serial.print(".");}Serial.println("\nUSB HID初始化完成,电脑应识别为USB键鼠!");// 连接WiFiconnectWiFi();}// ===================== 主循环 =====================voidloop(){// 检测TCP客户端连接if(!tcpClient.connected()){tcpClient=tcpServer.available();if(tcpClient){Serial.println("远程客户端已连接!");}delay(100);return;}// 读取远程指令while(tcpClient.available()>0){charc=tcpClient.read();if(c=='\n'){// 按换行符分割指令parseCmd(recvData);recvData="";}else{recvData+=c;}}delay(10);}五、关键代码解析(新手必看)
USB HID报告描述符:
- 是电脑识别“USB键鼠”的核心,上述代码用的是标准HID报告格式,无需修改,电脑会自动驱动;
- 鼠标报告包含“3个按键(左/右/中)、X/Y移动、滚轮”,键盘报告包含“8个修饰键(Ctrl/Shift/Alt等)+ 6个普通按键”。
指令协议:
- 自定义极简协议,远程端发送指令时按格式(如
M|10|5),ESP32-S3解析后调用mouseControl/keyboardControl发送HID报告; - 键盘按键码参考标准HID值(如0x04=A、0x05=B、0x1E=0、0x44=Enter),修饰键码:0x01=左Ctrl、0x02=左Shift、0x04=左Alt、0x08=左Win。
- 自定义极简协议,远程端发送指令时按格式(如
TCP通信:
- ESP32-S3作为TCP服务器,远程端(手机/电脑)用“网络调试助手”连接其IP+端口(8888),发送指令即可控制。
六、测试步骤(5分钟验证)
- 烧录代码:修改
WIFI_SSID和WIFI_PWD后,烧录到ESP32-S3,用USB Type-C线连接ESP32-S3的USB-OTG口到电脑; - 识别设备:电脑会自动识别“USB Human Interface Device”(无需装驱动),在「设备管理器」可看到“鼠标”“键盘”;
- 远程控制:
- 打开串口监视器,查看ESP32-S3的IP地址(如192.168.1.100);
- 远程端(如电脑)打开“网络调试助手”,选择「TCP客户端」,输入IP+8888,连接成功后发送指令:
- 发送
M|10|5→ 鼠标向右移动10像素、向下移动5像素; - 发送
MB|1→ 鼠标左键按下,发送MB|0→ 释放; - 发送
K|0|4→ 按下并释放A键,发送K|1|4→ 按下并释放Ctrl+A。
- 发送
七、避坑指南(新手常踩)
- USB线选数据款:仅充电的USB线会导致电脑无法识别HID设备,务必用带数据传输的Type-C线;
- HID初始化等待:代码中
while (!hid.ready())必须保留,否则HID未就绪会导致指令无响应; - 指令格式严格:远程指令需按
M|x|y/MB|btn/K|mod|key格式,且以换行符结尾(网络调试助手勾选“发送新行”); - WiFi断连处理:代码可扩展“重连WiFi”逻辑,避免远程端断连后无法恢复。
总结
实现ESP32-S3远程虚拟USB有线键鼠的核心关键点:
- USB HID配置:用标准报告描述符让电脑识别为有线键鼠,无需额外驱动;
- 远程通信:WiFi TCP是最通用的远程方式,传输距离远、稳定性高;
- 指令解析:自定义简单协议,降低远程端开发成本,适配手机/电脑等控制端。
这套方案无需复杂硬件,代码开箱即用,既实现了“USB有线键鼠模拟”的稳定性,又具备“远程控制”的灵活性,适合远程办公、智能家居控制等场景。