Compare commits
20 Commits
bdf1358b0a
...
master
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0969df9311 | ||
|
|
78b50e8ecf | ||
|
|
d5e0791f3c | ||
|
|
d0caea5b0c | ||
|
|
b5ea605e0d | ||
|
|
bc3b0a976b | ||
|
|
a22be802fd | ||
|
|
8c5772cac1 | ||
|
|
7af0fe5e47 | ||
|
|
47dab2e977 | ||
|
|
5eb4440c0a | ||
|
|
905e5b173f | ||
|
|
15e56120f4 | ||
|
|
bbf77c0143 | ||
|
|
4846b0fe4b | ||
|
|
2e7eac2c86 | ||
|
|
7c8faa2ac7 | ||
| afba38497b | |||
| 41ccd4174e | |||
| cb73725b6c |
6
.gitignore
vendored
6
.gitignore
vendored
@@ -30,3 +30,9 @@ Thumbs.db
|
||||
build/
|
||||
dist/
|
||||
*.egg-info/
|
||||
*.spec
|
||||
|
||||
# Rust 构建产物
|
||||
target/
|
||||
*.exe
|
||||
*.res
|
||||
244
README.md
244
README.md
@@ -4,6 +4,8 @@
|
||||
|
||||
面向32台终端的内网低延迟屏幕广播系统,支持网络投屏、硬件接口互通、一键自动化运维。
|
||||
|
||||
本项目提供 **Python (PySide6)** 和 **Rust (egui)** 两个版本的投屏控制客户端。
|
||||
|
||||
## 需求说明
|
||||
|
||||
当前会议投屏需求涉及通过视频矩阵系统向32台终端设备进行同步投屏。具体模式可分为以下两类:
|
||||
@@ -18,6 +20,17 @@
|
||||
|
||||
参考文档:<https://docs.qq.com/doc/DQXFpdHN5Rk9yRGpC>
|
||||
|
||||
## 客户端版本对比
|
||||
|
||||
| 特性 | Python (PySide6) | Rust (egui) |
|
||||
|------|------------------|-------------|
|
||||
| **GUI 框架** | PySide6 (Qt) | egui (即时模式) |
|
||||
| **编译方式** | PyInstaller | Cargo + GNU 工具链 |
|
||||
| **文件大小** | ~50MB | ~4MB |
|
||||
| **启动速度** | 较慢 | 快 |
|
||||
| **依赖** | 需 Python 运行时 | 独立可执行文件 |
|
||||
| **界面风格** | 原生 Windows 风格 | 自定义风格 |
|
||||
|
||||
## 整体部署步骤(细化版)
|
||||
|
||||
### 步骤1:MediaMTX服务器端
|
||||
@@ -48,13 +61,24 @@
|
||||
|
||||
### 主播端:推送本机屏幕
|
||||
|
||||
**方案A:使用push\_screen.py脚本**
|
||||
**方案A:使用 Rust 客户端(推荐)**
|
||||
|
||||
1. **下载预编译版本**
|
||||
- 从 Releases 下载 `push_screen.exe`
|
||||
- 或使用源码自行编译(见下方编译说明)
|
||||
|
||||
2. **运行程序**
|
||||
- 双击运行 `push_screen.exe`
|
||||
- 点击「设置」按钮配置服务器IP和FFmpeg路径
|
||||
- 点击「开始全屏投屏」按钮开始推流
|
||||
|
||||
**方案B:使用 Python 客户端**
|
||||
|
||||
- 双击运行 `push_screen.py`
|
||||
- 点击「一键全屏投屏」按钮
|
||||
- 脚本会自动启动MediaMTX并开始推流
|
||||
|
||||
**方案B:使用mss抓屏+FFmpeg推流**
|
||||
**方案C:使用mss抓屏+FFmpeg推流**
|
||||
|
||||
```python
|
||||
import subprocess
|
||||
@@ -217,6 +241,166 @@ MediaMTX 会返回内置的 WebRTC 播放页面,浏览器会自动播放HDMI
|
||||
|
||||
所有32台终端均可通过浏览器访问上述地址观看视频会议内容。
|
||||
|
||||
## Rust 客户端编译指南
|
||||
|
||||
### 环境准备
|
||||
|
||||
1. **安装 Rust**
|
||||
- 下载地址:`https://rustup.rs/`
|
||||
- 安装时选择 `x86_64-pc-windows-gnu` 目标
|
||||
|
||||
2. **安装 MinGW-w64**(GNU 工具链)
|
||||
- 推荐通过 MSYS2 安装:`pacman -S mingw-w64-x86_64-toolchain`
|
||||
- 或下载 winlibs MinGW-w64
|
||||
|
||||
3. **添加 Rust 目标**
|
||||
```bash
|
||||
rustup target add x86_64-pc-windows-gnu
|
||||
```
|
||||
|
||||
### 项目结构
|
||||
|
||||
```
|
||||
push_screen_rust/
|
||||
├── Cargo.toml # 项目配置
|
||||
├── build.rs # 构建脚本(用于嵌入图标)
|
||||
├── app.rc # Windows 资源文件
|
||||
├── vi.ico # 应用程序图标
|
||||
└── src/
|
||||
└── main.rs # 主程序
|
||||
```
|
||||
|
||||
### 依赖库对照(PySide6 vs Rust)
|
||||
|
||||
| Python/PySide6 | Rust 等效库 | 用途 |
|
||||
|----------------|-------------|------|
|
||||
| PySide6 (Qt) | `eframe` + `egui` | GUI 框架 |
|
||||
| `QThread` | `std::thread` + `mpsc` | 多线程 |
|
||||
| `QTimer` | `std::time::Duration` + 线程休眠 | 定时器 |
|
||||
| `socket` | `std::net::TcpStream` | 网络检测 |
|
||||
| `subprocess` | `std::process::Command` | 进程管理 |
|
||||
| `json` | `serde` + `serde_json` | JSON 序列化 |
|
||||
| `logging` | `tracing` + `tracing-subscriber` | 日志记录 |
|
||||
| `requests` | `reqwest` | HTTP 客户端 |
|
||||
|
||||
### 编译参数对照(PyInstaller vs Cargo)
|
||||
|
||||
| PyInstaller 参数 | Cargo/Rust 等效配置 | 说明 |
|
||||
|------------------|---------------------|------|
|
||||
| `--onefile` | `lto = true` + `strip = true` | 优化体积 |
|
||||
| `--windowed` | `#![windows_subsystem = "windows"]` | 隐藏控制台 |
|
||||
| `--icon=vi.ico` | `windres app.rc -O coff -o app.res` + 链接 | 嵌入图标 |
|
||||
| `--noconsole` | `windows_subsystem` 属性 | 无控制台窗口 |
|
||||
|
||||
### 编译步骤
|
||||
|
||||
1. **进入项目目录**
|
||||
```bash
|
||||
cd push_screen_rust
|
||||
```
|
||||
|
||||
2. **编译资源文件(图标)**
|
||||
```bash
|
||||
windres app.rc -O coff -o app.res
|
||||
```
|
||||
|
||||
3. **配置构建脚本**(`build.rs`)
|
||||
```rust
|
||||
use std::env;
|
||||
|
||||
fn main() {
|
||||
let target = env::var("TARGET").unwrap();
|
||||
if target.contains("windows") {
|
||||
println!("cargo:rustc-link-arg=app.res");
|
||||
}
|
||||
println!("cargo:rerun-if-changed=app.rc");
|
||||
println!("cargo:rerun-if-changed=vi.ico");
|
||||
}
|
||||
```
|
||||
|
||||
4. **配置 Cargo.toml**
|
||||
```toml
|
||||
[package]
|
||||
name = "push_screen_rust"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
build = "build.rs"
|
||||
|
||||
[dependencies]
|
||||
eframe = { version = "0.24", features = ["default"] }
|
||||
egui = "0.24"
|
||||
tokio = { version = "1", features = ["full"] }
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
reqwest = { version = "0.11", features = ["json"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = "0.3"
|
||||
winapi = { version = "0.3", features = ["winuser", "windef", "wingdi", ...] }
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
# strip = true # 取消注释以进一步减小体积
|
||||
|
||||
[[bin]]
|
||||
name = "push_screen"
|
||||
path = "src/main.rs"
|
||||
```
|
||||
|
||||
5. **编译发布版本**
|
||||
```bash
|
||||
cargo build --release --target x86_64-pc-windows-gnu
|
||||
```
|
||||
|
||||
6. **输出文件**
|
||||
- 位置:`target/x86_64-pc-windows-gnu/release/push_screen.exe`
|
||||
- 大小:约 4-5 MB
|
||||
|
||||
### 关键代码说明
|
||||
|
||||
**隐藏控制台窗口**
|
||||
```rust
|
||||
#![windows_subsystem = "windows"]
|
||||
```
|
||||
|
||||
**设置 UTF-8 编码(解决中文乱码)**
|
||||
```rust
|
||||
#[cfg(windows)]
|
||||
extern "system" {
|
||||
fn SetConsoleOutputCP(wCodePageID: u32) -> i32;
|
||||
fn SetConsoleCP(wCodePageID: u32) -> i32;
|
||||
}
|
||||
|
||||
fn set_utf8_encoding() {
|
||||
#[cfg(windows)]
|
||||
unsafe {
|
||||
SetConsoleOutputCP(65001); // UTF-8
|
||||
SetConsoleCP(65001);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
**加载中文字体**
|
||||
```rust
|
||||
fn configure_fonts(ctx: &egui::Context) {
|
||||
let mut fonts = egui::FontDefinitions::default();
|
||||
|
||||
// 从系统加载中文字体
|
||||
let font_paths = [
|
||||
r"C:\Windows\Fonts\msyh.ttc", // 微软雅黑
|
||||
r"C:\Windows\Fonts\simsun.ttc", // 宋体
|
||||
];
|
||||
|
||||
for font_path in &font_paths {
|
||||
if let Ok(font_data) = std::fs::read(font_path) {
|
||||
// 加载字体...
|
||||
}
|
||||
}
|
||||
|
||||
ctx.set_fonts(fonts);
|
||||
}
|
||||
```
|
||||
|
||||
## 测试方案
|
||||
|
||||
使用1台台式机模拟MediaMTX服务器,2台笔记本分别模拟信号源和观众,测试两种场景。
|
||||
@@ -249,7 +433,7 @@ MediaMTX 会返回内置的 WebRTC 播放页面,浏览器会自动播放HDMI
|
||||
确认控制台显示端口监听正常
|
||||
|
||||
2. **笔记本A启动推流**
|
||||
- 运行 `push_screen.py`
|
||||
- 运行 `push_screen.exe` (Rust) 或 `push_screen.py` (Python)
|
||||
- 或使用命令行推流:
|
||||
```bat
|
||||
ffmpeg -f gdigrab -framerate 30 -i desktop -c:v libx264 -preset ultrafast -tune zerolatency -f rtsp rtsp://192.168.1.100:8554/screen
|
||||
@@ -319,21 +503,57 @@ D:\ScreenCast
|
||||
│ └── mediamtx.exe
|
||||
├── ffmpeg/ # FFmpeg解压目录
|
||||
│ └── bin/ffmpeg.exe
|
||||
├── push_screen.py # 投屏源推流脚本(一键采集)
|
||||
├── push_screen_rust/ # Rust 客户端源码
|
||||
│ ├── Cargo.toml
|
||||
│ ├── build.rs
|
||||
│ ├── app.rc
|
||||
│ ├── vi.ico
|
||||
│ └── src/main.rs
|
||||
├── push_screen.exe # Rust 编译后的可执行文件(推荐)
|
||||
├── push_screen.py # Python 投屏源推流脚本
|
||||
├── auto_receive.py # 终端自动打开浏览器脚本
|
||||
└── manage_server.py # 运维总控脚本(启动/切换模式/停止)
|
||||
└── manage_server.py # 运维总控脚本
|
||||
```
|
||||
|
||||
## 核心Python脚本
|
||||
## 核心脚本说明
|
||||
|
||||
### 脚本1:投屏源推流脚本(push\_screen.py)
|
||||
### Rust 客户端(push_screen_rust)
|
||||
|
||||
功能:双击即可采集Win10屏幕,自动推流到MediaMTX,无需敲命令;支持「全屏/指定窗口」投屏,带可视化提示。
|
||||
**功能**:轻量级投屏控制客户端,单文件可执行,无需运行时依赖。
|
||||
|
||||
### 脚本2:终端自动打开浏览器脚本(auto\_receive.py)
|
||||
**特性**:
|
||||
- 实时状态检测(FFmpeg、服务器、端口)
|
||||
- 配置持久化(config.json)
|
||||
- 一键开始/停止推流
|
||||
- 中文字体支持
|
||||
- 自定义应用程序图标
|
||||
|
||||
功能:双击脚本自动打开Chrome浏览器(全屏),直接跳转到投屏/会议流页面;支持批量部署到32台终端,无需手动输入地址。
|
||||
**编译命令**:
|
||||
```bash
|
||||
cd push_screen_rust
|
||||
windres app.rc -O coff -o app.res
|
||||
cargo build --release --target x86_64-pc-windows-gnu
|
||||
```
|
||||
|
||||
### 脚本3:运维总控脚本(manage\_server.py)
|
||||
### Python 客户端(push_screen.py)
|
||||
|
||||
功能:一站式运维(启动MediaMTX、切换两种模式、批量控制32台终端、停止所有服务),适合管理员操作。
|
||||
**功能**:基于 PySide6 的投屏控制界面,功能完善。
|
||||
|
||||
**特性**:
|
||||
- 可视化配置界面
|
||||
- 实时状态指示器
|
||||
- 日志显示
|
||||
- 设置对话框
|
||||
|
||||
**运行命令**:
|
||||
```bash
|
||||
python push_screen.py
|
||||
```
|
||||
|
||||
### 终端自动打开浏览器脚本(auto_receive.py)
|
||||
|
||||
**功能**:双击脚本自动打开Chrome浏览器(全屏),直接跳转到投屏/会议流页面;支持批量部署到32台终端,无需手动输入地址。
|
||||
|
||||
### 运维总控脚本(manage_server.py)
|
||||
|
||||
**功能**:一站式运维(启动MediaMTX、切换两种模式、批量控制32台终端、停止所有服务),适合管理员操作。
|
||||
|
||||
207
anti_lockscreen.py
Normal file
207
anti_lockscreen.py
Normal file
@@ -0,0 +1,207 @@
|
||||
import sys
|
||||
import random
|
||||
import threading
|
||||
import time
|
||||
from PySide6.QtWidgets import QApplication, QWidget, QVBoxLayout, QPushButton, QLabel, QSpinBox, QHBoxLayout
|
||||
from PySide6.QtCore import Qt, QThread, Signal
|
||||
from PySide6.QtGui import QFont
|
||||
import pyautogui
|
||||
from loguru import logger
|
||||
|
||||
|
||||
class AntiLockThread(QThread):
|
||||
log_signal = Signal(str)
|
||||
|
||||
def __init__(self, interval=30):
|
||||
super().__init__()
|
||||
self.interval = interval
|
||||
self.running = False
|
||||
|
||||
def run(self):
|
||||
self.running = True
|
||||
self.log_signal.emit("防止锁屏已启动")
|
||||
logger.info("防止锁屏线程已启动")
|
||||
|
||||
while self.running:
|
||||
try:
|
||||
# 获取当前鼠标位置
|
||||
current_x, current_y = pyautogui.position()
|
||||
|
||||
# 随机微动 1-3 像素
|
||||
offset_x = random.choice([-1, 1]) * random.randint(1, 3)
|
||||
offset_y = random.choice([-1, 1]) * random.randint(1, 3)
|
||||
|
||||
# 移动鼠标
|
||||
pyautogui.moveTo(current_x + offset_x, current_y + offset_y, duration=0.1)
|
||||
time.sleep(0.1)
|
||||
pyautogui.moveTo(current_x, current_y, duration=0.1)
|
||||
|
||||
msg = f"鼠标微动: ({current_x}, {current_y}) -> ({current_x + offset_x}, {current_y + offset_y}) -> ({current_x}, {current_y})"
|
||||
self.log_signal.emit(msg)
|
||||
logger.info(msg)
|
||||
|
||||
# 等待指定间隔
|
||||
for _ in range(self.interval):
|
||||
if not self.running:
|
||||
break
|
||||
time.sleep(1)
|
||||
|
||||
except Exception as e:
|
||||
error_msg = f"发生错误: {str(e)}"
|
||||
self.log_signal.emit(error_msg)
|
||||
logger.error(error_msg)
|
||||
time.sleep(1)
|
||||
|
||||
def stop(self):
|
||||
self.running = False
|
||||
self.log_signal.emit("防止锁屏已停止")
|
||||
logger.info("防止锁屏线程已停止")
|
||||
|
||||
|
||||
class AntiLockScreenApp(QWidget):
|
||||
def __init__(self):
|
||||
super().__init__()
|
||||
self.anti_lock_thread = None
|
||||
self.init_ui()
|
||||
|
||||
def init_ui(self):
|
||||
self.setWindowTitle("防止锁屏工具")
|
||||
self.setFixedSize(400, 250)
|
||||
|
||||
# 主布局
|
||||
layout = QVBoxLayout()
|
||||
layout.setSpacing(15)
|
||||
layout.setContentsMargins(20, 20, 20, 20)
|
||||
|
||||
# 标题
|
||||
title_label = QLabel("防止锁屏工具")
|
||||
title_label.setFont(QFont("Microsoft YaHei", 16, QFont.Bold))
|
||||
title_label.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(title_label)
|
||||
|
||||
# 说明文字
|
||||
desc_label = QLabel("点击开始后,程序会定期模拟鼠标微动,防止系统自动锁屏")
|
||||
desc_label.setWordWrap(True)
|
||||
desc_label.setAlignment(Qt.AlignCenter)
|
||||
layout.addWidget(desc_label)
|
||||
|
||||
# 间隔设置
|
||||
interval_layout = QHBoxLayout()
|
||||
interval_label = QLabel("微动间隔(秒):")
|
||||
self.interval_spinbox = QSpinBox()
|
||||
self.interval_spinbox.setRange(10, 300)
|
||||
self.interval_spinbox.setValue(30)
|
||||
self.interval_spinbox.setSuffix(" 秒")
|
||||
interval_layout.addStretch()
|
||||
interval_layout.addWidget(interval_label)
|
||||
interval_layout.addWidget(self.interval_spinbox)
|
||||
interval_layout.addStretch()
|
||||
layout.addLayout(interval_layout)
|
||||
|
||||
# 状态标签
|
||||
self.status_label = QLabel("状态: 已停止")
|
||||
self.status_label.setFont(QFont("Microsoft YaHei", 10))
|
||||
self.status_label.setAlignment(Qt.AlignCenter)
|
||||
self.status_label.setStyleSheet("color: red;")
|
||||
layout.addWidget(self.status_label)
|
||||
|
||||
# 日志标签
|
||||
self.log_label = QLabel("")
|
||||
self.log_label.setWordWrap(True)
|
||||
self.log_label.setAlignment(Qt.AlignCenter)
|
||||
self.log_label.setStyleSheet("color: gray; font-size: 10px;")
|
||||
layout.addWidget(self.log_label)
|
||||
|
||||
# 按钮布局
|
||||
button_layout = QHBoxLayout()
|
||||
|
||||
# 开始按钮
|
||||
self.start_btn = QPushButton("开始")
|
||||
self.start_btn.setFixedHeight(40)
|
||||
self.start_btn.setFont(QFont("Microsoft YaHei", 11))
|
||||
self.start_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #4CAF50;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #45a049;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #3d8b40;
|
||||
}
|
||||
""")
|
||||
self.start_btn.clicked.connect(self.start_anti_lock)
|
||||
button_layout.addWidget(self.start_btn)
|
||||
|
||||
# 停止按钮
|
||||
self.stop_btn = QPushButton("停止")
|
||||
self.stop_btn.setFixedHeight(40)
|
||||
self.stop_btn.setFont(QFont("Microsoft YaHei", 11))
|
||||
self.stop_btn.setStyleSheet("""
|
||||
QPushButton {
|
||||
background-color: #f44336;
|
||||
color: white;
|
||||
border: none;
|
||||
border-radius: 5px;
|
||||
}
|
||||
QPushButton:hover {
|
||||
background-color: #da190b;
|
||||
}
|
||||
QPushButton:pressed {
|
||||
background-color: #b71c1c;
|
||||
}
|
||||
""")
|
||||
self.stop_btn.clicked.connect(self.stop_anti_lock)
|
||||
self.stop_btn.setEnabled(False)
|
||||
button_layout.addWidget(self.stop_btn)
|
||||
|
||||
layout.addLayout(button_layout)
|
||||
layout.addStretch()
|
||||
|
||||
self.setLayout(layout)
|
||||
|
||||
def start_anti_lock(self):
|
||||
interval = self.interval_spinbox.value()
|
||||
self.anti_lock_thread = AntiLockThread(interval)
|
||||
self.anti_lock_thread.log_signal.connect(self.update_log)
|
||||
self.anti_lock_thread.start()
|
||||
|
||||
self.status_label.setText("状态: 运行中")
|
||||
self.status_label.setStyleSheet("color: green;")
|
||||
self.start_btn.setEnabled(False)
|
||||
self.stop_btn.setEnabled(True)
|
||||
self.interval_spinbox.setEnabled(False)
|
||||
|
||||
def stop_anti_lock(self):
|
||||
if self.anti_lock_thread and self.anti_lock_thread.isRunning():
|
||||
self.anti_lock_thread.stop()
|
||||
self.anti_lock_thread.wait()
|
||||
|
||||
self.status_label.setText("状态: 已停止")
|
||||
self.status_label.setStyleSheet("color: red;")
|
||||
self.start_btn.setEnabled(True)
|
||||
self.stop_btn.setEnabled(False)
|
||||
self.interval_spinbox.setEnabled(True)
|
||||
|
||||
def update_log(self, message):
|
||||
self.log_label.setText(message)
|
||||
logger.info(message)
|
||||
|
||||
def closeEvent(self, event):
|
||||
self.stop_anti_lock()
|
||||
event.accept()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
logger.add("anti_lockscreen.log", rotation="1 MB", retention="7 days")
|
||||
|
||||
app = QApplication(sys.argv)
|
||||
app.setStyle("Fusion")
|
||||
|
||||
window = AntiLockScreenApp()
|
||||
window.show()
|
||||
|
||||
sys.exit(app.exec())
|
||||
2480
anti_lockscreen_rust/Cargo.lock
generated
Normal file
2480
anti_lockscreen_rust/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
22
anti_lockscreen_rust/Cargo.toml
Normal file
22
anti_lockscreen_rust/Cargo.toml
Normal file
@@ -0,0 +1,22 @@
|
||||
[package]
|
||||
name = "anti_lockscreen_rust"
|
||||
version = "1.0.0"
|
||||
edition = "2021"
|
||||
authors = ["Your Name"]
|
||||
description = "防止锁屏工具 - Rust版本"
|
||||
|
||||
[dependencies]
|
||||
eframe = { version = "0.24", default-features = false, features = ["default_fonts", "glow"] }
|
||||
egui = "0.24"
|
||||
winapi = { version = "0.3", features = ["winuser", "processthreadsapi", "handleapi", "winbase"] }
|
||||
chrono = "0.4"
|
||||
rand = "0.8"
|
||||
|
||||
[profile.release]
|
||||
opt-level = 3
|
||||
lto = true
|
||||
strip = true
|
||||
|
||||
[[bin]]
|
||||
name = "防止锁屏工具"
|
||||
path = "src/main.rs"
|
||||
38
anti_lockscreen_rust/build.rs
Normal file
38
anti_lockscreen_rust/build.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() {
|
||||
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||
|
||||
// 设置 Windows 应用程序图标
|
||||
let icon_path = PathBuf::from("unlock.ico");
|
||||
if icon_path.exists() {
|
||||
// 创建 .rc 文件
|
||||
let rc_content = format!(r#"1 ICON "{}""#, icon_path.canonicalize().unwrap().display());
|
||||
let rc_path = out_dir.join("app.rc");
|
||||
std::fs::write(&rc_path, rc_content).unwrap();
|
||||
|
||||
// 编译资源文件
|
||||
let res_path = out_dir.join("app.res");
|
||||
|
||||
// 使用 windres (MinGW) 编译资源
|
||||
let status = std::process::Command::new("windres")
|
||||
.args(&[
|
||||
rc_path.to_str().unwrap(),
|
||||
"-O",
|
||||
"coff",
|
||||
"-o",
|
||||
res_path.to_str().unwrap(),
|
||||
])
|
||||
.status();
|
||||
|
||||
if let Ok(status) = status {
|
||||
if status.success() {
|
||||
println!("cargo:rustc-link-arg={}", res_path.display());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("cargo:rerun-if-changed=build.rs");
|
||||
println!("cargo:rerun-if-changed=unlock.ico");
|
||||
}
|
||||
305
anti_lockscreen_rust/src/main.rs
Normal file
305
anti_lockscreen_rust/src/main.rs
Normal file
@@ -0,0 +1,305 @@
|
||||
#![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())),
|
||||
)
|
||||
}
|
||||
1
anti_lockscreen_rust/target/.rustc_info.json
Normal file
1
anti_lockscreen_rust/target/.rustc_info.json
Normal file
@@ -0,0 +1 @@
|
||||
{"rustc_fingerprint":10599383275472545403,"outputs":{"17747080675513052775":{"success":true,"status":"","code":0,"stdout":"rustc 1.91.1 (ed61e7d7e 2025-11-07) (Rev1, Built by MSYS2 project)\nbinary: rustc\ncommit-hash: ed61e7d7e242494fb7057f2657300d9e77bb4fcb\ncommit-date: 2025-11-07\nhost: x86_64-pc-windows-gnu\nrelease: 1.91.1\nLLVM version: 21.1.5\n","stderr":""},"7971740275564407648":{"success":true,"status":"","code":0,"stdout":"___.exe\nlib___.rlib\n___.dll\n___.dll\nlib___.a\n___.dll\nC:\\msys64\\mingw64\noff\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"windows\"\ntarget_feature=\"cmpxchg16b\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_feature=\"sse3\"\ntarget_has_atomic=\"128\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"windows\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"pc\"\nwindows\n","stderr":""}},"successes":{}}
|
||||
3
anti_lockscreen_rust/target/CACHEDIR.TAG
Normal file
3
anti_lockscreen_rust/target/CACHEDIR.TAG
Normal file
@@ -0,0 +1,3 @@
|
||||
Signature: 8a477f597d28d172789f06886806bc55
|
||||
# This file is a cache directory tag created by cargo.
|
||||
# For information about cache directory tags see https://bford.info/cachedir/
|
||||
0
anti_lockscreen_rust/target/release/.cargo-lock
Normal file
0
anti_lockscreen_rust/target/release/.cargo-lock
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
0aea0954fb89fbbf
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"default\", \"gvar-alloc\", \"std\", \"variable-fonts\"]","declared_features":"[\"default\", \"gvar-alloc\", \"libm\", \"std\", \"variable-fonts\"]","target":11794240345726188307,"profile":8522709134186534698,"path":15846241780100591775,"deps":[[4945662571602681759,"ab_glyph_rasterizer",false,13793263756019044055],[5327495677235252177,"owned_ttf_parser",false,16372985204910728762]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\ab_glyph-46947346f85505e1\\dep-lib-ab_glyph","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
d70ec9664e846bbf
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"libm\", \"std\"]","target":4335109392423587462,"profile":8522709134186534698,"path":18027761718527720286,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\ab_glyph_rasterizer-93210680eb8fc0de\\dep-lib-ab_glyph_rasterizer","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
1f37eef4207d0183
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[\"core\", \"default\", \"rustc-dep-of-std\", \"std\"]","target":6569825234462323107,"profile":8522709134186534698,"path":11497648957998962390,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\adler2-2566d54f8048fb6e\\dep-lib-adler2","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
024ecba942df3bc2
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[966925859616469517,"build_script_build",false,2719429618360280277]],"local":[{"RerunIfChanged":{"output":"release\\build\\ahash-3ce90528b514b15b\\output","paths":["build.rs"]}}],"rustflags":[],"config":0,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
0fcea5e853d62c40
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"no-rng\", \"std\"]","declared_features":"[\"atomic-polyfill\", \"compile-time-rng\", \"const-random\", \"default\", \"getrandom\", \"nightly-arm-aes\", \"no-rng\", \"runtime-rng\", \"serde\", \"std\"]","target":8470944000320059508,"profile":8522709134186534698,"path":10737047615438985422,"deps":[[966925859616469517,"build_script_build",false,13996025744393457154],[3612005756660025491,"zerocopy",false,7003619608483660582],[5855319743879205494,"once_cell",false,15896140823372711851],[7667230146095136825,"cfg_if",false,5360605253504749049]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\ahash-d7efea2f4f8ddbd9\\dep-lib-ahash","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
d5640a6ad45abd25
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"no-rng\", \"std\"]","declared_features":"[\"atomic-polyfill\", \"compile-time-rng\", \"const-random\", \"default\", \"getrandom\", \"nightly-arm-aes\", \"no-rng\", \"runtime-rng\", \"serde\", \"std\"]","target":17883862002600103897,"profile":17984201634715228204,"path":2185400903901838128,"deps":[[5398981501050481332,"version_check",false,17440821149541551126]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\ahash-ee0e155a7ea33f87\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
0de125b1145f42ac
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[1907269879737545682,"build_script_build",false,1509082888442765674]],"local":[{"RerunIfChanged":{"output":"release\\build\\anti_lockscreen_rust-0312abaaa830947e\\output","paths":["build.rs","unlock.ico"]}}],"rustflags":[],"config":0,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
35d004f50de0a3bb
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[]","target":10580490025165295728,"profile":17900900905202929101,"path":4942398508502643691,"deps":[[1907269879737545682,"build_script_build",false,12412588065462542605],[3856126590694406759,"chrono",false,16584125662738169044],[10020888071089587331,"winapi",false,7120860050230470933],[12468329946335389071,"eframe",false,1006866704764420669],[13208667028893622512,"rand",false,2652263060936371794],[17616349418391093976,"egui",false,17895285795470466051]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\anti_lockscreen_rust-d6595ecfae7c3d51\\dep-bin-防止锁屏工具","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1,4 @@
|
||||
{"$message_type":"diagnostic","message":"unused imports: `Stroke` and `Vec2`","code":{"code":"unused_imports","explanation":null},"level":"warning","spans":[{"file_name":"src\\main.rs","byte_start":156,"byte_end":160,"line_start":4,"line_end":4,"column_start":42,"column_end":46,"is_primary":true,"text":[{"text":"use egui::{FontFamily, FontId, RichText, Vec2, Color32, Rounding, Stroke};","highlight_start":42,"highlight_end":46}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"src\\main.rs","byte_start":181,"byte_end":187,"line_start":4,"line_end":4,"column_start":67,"column_end":73,"is_primary":true,"text":[{"text":"use egui::{FontFamily, FontId, RichText, Vec2, Color32, Rounding, Stroke};","highlight_start":67,"highlight_end":73}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"remove the unused imports","code":null,"level":"help","spans":[{"file_name":"src\\main.rs","byte_start":154,"byte_end":160,"line_start":4,"line_end":4,"column_start":40,"column_end":46,"is_primary":true,"text":[{"text":"use egui::{FontFamily, FontId, RichText, Vec2, Color32, Rounding, Stroke};","highlight_start":40,"highlight_end":46}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null},{"file_name":"src\\main.rs","byte_start":179,"byte_end":187,"line_start":4,"line_end":4,"column_start":65,"column_end":73,"is_primary":true,"text":[{"text":"use egui::{FontFamily, FontId, RichText, Vec2, Color32, Rounding, Stroke};","highlight_start":65,"highlight_end":73}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;11mwarning\u001b[0m\u001b[0m\u001b[1m\u001b[38;5;15m: unused imports: `Stroke` and `Vec2`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m--> \u001b[0m\u001b[0msrc\\main.rs:4:42\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;14m4\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\u001b[0m \u001b[0m\u001b[0muse egui::{FontFamily, FontId, RichText, Vec2, Color32, Rounding, Stroke};\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;11m^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;11m^^^^^^\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m= \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;15mnote\u001b[0m\u001b[0m: `#[warn(unused_imports)]` (part of `#[warn(unused)]`) on by default\u001b[0m\n\n"}
|
||||
{"$message_type":"diagnostic","message":"unused imports: `INPUT_MOUSE`, `INPUT`, `MOUSEINPUT`, and `SendInput`","code":{"code":"unused_imports","explanation":null},"level":"warning","spans":[{"file_name":"src\\main.rs","byte_start":326,"byte_end":331,"line_start":8,"line_end":8,"column_start":55,"column_end":60,"is_primary":true,"text":[{"text":"use winapi::um::winuser::{GetCursorPos, SetCursorPos, INPUT, INPUT_MOUSE, MOUSEINPUT, SendInput};","highlight_start":55,"highlight_end":60}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"src\\main.rs","byte_start":333,"byte_end":344,"line_start":8,"line_end":8,"column_start":62,"column_end":73,"is_primary":true,"text":[{"text":"use winapi::um::winuser::{GetCursorPos, SetCursorPos, INPUT, INPUT_MOUSE, MOUSEINPUT, SendInput};","highlight_start":62,"highlight_end":73}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"src\\main.rs","byte_start":346,"byte_end":356,"line_start":8,"line_end":8,"column_start":75,"column_end":85,"is_primary":true,"text":[{"text":"use winapi::um::winuser::{GetCursorPos, SetCursorPos, INPUT, INPUT_MOUSE, MOUSEINPUT, SendInput};","highlight_start":75,"highlight_end":85}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"src\\main.rs","byte_start":358,"byte_end":367,"line_start":8,"line_end":8,"column_start":87,"column_end":96,"is_primary":true,"text":[{"text":"use winapi::um::winuser::{GetCursorPos, SetCursorPos, INPUT, INPUT_MOUSE, MOUSEINPUT, SendInput};","highlight_start":87,"highlight_end":96}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"remove the unused imports","code":null,"level":"help","spans":[{"file_name":"src\\main.rs","byte_start":324,"byte_end":367,"line_start":8,"line_end":8,"column_start":53,"column_end":96,"is_primary":true,"text":[{"text":"use winapi::um::winuser::{GetCursorPos, SetCursorPos, INPUT, INPUT_MOUSE, MOUSEINPUT, SendInput};","highlight_start":53,"highlight_end":96}],"label":null,"suggested_replacement":"","suggestion_applicability":"MachineApplicable","expansion":null}],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;11mwarning\u001b[0m\u001b[0m\u001b[1m\u001b[38;5;15m: unused imports: `INPUT_MOUSE`, `INPUT`, `MOUSEINPUT`, and `SendInput`\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m--> \u001b[0m\u001b[0msrc\\main.rs:8:55\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;14m8\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\u001b[0m \u001b[0m\u001b[0muse winapi::um::winuser::{GetCursorPos, SetCursorPos, INPUT, INPUT_MOUSE, MOUSEINPUT, SendInput};\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;11m^^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;11m^^^^^^^^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;11m^^^^^^^^^^\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;11m^^^^^^^^^\u001b[0m\n\n"}
|
||||
{"$message_type":"diagnostic","message":"field `last_action` is never read","code":{"code":"dead_code","explanation":null},"level":"warning","spans":[{"file_name":"src\\main.rs","byte_start":486,"byte_end":494,"line_start":15,"line_end":15,"column_start":8,"column_end":16,"is_primary":false,"text":[{"text":"struct AppState {","highlight_start":8,"highlight_end":16}],"label":"field in this struct","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"src\\main.rs","byte_start":616,"byte_end":627,"line_start":19,"line_end":19,"column_start":5,"column_end":16,"is_primary":true,"text":[{"text":" last_action: Arc<Mutex<Instant>>,","highlight_start":5,"highlight_end":16}],"label":null,"suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"`AppState` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis","code":null,"level":"note","spans":[],"children":[],"rendered":null},{"message":"`#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default","code":null,"level":"note","spans":[],"children":[],"rendered":null}],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;11mwarning\u001b[0m\u001b[0m\u001b[1m\u001b[38;5;15m: field `last_action` is never read\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m--> \u001b[0m\u001b[0msrc\\main.rs:19:5\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;14m15\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\u001b[0m \u001b[0m\u001b[0mstruct AppState {\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m--------\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14mfield in this struct\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;14m...\u001b[0m\n\u001b[0m\u001b[1m\u001b[38;5;14m19\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m last_action: Arc<Mutex<Instant>>,\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;11m^^^^^^^^^^^\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m|\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m= \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;15mnote\u001b[0m\u001b[0m: `AppState` has a derived impl for the trait `Clone`, but this is intentionally ignored during dead code analysis\u001b[0m\n\u001b[0m \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;14m= \u001b[0m\u001b[0m\u001b[1m\u001b[38;5;15mnote\u001b[0m\u001b[0m: `#[warn(dead_code)]` (part of `#[warn(unused)]`) on by default\u001b[0m\n\n"}
|
||||
{"$message_type":"diagnostic","message":"3 warnings emitted","code":null,"level":"warning","spans":[],"children":[],"rendered":"\u001b[0m\u001b[1m\u001b[38;5;11mwarning\u001b[0m\u001b[0m\u001b[1m\u001b[38;5;15m: 3 warnings emitted\u001b[0m\n\n"}
|
||||
@@ -0,0 +1 @@
|
||||
6a61403ee456f114
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[]","target":5408242616063297496,"profile":17984201634715228204,"path":13767053534773805487,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\anti_lockscreen_rust-fca24639847553c4\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
9de33c2b907b857a
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[\"core-graphics\", \"default\", \"image\", \"image-data\", \"wayland-data-control\", \"windows-sys\", \"wl-clipboard-rs\"]","target":1337616771932055151,"profile":8522709134186534698,"path":8881149106804527623,"deps":[[6536293665624942953,"clipboard_win",false,5891368580674313545],[7263319592666514104,"windows_sys",false,9223110747449986730],[10630857666389190470,"log",false,14834647945323916320]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\arboard-3cd9bf4d692dc4e5\\dep-lib-arboard","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
ca040605e6d6151c
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[]","target":6962977057026645649,"profile":17984201634715228204,"path":6612028586417981611,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\autocfg-78e694de1788454a\\dep-lib-autocfg","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
3d9511e4eb72afd1
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"default\"]","declared_features":"[\"compiler_builtins\", \"core\", \"default\", \"example_generated\", \"rustc-dep-of-std\"]","target":12919857562465245259,"profile":8522709134186534698,"path":10468803546175576600,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\bitflags-461151397b2a93a8\\dep-lib-bitflags","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
ddd5c15a6ede6965
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"bytemuck_derive\", \"derive\", \"extern_crate_alloc\"]","declared_features":"[\"aarch64_simd\", \"align_offset\", \"alloc_uninit\", \"avx512_simd\", \"bytemuck_derive\", \"const_zeroed\", \"derive\", \"extern_crate_alloc\", \"extern_crate_std\", \"impl_core_error\", \"latest_stable_rust\", \"min_const_generics\", \"must_cast\", \"must_cast_extra\", \"nightly_docs\", \"nightly_float\", \"nightly_portable_simd\", \"nightly_stdsimd\", \"pod_saturating\", \"rustversion\", \"track_caller\", \"transparentwrapper_extra\", \"unsound_ptr_pod_impl\", \"wasm_simd\", \"zeroable_atomics\", \"zeroable_maybe_uninit\", \"zeroable_unwind_fn\"]","target":5195934831136530909,"profile":8633942403436047510,"path":16829734500957502801,"deps":[[15783091771682552589,"bytemuck_derive",false,8885535415941070524]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\bytemuck-cf0e8caba537d5b8\\dep-lib-bytemuck","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
bcfe511a62c34f7b
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[]","target":11496395835559002815,"profile":17984201634715228204,"path":17181723879467618639,"deps":[[4289358735036141001,"proc_macro2",false,16732422006193146601],[10420560437213941093,"syn",false,2293127967412728479],[13111758008314797071,"quote",false,5972981057059608043]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\bytemuck_derive-2869c311d2b3eb8d\\dep-lib-bytemuck_derive","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
e99c15736c6db281
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"i128\", \"std\"]","target":8344828840634961491,"profile":8522709134186534698,"path":10751045344836512076,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\byteorder-159bbed69bee9469\\dep-lib-byteorder","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
f94d3e8c13b2644a
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[\"core\", \"rustc-dep-of-std\"]","target":13840298032947503755,"profile":8522709134186534698,"path":2932095763114025643,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\cfg-if-beafaffeed9fa642\\dep-lib-cfg_if","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
07d3270985861850
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[]","target":14022534369768855544,"profile":17984201634715228204,"path":7690881672510681075,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\cfg_aliases-0ad3b8b587a53691\\dep-lib-cfg_aliases","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
d4bcf27d6ca626e6
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"alloc\", \"clock\", \"default\", \"iana-time-zone\", \"js-sys\", \"now\", \"oldtime\", \"std\", \"wasm-bindgen\", \"wasmbind\", \"winapi\", \"windows-link\"]","declared_features":"[\"__internal_bench\", \"alloc\", \"arbitrary\", \"clock\", \"core-error\", \"default\", \"defmt\", \"iana-time-zone\", \"js-sys\", \"libc\", \"now\", \"oldtime\", \"pure-rust-locales\", \"rkyv\", \"rkyv-16\", \"rkyv-32\", \"rkyv-64\", \"rkyv-validation\", \"serde\", \"std\", \"unstable-locales\", \"wasm-bindgen\", \"wasmbind\", \"winapi\", \"windows-link\"]","target":15315924755136109342,"profile":8522709134186534698,"path":16344449863874949787,"deps":[[5157631553186200874,"num_traits",false,12437634114862949875],[6959378045035346538,"windows_link",false,3938917974514006394]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\chrono-54bd2c6e91ffd0ee\\dep-lib-chrono","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
495dfda38258c251
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"std\"]","declared_features":"[\"monitor\", \"std\", \"windows-win\"]","target":1945234718698444063,"profile":8522709134186534698,"path":15538388337102223075,"deps":[[8705426877712808690,"error_code",false,10090969032961554588]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\clipboard-win-4556e739e030e9c4\\dep-lib-clipboard_win","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
011f644a231ffd0a
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[]","declared_features":"[]","target":16866256909581263957,"profile":8522709134186534698,"path":11241847968319279246,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\color_quant-ee4cf12156cb13c7\\dep-lib-color_quant","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
eabadb404272578f
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"","declared_features":"","target":0,"profile":0,"path":0,"deps":[[7312356825837975969,"build_script_build",false,2395505404276679777]],"local":[{"Precalculated":"1.5.0"}],"rustflags":[],"config":0,"compile_kind":0}
|
||||
@@ -0,0 +1 @@
|
||||
61a47027798b3e21
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"nightly\", \"std\"]","target":5408242616063297496,"profile":17984201634715228204,"path":11330017760966690325,"deps":[],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\crc32fast-2c03a86ba2adb1f6\\dep-build-script-build-script-build","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
f733939bf6abe25f
|
||||
@@ -0,0 +1 @@
|
||||
{"rustc":13930636876917425310,"features":"[\"default\", \"std\"]","declared_features":"[\"default\", \"nightly\", \"std\"]","target":10823605331999153028,"profile":8522709134186534698,"path":10739024644415095912,"deps":[[7312356825837975969,"build_script_build",false,10328849899279071978],[7667230146095136825,"cfg_if",false,5360605253504749049]],"local":[{"CheckDepInfo":{"dep_info":"release\\.fingerprint\\crc32fast-69ce539f8b997c8d\\dep-lib-crc32fast","checksum":false}}],"rustflags":[],"config":2069994364910194474,"compile_kind":0}
|
||||
Binary file not shown.
@@ -0,0 +1 @@
|
||||
This file has an mtime of when this was started.
|
||||
@@ -0,0 +1 @@
|
||||
d83b532e064135df
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user