使用音量加键监听来停止脚本,无法实现在while循环里面停止脚本
第 1 条补充
· 2 天前
考虑使用exit事件来执行清理工作的完整代码
第 2 条补充
· 2 天前
使用子线程来监听音量加按键来实现停止脚本
回答
你遇到的问题是因为JavaScript是单线程执行的,当你在脚本中使用while(true)死循环时,主线程会被完全占用,导致事件队列中的按键事件无法得到及时处理。
根据Hamibot的事件机制,事件处理是在原线程执行的,如果脚本主体有耗时操作或死循环,事件会进入队列等待,直到主线程空闲才能处理。
正确的实现方式应该是:
// 文档地址 https://docs.hamibot.com/
// 启用按键监听
events.observeKey();
// 设置音量加键停止脚本
events.on('key_down', function(keyCode, event) {
if (keyCode === keys.volume_up) {
toast("音量加键按下,脚本停止");
hamibot.exit();
}
});
// 不要使用死循环
// while(true) {} 会阻塞事件处理
// 正确的长时间运行方式:使用循环但加入sleep让出执行权
while(true) {
// 你的脚本逻辑
// 关键:加入sleep让出执行权,以便处理事件
sleep(100);
}
如果你确实需要长时间执行某些操作,应该在循环中加入sleep(100)这样的短暂休眠,让出执行权,这样事件系统才有机会处理按键事件。
另外,你也可以考虑使用exit事件来执行清理工作:
log('脚本开始运行');
events.on('exit', function() {
log('脚本已停止');
// 清理工作
});
// 主逻辑
while(true) {
// 你的操作
sleep(100);
}
这样设计后,当按下音量加键时,脚本就能及时响应并停止执行了。
补充回答 1
// 文档地址 https://docs.hamibot.com/
// 启用无障碍服务
auto.waitFor();
// 启用按键监听
events.observeKey();
// 设置音量加键停止脚本
events.on('key_down', function(keyCode, event) {
if (keyCode === keys.volume_up) {
toast("检测到音量加键,脚本将停止");
hamibot.exit();
}
});
// 注册exit事件处理程序 - 用于清理工作
events.on('exit', function() {
log('==== 脚本退出清理开始 ====');
// 执行清理操作
try {
// 关闭可能打开的应用
home();
sleep(500);
// 清理创建的悬浮窗
if (typeof myFloatyWindow !== 'undefined' && myFloatyWindow) {
myFloatyWindow.close();
log('已关闭悬浮窗');
}
// 保存重要数据
if (typeof scriptData !== 'undefined') {
files.write('./script_data.json', JSON.stringify(scriptData));
log('已保存脚本数据');
}
// 发送退出通知
hamibot.postMessage('脚本已安全退出', {
telemetry: true,
data: {
title: '脚本退出通知',
attachments: [{
type: 'json',
data: JSON.stringify({
exitTime: new Date().toISOString(),
status: 'normal'
})
}]
}
});
log('==== 脚本退出清理完成 ====');
} catch (e) {
log('清理过程中出错: ' + e.message);
}
});
// 创建一个简单的悬浮窗用于演示
var window = floaty.window(
<frame gravity="center">
<text id="text" textSize="16sp" textColor="#FFFFFF">脚本运行中...\n按音量加键停止</text>
</frame>
);
window.setPosition(100, 100);
window.exitOnClose();
// 在UI线程更新悬浮窗
setInterval(() => {
window.text.setText("脚本运行中...\n按音量加键停止");
}, 1000);
// 主循环 - 不要使用死循环阻塞事件队列
var counter = 0;
var scriptData = { runs: 0 };
while(true) {
try {
counter++;
scriptData.runs = counter;
// 模拟一些操作
log('脚本运行中...计数: ' + counter);
// 关键:加入sleep让出执行权,以便处理事件
sleep(1000);
// 每10秒更新悬浮窗
if (counter % 10 === 0) {
window.text.setText("脚本运行中...\n已运行 " + counter + " 秒\n按音量加键停止");
}
} catch (e) {
log('主循环出错: ' + e.message);
// 发送错误报告
hamibot.postMessage('脚本错误', {
telemetry: true,
data: {
title: '脚本错误',
attachments: [{
type: 'json',
data: JSON.stringify({
error: e.message,
stack: e.stack,
counter: counter
})
}]
}
});
sleep(5000); // 出错后暂停几秒再继续
}
}
补充回答 2
// 文档地址 https://docs.hamibot.com/
// 启用无障碍服务
auto.waitFor();
// 创建一个标志位用于控制脚本运行
var shouldExit = false;
// 在子线程中运行主逻辑
var mainThread = threads.start(function() {
try {
// 主逻辑循环
while(!shouldExit) {
log("主任务执行中...");
// 模拟一些操作
sleep(1000);
// 添加其他自动化操作
//例如: id("some_id").findOne().click();
}
} catch (e) {
if (e.javaException && e.javaException instanceof java.lang.InterruptedException) {
log("主任务线程被中断");
} else {
log("主任务出错: " + e.message);
}
} finally {
log("主任务线程结束");
}
});
// 在另一个子线程中专门监听按键事件
threads.start(function() {
// 必须在主线程启用按键监听,但可以在子线程中注册事件处理
events.on('key_down', function(keyCode, event) {
if (keyCode === keys.volume_up) {
toast("音量加键按下,准备停止脚本");
shouldExit = true;
// 中断主任务线程
if (mainThread && mainThread.isAlive()) {
mainThread.interrupt();
}
// 退出脚本
hamibot.exit();
}
});
// 持续启用按键监听
while(!shouldExit) {
try {
events.observeKey();
sleep(1000);
} catch (e) {
log("按键监听出错: " + e.message);
sleep(5000);
}
}
});
// 注册exit事件处理程序
events.on('exit', function() {
log('==== 脚本退出清理开始 ====');
// 执行清理操作
try {
// 关闭悬浮窗等资源
// 发送退出通知
toast("脚本已安全退出");
} catch (e) {
log('清理过程中出错: ' + e.message);
}
log('==== 脚本退出清理完成 ====');
});
// 主线程等待,但不要阻塞事件处理
while(!shouldExit) {
sleep(100);
}
ℹ️ 本回答由 AI 生成,内容仅供参考