Skip to content

Commit

Permalink
Merge pull request #83 from litwak913/autostart
Browse files Browse the repository at this point in the history
Abstract StartupConfig and shortcut-based autostart
  • Loading branch information
isHarryh authored Oct 26, 2024
2 parents adb1b02 + 030921f commit a1760de
Show file tree
Hide file tree
Showing 6 changed files with 214 additions and 88 deletions.
81 changes: 0 additions & 81 deletions core/src/cn/harryh/arkpets/ArkConfig.java
Original file line number Diff line number Diff line change
Expand Up @@ -185,87 +185,6 @@ public enum RenderOutline {
}


/** Only available in Windows OS.
*/
public static class StartupConfig {
public static File startupDir;
public static File startupFile;

static {
try {
startupDir = new File(System.getProperty("user.home") + "/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup");
if (!startupDir.isDirectory())
throw new FileNotFoundException("No such directory " + startupDir.getAbsolutePath());
startupFile = new File(startupDir.getAbsolutePath(), startUpScript);
} catch (Exception e) {
startupDir = null;
startupFile = null;
Logger.error("Config", "Auto-startup config may be unavailable, details see below.", e);
}
}

public static boolean addStartup() {
try {
String script = generateScript();
if (script == null || startupDir == null)
throw new IOException("Generate script failed.");
FileUtil.writeString(startupFile, charsetVBS, script, false);
Logger.info("Config", "Auto-startup was added: " + startupFile.getAbsolutePath());
return true;
} catch (Exception e) {
Logger.error("Config", "Auto-startup adding failed, details see below.", e);
return false;
}
}

public static void removeStartup() {
try {
FileUtil.delete(startupFile.toPath(), false);
Logger.info("Config", "Auto-startup was removed: " + startupFile.getAbsolutePath());
} catch (Exception e) {
Logger.error("Config", "Auto-startup removing failed, details see below.", e);
}
}

public static boolean isSetStartup() {
try {
if (!startupFile.exists())
return false;
String script = generateScript();
if (script == null || startupDir == null)
throw new IOException("Generate script failed.");
String checksum1 = FileUtil.getMD5(Objects.requireNonNull(script).getBytes(charsetVBS));
String checksum2 = FileUtil.getMD5(startupFile);
return checksum1.equals(checksum2);
} catch (Exception e) {
return false;
}
}

/** Gets a content of a VBS script which can start ArkPets.
* @return The script's content.
*/
public static String generateScript() {
if (!new File(startupTarget).exists())
return null;
String cd = System.getProperty("user.dir");
cd = cd.replaceAll("\"", "\"\"");
cd = cd + (cd.endsWith("\\") ? "" : "\\");
String run = startupTarget + " --direct-start";
run = run.replaceAll("\"", "\"\"");
return "rem *** This is an auto-startup script, you can delete it if you want. ***\n" +
"const cd = \"" + cd + "\"\n" +
"const ex = \"" + startupTarget + "\"\n" +
"set fso=WScript.CreateObject(\"Scripting.FileSystemObject\")\n" +
"if fso.FileExists(cd & ex) then\n" +
" set s = WScript.CreateObject(\"WScript.shell\")\n" +
" s.CurrentDirectory = cd\n" +
" s.Run \"" + run + "\"\n" +
"end if\n";
}
}


@SuppressWarnings("unused")
public static class Monitor {
public String name;
Expand Down
3 changes: 0 additions & 3 deletions core/src/cn/harryh/arkpets/Const.java
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,6 @@ public final class Const {

// Encoding presets
public static final String charsetDefault = "UTF-8";
public static final String charsetVBS = "GBK";

// Paths of static files and internal files
public static final String configExternal = "ArkPetsConfig.json";
Expand All @@ -65,8 +64,6 @@ public final class Const {
public static final String pass1FShader = "shaders/TCPBFragment.glsl";
public static final String pass2VShader = "shaders/TCPBVertex.glsl";
public static final String pass2FShader = "shaders/OutlineFragment.glsl";
public static final String startupTarget = "ArkPets.exe";
public static final String startUpScript = "ArkPetsStartupService.vbs";

// Changeable constants
public static boolean isHttpsTrustAll = false;
Expand Down
26 changes: 26 additions & 0 deletions core/src/cn/harryh/arkpets/platform/NullStartupConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/** Copyright (c) 2022-2024, Harry Huang, Litwak913
* At GPL-3.0 License
*/
package cn.harryh.arkpets.platform;

public class NullStartupConfig extends StartupConfig {
@Override
public boolean addStartup() {
return true;
}

@Override
public void removeStartup() {

}

@Override
public boolean isSetStartup() {
return false;
}

@Override
public boolean isStartupAvailable() {
return false;
}
}
36 changes: 36 additions & 0 deletions core/src/cn/harryh/arkpets/platform/StartupConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/** Copyright (c) 2022-2024, Harry Huang, Litwak913
* At GPL-3.0 License
*/
package cn.harryh.arkpets.platform;

import com.sun.jna.Platform;


public abstract class StartupConfig {
/** Gets the platform StartupConfig.
* @return platform StartupConfig.
*/
public static StartupConfig getInstance() {
if (Platform.isWindows()) {
return new WindowsStartupConfig();
}
return new NullStartupConfig();
}

/** Enable autostart.
* @return true=success, false=failure.
*/
public abstract boolean addStartup();

/** Disable autostart.
*/
public abstract void removeStartup();

/** Returns true if autostart is enabled.
*/
public abstract boolean isSetStartup();

/** Returns true if autostart is available.
*/
public abstract boolean isStartupAvailable();
}
146 changes: 146 additions & 0 deletions core/src/cn/harryh/arkpets/platform/WindowsStartupConfig.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
/** Copyright (c) 2022-2024, Harry Huang, Litwak913
* At GPL-3.0 License
*/
package cn.harryh.arkpets.platform;

import cn.harryh.arkpets.utils.IOUtils;
import cn.harryh.arkpets.utils.Logger;
import com.sun.jna.Pointer;
import com.sun.jna.WString;
import com.sun.jna.platform.win32.COM.COMUtils;
import com.sun.jna.platform.win32.COM.Unknown;
import com.sun.jna.platform.win32.Guid;
import com.sun.jna.platform.win32.Ole32;
import com.sun.jna.platform.win32.WTypes;
import com.sun.jna.platform.win32.WinNT;
import com.sun.jna.ptr.PointerByReference;

import java.io.File;
import java.io.FileNotFoundException;


public class WindowsStartupConfig extends StartupConfig {
private boolean available;
private File startupDir;
private File startupFile;

private static final String startupTarget = "ArkPets.exe";
private static final String startupShortcut = "ArkPetsStartup.lnk";
private static final String oldStartupScript = "ArkPetsStartupService.vbs";

public WindowsStartupConfig() {
try {
this.startupDir = new File(System.getProperty("user.home") + "/AppData/Roaming/Microsoft/Windows/Start Menu/Programs/Startup");
if (!this.startupDir.isDirectory())
throw new FileNotFoundException("No such directory " + startupDir.getAbsolutePath());
if (!new File(startupTarget).exists())
throw new FileNotFoundException("Executable not found.");
this.startupFile = new File(startupDir.getAbsolutePath(), startupShortcut);
this.available = true;
} catch (Exception e) {
this.startupDir = null;
this.startupFile = null;
this.available = false;
Logger.error("Config", "Auto-startup config may be unavailable, details see below.", e);
}
File oldStartup = new File(startupDir.getAbsolutePath(), oldStartupScript);
if (oldStartup.exists()) {
Logger.debug("Config", "Found old startup script,migrate to shortcut.");
if(oldStartup.delete()){
addStartup();
}
}
}

@Override
public boolean addStartup() {
if (!this.available) return false;
try {
IShellLink lnk = IShellLink.create();
IPersistFile pf = lnk.getPF();
String cd = System.getProperty("user.dir");
cd = cd.replaceAll("\"", "\"\"");
lnk.SetPath(cd + "\\" + startupTarget);
lnk.SetArguments("--direct-start");
lnk.SetWorkingDirectory(cd);
pf.Save(startupFile.getAbsolutePath().replaceAll("\"", "\"\""));
pf.Release();
lnk.Release();
return true;
} catch (Exception e) {
Logger.error("Config", "Auto-startup adding failed, details see below.", e);
return false;
}
}

@Override
public void removeStartup() {
try {
IOUtils.FileUtil.delete(startupFile.toPath(), false);
Logger.info("Config", "Auto-startup was removed: " + startupFile.getAbsolutePath());
} catch (Exception e) {
Logger.error("Config", "Auto-startup removing failed, details see below.", e);
}
}

@Override
public boolean isSetStartup() {
if (!this.available) return false;
return startupFile.exists();
}

@Override
public boolean isStartupAvailable() {
return this.available;
}

private static class IPersistFile extends Unknown {
private IPersistFile(Pointer ptr) {
super(ptr);
}

public void Save(String path) {
int res = this._invokeNativeInt(6, new Object[]{this.getPointer(), new WString(path), true});
COMUtils.checkRC(new WinNT.HRESULT(res));
}
}

private static class IShellLink extends Unknown {
private static final Guid.GUID CLSID_ShellLink = new Guid.GUID("{00021401-0000-0000-c000-000000000046}");
private static final Guid.GUID IID_IShellLinkW = new Guid.GUID("{000214F9-0000-0000-c000-000000000046}");
private static final Guid.GUID IID_IPersistFile = new Guid.GUID("{0000010B-0000-0000-c000-000000000046}");

private IShellLink(Pointer ptr) {
super(ptr);
}

public static IShellLink create() {
PointerByReference p = new PointerByReference();
WinNT.HRESULT hr = Ole32.INSTANCE.CoCreateInstance(CLSID_ShellLink, Pointer.NULL, WTypes.CLSCTX_INPROC_SERVER, IID_IShellLinkW, p);
COMUtils.checkRC(hr);
return new IShellLink(p.getValue());
}

public void SetPath(String path) {
int res = this._invokeNativeInt(20, new Object[]{this.getPointer(), new WString(path)});
COMUtils.checkRC(new WinNT.HRESULT(res));
}

public void SetWorkingDirectory(String path) {
int res = this._invokeNativeInt(9, new Object[]{this.getPointer(), new WString(path)});
COMUtils.checkRC(new WinNT.HRESULT(res));
}

public void SetArguments(String arg) {
int res = this._invokeNativeInt(11, new Object[]{this.getPointer(), new WString(arg)});
COMUtils.checkRC(new WinNT.HRESULT(res));
}

public IPersistFile getPF() {
PointerByReference p = new PointerByReference();
WinNT.HRESULT hr = this.QueryInterface(new Guid.REFIID(new Guid.IID(IID_IPersistFile)), p);
COMUtils.checkRC(hr);
return new IPersistFile(p.getValue());
}
}
}
10 changes: 6 additions & 4 deletions desktop/src/cn/harryh/arkpets/controllers/SettingsModule.java
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
import cn.harryh.arkpets.Const;
import cn.harryh.arkpets.guitasks.CheckAppUpdateTask;
import cn.harryh.arkpets.guitasks.GuiTask;
import cn.harryh.arkpets.platform.StartupConfig;
import cn.harryh.arkpets.utils.*;
import cn.harryh.arkpets.utils.GuiComponents.*;
import com.badlogic.gdx.graphics.Color;
Expand Down Expand Up @@ -287,18 +288,19 @@ else if (args.contains(Const.LogConfig.debugArg))
configNetworkAgentStatus.setText("未使用代理");
configNetworkAgentStatus.setStyle("-fx-text-fill:" + GuiPrefabs.Colors.COLOR_LIGHT_GRAY);

configAutoStartup.setSelected(ArkConfig.StartupConfig.isSetStartup());
StartupConfig startup = StartupConfig.getInstance();
configAutoStartup.setSelected(startup.isSetStartup());
configAutoStartup.setOnAction(e -> {
if (configAutoStartup.isSelected()) {
if (ArkConfig.StartupConfig.addStartup()) {
if (startup.addStartup()) {
GuiPrefabs.Dialogs.createCommonDialog(app.body,
GuiPrefabs.Icons.getIcon(GuiPrefabs.Icons.ICON_SUCCESS_ALT, GuiPrefabs.Colors.COLOR_SUCCESS),
"开机自启动",
"开机自启动设置成功。",
"下次开机时将会自动生成您最后一次启动的桌宠。",
null).show();
} else {
if (ArkConfig.StartupConfig.generateScript() == null)
if (!startup.isStartupAvailable())
GuiPrefabs.Dialogs.createCommonDialog(app.body,
GuiPrefabs.Icons.getIcon(GuiPrefabs.Icons.ICON_WARNING_ALT, GuiPrefabs.Colors.COLOR_WARNING),
"开机自启动",
Expand All @@ -315,7 +317,7 @@ else if (args.contains(Const.LogConfig.debugArg))
configAutoStartup.setSelected(false);
}
} else {
ArkConfig.StartupConfig.removeStartup();
startup.removeStartup();
}
});

Expand Down

0 comments on commit a1760de

Please sign in to comment.