From f5a657d5c3125e881d218e25260dc01a617aea8c Mon Sep 17 00:00:00 2001
From: CJKmkp <2564608840@qq.com>
Date: Sun, 5 Apr 2026 09:38:16 +0800
Subject: [PATCH] =?UTF-8?q?improve:=E5=B1=95=E5=8F=B0?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
新增将展台替换为希沃展台快捷启动功能
---
Ink Canvas/Helpers/SoftwareLauncher.cs | 171 +++++++++++++-----
Ink Canvas/MainWindow.xaml | 9 +
Ink Canvas/MainWindow_cs/MW_Settings.cs | 9 +
Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs | 5 +-
Ink Canvas/MainWindow_cs/MW_VideoPresenter.cs | 8 +
Ink Canvas/Properties/Strings.enUS.xml | 2 +
Ink Canvas/Properties/Strings.resx | 2 +
Ink Canvas/Resources/Settings.cs | 4 +
.../SettingsViews/CanvasAndInkPanel.xaml | 16 +-
.../SettingsViews/CanvasAndInkPanel.xaml.cs | 10 +
.../SettingsViews/MainWindowSettingsHelper.cs | 1 +
11 files changed, 188 insertions(+), 49 deletions(-)
diff --git a/Ink Canvas/Helpers/SoftwareLauncher.cs b/Ink Canvas/Helpers/SoftwareLauncher.cs
index e3dc7188..395eadf3 100644
--- a/Ink Canvas/Helpers/SoftwareLauncher.cs
+++ b/Ink Canvas/Helpers/SoftwareLauncher.cs
@@ -1,72 +1,151 @@
-using Microsoft.Win32;
+using Microsoft.Win32;
using System;
using System.Diagnostics;
using System.IO;
-using System.Runtime.InteropServices;
+using System.Windows;
namespace Ink_Canvas.Helpers
{
- internal class SoftwareLauncher
+ internal static class SoftwareLauncher
{
- [DllImport("user32.dll")]
- private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
-
+ /// 与 ICA 一致:在「程序和功能」卸载列表中按 DisplayName 匹配后启动 sweclauncher.exe。
public static void LaunchEasiCamera(string softwareName)
{
string executablePath = FindEasiCameraExecutablePath(softwareName);
- if (!string.IsNullOrEmpty(executablePath))
+ if (string.IsNullOrEmpty(executablePath))
{
- try
- {
- Process.Start(executablePath);
- //Console.WriteLine(softwareName + " 启动成功!");
- }
- catch (Exception ex)
- {
- Console.WriteLine("启动失败: " + ex.Message);
- //MessageBox.Show("启动失败: " + ex.Message);
- }
+ MessageBox.Show(
+ "未找到希沃视频展台安装信息(已扫描 64 位与 32 位卸载注册表)。请确认已通过官方安装包安装「希沃视频展台」。",
+ "Ink Canvas",
+ MessageBoxButton.OK,
+ MessageBoxImage.Information);
+ return;
+ }
+
+ try
+ {
+ var directory = Path.GetDirectoryName(executablePath);
+ var psi = new ProcessStartInfo
+ {
+ FileName = executablePath,
+ UseShellExecute = true,
+ WorkingDirectory = string.IsNullOrEmpty(directory) ? Environment.SystemDirectory : directory
+ };
+ Process.Start(psi);
+ }
+ catch (Exception ex)
+ {
+ MessageBox.Show(
+ "无法启动希沃视频展台:" + ex.Message,
+ "Ink Canvas",
+ MessageBoxButton.OK,
+ MessageBoxImage.Warning);
}
- //Console.WriteLine(softwareName + " 未找到可执行文件路径。");
}
private static string FindEasiCameraExecutablePath(string softwareName)
{
- string executablePath = null;
+ if (string.IsNullOrWhiteSpace(softwareName))
+ return null;
- using (RegistryKey key = Registry.LocalMachine.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Uninstall"))
+ // 64 位进程默认只枚举 64 位注册表视图;32 位希沃常写在 WOW6432Node 下,需一并扫描。
+ string[] uninstallRoots =
{
- foreach (string subkeyName in key.GetSubKeyNames())
- {
- using (RegistryKey subkey = key.OpenSubKey(subkeyName))
- {
- string displayName = subkey.GetValue("DisplayName") as string;
- string installLocation = subkey.GetValue("InstallLocation") as string;
- string uninstallString = subkey.GetValue("UninstallString") as string;
+ @"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall",
+ @"SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall",
+ };
- if (!string.IsNullOrEmpty(displayName) && displayName.Contains(softwareName))
- {
- if (!string.IsNullOrEmpty(installLocation))
- {
- executablePath = Path.Combine(installLocation, "sweclauncher.exe");
- }
- else if (!string.IsNullOrEmpty(uninstallString))
- {
- int lastSlashIndex = uninstallString.LastIndexOf("\\");
- if (lastSlashIndex >= 0)
- {
- string folderPath = uninstallString.Substring(0, lastSlashIndex);
- executablePath = Path.Combine(folderPath, "sweclauncher", "sweclauncher.exe");
- }
- }
- break;
- }
- }
+ foreach (string root in uninstallRoots)
+ {
+ using (RegistryKey key = Registry.LocalMachine.OpenSubKey(root))
+ {
+ if (key == null) continue;
+ string found = FindInUninstallKey(key, softwareName);
+ if (!string.IsNullOrEmpty(found))
+ return found;
}
}
- return executablePath;
+ return null;
+ }
+
+ private static string FindInUninstallKey(RegistryKey uninstallKey, string softwareName)
+ {
+ foreach (string subkeyName in uninstallKey.GetSubKeyNames())
+ {
+ using (RegistryKey subkey = uninstallKey.OpenSubKey(subkeyName))
+ {
+ if (subkey == null) continue;
+
+ string displayName = subkey.GetValue("DisplayName") as string;
+ if (string.IsNullOrEmpty(displayName) || !displayName.Contains(softwareName))
+ continue;
+
+ string installLocation = subkey.GetValue("InstallLocation") as string;
+ string uninstallString = subkey.GetValue("UninstallString") as string;
+
+ string resolved = TryResolveSweclauncher(installLocation, uninstallString);
+ if (!string.IsNullOrEmpty(resolved) && File.Exists(resolved))
+ return resolved;
+ }
+ }
+
+ return null;
+ }
+
+ private static string TryResolveSweclauncher(string installLocation, string uninstallString)
+ {
+ if (!string.IsNullOrWhiteSpace(installLocation))
+ {
+ string fromLoc = ResolveSweclauncherUnderInstallRoot(installLocation.Trim().TrimEnd('\\'));
+ if (!string.IsNullOrEmpty(fromLoc))
+ return fromLoc;
+ }
+
+ if (!string.IsNullOrWhiteSpace(uninstallString))
+ {
+ // 常见:"...\uninstall.exe" 或带引号路径
+ string trimmed = uninstallString.Trim();
+ if (trimmed.Length >= 2 && trimmed[0] == '"')
+ {
+ int end = trimmed.IndexOf('"', 1);
+ if (end > 1)
+ trimmed = trimmed.Substring(1, end - 1);
+ }
+
+ int lastSlash = trimmed.LastIndexOf('\\');
+ if (lastSlash < 0)
+ return null;
+
+ string folderPath = trimmed.Substring(0, lastSlash);
+ string candidate = Path.Combine(folderPath, "sweclauncher", "sweclauncher.exe");
+ if (File.Exists(candidate))
+ return candidate;
+
+ candidate = Path.Combine(folderPath, "sweclauncher.exe");
+ if (File.Exists(candidate))
+ return candidate;
+ }
+
+ return null;
+ }
+
+ private static string ResolveSweclauncherUnderInstallRoot(string installRoot)
+ {
+ string[] candidates =
+ {
+ Path.Combine(installRoot, "sweclauncher.exe"),
+ Path.Combine(installRoot, "sweclauncher", "sweclauncher.exe"),
+ };
+
+ foreach (string p in candidates)
+ {
+ if (File.Exists(p))
+ return p;
+ }
+
+ return null;
}
}
}
diff --git a/Ink Canvas/MainWindow.xaml b/Ink Canvas/MainWindow.xaml
index 6a5ebc67..698fd6da 100644
--- a/Ink Canvas/MainWindow.xaml
+++ b/Ink Canvas/MainWindow.xaml
@@ -903,6 +903,15 @@
IsOn="True" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchCompressPicturesUploaded_Toggled" />
+
+
+
+
+
diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs
index a3e2eead..cedea1b4 100644
--- a/Ink Canvas/MainWindow_cs/MW_Settings.cs
+++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs
@@ -2705,6 +2705,15 @@ namespace Ink_Canvas
SaveSettingsToFile();
}
+ private void ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth_Toggled(object sender, RoutedEventArgs e)
+ {
+ if (!isLoaded) return;
+
+ Settings.Canvas.LaunchSeewoVideoShowcaseForWhiteboardBooth =
+ ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth.IsOn;
+ SaveSettingsToFile();
+ }
+
private void ToggleSwitchAutoStraightenLine_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
diff --git a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
index dafc9971..13277e7a 100644
--- a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
+++ b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs
@@ -852,6 +852,9 @@ namespace Ink_Canvas
ToggleSwitchDisablePressure.IsOn = Settings.Canvas.DisablePressure;
inkCanvas.DefaultDrawingAttributes.IgnorePressure = Settings.Canvas.DisablePressure;
+ ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth.IsOn =
+ Settings.Canvas.LaunchSeewoVideoShowcaseForWhiteboardBooth;
+
if (Settings.Canvas.EnableVelocityBrushTip)
{
Settings.Canvas.InkStyle = 3;
@@ -874,8 +877,6 @@ namespace Ink_Canvas
ToggleSwitchClearCanvasAlsoClearImages.IsOn = Settings.Canvas.ClearCanvasAlsoClearImages;
ToggleSwitchShowCircleCenter.IsOn = Settings.Canvas.ShowCircleCenter;
- ApplyWhiteboardBoothToolbarFromSettings();
-
switch (Settings.Canvas.EraserShapeType)
{
case 0:
diff --git a/Ink Canvas/MainWindow_cs/MW_VideoPresenter.cs b/Ink Canvas/MainWindow_cs/MW_VideoPresenter.cs
index e55d24c8..e276e9b5 100644
--- a/Ink Canvas/MainWindow_cs/MW_VideoPresenter.cs
+++ b/Ink Canvas/MainWindow_cs/MW_VideoPresenter.cs
@@ -51,6 +51,14 @@ namespace Ink_Canvas
/// 鼠标按钮事件的参数。
private void BtnToggleVideoPresenter_Click(object sender, System.Windows.Input.MouseButtonEventArgs e)
{
+ if (Settings?.Canvas?.LaunchSeewoVideoShowcaseForWhiteboardBooth == true)
+ {
+ // 与主窗口「希沃视频展台」入口(BoardLaunchEasiCamera_MouseUp)一致:先走黑板/白板入口逻辑再启动
+ ImageBlackboard_MouseUp(null, null);
+ SoftwareLauncher.LaunchEasiCamera("希沃视频展台");
+ return;
+ }
+
ToggleVideoPresenterSidebar();
}
diff --git a/Ink Canvas/Properties/Strings.enUS.xml b/Ink Canvas/Properties/Strings.enUS.xml
index 8b85772e..84f509cb 100644
--- a/Ink Canvas/Properties/Strings.enUS.xml
+++ b/Ink Canvas/Properties/Strings.enUS.xml
@@ -179,6 +179,8 @@
Ask each time
# Disabling may cause undo bugs.
Show circle center
+ Whiteboard booth opens Seewo Video Showcase
+ When enabled, the whiteboard toolbar Booth button launches Seewo Video Showcase (must be installed). When disabled, the built-in booth is used.
WPF default Bezier smoothing
Advanced curve smoothing (recommended)
Ink fade
diff --git a/Ink Canvas/Properties/Strings.resx b/Ink Canvas/Properties/Strings.resx
index 3f00ba51..df7fb722 100644
--- a/Ink Canvas/Properties/Strings.resx
+++ b/Ink Canvas/Properties/Strings.resx
@@ -194,6 +194,8 @@
每次询问
# 请注意,若不保留双曲线渐近线可能会有遇到撤回相关的 BUG…
绘制圆时显示圆心位置
+ 白板展台按钮启动希沃视频展台
+ 开启后,点击白板工具栏「展台」将打开希沃视频展台(需已安装);关闭则使用内置展台。
使用WPF默认贝塞尔曲线平滑
使用高级曲线平滑(推荐)
启用墨迹渐隐功能
diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs
index e0b93049..4f3baec5 100644
--- a/Ink Canvas/Resources/Settings.cs
+++ b/Ink Canvas/Resources/Settings.cs
@@ -151,6 +151,10 @@ namespace Ink_Canvas
[JsonProperty("enableVelocityBrushTip")]
public bool EnableVelocityBrushTip { get; set; }
+ /// 为 true 时,白板工具栏「展台」按钮启动希沃视频展台(sweclauncher),否则使用内置展台。
+ [JsonProperty("launchSeewoVideoShowcaseForWhiteboardBooth")]
+ public bool LaunchSeewoVideoShowcaseForWhiteboardBooth { get; set; } = false;
+
}
public enum OptionalOperation
diff --git a/Ink Canvas/Windows/SettingsViews/SettingsViews/CanvasAndInkPanel.xaml b/Ink Canvas/Windows/SettingsViews/SettingsViews/CanvasAndInkPanel.xaml
index b0353e3e..c6c9891b 100644
--- a/Ink Canvas/Windows/SettingsViews/SettingsViews/CanvasAndInkPanel.xaml
+++ b/Ink Canvas/Windows/SettingsViews/SettingsViews/CanvasAndInkPanel.xaml
@@ -63,7 +63,7 @@
-
+
@@ -155,6 +155,20 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Ink Canvas/Windows/SettingsViews/SettingsViews/CanvasAndInkPanel.xaml.cs b/Ink Canvas/Windows/SettingsViews/SettingsViews/CanvasAndInkPanel.xaml.cs
index d7812d80..e3b5bfaf 100644
--- a/Ink Canvas/Windows/SettingsViews/SettingsViews/CanvasAndInkPanel.xaml.cs
+++ b/Ink Canvas/Windows/SettingsViews/SettingsViews/CanvasAndInkPanel.xaml.cs
@@ -101,6 +101,9 @@ namespace Ink_Canvas.Windows.SettingsViews
// 插入图片时自动压缩
SetToggleSwitchState(FindToggleSwitch("ToggleSwitchCompressPicturesUploaded"), canvas.IsCompressPicturesUploaded);
+ // 白板展台按钮启动希沃视频展台
+ SetToggleSwitchState(FindToggleSwitch("ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth"), canvas.LaunchSeewoVideoShowcaseForWhiteboardBooth);
+
// 保留双曲线渐近线
SetOptionButtonState("HyperbolaAsymptote", (int)canvas.HyperbolaAsymptoteOption);
@@ -247,6 +250,8 @@ namespace Ink_Canvas.Windows.SettingsViews
return canvas.EnablePressureTouchMode;
case "DisablePressure":
return canvas.DisablePressure;
+ case "LaunchSeewoVideoShowcaseForWhiteboardBooth":
+ return canvas.LaunchSeewoVideoShowcaseForWhiteboardBooth;
case "HideStrokeWhenSelecting":
return canvas.HideStrokeWhenSelecting;
case "ClearCanvasAndClearTimeMachine":
@@ -342,6 +347,11 @@ namespace Ink_Canvas.Windows.SettingsViews
}
break;
+ case "LaunchSeewoVideoShowcaseForWhiteboardBooth":
+ MainWindowSettingsHelper.InvokeToggleSwitchToggled(
+ "ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth", newState);
+ break;
+
case "HideStrokeWhenSelecting":
// 调用 MainWindow 中的方法
MainWindowSettingsHelper.InvokeToggleSwitchToggled("ToggleSwitchHideStrokeWhenSelecting", newState);
diff --git a/Ink Canvas/Windows/SettingsViews/SettingsViews/MainWindowSettingsHelper.cs b/Ink Canvas/Windows/SettingsViews/SettingsViews/MainWindowSettingsHelper.cs
index 34eddb0c..8f78b5a1 100644
--- a/Ink Canvas/Windows/SettingsViews/SettingsViews/MainWindowSettingsHelper.cs
+++ b/Ink Canvas/Windows/SettingsViews/SettingsViews/MainWindowSettingsHelper.cs
@@ -419,6 +419,7 @@ namespace Ink_Canvas.Windows.SettingsViews
{ "ToggleSwitchShowCursor", "CanvasAndInkPanel" },
{ "ToggleSwitchDisablePressure", "CanvasAndInkPanel" },
{ "ToggleSwitchEnablePressureTouchMode", "CanvasAndInkPanel" },
+ { "ToggleSwitchLaunchSeewoVideoShowcaseForWhiteboardBooth", "CanvasAndInkPanel" },
{ "ComboBoxEraserSize", "CanvasAndInkPanel" },
{ "ComboBoxHyperbolaAsymptoteOption", "CanvasAndInkPanel" },
{ "ComboBoxAutoSaveStrokesInterval", "CanvasAndInkPanel" },