跳转到内容

$hid - ESP32 HID 操作

更新: 2026/3/2 字数: 0 字 时长: 0 分钟

Stability: 2 - Stable

$hid 模块用于在脚本中通过 ESP32 模拟 HID 设备,实现对目标设备的 按键模拟、文本输入、触控操作、屏幕截图 等功能,适用于自动化控制、远程操作及人机交互相关场景。

使用前必读

  • 本模块基于 ESP32 HID 硬件实现,不依赖无障碍、ADB、Root 权限
  • 所有操作必须在成功 init + connect 后执行
  • connect()restart() 等方法为阻塞调用,禁止在 UI 线程执行

$hid 基于 $hid.esp32otg$hid.esp32ble 模块进行封装,可在运行时自动识别当前连接方式(OTG 或蓝牙),对外提供统一的调用接口,使同一套代码同时兼容 OTG 与 BLE 两种模式,从而降低脚本维护成本并提升复用性。

如果使用场景中 始终固定为某一种连接方式,建议直接使用对应的 $hid.esp32otg$hid.esp32ble 模块,以减少中间判断逻辑,获得更高的执行效率。

支持的 ESP32 开发板

HID 固件的烧录教程

设备状态监听

HID 模块支持监听设备状态变化事件,包括 ESP32 设备插入、拔出、权限请求、连接和断开等。

可用于自动授权处理、设备连接管理和状态监控。

👉 完整示例请参考:

HID 设备状态监听指南

初始化与OTG/蓝牙管理

$hid.init()

  • 返回 {boolean} 初始化成功返回 true,失败返回 false

初始化 ESP32 OTG/蓝牙 HID 模块,建立本地蓝牙通信环境,所有操作前必须先执行初始化

js
var initResult = $hid.init();
console.log("OTG/蓝牙 模块初始化结果: ", initResult);

if (!initResult) {
    console.error("OTG/蓝牙 初始化失败");
    // 后续错误处理
}

$hid.connect([mac])

  • mac {string} 可选,目标 ESP32 设备的 MAC 地址,格式如 "A4:C1:38:12:34:56"
  • 返回 {boolean}

连接 ESP32 OTG/蓝牙 HID 设备。

  • 不传 mac:自动连接默认已配对设备
  • mac:连接已配对的指定设备

连接 ESP32 OTG HID 设备。

  • 不传 mac:自动连接默认 OTG 设备

⚠️ 注意:此方法为同步阻塞操作,不能在 UI 线程中执行,建议放在子线程或异步任务中调用,以免界面卡死。

自动连接已配对设备蓝牙设备或者默认的OTG设备

js
var connectResult = $hid.connect();
console.log("连接: ", connectResult);

连接指定MAC地址的蓝牙设备

js
var macAddress = "A4:C1:38:12:34:56";//MAC地址可以通过其他方式获取
var connectResult = $hid.connect(macAddress);
console.log("指定MAC连接: ", connectResult);

$hid.restart()

  • 返回 {boolean}

重启 ESP32 OTG/蓝牙开发板,用于设备异常时的重置。

js
var restartResult = $hid.restart();
console.log("重启 ESP32 开发板: ", restartResult);

$hid.state()

  • 返回 {boolean}

获取当前 ESP32 OTG/蓝牙 设备的连接状态,判断通信通道是否正常。

js
var state = $hid.state();
console.log("OTG/蓝牙 设备连接状态: ", state);

$hid.getModel()

  • 返回 {string} 当前 ESP32 HID 模块使用的控制器模式,可能值为 "otg""ble"

获取当前 HID 模块的模式信息,用于区分不同 HID 控制器。通常用于调试或确认模块当前模式。

js
var model = $hid.getModel();
console.log("当前 HID 模块模式: ", model);

// 输出示例: "ble"

$hid.setModel(model)

  • model {string} 要切换的 HID 模式,可选值:

    • "otg" 切换到 OTG HID 模式
    • "ble" 切换到 BLE 蓝牙 HID 模式
  • 返回 {boolean} 切换成功返回 true,失败返回 false

手动设置 ESP32 HID 模块的连接模式,用于 自动识别失败或本地缓存异常 时恢复正常连接。

注意事项

  • ESP32 硬件通常会自动识别 HID 连接模式,并更新本地缓存
  • 如果本地缓存的模式信息错误,可能导致连接失败
  • 这时可以手动调用 $hid.setModel(model) 设置正确的模式,然后再调用 $hid.connect()

示例:设置为 BLE 蓝牙连接模式

js
$hid.setModel("ble");

示例:设置为 OTG 连接模式

js
$hid.setModel("otg");

$hid.checkPermission()

  • 返回 {boolean}

检查当前应用的蓝牙相关权限(位置信息、蓝牙 扫描、连接、通信),确保模块正常运行。 ⚠OTG不需要此操作

js
var permissionsCheck = $hid.checkPermission();
console.log("蓝牙权限检查结果: ", permissionsCheck);

$hid.requestPermission([activity])

  • activity {Activity} 用于发起运行时权限请求的 Activity 实例,可选

用于引导用户授予 HID 相关所需权限。

  • 当传入 activity
    将通过该 Activity 发起运行时权限请求(如蓝牙、位置等),适用于前台交互场景。

  • 当未传入 activity
    将直接跳转至当前应用的系统权限设置页面,由用户手动开启所需权限,适用于后台或无界面场景。

该方法仅负责权限引导,不保证权限一定被授予,调用方需在后续逻辑中自行校验权限状态。

⚠OTG不需要此操作

在 UI 页面中请求权限(推荐)

js
"ui";
$hid.multi.requestPermission(activity);
setTimeout(function () {
  ui.finish(); //关闭UI
}, 2000);

无 Activity 时跳转到系统权限设置页

js
$hid.requestPermission();

$hid.open()

  • 返回 {boolean}

打开本地设备的蓝牙开关(若未开启)。

⚠OTG不需要此操作

js
var openResult = $hid.open();
console.log("打开本地蓝牙: ", openResult);

$hid.close()

  • 返回 {boolean}

关闭本地设备的蓝牙开关。

⚠OTG不需要此操作

js
var closeResult = $hid.close();
console.log("关闭本地蓝牙: ", closeResult);

$hid.isEnabled()

  • 返回 {boolean}

⚠OTG不需要此操作

本地设备的蓝牙开关是否已启用。

js
if (!$hid.isEnabled()) {
  toastLog("蓝牙未开启,正在尝试开启");
  $hid.open();
} else {
  toastLog("蓝牙已开启");
}

$hid.destroy()

  • 无返回值

销毁 $hid 模块资源,释放通信通道,脚本结束前建议执行。

js
$hid.destroy();

按键模拟

$hid.home()

  • 返回 {boolean}

模拟按下主页键,返回设备主屏幕。

js
var homeResult = $hid.home();
console.log("按下主页键: ", homeResult);

$hid.back()

  • 返回 {boolean}

模拟按下返回键,返回上一个页面。

js
var backResult = $hid.back();
console.log("按下返回键: ", backResult);

$hid.recents()

  • 返回 {boolean}

模拟按下最近任务键,打开后台任务列表。

js
var recentResult = $hid.recents();
console.log("打开最近任务: ", recentResult);

屏幕截图

$hid.screenshot()

  • 返回 {boolean}

通过 ESP32 OTG/蓝牙 HID 模拟系统截图按键,触发设备原生截图行为。

仅触发截图动作,不获取截图内容。

说明

  • 等同于手动按下手机截图快捷键
  • 截图会保存到系统相册
  • 速度取决于设备系统响应
js
var screenshotResult = $hid.screenshot();
console.log("触发系统截图: ", screenshotResult);

$hid.captureScreen()

通过 ESP32 OTG/蓝牙 HID 模拟系统截图按键并读取截图结果

⚠️ 注意

  • 截图速度较慢,通常约 150 ~ 800 ms
  • 调用限制:同一设备上 1500 ms 内只允许执行一次,否则可能导致截图失败或报错。

若追求高速截图,推荐使用 HID 语音助手方式: $assistant.captureScreen()(速度接近 images.captureScreen()

特点

  • 会阻塞当前线程直到截图完成
  • 返回 Image 对象,可直接处理
  • 适合低频截图场景
js
var img = $hid.captureScreen();
console.log("截图对象: ", img);
img.saveTo("/sdcard/test.png");
img.recycle();

$hid.captureScreen(path)

  • path {string} 保存路径
  • 返回 {boolean}

通过 ESP32 OTG/蓝牙 HID 模拟系统截图按键并保存截图到指定路径

⚠️ 注意

  • 截图速度较慢,通常约 150 ~ 800 ms
  • 调用限制:同一设备上 1500 ms 内只允许执行一次,否则可能导致截图失败或报错。

若追求高速截图,推荐使用 HID 语音助手方式: $assistant.captureScreen(path)(速度接近 images.captureScreen(path)

特点

  • 会阻塞当前线程直到截图完成
  • 返回 Image 对象,可直接处理
  • 适合低频截图场景
js
var saveResult = $hid.captureScreen("/sdcard/test.png");
console.log("截图保存: ", saveResult);

剪贴板与文本操作

$hid.setSelection()

  • 返回 {boolean}

模拟全选操作。

js
var setSelectionResult = $hid.setSelection();
console.log("全选内容: ", setSelectionResult);

$hid.copy()

  • 返回 {boolean}

模拟复制操作,将选中的内容复制到剪贴板。

js
var copyResult = $hid.copy();
console.log("复制选中内容: ", copyResult);

$hid.cut()

  • 返回 {boolean}

模拟剪切操作,将选中的内容剪切到剪贴板。

js
var cutResult = $hid.cut();
console.log("剪切选中内容: ", cutResult);

$hid.paste()

  • 返回 {boolean}

模拟粘贴操作,将剪贴板内容粘贴到当前焦点位置(支持中文、特殊字符)。

js
// 先设置剪贴板内容,再粘贴
setClip("这是要粘贴的中文内容");
var pasteResult = $hid.paste();
console.log("粘贴剪贴板内容: ", pasteResult);

$hid.input(txt)

  • txt {string} 要输入的文本(仅支持英文、数字)
  • 返回 {boolean}

模拟键盘逐个输入字符,不支持中文

js
$hid.input("abcdefghijklmnopqrstuvwxyz1234567890");  // ✓ 纯英文数字符号

中文输入

  1. 剪贴板+粘贴方案(推荐):
js
setClip("你好世界");
sleep(500)
$hid.paste();  // 粘贴
  1. $input 输入法(复杂场景):
js
$input.setText("你好世界");

$hid.enter()

  • 返回 {boolean}

模拟按下回车键,适用于搜索、确认、换行等场景。

js
var enterResult = $hid.enter();
console.log("按下回车键: ", enterResult);

$hid.delete([count])

  • count {number} 可选,删除的字符数,默认 1
  • 返回 {boolean}

模拟删除键(Delete),删除光标后方的字符,可指定删除数量。

js
var deleteSingleResult = $hid.delete();
console.log("删除1个字符: ", deleteSingleResult);

var deleteMultipleResult = $hid.delete(3);
console.log("删除3个字符: ", deleteMultipleResult);

$hid.backspace([count])

  • count {number} 可选,退格的字符数,默认 1
  • 返回 {boolean}

模拟退格键(Backspace),删除光标前方的字符,可指定退格数量。

js
var backspaceSingleResult = $hid.backspace();
console.log("退格1个字符: ", backspaceSingleResult);

var backspaceMultipleResult = $hid.backspace(2);
console.log("退格2个字符: ", backspaceMultipleResult);

原生键码操作

$hid.keyPress(keyCode[, modifier])

  • keyCode {number} 按键对应的原生键码
  • modifier {number} 可选,修饰键码,用于组合键
  • 返回 {boolean}

模拟按下指定键码的按键,可用于单键操作或组合键操作。


重要说明

  • 单独按键(不传 modifier)时,仅执行按下动作,不会自动释放 → 必须手动调用 $hid.keyRelease(keyCode) 释放按键
  • 若单键按下后未释放,将导致 HID 处于按键锁定状态,后续指令可能全部失效
  • 组合键操作(传入 modifier)会自动完成按下并释放

示例

$hid.keyRelease(keyCode)

  • keyCode {number} 按键对应的原生键码
  • 返回 {boolean}

模拟释放指定键码的按键,与 keyPress 配合实现长按效果。

$hid.keyRelease()

  • 返回 {boolean}

释放所有已按下的按键,用于清空按键状态。

js
$hid.keyRelease();

$hid.keyWrite(keyCode)

  • keyCode {number} 按键对应的原生键码
  • 返回 {boolean}

直接写入指定键码到通信通道,模拟单次按键触发(按下+释放一体化)。

示例

触控操作

$hid.click(x, y)

  • x {number} 触控点横坐标
  • y {number} 触控点纵坐标
  • 返回 {boolean}

模拟单击操作,点击指定坐标位置,按下的时间为100ms,如果需要点击时间更短,请使用press

点击指定坐标(示例)

js
$hid.click(540, 960);

点击屏幕中心点(示例)

js
var x = device.width / 2;
var y = device.height / 2;
$hid.click(x, y);

$hid.longClick(x, y)

  • x {number} 触控点横坐标
  • y {number} 触控点纵坐标
  • 返回 {boolean}

模拟长按操作,长按指定坐标位置,按下的时间为650ms。

长按指定坐标(示例)

js
$hid.longClick(540, 960);

长按屏幕中心点(示例)

js
var x = device.width / 2;
var y = device.height / 2;
$hid.longClick(x, y);

$hid.press(x, y, duration)

  • x {number} 触控点横坐标
  • y {number} 触控点纵坐标
  • duration {number} 按住的时长(毫秒)
  • 返回 {boolean}

自定义按住操作,按住指定坐标并保持指定时长,比 longClick 更灵活。

在指定坐标执行一次持续 2000 毫秒的长按操作(示例)

js
$hid.press(540, 960, 2000);

在屏幕中心位置执行一次持续 2000 毫秒的长按操作(示例)

js
var x = device.width / 2;
var y = device.height / 2;
$hid.press(x, y, 2000);

$hid.touchDown(x, y[, id])

  • x {number} 触控点横坐标
  • y {number} 触控点纵坐标
  • id {number} 可选,触控点ID(多触点时区分),默认 0
  • 返回 {boolean}

模拟触控按下,手指按下指定坐标(未抬起),用于自定义滑动/拖拽。

$hid.touchMove(x, y[, id])

  • x {number} 移动后的横坐标
  • y {number} 移动后的纵坐标
  • id {number} 可选,触控点ID,默认 0
  • 返回 {boolean}

模拟触控移动,手指在按下状态下移动到指定坐标,与 touchDown 配合使用。

$hid.touchUp([id])

  • id {number} 可选,触控点ID,默认 0
  • 返回 {boolean}

模拟触控抬起,手指从按下状态抬起,结束触控操作,与 touchDown/touchMove 配合。

按下→抬起实现模拟点击示例

js
// 按下→休息200毫秒→抬起
$hid.touchDown(200, 500);
sleep(200);
$hid.touchUp()

按下→移动→抬起实现自定义轨迹的滑动示例

js
// 按下→移动→抬起
$hid.touchDown(200, 500);
sleep(200);
$hid.touchMove(250, 550);
sleep(200);
$hid.touchMove(300, 550);
sleep(200);
$hid.touchMove(350, 550);
sleep(200);
$hid.touchMove(500, 550);
sleep(100);
$hid.touchUp();

$hid.swipe(x1, y1, x2, y2, duration)

  • x1 {number} 滑动起点横坐标
  • y1 {number} 滑动起点纵坐标
  • x2 {number} 滑动终点横坐标
  • y2 {number} 滑动终点纵坐标
  • duration {number} 滑动总时长(毫秒)
  • 返回 {boolean}

基础自定义滑动,指定起点、终点和时长,实现直线滑动。

js
// 从(500,800)滑动到(500,200),时长1000毫秒(向上滑)
$hid.swipe(500, 800, 500, 200, 1000);

$hid.swipe(x1, y1, x2, y2, steps, downTime, duration, upTime)

  • x1/y1 {number} 滑动起点坐标
  • x2/y2 {number} 滑动终点坐标
  • steps {number} 滑动步数(步数越多越平滑)
  • downTime {number} 按下后延时(毫秒)
  • duration {number} 滑动核心时长(毫秒)
  • upTime {number} 抬起前延时(毫秒)
  • 返回 {boolean}

高级自定义滑动,精细控制滑动的平滑度、按下/抬起延时。

js
// 高平滑度滑动:从(500,850)到(500,200),步数30,按下延时200ms,滑动500ms,抬起延时1000ms
$hid.swipe(500, 850, 500, 200, 30, 200, 500, 1000);

$hid.swipe(x1, y1, x2, y2, steps, downTime, duration, upTime, shape)

  • shape {number} 滑动曲线形状(1~6,不同数值对应不同的速度曲线,如先快后慢、匀速等)
  • 其余参数同「高级自定义滑动」
  • 返回 {boolean}

曲线滑动,在高级滑动基础上增加速度曲线,模拟真人滑动的非匀速效果,仅仅在横向方向滑动有效。

js
// 曲线向右滑动,形状5(横向曲线)
$hid.swipe(200, 500, 520, 500, 50, 200, 2000, 3000, 5);

$hid.swipeUp([width, height])

  • width {number} 可选,参考屏幕宽度,用于计算滑动起点和终点,默认取本地 device.width
  • height {number} 可选,参考屏幕高度,用于计算滑动起点和终点,默认取本地 device.height
  • 返回 {boolean}

模拟向上滑动操作,起点位于屏幕底部,终点位于屏幕上方,自动适配指定或本地屏幕尺寸。

基础滑动(使用本地屏幕尺寸)

js
$hid.swipeUp();

自定义屏幕尺寸滑动

js
$hid.swipeUp(device.width, device.height);

$hid.swipeDown([width, height])

  • width {number} 可选,参考屏幕宽度,用于计算滑动起点和终点,默认取本地 device.width
  • height {number} 可选,参考屏幕高度,用于计算滑动起点和终点,默认取本地 device.height
  • 返回 {boolean}

模拟向下滑动操作,起点位于屏幕上方,终点位于屏幕底部,自动适配指定或本地屏幕尺寸。

$hid.swipeLeft([width, height])

  • width {number} 可选,参考屏幕宽度,用于计算滑动起点和终点,默认取本地 device.width
  • height {number} 可选,参考屏幕高度,用于计算滑动起点和终点,默认取本地 device.height
  • 返回 {boolean}

模拟向左滑动操作,起点位于屏幕右侧,终点位于屏幕左侧,自动适配指定或本地屏幕尺寸。

$hid.swipeRight([width, height])

  • width {number} 可选,参考屏幕宽度,用于计算滑动起点和终点,默认取本地 device.width
  • height {number} 可选,参考屏幕高度,用于计算滑动起点和终点,默认取本地 device.height
  • 返回 {boolean}

模拟向右滑动操作,起点位于屏幕左侧,终点位于屏幕右侧,自动适配指定或本地屏幕尺寸。

$hid.zoomIn(targetX, targetY, stride)

  • targetX {number} 缩放中心横坐标
  • targetY {number} 缩放中心纵坐标
  • stride {number} 缩放步长(步长越大,缩放幅度越大)
  • 返回 {boolean}

模拟双指放大操作,以指定坐标为中心放大屏幕内容(如图片、页面)。

以屏幕中心为中心,步长20放大

js
var x = device.width / 2;
var y = device.height / 2;
$hid.zoomIn(x, y, 20);
sleep(1000)
$hid.zoomIn(x, y, 20);
sleep(1000)
$hid.zoomIn(x, y, 20);

$hid.zoomOut(targetX, targetY, stride)

  • targetX/targetY {number} 缩放中心坐标
  • stride {number} 缩放步长
  • 返回 {boolean}

模拟双指缩小操作,以指定坐标为中心缩小屏幕内容。

以屏幕中心为中心,步长20缩小

js
var x = device.width / 2;
var y = device.height / 2;
$hid.zoomOut(x, y, 20);
sleep(1000)
$hid.zoomOut(x, y, 20);
sleep(1000)
$hid.zoomOut(x, y, 20);

示例

全功能测试脚本

js
/**
 * ESP32 OTG/蓝牙 HID 全功能演示
 * 流程:初始化 → 连接 → 状态检查 → 操作演示 → 结束
 */

// ==================== 初始化 ====================
toastLog("正在初始化 OTG/蓝牙 模块...");
if (!$hid.init()) {
    toastLog("OTG/蓝牙 初始化失败");
    console.error("OTG/蓝牙模块初始化失败");
    exit();
}

// ==================== 连接设备 ====================
toastLog("正在连接 ESP32 设备...");
if (!$hid.connect()) {
    toastLog("ESP32 设备连接失败");
    console.error("连接失败");
    exit();
}

// ==================== 状态检查 ====================
var state = $hid.state();
if (!state) {
    toastLog("设备未连接,结束测试");
    exit();
}

toastLog("OTG/蓝牙 连接成功!");
console.log("当前状态:", state);

// ==================== 系统按键演示 ====================

toastLog("5秒后执行 返回键");
sleep(5000);
$hid.back();

toastLog("5秒后执行 任务键");
sleep(5000);
$hid.recents();

toastLog("5秒后执行 主页键");
sleep(5000);
$hid.home();

// ==================== 坐标提示 ====================

toastLog("请开启 开发者选项 → 指针位置\n可查看触控坐标");

// ==================== 点击中心点 ====================

var x = device.width / 2;
var y = device.height / 2;

toastLog("5秒后点击屏幕中心点\n(" + x + ", " + y + ")");
sleep(5000);

$hid.click(x, y);

// ==================== 上滑演示 ====================

toastLog("5秒后模拟上滑操作");
sleep(5000);

// 起点与终点(基于屏幕比例)
var x1 = device.width / 2;
var y1 = device.height * 0.8;

var x2 = device.width / 2;
var y2 = device.height * 0.2;

// 使用真实坐标滑动函数
$hid.swipe(x1, y1, x2, y2, 1000);

// ==================== 结束 ====================

toastLog("ESP32 OTG/蓝牙 HID 测试完成!");
console.log("测试流程结束");

HID 控件节点查找点击

HID 控件请参见

js
// 初始化 OTG/蓝牙 HID 模块(仅需调用一次,阻塞操作,请勿在 UI 线程执行)
$hid.init(context);

// 连接 ESP32 设备(仅需连接一次,建议在脚本启动时执行,阻塞操作,请勿在 UI 线程执行)
$hid.connect();

// ==================== 状态检查 ====================
var state = $hid.state();
if (!state) {
  toastLog("设备未连接,结束测试");
  exit();
}

toastLog("OTG/蓝牙 连接成功!");
console.log("当前状态:", state);

//然后下面就可以写具体的自动化业务操作逻辑了

var uiObject = selector(1).desc("任务管理").className("android.widget.LinearLayout").visibleToUser(true).findOne(1000);
if (uiObject) {
  $hid.click(uiObject.bounds().centerX(), uiObject.bounds().centerY());
  sleep(1000);
} else {
  toastLog("未找到符合条件的控件");
}

HID YOLO目标检测点击

YOLO 基于深度学习目标检测模型进行图像推理,可自动识别画面中的目标对象,不依赖固定分辨率与坐标规则,适用于游戏界面、复杂动画场景等传统找图难以处理的画面环境。

通常可与 OCR 文字识别结合使用,实现对图像目标与文本信息的综合自动化控制。

js
// 初始化 OTG/蓝牙 HID 模块(仅需调用一次,阻塞操作,请勿在 UI 线程执行)
$hid.init(context);

// 连接 ESP32 设备(仅需连接一次,建议在脚本启动时执行,阻塞操作,请勿在 UI 线程执行)
$hid.connect();

// ==================== 状态检查 ====================
var state = $hid.state();
if (!state) {
  toastLog("设备未连接,结束测试");
  exit();
}

toastLog("OTG/蓝牙 连接成功!");
console.log("当前状态:", state);

// 加载 ONNX 格式 YOLO 模型
var yolo = $yolo.load(
  {
    binPath: "/sdcard/yolo26n.ncnn.bin",
    paramPath: "/sdcard/yolo26n.ncnn.param",
    classes: [
        "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
        "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
        "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
        "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
        "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
        "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
        "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
        "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
        "hair drier", "toothbrush"
    ],
    version: 26,
    task: 0, // 目标检测
    device: 0, // CPU
  },
  {
    onload: function (yolo, success) {
      console.log(success ? "NCNN 模型加载成功" : "NCNN 模型加载失败");
    },
  }
);

if (!yolo) {
  console.error("加载失败");
  exit();
}
// 设置全局配置
yolo.setConfig({
  width: 640,
  height: 640,
  conf: 0.25,
  iou: 0.7,
});

// ==================== 截取当前屏幕(一共有6中截图方式 当前采用系统截图方式) ====================
// 请求截图
if (!requestScreenCapture()) {
  toastLog("请求截图失败");
  exit();
}
var img = images.captureScreen();

var yoloResults = yolo.predict(img);

// 输出结果
console.log("检测到", yoloResults.size(), "个目标");
// 遍历每一个 YOLOObject(目标检测结果)
for (var index = 0; index < yoloResults.size(); index++) {
  var yoloObject = yoloResults.get(index);

  // 类别 ID
  var cls = yoloObject.cls;

  // 类别名称
  var name = yoloResults.names[cls];

  console.log("目标 " + (index + 1));
  console.log("  类别ID:", cls);
  console.log("  类别名称:", name);
  console.log("  置信度:", yoloObject.conf);

  // 位置信息
  console.log("  位置: 左上角x=" + yoloObject.x + ", 左上角y=" + yoloObject.y + ", 宽=" + yoloObject.w + ", 高=" + yoloObject.h);

  // ==================== 仅点击类别为 1 的目标 ====================

  if (cls === 1) {
    $hid.click(yoloObject.bounds().centerX(), yoloObject.bounds().centerY());
    sleep(2000);

    // 如果只需要点一个目标,可直接跳出循环
    break;
  }
}

//在不需要时记得释放模型资源
yolo.release();

HID 找图查找点击

通过截图获取当前屏幕图像,使用找图算法定位目标位置,获取坐标后通过 HID 模拟点击。

js
// ==================== 初始化与连接 ====================
$hid.init();
$hid.connect();

var state = $hid.state();
if (!state) {
  toastLog("设备未连接");
  exit();
}

// ==================== 截取当前屏幕(一共有6中截图方式 当前采用系统截图方式) ====================
// 请求截图
if (!requestScreenCapture()) {
  toastLog("请求截图失败");
  exit();
}
var img = images.captureScreen();

// ==================== 查找目标图片 ====================

// 目标小图图片路径
var targetImg = images.read("/sdcard/target.png");

// 在截图中查找目标
var point = images.findImage(img, targetImg, {
  threshold: 0.8,
});

// ==================== 根据结果点击 ====================

if (point) {
  // 获取目标中心坐标
  var x = point.x + targetImg.getWidth() / 2;
  var y = point.y + targetImg.getHeight() / 2;

  toastLog("找到目标,点击坐标: " + x + ", " + y);

  $hid.click(x, y);
  sleep(2000);
} else {
  toastLog("未找到目标图片");
}

// 释放小图片资源
targetImg.recycle();

HID OCR文字识别找字点击

js

// ==================== 初始化与连接 ====================
$hid.init();
$hid.connect();

var state = $hid.state();
if (!state) {
  toastLog("设备未连接");
  exit();
}

// 加载OCR插件,需要先下载官方MLKitOCR插件
var MLKitOCR = $plugins.load("org.autojs.autojspro.plugin.mlkit.ocr");
var ocr = new MLKitOCR();

// 请求截图
if (!requestScreenCapture()) {
  toastLog("请求截图失败");
  exit();
}

//循环5次截图
for (var i = 0; i < 5; i++) {
  var capture = captureScreen();

  // 检测截图文字并计算检测时间,首次检测的耗时比较长
  // 检测时间取决于图片大小、内容、文字数量
  var start = Date.now();
  var results = ocr.detect(capture);
  var end = Date.now();

  if (results.length > 0) {
    for (var index = 0; index < results.length; index++) {
      var result = results[index];
      if ("改成要识别的文字".includes(result.text)) {
        var bounds = result.bounds;
        console.log(bounds);
        var x = bounds.centerX();
        var y = bounds.centerY();
        $hid.click(x, y);
        sleep(2000);
        break;
      }
    }
  }

  toastLog(`第${i + 1}次检测: ${end - start}ms`);
  sleep(3000);
}

ocr.release();

总结

  1. 基础流程固定

    所有 HID 操作必须遵循统一流程:

    初始化 OTG/蓝牙 模块 → 连接 ESP32 设备 → 状态检查 → 业务自动化操作

    其中:

    • $hid.init()$hid.connect() 仅需执行一次
    • 建议每次操作前通过 $hid.state() 确认连接状态

  1. 文本输入推荐方案

    • 英文、数字: 使用 $hid.input() 直接模拟键盘输入

    • 中文、特殊字符: 推荐使用 剪贴板 + 粘贴方案

      js
      setClip("需要输入的中文内容");
      $hid.paste();
    • 复杂输入场景建议配合专业输入模块(如 $input


  1. 权限与稳定性建议

    • 使用 $hid.checkPermissions() 检查蓝牙相关权限
    • 操作前确认蓝牙已开启及设备已连接,避免指令执行失败

  1. 截图方式灵活选择

具体可参阅屏幕截图的 7 种方式


  1. 目标定位方式多样

    HID 并不限制坐标来源,可结合多种识别方式获取目标位置:

    • 控件节点查找(无障碍 | HID / 数字助理 | ADB / XML 模式,具体可参阅选择器
    • YOLO 目标检测(复杂画面、游戏场景推荐),具体可参阅YOLO
    • 找图找色,具体可参阅找图找色
    • OCR 文字识别,具体可参阅OCR 模块OCR 插件

  1. 坐标操作统一

    无论使用哪种识别方式:

    👉 最终统一转换为坐标

    再通过 $hid 执行:

    实现完整的自动化控制流程。