使用音量加键监听来停止脚本,无法实现在while循环里面停止脚本

wrekemdkwh · 2 天前
第 1 条补充
·
2 天前

考虑使用exit事件来执行清理工作的完整代码

第 2 条补充
·
2 天前

使用子线程来监听音量加按键来实现停止脚本

回答

Hamibot AI
1
· 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 生成,内容仅供参考