diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 0de819d8..8f694e96 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -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" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 249e656c..554727d1 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -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 = [ diff --git a/src-tauri/src/commands.rs b/src-tauri/src/commands.rs index 819a439b..923edfaf 100644 --- a/src-tauri/src/commands.rs +++ b/src-tauri/src/commands.rs @@ -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 { + utils::read_text_scale_factor() +} diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 96891d3f..1ab1b82d 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -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")] diff --git a/src-tauri/src/plugins.rs b/src-tauri/src/plugins.rs deleted file mode 100644 index e1045050..00000000 --- a/src-tauri/src/plugins.rs +++ /dev/null @@ -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() -> TauriPlugin { - init(move |app, argv, _cwd| { - // 把 argv 转成 Vec - // let args: Vec = 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() -> TauriPlugin { - #[cfg(debug_assertions)] - Builder::default() - .targets([Target::new(TargetKind::Webview)]) - .timezone_strategy(TimezoneStrategy::UseLocal) - .level(LevelFilter::Debug) - .build::(); - 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::() -} diff --git a/src-tauri/src/plugins/custom_log.rs b/src-tauri/src/plugins/custom_log.rs new file mode 100644 index 00000000..df24ba08 --- /dev/null +++ b/src-tauri/src/plugins/custom_log.rs @@ -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::::from(now); + let date = date_time.format("%Y-%m-%d").to_string(); + return date; +} + +pub fn build_log_plugin() -> TauriPlugin { + #[cfg(debug_assertions)] + Builder::default() + .targets([Target::new(TargetKind::Webview)]) + .timezone_strategy(TimezoneStrategy::UseLocal) + .level(LevelFilter::Debug) + .build::(); + 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::() +} diff --git a/src-tauri/src/plugins/mod.rs b/src-tauri/src/plugins/mod.rs new file mode 100644 index 00000000..e82f825a --- /dev/null +++ b/src-tauri/src/plugins/mod.rs @@ -0,0 +1,5 @@ +// 插件 +// @since Beta v0.9.1 + +pub mod custom_log; +pub mod text_scale; diff --git a/src-tauri/src/plugins/text_scale.rs b/src-tauri/src/plugins/text_scale.rs new file mode 100644 index 00000000..7dc8025c --- /dev/null +++ b/src-tauri/src/plugins/text_scale.rs @@ -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)); + } + }); +} diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index eed02c48..bbfd8eec 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -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 { + #[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::::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) + } }