为Nodejs应用快速集成稳定可靠的大模型api服务
2026/4/30 22:19:40
想要用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”) |
https://dl.espressif.com/dl/package_esp32_index.json;ESP32-S3 Dev Module;USB Mode选USB-OTG (HID),CPU Frequency选80MHz(降频降功耗),Flash Size选4MB。以下代码实现核心功能:
#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报告描述符:
指令协议:
M|10|5),ESP32-S3解析后调用mouseControl/keyboardControl发送HID报告;TCP通信:
WIFI_SSID和WIFI_PWD后,烧录到ESP32-S3,用USB Type-C线连接ESP32-S3的USB-OTG口到电脑;M|10|5→ 鼠标向右移动10像素、向下移动5像素;MB|1→ 鼠标左键按下,发送MB|0→ 释放;K|0|4→ 按下并释放A键,发送K|1|4→ 按下并释放Ctrl+A。while (!hid.ready())必须保留,否则HID未就绪会导致指令无响应;M|x|y/MB|btn/K|mod|key格式,且以换行符结尾(网络调试助手勾选“发送新行”);实现ESP32-S3远程虚拟USB有线键鼠的核心关键点:
这套方案无需复杂硬件,代码开箱即用,既实现了“USB有线键鼠模拟”的稳定性,又具备“远程控制”的灵活性,适合远程办公、智能家居控制等场景。