跳转到内容

$hid.multi - ESP32 BLE蓝牙/OTG/USB HID 操作

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

Stability: 2 - Stable

$hid.multi 模块用于在脚本中通过 BLE蓝牙/OTG/USB 模拟 HID 设备,实现对目标设备的按键模拟、文本输入、触控操作、屏幕截图等功能,支持基础操作与高级自定义操作,适用于自动化控制、远程操作等场景。

使用前必读

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

HID支持的开发板

  • 多模三合一版
    包含蓝牙、OTG、USB 三种HID模式,可随意切换,价格比ESP32高,暂不支持自己烧录

  • 多模二合一版
    包含蓝牙、OTG 二种 HID 模式,可控制充电、断电,价格比ESP32高,暂不支持自己烧录

设备状态监听

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

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

👉 完整示例请参考:

HID 设备状态监听指南

初始化与蓝牙管理

$hid.multi.init()

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

初始化 多模 HID 模块,所有操作前必须先执行初始化

js
var initResult = $hid.multi.init();
console.log("初始化结果: ", initResult);

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

$hid.multi.connect()

  • 返回 {boolean}

连接 多模 HID 设备。

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

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

$hid.multi.restart()

  • 返回 {boolean}

重启 多模 设备,用于设备异常时的重置。

js
var restartResult = $hid.multi.restart();
console.log("重启 多模 设备: ", restartResult);

$hid.multi.state()

  • 返回 {boolean}

获取当前 多模 设备的连接状态,判断通信通道是否正常。

js
var state = $hid.multi.state();
console.log("多模 设备连接状态: ", state);

$hid.multi.getModel()

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

获取当前 HID 模块的模式信息,用于区分不同 HID 控制器。

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

// 输出示例: "ble"

$hid.multi.setModel(model)

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

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

切换 HID 模块的控制模式,用于在多模设备上灵活选择控制方式。

注意事项

  • 切换模式可能需要设备支持对应 HID 模式
  • 仅在模块处于连接状态 ($hid.multi.state() === true) 时,才能通过 API 切换模式
  • 如果模块未连接或状态为 false,需要通过硬件上的切换按钮手动切换模式
  • 切换模式时请确保当前操作不会中断正在进行的任务

切换到 BLE蓝牙 模式

js
if ($hid.multi.state()) {
    var result = $hid.multi.setModel("ble");
    console.log("切换到 BLE蓝牙 模式: ", result);
} else {
    console.warn("模块未连接,请手动切换模式");
}

切换到 OTG 模式

js
if ($hid.multi.state()) {
    $hid.multi.setModel("otg");
}

切换到 USB 模式

js
if ($hid.multi.state()) {
    $hid.multi.setModel("usb");
}

$hid.multi.checkPermission()

  • 返回 {boolean}

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

⚠OTG/USB不需要此操作

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

$hid.multi.requestPermission([activity])

  • activity {Activity} 用于发起运行时权限请求的 Activity 实例,可选 用于引导用户授予 HID 相关所需权限。
  • 当传入 activity
    将通过该 Activity 发起运行时权限请求(如蓝牙、位置等),适用于前台交互场景。

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

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

⚠OTG/USB不需要此操作

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

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

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

js
$hid.multi.requestPermission();

$hid.multi.open()

  • 返回 {boolean}

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

⚠OTG/USB不需要此操作

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

$hid.multi.close()

  • 返回 {boolean}

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

⚠OTG/USB不需要此操作

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

$hid.multi.isEnabled()

  • 返回 {boolean}

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

⚠OTG/USB不需要此操作

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

$hid.multi.destroy()

  • 无返回值

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

js
$hid.multi.destroy();

按键模拟

$hid.multi.home()

  • 返回 {boolean}

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

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

$hid.multi.back()

  • 返回 {boolean}

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

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

$hid.multi.recents()

  • 返回 {boolean}

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

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

屏幕截图

$hid.multi.screenshot()

  • 返回 {boolean}

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

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

说明

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

$hid.multi.captureScreen()

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

⚠️ 注意

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

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

特点

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

$hid.multi.captureScreen(path)

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

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

⚠️ 注意

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

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

特点

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

剪贴板与文本操作

$hid.multi.setSelection()

  • 返回 {boolean}

模拟全选操作。

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

$hid.multi.copy()

  • 返回 {boolean}

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

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

$hid.multi.cut()

  • 返回 {boolean}

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

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

$hid.multi.paste()

  • 返回 {boolean}

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

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

$hid.multi.input(txt)

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

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

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

中文输入

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

$hid.multi.enter()

  • 返回 {boolean}

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

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

$hid.multi.delete([count])

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

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

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

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

$hid.multi.backspace([count])

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

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

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

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

原生键码操作

$hid.multi.keyPress(keyCode[, modifier])

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

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


单独按下截图键

js
// 按下截图键
$hid.multi.keyPress(70);

任务键组合模拟

js
var taskKeyCombo = $hid.multi.keyPress(43, 4);
console.log("任务键组合: ", taskKeyCombo);

主页键组合模拟

js
var homeKeyCombo = $hid.multi.keyPress(40, 8);
console.log("主页键组合: ", homeKeyCombo);

返回键组合模拟

js
var backKeyCombo = $hid.multi.keyPress(42, 5);
console.log("返回键组合: ", backKeyCombo);

触控操作

$hid.multi.click(x, y)

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

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

点击指定坐标(示例)

js
$hid.multi.click(540, 960);

点击屏幕中心点(示例)

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

$hid.multi.longClick(x, y)

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

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

长按指定坐标(示例)

js
$hid.multi.longClick(540, 960);

长按屏幕中心点(示例)

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

$hid.multi.press(x, y, duration)

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

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

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

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

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

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

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

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

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

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

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

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

$hid.multi.touchUp([id])

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

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

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

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

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

js
// 按下→移动→抬起
$hid.multi.touchDown(665, 557, 0);
sleep(2000);
$hid.multi.touchMove(400, 600, 1);
sleep(2000);
$hid.multi.touchMove(450, 500, 1);
sleep(2000);
$hid.multi.touchMove(600, 1100, 0);
sleep(2000);
$hid.multi.touchUp(0);
$hid.multi.touchUp(1);

多指触控示例

js
var width = device.width;
var height = device.height;
console.log("屏幕尺寸: ", width + "x" + height);
/* 蓝牙 OTG 支持多点触控 手指顺序必须从0开始 */
/* 带 ID 的多点触控 部分手机不兼容 */
/** 🖐️ 手指1(ID=0)从左侧中部向右滑动 */
console.log("手指1按下(ID=0):",  $hid.multi.touchDown(width / 4, height / 2, 0));
sleep(200);
/** 🖐️ 手指2(ID=1)从右侧中部向左滑动 */
console.log("手指2按下(ID=1):",  $hid.multi.touchDown(width * 3 / 4, height / 2, 1));
sleep(200);
/** 🖐️ 手指3(ID=2)从上方中间向下滑动 */
console.log("手指3按下(ID=2):",  $hid.multi.touchDown(width / 2, height / 4, 2));
sleep(200);
/** 🖐️ 手指4(ID=3)从下方中间向上滑动 */
console.log("手指4按下(ID=3):",  $hid.multi.touchDown(width / 2, height * 3 / 4, 3));
sleep(200);
/** 🖐️ 手指5(ID=4)左下角往右上 */
console.log("手指5按下(ID=4):",  $hid.multi.touchDown(width / 4, height * 3 / 4, 4));
sleep(200);

/** 多指同时移动 */
for (let i = 0; i < 5; i++) {
  let delta = i * 30; // 每步偏移量
  console.log("手指1移动:",  $hid.multi.touchMove(width / 4 + delta, height / 2, 0));
  console.log("手指2移动:",  $hid.multi.touchMove(width * 3 / 4 - delta, height / 2, 1));
  console.log("手指3移动:",  $hid.multi.touchMove(width / 2, height / 4 + delta, 2));
  console.log("手指4移动:",  $hid.multi.touchMove(width / 2, height * 3 / 4 - delta, 3));
  console.log("手指5移动:",  $hid.multi.touchMove(width / 4 + delta, height * 3 / 4 - delta, 4));
  sleep(800);
}
/** 抬起所有手指 */
for (let id = 0; id < 5; id++) {
  console.log(`手指${id+1}抬起:`,  $hid.multi.touchUp(id));
  sleep(300);
}

console.log("✅ 多指指触控测试完成");

多指触控兼容性

  • 部分设备或 ROM 不支持带 ID 的多点触控 API
  • 建议先在目标设备上验证兼容性
  • 若不支持可降级为两指/三指操作

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

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

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

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

$hid.multi.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.multi.swipe(500, 850, 500, 200, 30, 200, 500, 1000);

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

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

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

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

$hid.multi.swipeUp([width, height])

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

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

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

js
$hid.multi.swipeUp();

自定义屏幕尺寸滑动

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

$hid.multi.swipeDown([width, height])

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

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

$hid.multi.swipeLeft([width, height])

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

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

$hid.multi.swipeRight([width, height])

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

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

$hid.multi.zoomIn(targetX, targetY, stride)

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

模拟双指放大操作,以指定坐标为中心放大屏幕内容(如图片、页面)。
连续调用时间隔不应超过 800 毫秒,否则可能无法形成连续缩放效果。

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

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

$hid.multi.zoomOut(targetX, targetY, stride)

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

模拟双指缩小操作,以指定坐标为中心缩小屏幕内容。 连续调用时间隔不应超过 800 毫秒,否则可能无法形成连续缩放效果。

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

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

示例

全功能测试脚本

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

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

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

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

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

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

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

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

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

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

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

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

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

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

$hid.multi.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.multi.swipe(x1, y1, x2, y2, 1000);

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

toastLog("HID 测试完成!");
console.log("测试流程结束");

HID 控件节点查找点击

HID 控件请参见

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

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

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

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

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

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

HID YOLO目标检测点击

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

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

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

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

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

toastLog("连接成功!");
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.multi.click(yoloObject.bounds().centerX(), yoloObject.bounds().centerY());
    sleep(2000);

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

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

HID 找图查找点击

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

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

var state = $hid.multi.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.multi.click(x, y);
  sleep(2000);
} else {
  toastLog("未找到目标图片");
}

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

HID OCR文字识别找字点击

js

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

var state = $hid.multi.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.multi.click(x, y);
        sleep(2000);
        break;
      }
    }
  }

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

ocr.release();

总结

  1. 基础流程固定

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

    初始化 → 连接 多模 设备 → 状态检查 → 业务自动化操作

    其中:

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

  1. 文本输入推荐方案

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

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

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


  1. 权限与稳定性建议

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

  1. 截图方式灵活选择

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


  1. 目标定位方式多样

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

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

  1. 坐标操作统一

    无论使用哪种识别方式:

    👉 最终统一转换为坐标

    再通过 $hid.multi 执行:

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