add existing settings
|
Before Width: | Height: | Size: 3.4 KiB After Width: | Height: | Size: 14 KiB |
|
Before Width: | Height: | Size: 6.8 KiB After Width: | Height: | Size: 48 KiB |
|
Before Width: | Height: | Size: 974 B After Width: | Height: | Size: 2.1 KiB |
BIN
src-tauri/icons/CS工具箱#FULL.png
Normal file
|
After Width: | Height: | Size: 855 KiB |
BIN
src-tauri/icons/CS工具箱#无圆角.png
Normal file
|
After Width: | Height: | Size: 863 KiB |
BIN
src-tauri/icons/CS工具箱.png
Normal file
|
After Width: | Height: | Size: 802 KiB |
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 7.0 KiB |
|
Before Width: | Height: | Size: 3.8 KiB After Width: | Height: | Size: 12 KiB |
|
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 13 KiB |
|
Before Width: | Height: | Size: 7.6 KiB After Width: | Height: | Size: 45 KiB |
|
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 1.3 KiB |
|
Before Width: | Height: | Size: 8.4 KiB After Width: | Height: | Size: 56 KiB |
|
Before Width: | Height: | Size: 1.3 KiB After Width: | Height: | Size: 2.0 KiB |
|
Before Width: | Height: | Size: 2.0 KiB After Width: | Height: | Size: 3.8 KiB |
|
Before Width: | Height: | Size: 2.4 KiB After Width: | Height: | Size: 5.6 KiB |
|
Before Width: | Height: | Size: 1.5 KiB After Width: | Height: | Size: 4.0 KiB |
BIN
src-tauri/icons/icon-tray.png
Normal file
|
After Width: | Height: | Size: 186 KiB |
|
Before Width: | Height: | Size: 85 KiB After Width: | Height: | Size: 65 KiB |
|
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 203 KiB |
57
src-tauri/src/cmds.rs
Normal 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()
|
||||
}
|
||||
@@ -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()
|
||||
.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
@@ -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()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
38
src-tauri/src/steam/mod.rs
Normal 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(())
|
||||
}
|
||||
48
src-tauri/src/steam/path.rs
Normal 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
@@ -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");
|
||||
}
|
||||
}
|
||||
35
src-tauri/src/tool/common.rs
Normal 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",
|
||||
))
|
||||
}
|
||||
44
src-tauri/src/tool/macros.rs
Normal 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()))
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
2
src-tauri/src/tool/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod common;
|
||||
pub mod macros;
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||