From d59d087682927cf776989c23283c0bb2ff4e7c52 Mon Sep 17 00:00:00 2001 From: crschnick Date: Mon, 20 Jan 2025 16:12:14 +0000 Subject: [PATCH] Rework --- .../xpipe/app/prefs/ExternalEditorType.java | 4 +- .../app/prefs/ExternalRdpClientType.java | 2 +- .../app/terminal/MobaXTermTerminalType.java | 2 +- .../xpipe/app/terminal/TabbyTerminalType.java | 4 +- .../app/terminal/TermiusTerminalType.java | 2 +- .../xpipe/app/terminal/WezTerminalType.java | 2 +- .../app/terminal/XShellTerminalType.java | 2 +- .../io/xpipe/app/util/WindowsRegistry.java | 66 +++++++++++++++++-- lang/strings/translations_en.properties | 2 + 9 files changed, 70 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java index bfce81b45..60730dd80 100644 --- a/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalEditorType.java @@ -65,12 +65,12 @@ public interface ExternalEditorType extends PrefsChoiceValue { @Override protected Optional determineInstallation() { var found = - WindowsRegistry.local().readValue(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Notepad++", null); + WindowsRegistry.local().readStringValueIfPresent(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Notepad++", null); // Check 32 bit install if (found.isEmpty()) { found = WindowsRegistry.local() - .readValue(WindowsRegistry.HKEY_LOCAL_MACHINE, "WOW6432Node\\SOFTWARE\\Notepad++", null); + .readStringValueIfPresent(WindowsRegistry.HKEY_LOCAL_MACHINE, "WOW6432Node\\SOFTWARE\\Notepad++", null); } return found.map(p -> p + "\\notepad++.exe").map(Path::of); } diff --git a/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java b/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java index aba556edf..cccd4313e 100644 --- a/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java +++ b/app/src/main/java/io/xpipe/app/prefs/ExternalRdpClientType.java @@ -83,7 +83,7 @@ public interface ExternalRdpClientType extends PrefsChoiceValue { protected Optional determineInstallation() { try { var r = WindowsRegistry.local() - .readValue(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\rdm\\DefaultIcon"); + .readStringValueIfPresent(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\rdm\\DefaultIcon"); return r.map(Path::of); } catch (Exception e) { ErrorEvent.fromThrowable(e).omit().handle(); diff --git a/app/src/main/java/io/xpipe/app/terminal/MobaXTermTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/MobaXTermTerminalType.java index dad2d89a0..4f9a0d0d9 100644 --- a/app/src/main/java/io/xpipe/app/terminal/MobaXTermTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/MobaXTermTerminalType.java @@ -26,7 +26,7 @@ public class MobaXTermTerminalType extends ExternalTerminalType.WindowsType { protected Optional determineInstallation() { try { var r = WindowsRegistry.local() - .readValue(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\mobaxterm\\DefaultIcon"); + .readStringValueIfPresent(WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Classes\\mobaxterm\\DefaultIcon"); return r.map(Path::of); } catch (Exception e) { ErrorEvent.fromThrowable(e).omit().handle(); diff --git a/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java index 71f62fce2..5cf0a238d 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/TabbyTerminalType.java @@ -91,7 +91,7 @@ public interface TabbyTerminalType extends ExternalTerminalType, TrackableTermin @Override protected Optional determineInstallation() { var perUser = WindowsRegistry.local() - .readValue( + .readStringValueIfPresent( WindowsRegistry.HKEY_CURRENT_USER, "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", "InstallLocation") @@ -102,7 +102,7 @@ public interface TabbyTerminalType extends ExternalTerminalType, TrackableTermin } var systemWide = WindowsRegistry.local() - .readValue( + .readStringValueIfPresent( WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\71445fac-d6ef-5436-9da7-5a323762d7f5", "InstallLocation") diff --git a/app/src/main/java/io/xpipe/app/terminal/TermiusTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/TermiusTerminalType.java index eed3984c0..652c3bcc1 100644 --- a/app/src/main/java/io/xpipe/app/terminal/TermiusTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/TermiusTerminalType.java @@ -40,7 +40,7 @@ public class TermiusTerminalType implements ExternalTerminalType { } case OsType.Windows windows -> { var r = WindowsRegistry.local() - .readValue(WindowsRegistry.HKEY_CURRENT_USER, "SOFTWARE\\Classes\\termius"); + .readStringValueIfPresent(WindowsRegistry.HKEY_CURRENT_USER, "SOFTWARE\\Classes\\termius"); yield r.isPresent(); } }; diff --git a/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java index a4e94bdbd..a6d9573ec 100644 --- a/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/WezTerminalType.java @@ -63,7 +63,7 @@ public interface WezTerminalType extends ExternalTerminalType, TrackableTerminal "http://wezfurlong.org/wezterm"); if (foundKey.isPresent()) { var installKey = WindowsRegistry.local() - .readValue(foundKey.get().getHkey(), foundKey.get().getKey(), "InstallLocation"); + .readStringValueIfPresent(foundKey.get().getHkey(), foundKey.get().getKey(), "InstallLocation"); if (installKey.isPresent()) { return installKey.map(p -> p + "\\wezterm-gui.exe").map(Path::of); } diff --git a/app/src/main/java/io/xpipe/app/terminal/XShellTerminalType.java b/app/src/main/java/io/xpipe/app/terminal/XShellTerminalType.java index 99d36d546..11ec59ebb 100644 --- a/app/src/main/java/io/xpipe/app/terminal/XShellTerminalType.java +++ b/app/src/main/java/io/xpipe/app/terminal/XShellTerminalType.java @@ -29,7 +29,7 @@ public class XShellTerminalType extends ExternalTerminalType.WindowsType { protected Optional determineInstallation() { try { var r = WindowsRegistry.local() - .readValue( + .readStringValueIfPresent( WindowsRegistry.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\App Paths\\Xshell.exe"); return r.map(Path::of); diff --git a/app/src/main/java/io/xpipe/app/util/WindowsRegistry.java b/app/src/main/java/io/xpipe/app/util/WindowsRegistry.java index fc7f257b5..0b177bad1 100644 --- a/app/src/main/java/io/xpipe/app/util/WindowsRegistry.java +++ b/app/src/main/java/io/xpipe/app/util/WindowsRegistry.java @@ -8,7 +8,7 @@ import com.sun.jna.platform.win32.Advapi32Util; import com.sun.jna.platform.win32.WinReg; import lombok.Value; -import java.util.Optional; +import java.util.*; public abstract class WindowsRegistry { @@ -31,12 +31,16 @@ public abstract class WindowsRegistry { public abstract boolean keyExists(int hkey, String key) throws Exception; + public abstract List listSubKeys(int hkey, String key) throws Exception; + public abstract boolean valueExists(int hkey, String key, String valueName) throws Exception; - public abstract Optional readValue(int hkey, String key, String valueName) throws Exception; + public abstract OptionalInt readIntegerValueIfPresent(int hkey, String key, String valueName) throws Exception; - public Optional readValue(int hkey, String key) throws Exception { - return readValue(hkey, key, null); + public abstract Optional readStringValueIfPresent(int hkey, String key, String valueName) throws Exception; + + public Optional readStringValueIfPresent(int hkey, String key) throws Exception { + return readStringValueIfPresent(hkey, key, null); } public abstract Optional findValuesRecursive(int hkey, String key, String valueName) throws Exception; @@ -61,6 +65,17 @@ public abstract class WindowsRegistry { } } + @Override + public List listSubKeys(int hkey, String key) throws Exception { + // This can fail even with errors in case the jna native library extraction or loading fails + try { + return Arrays.asList(Advapi32Util.registryGetKeys(hkey(hkey), key)); + } catch (Throwable t) { + ErrorEvent.fromThrowable(t).handle(); + return List.of(); + } + } + @Override public boolean valueExists(int hkey, String key, String valueName) { // This can fail even with errors in case the jna native library extraction or loading fails @@ -73,7 +88,22 @@ public abstract class WindowsRegistry { } @Override - public Optional readValue(int hkey, String key, String valueName) { + public OptionalInt readIntegerValueIfPresent(int hkey, String key, String valueName) throws Exception { + // This can fail even with errors in case the jna native library extraction or loading fails + try { + if (!Advapi32Util.registryValueExists(hkey(hkey), key, valueName)) { + return OptionalInt.empty(); + } + + return OptionalInt.of(Advapi32Util.registryGetIntValue(hkey(hkey), key, valueName)); + } catch (Throwable t) { + ErrorEvent.fromThrowable(t).handle(); + return OptionalInt.empty(); + } + } + + @Override + public Optional readStringValueIfPresent(int hkey, String key, String valueName) { // This can fail even with errors in case the jna native library extraction or loading fails try { if (!Advapi32Util.registryValueExists(hkey(hkey), key, valueName)) { @@ -113,7 +143,7 @@ public abstract class WindowsRegistry { } if (original.contains(" ")) { - String[] parsed = original.split(" "); + String[] parsed = original.split(" {4}"); return Optional.of(parsed[parsed.length - 1]); } @@ -141,6 +171,18 @@ public abstract class WindowsRegistry { } } + @Override + public List listSubKeys(int hkey, String key) throws Exception { + var prefix = hkey(hkey) + "\\"; + var command = CommandBuilder.of() + .add("reg", "query") + .addQuoted(prefix + key); + var out = shellControl.command(command).readStdoutOrThrow(); + return out.lines().filter(s -> { + return s.contains(prefix); + }).map(s -> s.replace(prefix, "")).toList(); + } + @Override public boolean valueExists(int hkey, String key, String valueName) throws Exception { var command = CommandBuilder.of() @@ -154,7 +196,17 @@ public abstract class WindowsRegistry { } @Override - public Optional readValue(int hkey, String key, String valueName) throws Exception { + public OptionalInt readIntegerValueIfPresent(int hkey, String key, String valueName) throws Exception { + var r = readStringValueIfPresent(hkey, key, valueName); + if (r.isPresent()) { + return OptionalInt.of(Integer.parseInt(r.get())); + } else { + return OptionalInt.empty(); + } + } + + @Override + public Optional readStringValueIfPresent(int hkey, String key, String valueName) throws Exception { var command = CommandBuilder.of() .add("reg", "query") .addQuoted(hkey(hkey) + "\\" + key) diff --git a/lang/strings/translations_en.properties b/lang/strings/translations_en.properties index 86d128d1e..edc3b822e 100644 --- a/lang/strings/translations_en.properties +++ b/lang/strings/translations_en.properties @@ -1294,3 +1294,5 @@ identityName=Identity name identityNameDescription=Give this identity a custom name tailscaleTailnet.displayName=Tailnet tailscaleTailnet.displayDescription=Connect to a specific tailnet with your account +puttyConnections=PuTTY connections +kittyConnections=KiTTY connections