Files
TeyvatGuide/src-tauri/src/commands.rs
2026-02-22 18:03:49 +08:00

270 lines
7.3 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// 命令模块,负责处理命令
// @since Beta v0.9.1
use crate::utils;
use tauri::{AppHandle, Emitter, Manager, WebviewWindowBuilder};
use tauri_utils::config::{WebviewUrl, WindowConfig};
// 放一个常数,用来判断应用是否初始化
static mut APP_INITIALIZED: bool = false;
// 初始化应用
#[tauri::command]
pub async fn init_app(app_handle: AppHandle) {
unsafe {
if APP_INITIALIZED == true {
return;
}
}
app_handle.emit("initApp", ()).unwrap();
unsafe {
APP_INITIALIZED = true;
}
}
// 创建窗口
#[tauri::command]
pub async fn create_window(
app_handle: AppHandle,
label: String,
url: String,
option: WindowConfig,
) {
let window_find = app_handle.get_webview_window(&label);
if window_find.is_some() {
window_find.unwrap().destroy().unwrap();
return;
}
let url_parse = WebviewUrl::App(url.parse().unwrap());
WebviewWindowBuilder::new(&app_handle, &label, url_parse)
.inner_size(option.width, option.height)
.resizable(option.resizable)
.visible(option.visible)
.title(option.title)
.center()
.additional_browser_args("--disable-features=msWebOOUI,msPdfOOUI,msSmartScreenProtection --autoplay-policy=no-user-gesture-required")
.build()
.unwrap();
}
// 执行 js
#[tauri::command]
pub async fn execute_js(app_handle: AppHandle, label: String, js: String) {
let window = app_handle.get_webview_window(&label);
if window.is_some() {
window.unwrap().eval(js).unwrap();
}
}
// 获取目录大小
#[tauri::command]
pub async fn get_dir_size(path: String) -> u64 {
let walk_dir = walkdir::WalkDir::new(path);
let mut size = 0;
for entry in walk_dir {
let entry = entry.unwrap();
let file_type = entry.file_type();
if file_type.is_file() {
size += entry.metadata().unwrap().len();
}
}
size
}
// 判断是否是管理员权限
#[tauri::command]
pub fn is_in_admin() -> bool {
#[cfg(not(target_os = "windows"))]
{
return false;
}
#[cfg(target_os = "windows")]
{
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE};
use windows_sys::Win32::Security::{
GetTokenInformation, TOKEN_ELEVATION, TOKEN_QUERY, TokenElevation,
};
use windows_sys::Win32::System::Threading::{GetCurrentProcess, OpenProcessToken};
unsafe {
let mut token_handle: HANDLE = std::ptr::null_mut();
if OpenProcessToken(GetCurrentProcess(), TOKEN_QUERY, &mut token_handle) == 0 {
return false;
}
let mut elevation = TOKEN_ELEVATION { TokenIsElevated: 0 };
let mut return_length = 0;
let result = GetTokenInformation(
token_handle,
TokenElevation,
&mut elevation as *mut _ as *mut _,
std::mem::size_of::<TOKEN_ELEVATION>() as u32,
&mut return_length,
);
CloseHandle(token_handle);
result != 0 && elevation.TokenIsElevated != 0
}
}
}
// 隐藏主窗口到托盘
#[tauri::command]
pub async fn hide_main_window(app_handle: AppHandle) {
// 关闭所有子窗口
for label in crate::SUB_WINDOW_LABELS.iter() {
if let Some(sub) = app_handle.get_webview_window(label) {
let _ = sub.destroy();
}
}
// 隐藏主窗口
if let Some(window) = app_handle.get_webview_window("TeyvatGuide") {
let _ = window.hide();
}
}
// 退出应用
#[tauri::command]
pub async fn quit_app(app_handle: AppHandle) {
// 关闭所有子窗口
for label in crate::SUB_WINDOW_LABELS.iter() {
if let Some(sub) = app_handle.get_webview_window(label) {
let _ = sub.destroy();
}
}
// 退出应用
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()
}
#[tauri::command]
pub fn launch_game(path: String, ticket: String) -> Result<(), String> {
#[cfg(target_os = "windows")]
{
// 依赖 widestring 和 windows-sys
use widestring::U16CString;
use windows_sys::Win32::Foundation::HWND;
use windows_sys::Win32::UI::Shell::ShellExecuteW;
use windows_sys::Win32::UI::WindowsAndMessaging::SW_SHOWNORMAL;
// 构造参数字符串
let args = format!("login_auth_ticket={}", ticket);
// 转为 UTF-16 C 字符串
let operation =
U16CString::from_str("runas").map_err(|e| format!("encode operation error: {}", e))?;
let file = U16CString::from_str(&path).map_err(|e| format!("encode path error: {}", e))?;
let params = U16CString::from_str(&args).map_err(|e| format!("encode params error: {}", e))?;
// 调用 ShellExecuteW
unsafe {
let res = ShellExecuteW(
0 as HWND,
operation.as_ptr(),
file.as_ptr(),
params.as_ptr(),
std::ptr::null(),
SW_SHOWNORMAL,
);
let code = res as isize;
if code <= 32 {
return Err(format!("ShellExecuteW failed, code: {}.", code));
}
}
Ok(())
}
#[cfg(not(target_os = "windows"))]
{
Err("This command is only supported on Windows".into())
}
}
#[tauri::command]
pub fn is_msix() -> bool {
#[cfg(not(windows))]
{
false
}
#[cfg(windows)]
{
use std::ptr;
use widestring::U16CStr;
use windows_sys::Win32::Foundation::ERROR_INSUFFICIENT_BUFFER;
use windows_sys::Win32::Storage::Packaging::Appx::GetCurrentPackageFullName;
unsafe {
let mut length: u32 = 0;
let result = GetCurrentPackageFullName(&mut length, ptr::null_mut());
if result != ERROR_INSUFFICIENT_BUFFER {
println!("Not running in MSIX package. Error code: {}", result);
return false;
}
let mut buffer = vec![0u16; length as usize];
let result = GetCurrentPackageFullName(&mut length, buffer.as_mut_ptr());
if result != 0 {
println!("Failed to retrieve package full name. Error code: {}", result);
return false;
}
let pkg_name = U16CStr::from_ptr_str(buffer.as_ptr());
println!("MSIX Package Full Name: {}", pkg_name.to_string_lossy());
true
}
}
}
#[tauri::command]
pub fn is_process_running(process_name: String) -> bool {
#[cfg(not(target_os = "windows"))]
{
false
}
#[cfg(target_os = "windows")]
{
use windows_sys::Win32::Foundation::{CloseHandle, HANDLE, INVALID_HANDLE_VALUE};
use windows_sys::Win32::System::Diagnostics::ToolHelp::{
CreateToolhelp32Snapshot, PROCESSENTRY32W, Process32FirstW, Process32NextW,
TH32CS_SNAPPROCESS,
};
unsafe {
// 创建进程快照
let snapshot: HANDLE = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
if snapshot == INVALID_HANDLE_VALUE {
return false;
}
let mut entry: PROCESSENTRY32W = std::mem::zeroed();
entry.dwSize = std::mem::size_of::<PROCESSENTRY32W>() as u32;
// 遍历进程列表
if Process32FirstW(snapshot, &mut entry) != 0 {
loop {
// 将 exe 文件名转为 Rust String
let exe_name = {
let len = entry.szExeFile.iter().position(|&c| c == 0).unwrap_or(entry.szExeFile.len());
String::from_utf16_lossy(&entry.szExeFile[..len])
};
if exe_name.eq_ignore_ascii_case(&process_name) {
CloseHandle(snapshot);
return true;
}
if Process32NextW(snapshot, &mut entry) == 0 {
break;
}
}
}
CloseHandle(snapshot);
false
}
}
}