forked from akanyan/STARTLINER
feat: shortcuts
This commit is contained in:
BIN
res/icon-chunithm.ico
Normal file
BIN
res/icon-chunithm.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 81 KiB |
BIN
res/icon-ongeki.ico
Normal file
BIN
res/icon-ongeki.ico
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
2
rust/Cargo.lock
generated
2
rust/Cargo.lock
generated
@ -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]]
|
||||
|
@ -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"
|
||||
|
@ -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");
|
||||
|
@ -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,
|
||||
|
@ -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",
|
||||
|
@ -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(())
|
||||
}
|
@ -2,6 +2,7 @@
|
||||
import { ref } from 'vue';
|
||||
import Button from 'primevue/button';
|
||||
import InputText from 'primevue/inputtext';
|
||||
import { useConfirm } from 'primevue/useconfirm';
|
||||
import * as path from '@tauri-apps/api/path';
|
||||
import { invoke } from '../invoke';
|
||||
import { useGeneralStore, usePrfStore } from '../stores';
|
||||
@ -9,6 +10,8 @@ import { ProfileMeta } from '../types';
|
||||
|
||||
const general = useGeneralStore();
|
||||
const prf = usePrfStore();
|
||||
const confirmDialog = useConfirm();
|
||||
|
||||
const isEditing = ref(false);
|
||||
|
||||
const props = defineProps({
|
||||
@ -54,6 +57,14 @@ const deleteProfile = async () => {
|
||||
await prf.reloadList();
|
||||
await prf.reload();
|
||||
};
|
||||
|
||||
const promptDeleteProfile = async () => {
|
||||
confirmDialog.require({
|
||||
message: `Are you sure you want to delete ${props.p?.game}-${props.p?.name}?`,
|
||||
header: 'Delete profile',
|
||||
accept: deleteProfile,
|
||||
});
|
||||
};
|
||||
</script>
|
||||
|
||||
<template>
|
||||
@ -90,7 +101,7 @@ const deleteProfile = async () => {
|
||||
size="small"
|
||||
class="self-center ml-2"
|
||||
style="width: 2rem; height: 2rem"
|
||||
@click="deleteProfile"
|
||||
@click="promptDeleteProfile"
|
||||
/>
|
||||
<Button
|
||||
rounded
|
||||
|
@ -85,6 +85,15 @@ listen('launch-end', () => {
|
||||
getCurrentWindow().setFocus();
|
||||
});
|
||||
|
||||
const createShortcut = async () => {
|
||||
const current = prf.current;
|
||||
if (current !== null) {
|
||||
await invoke('create_shortcut', {
|
||||
profileMeta: current.meta,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const menuItems = [
|
||||
{
|
||||
label: 'Refresh and start',
|
||||
@ -96,6 +105,11 @@ const menuItems = [
|
||||
icon: 'pi pi-exclamation-circle',
|
||||
command: async () => await startline(true, false),
|
||||
},
|
||||
{
|
||||
label: 'Create shortcut',
|
||||
icon: 'pi pi-link',
|
||||
command: createShortcut,
|
||||
},
|
||||
];
|
||||
const menu = ref();
|
||||
|
||||
|
Reference in New Issue
Block a user