add existing settings

This commit is contained in:
Purp1e
2024-09-20 09:52:13 +08:00
parent 3be7e8a0b5
commit 7229e79cd4
30 changed files with 503 additions and 6 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 974 B

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 855 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 863 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 802 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

After

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.9 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 903 B

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.4 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 2.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 4.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 85 KiB

After

Width:  |  Height:  |  Size: 65 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 203 KiB

57
src-tauri/src/cmds.rs Normal file
View File

@@ -0,0 +1,57 @@
use crate::steam;
use crate::tool::*;
#[tauri::command]
pub fn greet(name: &str) -> String {
format!("Hello, {}! You've been greeted from Rust!", name)
}
// 工具
#[tauri::command]
pub fn launch_game(steam_path: &str, launch_option: &str, server: &str) -> String {
steam::launch_game(steam_path, launch_option, server).expect("启动失败");
format!(
"Launching game on server: {}, with launch Option {}",
server, launch_option
)
}
#[tauri::command]
pub fn kill_game() -> String {
common::kill("cs2.exe")
}
#[tauri::command]
pub fn kill_steam() -> String {
common::kill("steam.exe")
}
// Steam
#[tauri::command]
pub fn get_steam_path() -> String {
steam::path::get_steam_path().expect("获取Steam路径失败")
}
// TODO get_cs_path
// TODO get_powerplan
// TODO set_powerplan
// TODO watch_steam_users
// TODO watch_video_settings
// TODO watch + cancel
// TODO fs_list_dir
// TODO fs_watch_dir
#[tauri::command]
pub fn set_auto_login_user(user: &str) -> String {
#[cfg(target_os = "windows")]
steam::reg::set_auto_login_user(user).expect("设置自动登录用户失败");
format!("Set auto login user to {}", user)
}
#[tauri::command]
pub fn check_file_exists(file: &str) -> bool {
std::path::Path::new(&file).exists()
}

View File

@@ -2,9 +2,31 @@
all(not(debug_assertions), target_os = "windows"),
windows_subsystem = "windows"
)]
use tauri::Manager;
// Window Vibrancy
#[cfg(target_os = "windows")]
use window_vibrancy::apply_mica;
#[cfg(target_os = "macos")]
use window_vibrancy::{apply_vibrancy, NSVisualEffectMaterial};
// System Tray
use tauri::{
menu::{MenuBuilder, MenuItemBuilder},
tray::{ClickType, TrayIconBuilder},
};
// Auto Start
use tauri_plugin_autostart::MacosLauncher;
// use tauri_plugin_autostart::ManagerExt;
use std::time::{SystemTime, UNIX_EPOCH};
// Local Modules
mod cmds;
mod steam;
mod tool;
#[tauri::command]
fn on_button_clicked() -> String {
let start = SystemTime::now();
@@ -17,7 +39,109 @@ fn on_button_clicked() -> String {
fn main() {
tauri::Builder::default()
.invoke_handler(tauri::generate_handler![on_button_clicked])
.run(tauri::generate_context!())
.expect("error while running tauri application");
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_os::init())
.plugin(tauri_plugin_autostart::init(
MacosLauncher::LaunchAgent,
Some(vec![]),
))
.plugin(tauri_plugin_process::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_store::Builder::default().build())
// .plugin(tauri_plugin_updater::Builder::new().build())
.invoke_handler(tauri::generate_handler![on_button_clicked])
.setup(|app| {
// Tray Menu
// let quit = CustomMenuItem::new("quit".to_string(), "Quit");
// let hide = CustomMenuItem::new("hide".to_string(), "Hide");
// let tray_menu = SystemTrayMenu::new() // insert the menu items here
// .add_item(hide)
// .add_item(quit);
// .add_native_item(SystemTrayMenuItem::Separator)
let toggle = MenuItemBuilder::with_id("toggle", "Toggle").build(app)?;
let menu = MenuBuilder::new(app).items(&[&toggle]).build()?;
// Setup Tray
// let tray = tauri::tray::TrayIconBuilder::with_id("my-tray").build(app)?;
let _ = TrayIconBuilder::new()
.menu(&menu)
.on_menu_event(move |_, event| {
match event.id().as_ref() {
"toggle" => {
println!("toggle clicked");
}
_ => (),
}
// match event {
// SystemTrayEvent::LeftClick { position: _, size: _, .. } => {
// let window = app.get_window("main").unwrap();
// window.show().unwrap();
// window.set_focus().unwrap();
// // thread::sleep(Duration::from_millis(100));
// // window.set_always_on_top(false).unwrap();
// println!("system tray received a left click");
// }
// SystemTrayEvent::RightClick { position: _, size: _, .. } => {
// // let window = app.get_window("main").unwrap();
// // window.hide().unwrap();
// println!("system tray received a right click");
// }
// SystemTrayEvent::DoubleClick { position: _, size: _, .. } => {
// println!("system tray received a double click");
// }
// SystemTrayEvent::MenuItemClick { id, .. } =>
// match id.as_str() {
// "quit" => {
// std::process::exit(0);
// }
// "hide" => {
// let window = app.get_window("main").unwrap();
// window.hide().unwrap();
// }
// _ => {}
// }
// _ => {}
// }
})
.on_tray_icon_event(|tray, event| {
if event.click_type == ClickType::Left {
let app = tray.app_handle();
if let Some(webview_window) = app.get_webview_window("main") {
let _ = webview_window.show();
let _ = webview_window.set_focus();
}
}
})
.build(app)
.unwrap();
// Get Window
let window = app.get_webview_window("main").unwrap();
// Vibrant Window
#[cfg(target_os = "macos")]
apply_vibrancy(&window, NSVisualEffectMaterial::HudWindow, None, Some(10.0))
.expect("Unsupported platform! 'apply_vibrancy' is only supported on macOS");
#[cfg(target_os = "windows")]
apply_mica(&window, Some(false))
.expect("Unsupported platform! 'apply_mica' is only supported on Windows");
// apply_blur(&window, Some((18, 18, 18, 0)))
// .expect("Unsupported platform! 'apply_blur' is only supported on Windows");
Ok(())
})
.invoke_handler(tauri::generate_handler![
cmds::greet,
cmds::launch_game,
cmds::kill_game,
cmds::kill_steam,
cmds::get_steam_path,
cmds::set_auto_login_user,
cmds::check_file_exists
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}

41
src-tauri/src/steam/id.rs Normal file
View File

@@ -0,0 +1,41 @@
// Steam users, including:
// - ID Conversion
#![allow(unused)]
static ID_BASE: u64 = 76561197960265728;
pub fn id64_to_32(id64: u64) -> u32 {
(id64 - ID_BASE) as u32
}
pub fn id32_to_64(id32: u32) -> u64 {
(id32 as u64) + ID_BASE
}
#[cfg(test)]
mod tests {
use super::*;
const ID32: [&str; 2] = ["354813078", "146859713"];
const ID64: [&str; 2] = ["76561198315078806", "76561198107125441"];
#[test]
fn test_id32_to_64() {
for (i32, i64) in ID32.iter().zip(ID64.iter()) {
assert_eq!(
id32_to_64(i32.parse::<u32>().unwrap()),
i64.parse::<u64>().unwrap()
);
}
}
#[test]
fn test_id64_to_32() {
for (i32, i64) in ID32.iter().zip(ID64.iter()) {
assert_eq!(
id64_to_32(i64.parse::<u64>().unwrap()),
i32.parse::<u32>().unwrap()
);
}
}
}

View File

@@ -0,0 +1,38 @@
// Manage sub modules
pub mod id;
pub mod path;
pub mod reg;
// common steam utils
use std::error::Error;
use std::process::{Command, Output};
pub fn launch_game(
steam_path: &str,
launch_option: &str,
server: &str,
) -> Result<(), Box<dyn Error>> {
let mut opt = launch_option.replace("\n", " ");
if server == "perfectworld" {
opt = opt.replace("-worldwide", "") + " -perfectworld";
} else if server == "worldwide" {
opt = opt.replace("-perfectworld", "") + " -worldwide";
}
let opts = format!("-applaunch 730 {}", opt);
let opts_split = opts.split_whitespace().collect::<Vec<&str>>();
let output: Output = Command::new(steam_path).args(opts_split).output()?;
if !output.status.success() {
let error_message = String::from_utf8_lossy(&output.stderr);
println!("Error: {}", error_message);
return Err(Box::new(std::io::Error::new(
std::io::ErrorKind::Other,
"Failed to launch game",
)));
}
Ok(())
}

View File

@@ -0,0 +1,48 @@
// Steam related path utils, including:
// - Steam Path
// - CS2(CS:GO) Path
#![allow(unused)]
use crate::tool::common::get_exe_path;
use super::reg;
pub fn get_steam_path<'a>() -> Result<String, &'a str> {
// Windows Registry
#[cfg(target_os = "windows")]
if let Ok(reg) = reg::SteamReg::get_all() {
return Ok(reg.steam_path);
}
// Running steam.exe
#[cfg(target_os = "windows")]
if let Ok(steam_path) = get_exe_path("steam.exe") {
return Ok(steam_path);
}
Err("no steam path found")
}
pub fn get_cs_path<'a>(name: &str) -> Result<String, &'a str> {
if name != "csgo" || name != "cs2" {
return Err("invalid cs name");
}
#[cfg(target_os = "windows")]
if let Ok(cs_path) = get_exe_path(&(name.to_owned() + ".exe")) {
return Ok(cs_path);
}
Err("no cs path found")
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_get_steam_path() {
let path = get_steam_path().unwrap();
println!("{}", path);
}
}

101
src-tauri/src/steam/reg.rs Normal file
View File

@@ -0,0 +1,101 @@
// Steam metadata parsing from reg, including:
// - Steam Path
// - Users (ID32)
#![allow(unused)]
use crate::tool::common::kill;
use crate::tool::common::run_steam;
use std::process::Command;
#[cfg(target_os = "windows")]
use winreg::enums::*;
#[cfg(target_os = "windows")]
use winreg::RegKey;
#[cfg(target_os = "windows")]
static STEAM_REG: &str = r"Software\Valve\Steam";
#[derive(Debug)]
pub struct SteamReg {
pub steam_path: String,
pub auto_login_user: String,
pub suppress_auto_run: u32,
pub remember_password: u32,
pub language: String,
pub users: Vec<String>,
}
impl SteamReg {
#[cfg(target_os = "windows")]
pub fn get_all<'a>() -> Result<Self, &'a str> {
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let cur_ver = hkcu.open_subkey(STEAM_REG).expect("steam reg");
let steam_path: String = cur_ver.get_value("SteamExe").expect("steam path");
let auto_login_user: String = cur_ver.get_value("AutoLoginUser").expect("auto login user");
let suppress_auto_run: u32 = cur_ver
.get_value("SuppressAutoRun")
.expect("suppress auto run");
let remember_password: u32 = cur_ver
.get_value("RememberPassword")
.expect("remember password");
let language: String = cur_ver.get_value("Language").expect("language");
let users = cur_ver
.open_subkey("Users")
.expect("users")
.enum_keys()
.map(|x| x.unwrap().to_string())
.collect::<Vec<String>>();
Ok(Self {
steam_path,
auto_login_user,
suppress_auto_run,
remember_password,
language,
users: users,
})
}
}
#[cfg(target_os = "windows")]
pub fn set_auto_login_user(user: &str) -> Result<(), &str> {
// ensure steam.exe is not running
kill("steam.exe");
// set reg key value
let hkcu = RegKey::predef(HKEY_CURRENT_USER);
let cur_ver = hkcu
.open_subkey_with_flags(STEAM_REG, KEY_WRITE)
.expect("steam reg");
cur_ver
.set_value("AutoLoginUser", &user)
.expect("auto login user");
cur_ver
.set_value("RememberPassword", &1u32)
.expect("remember passwd");
// open steam.exe again
let output = run_steam().expect("failed to execute process");
Ok(())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
#[cfg(target_os = "windows")]
fn test_get_steam_path() {
let path = SteamReg::get_all().unwrap();
println!("{:?}", path);
}
#[test]
#[cfg(target_os = "windows")]
fn test_set_auto_login() {
// set_auto_login_user("_im_ai_");
set_auto_login_user("_jerry_dota2");
}
}

View File

@@ -0,0 +1,35 @@
use std::process::Command;
pub fn kill(name: &str) -> String {
Command::new("taskkill")
.args(&["/IM", name, "/F"])
.output()
.unwrap();
format!("Killing {}", name)
}
pub fn run_steam() -> std::io::Result<std::process::Output> {
Command::new("cmd")
.args(&["/C", "start", "steam://run"])
.output()
}
pub fn get_exe_path(name: &str) -> Result<String, std::io::Error> {
let command = format!("/C wmic process where name='{}' get ExecutablePath", name);
let args = command.split_whitespace().collect::<Vec<&str>>();
let output = Command::new("cmd.exe").args(&args).output()?;
let out = String::from_utf8_lossy(&output.stdout).trim().to_string();
if out.contains("ExecutablePath") {
let spt: Vec<&str> = out.split("\r\n").collect();
if spt.len() >= 2 {
return Ok(spt[1].to_string());
}
}
Err(std::io::Error::new(
std::io::ErrorKind::Other,
"Failed to get executable path",
))
}

View File

@@ -0,0 +1,44 @@
#[macro_export]
macro_rules! error {
($result: expr) => {
log::error!(target: "app", "{}", $result);
};
}
#[macro_export]
macro_rules! log_err {
($result: expr) => {
if let Err(err) = $result {
log::error!(target: "app", "{err}");
}
};
($result: expr, $err_str: expr) => {
if let Err(_) = $result {
log::error!(target: "app", "{}", $err_str);
}
};
}
#[macro_export]
macro_rules! trace_err {
($result: expr, $err_str: expr) => {
if let Err(err) = $result {
log::trace!(target: "app", "{}, err {}", $err_str, err);
}
}
}
/// transform the error to String
#[macro_export]
macro_rules! wrap_err {
($stat: expr) => {
match $stat {
Ok(a) => Ok(a),
Err(err) => {
log::error!(target: "app", "{}", err.to_string());
Err(format!("{}", err.to_string()))
}
}
};
}

View File

@@ -0,0 +1,2 @@
pub mod common;
pub mod macros;

View File

@@ -57,9 +57,16 @@
{
"fullscreen": false,
"resizable": true,
"title": "Tauri NextJS App",
"width": 1280,
"height": 800
"title": "CS Toolbox",
"width": 976,
"height": 720,
"minWidth": 600,
"minHeight": 480,
"decorations": false,
"transparent": true,
"theme": "Light",
"hiddenTitle": true,
"titleBarStyle": "Overlay"
}
]
}