feat: shortcuts

This commit is contained in:
2025-04-16 13:20:43 +00:00
parent d3145bfc4e
commit e6c21ef04a
10 changed files with 83 additions and 3 deletions

2
rust/Cargo.lock generated
View File

@ -803,7 +803,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "117725a109d387c937a1533ce01b450cbde6b88abceea8473c4d7a85853cda3c"
dependencies = [
"lazy_static",
"windows-sys 0.48.0",
"windows-sys 0.59.0",
]
[[package]]

View File

@ -53,5 +53,5 @@ tauri-plugin-single-instance = { version = "2", features = ["deep-link"] }
tauri-plugin-updater = "2"
[target.'cfg(target_os = "windows")'.dependencies]
winsafe = { version = "0.0.23", features = ["user"] }
winsafe = { version = "0.0.23", features = ["user", "ole", "shell"] }
displayz = "^0.2.0"

View File

@ -397,6 +397,13 @@ pub async fn load_segatools_ini(state: State<'_, Mutex<AppData>>, path: PathBuf)
Ok(())
}
#[tauri::command]
pub async fn create_shortcut(app: AppHandle, profile_meta: ProfileMeta) -> Result<(), String> {
log::debug!("invoke: create_shortcut({:?})", profile_meta);
util::create_shortcut(app, &profile_meta).map_err(|e| e.to_string())
}
#[tauri::command]
pub async fn list_platform_capabilities() -> Result<Vec<String>, ()> {
log::debug!("invoke: list_platform_capabilities");

View File

@ -199,6 +199,7 @@ pub async fn run(_args: Vec<String>) {
cmd::sync_current_profile,
cmd::save_current_profile,
cmd::load_segatools_ini,
cmd::create_shortcut,
cmd::get_global_config,
cmd::set_global_config,

View File

@ -20,6 +20,13 @@ impl Game {
}
}
pub fn print(&self) -> &'static str {
match self {
Game::Ongeki => "O.N.G.E.K.I.",
Game::Chunithm => "CHUNITHM"
}
}
pub fn hook_exe(&self) -> &'static str {
match self {
Game::Ongeki => "mu3hook.dll",

View File

@ -173,4 +173,44 @@ pub async fn remove_dir_all(path: impl AsRef<Path>) -> Result<()> {
} else {
Err(anyhow!("invalid remove_dir_all target: not in a data directory"))
}
}
#[cfg(target_os = "windows")]
pub fn create_shortcut(
apph: AppHandle,
meta: &crate::profiles::ProfileMeta
) -> Result<()> {
use winsafe::{co, prelude::{ole_IPersistFile, ole_IUnknown, shell_IShellLink}, CoCreateInstance, CoInitializeEx, IPersistFile};
let _com_guard = CoInitializeEx(
co::COINIT::APARTMENTTHREADED
| co::COINIT::DISABLE_OLE1DDE,
)?;
let obj = CoCreateInstance::<winsafe::IShellLink>(
&co::CLSID::ShellLink,
None,
co::CLSCTX::INPROC_SERVER,
)?;
let target_dir = apph.path().cache_dir()?.join(NAME);
let target_path = target_dir.join("startliner.exe");
let lnk_path = apph.path().desktop_dir()?.join(format!("{}-{}.lnk", &meta.game, &meta.name));
obj.SetPath(target_path.to_str().ok_or_else(|| anyhow!("Illegal target path"))?)?;
obj.SetDescription(&format!("{} {}", &meta.game.print(), &meta.name))?;
obj.SetArguments(&format!("--start --game {} --profile {}", &meta.game, &meta.name))?;
obj.SetIconLocation(
target_dir.join(format!("icon-{}.ico", &meta.game)).to_str().ok_or_else(|| anyhow!("Illegal icon path"))?,
0
)?;
match meta.game {
Game::Ongeki => std::fs::write(target_dir.join("icon-ongeki.ico"), include_bytes!("../../res/icon-ongeki.ico")),
Game::Chunithm => std::fs::write(target_dir.join("icon-chunithm.ico"), include_bytes!("../../res/icon-chunithm.ico"))
}?;
let file = obj.QueryInterface::<IPersistFile>()?;
file.Save(Some(lnk_path.to_str().ok_or_else(|| anyhow!("Illegal shortcut path"))?), true)?;
Ok(())
}