306 lines
11 KiB
Rust
306 lines
11 KiB
Rust
#![cfg_attr(not(debug_assertions), windows_subsystem = "windows")]
|
|
|
|
use eframe::{egui, App, Frame, NativeOptions};
|
|
use egui::{FontFamily, FontId, RichText, Vec2, Color32, Rounding, Stroke};
|
|
use std::sync::{Arc, Mutex};
|
|
use std::thread;
|
|
use std::time::{Duration, Instant};
|
|
use winapi::um::winuser::{GetCursorPos, SetCursorPos, INPUT, INPUT_MOUSE, MOUSEINPUT, SendInput};
|
|
use winapi::shared::windef::POINT;
|
|
use rand::Rng;
|
|
use chrono::Local;
|
|
|
|
// 应用程序状态
|
|
#[derive(Clone)]
|
|
struct AppState {
|
|
running: Arc<Mutex<bool>>,
|
|
interval: Arc<Mutex<u64>>, // 间隔秒数
|
|
log_message: Arc<Mutex<String>>,
|
|
last_action: Arc<Mutex<Instant>>,
|
|
}
|
|
|
|
impl AppState {
|
|
fn new() -> Self {
|
|
AppState {
|
|
running: Arc::new(Mutex::new(false)),
|
|
interval: Arc::new(Mutex::new(30)),
|
|
log_message: Arc::new(Mutex::new(String::from("准备就绪"))),
|
|
last_action: Arc::new(Mutex::new(Instant::now())),
|
|
}
|
|
}
|
|
}
|
|
|
|
// 模拟鼠标微动
|
|
fn simulate_mouse_move() -> Result<(i32, i32), String> {
|
|
unsafe {
|
|
let mut point = POINT { x: 0, y: 0 };
|
|
if GetCursorPos(&mut point) == 0 {
|
|
return Err("无法获取鼠标位置".to_string());
|
|
}
|
|
|
|
let current_x = point.x;
|
|
let current_y = point.y;
|
|
|
|
// 随机微动 1-3 像素
|
|
let mut rng = rand::thread_rng();
|
|
let offset_x: i32 = if rng.gen_bool(0.5) { 1 } else { -1 } * rng.gen_range(1..=3);
|
|
let offset_y: i32 = if rng.gen_bool(0.5) { 1 } else { -1 } * rng.gen_range(1..=3);
|
|
|
|
let new_x = current_x + offset_x;
|
|
let new_y = current_y + offset_y;
|
|
|
|
// 移动鼠标到新位置
|
|
if SetCursorPos(new_x, new_y) == 0 {
|
|
return Err("无法移动鼠标".to_string());
|
|
}
|
|
|
|
// 短暂延迟后移回原位
|
|
thread::sleep(Duration::from_millis(100));
|
|
|
|
if SetCursorPos(current_x, current_y) == 0 {
|
|
return Err("无法恢复鼠标位置".to_string());
|
|
}
|
|
|
|
Ok((offset_x, offset_y))
|
|
}
|
|
}
|
|
|
|
// 后台工作线程
|
|
fn worker_thread(state: AppState) {
|
|
let mut last_move = Instant::now();
|
|
|
|
loop {
|
|
let running = *state.running.lock().unwrap();
|
|
if !running {
|
|
thread::sleep(Duration::from_millis(100));
|
|
continue;
|
|
}
|
|
|
|
let interval = *state.interval.lock().unwrap();
|
|
let elapsed = last_move.elapsed().as_secs();
|
|
|
|
if elapsed >= interval {
|
|
match simulate_mouse_move() {
|
|
Ok((offset_x, offset_y)) => {
|
|
let time_str = Local::now().format("%H:%M:%S").to_string();
|
|
let msg = format!("{} - 鼠标微动: ({}, {})", time_str, offset_x, offset_y);
|
|
*state.log_message.lock().unwrap() = msg;
|
|
}
|
|
Err(e) => {
|
|
let time_str = Local::now().format("%H:%M:%S").to_string();
|
|
let msg = format!("{} - 错误: {}", time_str, e);
|
|
*state.log_message.lock().unwrap() = msg;
|
|
}
|
|
}
|
|
last_move = Instant::now();
|
|
}
|
|
|
|
thread::sleep(Duration::from_millis(100));
|
|
}
|
|
}
|
|
|
|
// 主应用程序结构
|
|
struct AntiLockScreenApp {
|
|
state: AppState,
|
|
interval_input: String,
|
|
}
|
|
|
|
impl AntiLockScreenApp {
|
|
fn new() -> Self {
|
|
AntiLockScreenApp {
|
|
state: AppState::new(),
|
|
interval_input: "30".to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
impl App for AntiLockScreenApp {
|
|
fn update(&mut self, ctx: &egui::Context, _frame: &mut Frame) {
|
|
// 中文字体在第一次更新时加载
|
|
static FONT_LOADED: std::sync::Once = std::sync::Once::new();
|
|
FONT_LOADED.call_once(|| {
|
|
let mut fonts = egui::FontDefinitions::default();
|
|
|
|
// 尝试从系统加载中文字体
|
|
let font_paths = [
|
|
"C:/Windows/Fonts/msyh.ttc", // 微软雅黑
|
|
"C:/Windows/Fonts/simhei.ttf", // 黑体
|
|
"C:/Windows/Fonts/simsun.ttc", // 宋体
|
|
"C:/Windows/Fonts/msgothic.ttc", // 日文哥特体(备用)
|
|
];
|
|
|
|
for font_path in &font_paths {
|
|
if let Ok(font_data) = std::fs::read(font_path) {
|
|
fonts.font_data.insert(
|
|
"chinese_font".to_owned(),
|
|
egui::FontData::from_owned(font_data),
|
|
);
|
|
|
|
// 更新字体族
|
|
fonts.families.get_mut(&egui::FontFamily::Proportional)
|
|
.unwrap()
|
|
.insert(0, "chinese_font".to_owned());
|
|
|
|
fonts.families.get_mut(&egui::FontFamily::Monospace)
|
|
.unwrap()
|
|
.push("chinese_font".to_owned());
|
|
|
|
ctx.set_fonts(fonts);
|
|
break;
|
|
}
|
|
}
|
|
});
|
|
|
|
// 主窗口
|
|
egui::CentralPanel::default().show(ctx, |ui| {
|
|
ui.vertical_centered(|ui| {
|
|
ui.add_space(20.0);
|
|
|
|
// 标题
|
|
ui.label(
|
|
RichText::new("防止锁屏工具")
|
|
.font(FontId::new(24.0, FontFamily::Proportional))
|
|
.strong()
|
|
.color(Color32::from_rgb(51, 51, 51))
|
|
);
|
|
|
|
ui.add_space(15.0);
|
|
|
|
// 说明文字
|
|
ui.label(
|
|
RichText::new("点击开始后,程序会定期模拟鼠标微动")
|
|
.font(FontId::new(12.0, FontFamily::Proportional))
|
|
.color(Color32::from_rgb(102, 102, 102))
|
|
);
|
|
|
|
ui.label(
|
|
RichText::new("防止系统自动锁屏")
|
|
.font(FontId::new(12.0, FontFamily::Proportional))
|
|
.color(Color32::from_rgb(102, 102, 102))
|
|
);
|
|
|
|
ui.add_space(20.0);
|
|
|
|
// 间隔设置
|
|
ui.horizontal(|ui| {
|
|
ui.label(
|
|
RichText::new("微动间隔(秒):")
|
|
.font(FontId::new(12.0, FontFamily::Proportional))
|
|
);
|
|
|
|
let running = *self.state.running.lock().unwrap();
|
|
ui.add_enabled_ui(!running, |ui| {
|
|
ui.text_edit_singleline(&mut self.interval_input);
|
|
});
|
|
});
|
|
|
|
ui.add_space(15.0);
|
|
|
|
// 状态显示
|
|
let running = *self.state.running.lock().unwrap();
|
|
let status_text = if running { "状态: 运行中" } else { "状态: 已停止" };
|
|
let status_color = if running {
|
|
Color32::from_rgb(76, 175, 80)
|
|
} else {
|
|
Color32::from_rgb(244, 67, 54)
|
|
};
|
|
|
|
ui.label(
|
|
RichText::new(status_text)
|
|
.font(FontId::new(14.0, FontFamily::Proportional))
|
|
.color(status_color)
|
|
);
|
|
|
|
ui.add_space(10.0);
|
|
|
|
// 日志消息
|
|
let log_msg = self.state.log_message.lock().unwrap().clone();
|
|
ui.label(
|
|
RichText::new(&log_msg)
|
|
.font(FontId::new(10.0, FontFamily::Proportional))
|
|
.color(Color32::from_rgb(128, 128, 128))
|
|
);
|
|
|
|
ui.add_space(20.0);
|
|
|
|
// 按钮区域
|
|
ui.horizontal(|ui| {
|
|
// 开始按钮
|
|
let start_btn = ui.add_sized(
|
|
[100.0, 40.0],
|
|
egui::Button::new(
|
|
RichText::new("开始")
|
|
.font(FontId::new(14.0, FontFamily::Proportional))
|
|
.color(Color32::WHITE)
|
|
)
|
|
.fill(Color32::from_rgb(76, 175, 80))
|
|
.rounding(Rounding::same(5.0))
|
|
);
|
|
|
|
if start_btn.clicked() && !running {
|
|
// 解析间隔时间
|
|
if let Ok(interval) = self.interval_input.parse::<u64>() {
|
|
if interval >= 10 && interval <= 300 {
|
|
*self.state.interval.lock().unwrap() = interval;
|
|
*self.state.running.lock().unwrap() = true;
|
|
*self.state.log_message.lock().unwrap() = "防止锁屏已启动".to_string();
|
|
} else {
|
|
*self.state.log_message.lock().unwrap() = "间隔必须在10-300秒之间".to_string();
|
|
}
|
|
} else {
|
|
*self.state.log_message.lock().unwrap() = "请输入有效的数字".to_string();
|
|
}
|
|
}
|
|
|
|
ui.add_space(20.0);
|
|
|
|
// 停止按钮
|
|
let stop_btn = ui.add_sized(
|
|
[100.0, 40.0],
|
|
egui::Button::new(
|
|
RichText::new("停止")
|
|
.font(FontId::new(14.0, FontFamily::Proportional))
|
|
.color(Color32::WHITE)
|
|
)
|
|
.fill(Color32::from_rgb(244, 67, 54))
|
|
.rounding(Rounding::same(5.0))
|
|
);
|
|
|
|
if stop_btn.clicked() && running {
|
|
*self.state.running.lock().unwrap() = false;
|
|
*self.state.log_message.lock().unwrap() = "防止锁屏已停止".to_string();
|
|
}
|
|
});
|
|
});
|
|
});
|
|
|
|
// 请求连续更新以刷新UI
|
|
ctx.request_repaint_after(Duration::from_millis(100));
|
|
}
|
|
}
|
|
|
|
fn main() -> Result<(), eframe::Error> {
|
|
// 启动后台工作线程
|
|
let state = AppState::new();
|
|
let worker_state = state.clone();
|
|
|
|
thread::spawn(move || {
|
|
worker_thread(worker_state);
|
|
});
|
|
|
|
// 应用程序选项
|
|
let options = NativeOptions {
|
|
viewport: egui::ViewportBuilder::default()
|
|
.with_inner_size([400.0, 280.0])
|
|
.with_resizable(false),
|
|
..Default::default()
|
|
};
|
|
|
|
// 运行应用程序
|
|
eframe::run_native(
|
|
"防止锁屏工具",
|
|
options,
|
|
Box::new(|_cc| Box::new(AntiLockScreenApp::new())),
|
|
)
|
|
}
|