🌱 监听&获取文本缩放

#192
This commit is contained in:
BTMuli
2025-12-29 21:15:52 +08:00
parent 66b54dfc5e
commit cc3655a700
9 changed files with 132 additions and 63 deletions

8
src-tauri/Cargo.lock generated
View File

@@ -30,7 +30,9 @@ dependencies = [
"tauri-utils",
"url",
"walkdir",
"widestring",
"windows-sys 0.61.2",
"winreg",
]
[[package]]
@@ -7319,6 +7321,12 @@ dependencies = [
"wasite",
]
[[package]]
name = "widestring"
version = "1.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72069c3113ab32ab29e5584db3c6ec55d416895e60715417b5b883a357c3e471"
[[package]]
name = "winapi"
version = "0.3.9"

View File

@@ -32,7 +32,10 @@ tauri = { version = "2.9.5", features = ["tray-icon"] }
tauri-utils = "2.8.1"
url = "2.5.7"
walkdir = "2.5.0"
widestring = "1.2.1"
[target.'cfg(windows)'.dependencies.winreg]
version = "0.55.0"
[target.'cfg(windows)'.dependencies.windows-sys]
version = "0.61.2"
features = [

View File

@@ -1,6 +1,7 @@
// 命令模块,负责处理命令
// @since Beta v0.9.1
use crate::utils;
use tauri::{AppHandle, Emitter, Manager, WebviewWindowBuilder};
use tauri_utils::config::{WebviewUrl, WindowConfig};
@@ -136,3 +137,10 @@ pub async fn quit_app(app_handle: AppHandle) {
// 退出应用
app_handle.exit(0);
}
/// 获取当前系统的文本缩放比例TextScaleFactor
/// 返回值示例1.0 表示 100%1.25 表示 125%
#[tauri::command]
pub fn read_text_scale() -> Result<f64, String> {
utils::read_text_scale_factor()
}

View File

@@ -1,5 +1,5 @@
//! 主模块,用于启动应用
//! @since Beta v0.8.8
//! @since Beta v0.9.1
mod client;
mod commands;
@@ -14,8 +14,8 @@ mod yae;
use crate::client::create_mhy_client;
use crate::commands::{
create_window, execute_js, get_dir_size, hide_main_window, init_app, is_in_admin, quit_app,
read_text_scale,
};
use crate::plugins::{build_log_plugin, build_si_plugin};
use tauri::{generate_context, generate_handler, Emitter, Manager, Window, WindowEvent};
// 子窗口 label 的数组
@@ -66,7 +66,11 @@ pub fn run() {
let mut builder = tauri::Builder::default();
// 只有在正常/管理员实例下才加载单例插件;看门狗不加载
builder = builder.plugin(build_si_plugin());
builder = builder.plugin(tauri_plugin_single_instance::init(move |app, argv, _cwd| {
if let Err(e) = app.emit("active_deep_link", argv) {
eprintln!("emit active_deep_link failed: {}", e);
}
}));
builder
.on_window_event(move |app, event| window_event_handler(app, event))
.plugin(tauri_plugin_deep_link::init())
@@ -78,13 +82,14 @@ pub fn run() {
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_shell::init())
.plugin(tauri_plugin_sql::Builder::default().build())
.plugin(build_log_plugin())
.plugin(plugins::custom_log::build_log_plugin())
.setup(|_app| {
// 创建系统托盘图标
tray::create_tray(_app.handle())
.expect("Failed to initialize system tray icon. Please check if the tray icon file exists and the system supports tray icons.");
let _window = _app.get_webview_window("TeyvatGuide");
#[cfg(debug_assertions)]
plugins::text_scale::init(_app.handle().clone());
if _window.is_some() {
_window.unwrap().open_devtools();
}
@@ -99,6 +104,7 @@ pub fn run() {
is_in_admin,
hide_main_window,
quit_app,
read_text_scale,
#[cfg(target_os = "windows")]
yae::call_yae_dll,
#[cfg(target_os = "windows")]

View File

@@ -1,48 +0,0 @@
//! 插件模块,用于注册插件
//! @since Beta v0.7.8
use crate::utils::get_current_date;
use log::LevelFilter;
use tauri::plugin::TauriPlugin;
use tauri::{Emitter, Runtime};
use tauri_plugin_log::{Builder, Target, TargetKind, TimezoneStrategy};
use tauri_plugin_single_instance::init;
// 单例插件
pub fn build_si_plugin<R: Runtime>() -> TauriPlugin<R> {
init(move |app, argv, _cwd| {
// 把 argv 转成 Vec<String>
// let args: Vec<String> = argv.iter().map(|s| s.to_string()).collect();
// 如果包含提升约定参数,发出专门事件并短路退出
// if args.iter().any(|a| a == "--elevated") {
// 提升实例通常只负责传参或执行一次性任务,退出避免与主实例冲突
// std::process::exit(0);
// }
// 非提升启动:按原逻辑广播 deep link
if let Err(e) = app.emit("active_deep_link", argv) {
eprintln!("emit active_deep_link failed: {}", e);
}
// 回调必须返回 unit直接结束即可
})
}
// 日志插件
pub fn build_log_plugin<R: Runtime>() -> TauriPlugin<R> {
#[cfg(debug_assertions)]
Builder::default()
.targets([Target::new(TargetKind::Webview)])
.timezone_strategy(TimezoneStrategy::UseLocal)
.level(LevelFilter::Debug)
.build::<R>();
Builder::default()
.targets([
Target::new(TargetKind::Webview),
Target::new(TargetKind::LogDir { file_name: get_current_date().into() }),
])
.timezone_strategy(TimezoneStrategy::UseLocal)
.level(LevelFilter::Info)
.build::<R>()
}

View File

@@ -0,0 +1,34 @@
// tauri-plugin-log 简单处理
// @since Beta v0.9.1
use chrono::DateTime;
use log::LevelFilter;
use std::time::SystemTime;
use tauri::plugin::TauriPlugin;
use tauri::Runtime;
use tauri_plugin_log::{Builder, Target, TargetKind, TimezoneStrategy};
// 获取当前日期 yyyy-mm-dd
fn get_current_date() -> String {
let now = SystemTime::now();
let date_time = DateTime::<chrono::Local>::from(now);
let date = date_time.format("%Y-%m-%d").to_string();
return date;
}
pub fn build_log_plugin<R: Runtime>() -> TauriPlugin<R> {
#[cfg(debug_assertions)]
Builder::default()
.targets([Target::new(TargetKind::Webview)])
.timezone_strategy(TimezoneStrategy::UseLocal)
.level(LevelFilter::Debug)
.build::<R>();
Builder::default()
.targets([
Target::new(TargetKind::Webview),
Target::new(TargetKind::LogDir { file_name: get_current_date().into() }),
])
.timezone_strategy(TimezoneStrategy::UseLocal)
.level(LevelFilter::Info)
.build::<R>()
}

View File

@@ -0,0 +1,5 @@
// 插件
// @since Beta v0.9.1
pub mod custom_log;
pub mod text_scale;

View File

@@ -0,0 +1,43 @@
// 监听系统文本放缩
// @since Beta v0.9.1
use crate::utils;
use std::{thread, time::Duration};
use tauri::{AppHandle, Emitter};
use widestring::U16CString;
use windows_sys::Win32::Foundation::ERROR_SUCCESS;
use windows_sys::Win32::System::Registry::{
RegNotifyChangeKeyValue, RegOpenKeyExW, HKEY, HKEY_CURRENT_USER, KEY_NOTIFY, KEY_READ,
REG_NOTIFY_CHANGE_LAST_SET,
};
pub fn init(app: AppHandle) {
thread::spawn(move || unsafe {
let subkey = U16CString::from_str("Software\\Microsoft\\Accessibility").unwrap();
let mut hkey: HKEY = std::ptr::null_mut();
let status =
RegOpenKeyExW(HKEY_CURRENT_USER, subkey.as_ptr(), 0, KEY_READ | KEY_NOTIFY, &mut hkey);
if status != ERROR_SUCCESS {
eprintln!("❌ 无法打开注册表键: {}", status);
return;
}
loop {
let notify_status =
RegNotifyChangeKeyValue(hkey, 0, REG_NOTIFY_CHANGE_LAST_SET, std::ptr::null_mut(), 0);
if notify_status == ERROR_SUCCESS {
if let Ok(scale) = utils::read_text_scale_factor() {
let _ = app.emit("text_scale_change", scale);
}
} else {
eprintln!("❌ 注册表监听失败: {}", notify_status);
break;
}
thread::sleep(Duration::from_secs(1));
}
});
}

View File

@@ -1,14 +1,24 @@
//! @file src/utils.rs
//! @desc 工具模块,用于提供一些工具函数
//! @since Beta v0.4.2
// 杂项
// @since Beta v0.9.1
use chrono::DateTime;
use std::time::SystemTime;
/// 获取当前系统的文本缩放比例TextScaleFactor
/// 返回值示例1.0 表示 100%1.25 表示 125%
pub fn read_text_scale_factor() -> Result<f64, String> {
#[cfg(not(target_os = "windows"))]
{
Ok(1.0)
}
#[cfg(target_os = "windows")]
{
use winreg::enums::*;
use winreg::RegKey;
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let key = hkcu
.open_subkey("Software\\Microsoft\\Accessibility")
.map_err(|e| format!("无法打开注册表: {}", e))?;
// 获取当前日期 yyyy-mm-dd
pub fn get_current_date() -> String {
let now = SystemTime::now();
let date_time = DateTime::<chrono::Local>::from(now);
let date = date_time.format("%Y-%m-%d").to_string();
return date;
let value: u32 = key.get_value("TextScaleFactor").unwrap_or(100u32); // 默认值为 100%
Ok(value as f64 / 100.0)
}
}