Rust中如何使用enigo库结合test.json配置实现定时模拟按键操作
问题背景
现有test.json配置文件内容如下:
[ [1000,800,1], [1500,0,2], [1600,0,3], [2500,300,4] ]
数组每一项的三个元素分别对应:
- 第一个:触发开始时间,单位毫秒
- 第二个:按键持续时长,单位毫秒
- 第三个:按键标识,1/2/3/4分别对应a/b/c/d键
需求:运行时间达到指定开始时间时,按下对应按键并保持指定时长后松开。
现有依赖配置(Cargo.toml)
[dependencies] delay_timer = "0.10.1" enigo = "0.0.14" serde_json = "1.0" anyhow = "1.0.51" smol = "1.2.5"
现有main.rs代码
use anyhow::Result; use delay_timer::prelude::*; use enigo::*; use serde_json::{Result as SResult, Value}; use smol::Timer; use std::fs::File; use std::io::BufReader; use std::thread; use std::time::Duration; fn main() -> Result<()> { let delay_timer = DelayTimerBuilder::default().build(); let task_instance_chain = delay_timer .insert_task(build_task_async_print().unwrap()) .unwrap(); let task_instance = task_instance_chain.next_with_wait().unwrap(); while task_instance.get_state() != delay_timer::prelude::instance::COMPLETED {} delay_timer.remove_task(1).unwrap(); Ok(()) } fn build_task_async_print() -> Result<Task, TaskError> { let mut task_builder = TaskBuilder::default(); let body = create_async_fn_body!({ let json_data = get_json().unwrap(); for element in json_data.as_array().unwrap().iter() { Timer::after(Duration::from_millis(element[0].as_f64().unwrap() as u64)).await; println!("the value is: {}", element[0]); // 此处为需要补全的enigo按键逻辑,当前为固定按a键的示例代码 let mut enigo = Enigo::new(); enigo.key_down(Key::Layout('a')); thread::sleep(Duration::from_millis(element[1].as_f64().unwrap() as u64)); enigo.key_up(Key::Layout('a')); } }); task_builder.set_task_id(1).spawn(body) } fn get_json() -> SResult<Value> { let file = File::open("test.json").expect("file should open read only"); let reader = BufReader::new(file); let mut v: Value = serde_json::from_reader(reader)?; Ok(v.take()) }
补全实现方案
首先需要在main.rs头部新增导入:use std::time::Instant;
核心修改点如下:
- 增加按键标识到字符的映射逻辑,实现动态按键
- 修复原有时间计算错误:原逻辑每次循环都等待对应开始时间,会导致后续按键触发时间远晚于预期,改为以任务启动时间为基准计算等待间隔
- 将异步块内的阻塞式
thread::sleep替换为异步延时,避免阻塞runtime - 将enigo实例初始化移到循环外,减少重复初始化开销
修改后的build_task_async_print函数完整代码:
fn build_task_async_print() -> Result<Task, TaskError> { let mut task_builder = TaskBuilder::default(); let body = create_async_fn_body!({ let json_data = get_json().unwrap(); let mut enigo = Enigo::new(); // 记录任务启动基准时间 let start_time = Instant::now(); for element in json_data.as_array().unwrap().iter() { let trigger_time = element[0].as_f64().unwrap() as u64; let duration = element[1].as_f64().unwrap() as u64; let key_id = element[2].as_u64().unwrap() as u8; // 计算实际需要等待的时间 let elapsed = start_time.elapsed().as_millis() as u64; if trigger_time > elapsed { Timer::after(Duration::from_millis(trigger_time - elapsed)).await; } // 映射按键 let key_char = match key_id { 1 => 'a', 2 => 'b', 3 => 'c', 4 => 'd', _ => panic!("不支持的按键标识: {}", key_id) }; println!("触发按键: {},持续时长: {}ms", key_char, duration); enigo.key_down(Key::Layout(key_char)); // 异步等待按键持续时长 Timer::after(Duration::from_millis(duration)).await; enigo.key_up(Key::Layout(key_char)); } }); task_builder.set_task_id(1).spawn(body) }
内容的提问来源于stack exchange,提问作者zwl1619
相关产品推荐
相关产品推荐

