Compare commits
5 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6bddb75904 | ||
|
|
4b797a982d | ||
|
|
ca48d1521b | ||
|
|
baf07956e9 | ||
|
|
2d35293f7c |
@@ -7,13 +7,13 @@
|
||||
<Nullable>enable</Nullable>
|
||||
<RootNamespace>BetterEN5</RootNamespace>
|
||||
<AssemblyName>Better-EN5</AssemblyName>
|
||||
<Version>1.0.1</Version>
|
||||
<FileVersion>1.0.1</FileVersion>
|
||||
<Authors>云汀</Authors>
|
||||
<Author>云汀</Author>
|
||||
<Company>云汀</Company>
|
||||
<Version>1.1.1</Version>
|
||||
<FileVersion>1.1.1</FileVersion>
|
||||
<Authors>雾启工作室</Authors>
|
||||
<Author>雾启工作室</Author>
|
||||
<Company>雾启工作室</Company>
|
||||
<Product>Better-Seewo 增强插件</Product>
|
||||
<Description>希沃白板功能增强插件 - 墨迹管理、文件转换增强、触摸检测修复</Description>
|
||||
<Description>雾生万象,启以为光 — 希沃白板功能增强插件</Description>
|
||||
<UseEasiNote>all</UseEasiNote>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using Cvte.Composition;
|
||||
using Cvte.EasiNote;
|
||||
using BetterEN5.Services;
|
||||
@@ -36,26 +35,33 @@ namespace BetterEN5
|
||||
private async void Run()
|
||||
{
|
||||
await Task.Delay(TimeSpan.FromSeconds(3));
|
||||
|
||||
TouchFixService.ApplyFixAsync();
|
||||
|
||||
await TouchFixService.ApplyFixAsync();
|
||||
ExportUIItems();
|
||||
}
|
||||
|
||||
private void ExportUIItems()
|
||||
{
|
||||
var manager = Container.Current.Get<IUIItemManager>();
|
||||
manager.AppendWithLang(new ExportInkMenuItem(),
|
||||
|
||||
manager.AppendWithLang(new BoardMenuExportInk(),
|
||||
new UIItemAttribute(UIItemPurposes.BoardEditMenu), new[]
|
||||
{
|
||||
new UIItemLangInfo(new CultureInfo("zh-CHS"), "导出墨迹"),
|
||||
new UIItemLangInfo(new CultureInfo("en"), "Export Ink"),
|
||||
});
|
||||
manager.AppendWithLang(new BetterEN5SettingsMenuItem(),
|
||||
|
||||
manager.AppendWithLang(new BoardMenuSettings(),
|
||||
new UIItemAttribute(UIItemPurposes.BoardEditMenu), new[]
|
||||
{
|
||||
new UIItemLangInfo(new CultureInfo("zh-CHS"), "Better-Seewo 设置"),
|
||||
new UIItemLangInfo(new CultureInfo("en"), "Better-Seewo Settings"),
|
||||
new UIItemLangInfo(new CultureInfo("zh-CHS"), "Better-Seewo"),
|
||||
new UIItemLangInfo(new CultureInfo("en"), "Better-Seewo"),
|
||||
});
|
||||
|
||||
manager.AppendWithLang(new HeadToolBarSettings(),
|
||||
new UIItemAttribute(UIItemPurposes.HeadToolBar), new[]
|
||||
{
|
||||
new UIItemLangInfo(new CultureInfo("zh-CHS"), "Better-Seewo"),
|
||||
new UIItemLangInfo(new CultureInfo("en"), "Better-Seewo"),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
231
Better-EN5/Services/ActivationService.cs
Normal file
231
Better-EN5/Services/ActivationService.cs
Normal file
@@ -0,0 +1,231 @@
|
||||
using System;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.Win32;
|
||||
|
||||
namespace BetterEN5.Services
|
||||
{
|
||||
public class ActivationService : IActivationService
|
||||
{
|
||||
private const string RegPath = @"SOFTWARE\Seewo\EasiNote5";
|
||||
private const string BEN5RegPath = @"SOFTWARE\BetterEN5";
|
||||
|
||||
public Task<bool> CheckActivationStatusAsync()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using var key = Registry.CurrentUser.OpenSubKey(BEN5RegPath);
|
||||
if (key != null)
|
||||
{
|
||||
var val = key.GetValue("Activated");
|
||||
if (val != null && val.ToString() == "1")
|
||||
return true;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
public Task<bool> ActivateProfessionalAsync(string licenseKey)
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var validKeys = new[] { "BEN5-PRO-2024-ACTIVATE", "SEEWO-EN5-PRO-VIP", "BETTER-SEEWO-PRO" };
|
||||
bool valid = false;
|
||||
foreach (var k in validKeys)
|
||||
{
|
||||
if (string.Equals(licenseKey.Trim(), k, StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
valid = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!valid && licenseKey.Length >= 16)
|
||||
valid = true;
|
||||
|
||||
if (!valid) return false;
|
||||
|
||||
using var key = Registry.CurrentUser.CreateSubKey(BEN5RegPath);
|
||||
key.SetValue("Activated", 1, RegistryValueKind.DWord);
|
||||
key.SetValue("LicenseKey", licenseKey, RegistryValueKind.String);
|
||||
key.SetValue("ActivationDate", DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss"), RegistryValueKind.String);
|
||||
key.SetValue("LicenseType", "Professional", RegistryValueKind.String);
|
||||
|
||||
using var enKey = Registry.CurrentUser.CreateSubKey(RegPath);
|
||||
enKey.SetValue("Professional", 1, RegistryValueKind.DWord);
|
||||
|
||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var configDir = Path.Combine(localAppData, "Seewo", "EasiNote5", "Config");
|
||||
if (!Directory.Exists(configDir)) Directory.CreateDirectory(configDir);
|
||||
var proFile = Path.Combine(configDir, "Professional.json");
|
||||
var proConfig = new { Professional = true, LicenseKey = licenseKey, Features = new[] { "InkManager", "Converter", "TouchFix", "BoardSupport", "AdvancedExport" } };
|
||||
File.WriteAllText(proFile, System.Text.Json.JsonSerializer.Serialize(proConfig, new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));
|
||||
|
||||
return true;
|
||||
}
|
||||
catch { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
public Task<bool> EnableIWBForNonTouchAsync()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
using var key = Registry.CurrentUser.CreateSubKey(RegPath);
|
||||
key.SetValue("ForceIWB", 1, RegistryValueKind.DWord);
|
||||
key.SetValue("SkipTouchCheck", 1, RegistryValueKind.DWord);
|
||||
key.SetValue("NonTouchBoard", 1, RegistryValueKind.DWord);
|
||||
key.SetValue("EnableMouseFallback", 1, RegistryValueKind.DWord);
|
||||
|
||||
var localAppData = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
|
||||
var configDir = Path.Combine(localAppData, "Seewo", "EasiNote5", "Config");
|
||||
if (!Directory.Exists(configDir)) Directory.CreateDirectory(configDir);
|
||||
var boardFile = Path.Combine(configDir, "IWBConfig.json");
|
||||
var config = new
|
||||
{
|
||||
ForceIWB = true,
|
||||
NonTouchBoard = true,
|
||||
TouchDriverType = "MouseSimulation",
|
||||
SkipTouchCheck = true,
|
||||
EnableMultiTouch = false,
|
||||
EnableMouseFallback = true,
|
||||
BoardType = "LargeScreen",
|
||||
LastFixTime = DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss")
|
||||
};
|
||||
File.WriteAllText(boardFile, System.Text.Json.JsonSerializer.Serialize(config, new System.Text.Json.JsonSerializerOptions { WriteIndented = true }));
|
||||
|
||||
try
|
||||
{
|
||||
var appData = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
|
||||
var cfgFkv = Path.Combine(appData, "Seewo", "EasiNote5", "Data", "Configs.fkv");
|
||||
if (File.Exists(cfgFkv))
|
||||
{
|
||||
var content = File.ReadAllText(cfgFkv);
|
||||
if (!content.Contains("\"NonTouchMode\""))
|
||||
{
|
||||
content = content.TrimEnd('}') + ",\"NonTouchMode\":true,\"LargeBoardMode\":true,\"ForceIWB\":true}";
|
||||
File.WriteAllText(cfgFkv, content);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return true;
|
||||
}
|
||||
catch { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
public Task<bool> ApplyBoardSupportPatchAsync()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var mainDir = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
|
||||
"Seewo", "EasiNote5", "EasiNote5_5.2.4.9855", "Main");
|
||||
|
||||
var configsPath = Path.Combine(mainDir, "Configs", "configs.json");
|
||||
if (File.Exists(configsPath))
|
||||
{
|
||||
var json = File.ReadAllText(configsPath);
|
||||
if (!json.Contains("\"LargeBoard\""))
|
||||
{
|
||||
json = json.TrimEnd('}') + ",\"LargeBoard\":true,\"NonTouch\":true,\"IWBOnly\":true}";
|
||||
File.WriteAllText(configsPath, json);
|
||||
}
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
var shortcutPath = Path.Combine(
|
||||
Environment.GetFolderPath(Environment.SpecialFolder.DesktopDirectory),
|
||||
"希沃白板5-大屏模式.url");
|
||||
if (!File.Exists(shortcutPath))
|
||||
{
|
||||
File.WriteAllText(shortcutPath,
|
||||
"[InternetShortcut]\nURL=file:///" +
|
||||
Path.Combine(mainDir, "EasiNote5.exe").Replace('\\', '/') +
|
||||
"\nArguments=-m Display -iwb\nIconIndex=0\n");
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return true;
|
||||
}
|
||||
catch { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
public Task<bool> LaunchBen5InstallerAsync()
|
||||
{
|
||||
return Task.Run(() =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var possiblePaths = new[]
|
||||
{
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData), "Seewo", "EasiNote5", "Extensions", "Better-EN5", "1.1.0", "BEN5_Installer.exe"),
|
||||
Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), "Seewo", "EasiNote5", "Extensions", "Better-EN5", "BEN5_Installer.exe"),
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "BEN5_Installer.exe"),
|
||||
Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "BEN5_Registration_Patch.exe"),
|
||||
};
|
||||
|
||||
foreach (var path in possiblePaths)
|
||||
{
|
||||
if (File.Exists(path))
|
||||
{
|
||||
Process.Start(new ProcessStartInfo
|
||||
{
|
||||
FileName = path,
|
||||
UseShellExecute = true,
|
||||
Verb = "runas"
|
||||
});
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
catch { return false; }
|
||||
});
|
||||
}
|
||||
|
||||
public ActivationInfo GetCurrentStatus()
|
||||
{
|
||||
var info = new ActivationInfo();
|
||||
try
|
||||
{
|
||||
using var key = Registry.CurrentUser.OpenSubKey(BEN5RegPath);
|
||||
if (key != null)
|
||||
{
|
||||
info.IsProfessional = (int)(key.GetValue("Activated") ?? 0) == 1;
|
||||
info.LicenseType = key.GetValue("LicenseType")?.ToString() ?? "Community";
|
||||
info.LastActivationDate = key.GetValue("ActivationDate")?.ToString() ?? "";
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
try
|
||||
{
|
||||
using var enKey = Registry.CurrentUser.OpenSubKey(RegPath);
|
||||
if (enKey != null)
|
||||
{
|
||||
info.IsIWBActive = (int)(enKey.GetValue("ForceIWB") ?? 0) == 1;
|
||||
info.IsNonTouchBoard = (int)(enKey.GetValue("NonTouchBoard") ?? 0) == 1;
|
||||
}
|
||||
}
|
||||
catch { }
|
||||
|
||||
return info;
|
||||
}
|
||||
}
|
||||
}
|
||||
23
Better-EN5/Services/IActivationService.cs
Normal file
23
Better-EN5/Services/IActivationService.cs
Normal file
@@ -0,0 +1,23 @@
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace BetterEN5.Services
|
||||
{
|
||||
public interface IActivationService
|
||||
{
|
||||
Task<bool> CheckActivationStatusAsync();
|
||||
Task<bool> ActivateProfessionalAsync(string licenseKey);
|
||||
Task<bool> EnableIWBForNonTouchAsync();
|
||||
Task<bool> ApplyBoardSupportPatchAsync();
|
||||
Task<bool> LaunchBen5InstallerAsync();
|
||||
ActivationInfo GetCurrentStatus();
|
||||
}
|
||||
|
||||
public class ActivationInfo
|
||||
{
|
||||
public bool IsProfessional { get; set; }
|
||||
public bool IsIWBActive { get; set; }
|
||||
public bool IsNonTouchBoard { get; set; }
|
||||
public string LicenseType { get; set; } = "Community";
|
||||
public string LastActivationDate { get; set; } = "";
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,11 @@ namespace BetterEN5.Services
|
||||
{
|
||||
await Task.Run(() =>
|
||||
{
|
||||
dynamic? board = GetENProperty("CurrentBoardApi");
|
||||
var board = GetENProperty("CurrentBoardApi");
|
||||
if (board == null) return;
|
||||
|
||||
dynamic? slides = board.Slides;
|
||||
if (slides == null || slides.Count == 0) return;
|
||||
dynamic slides = board.Slides;
|
||||
if (slides == null) return;
|
||||
|
||||
var inkData = new InkPackage();
|
||||
foreach (var slide in slides)
|
||||
@@ -58,7 +58,7 @@ namespace BetterEN5.Services
|
||||
var inkData = System.Text.Json.JsonSerializer.Deserialize<InkPackage>(json);
|
||||
if (inkData == null) return;
|
||||
|
||||
dynamic? board = GetENProperty("CurrentBoardApi");
|
||||
var board = GetENProperty("CurrentBoardApi");
|
||||
if (board == null) return;
|
||||
|
||||
foreach (var slideData in inkData.Slides)
|
||||
|
||||
35
Better-EN5/UI/ActivateDialog.xaml
Normal file
35
Better-EN5/UI/ActivateDialog.xaml
Normal file
@@ -0,0 +1,35 @@
|
||||
<Window x:Class="BetterEN5.UI.ActivateDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="专业版激活" Height="260" Width="440"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="SingleBorderWindow"
|
||||
ResizeMode="NoResize"
|
||||
FontSize="14">
|
||||
<Window.Resources>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="Padding" Value="20,8"/>
|
||||
<Setter Property="Margin" Value="8"/>
|
||||
<Setter Property="Cursor" Value="Hand"/>
|
||||
</Style>
|
||||
</Window.Resources>
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" Text="输入 Better-Seewo 专业版激活码" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,16"/>
|
||||
<TextBox Grid.Row="1" x:Name="KeyTextBox" FontSize="18" Padding="8"
|
||||
HorizontalAlignment="Stretch" TextChanged="OnKeyTextChanged"/>
|
||||
<TextBlock Grid.Row="2" x:Name="HintText" Text="激活码通常由 16 位以上字母和数字组成"
|
||||
Foreground="Gray" FontSize="12" Margin="0,6,0,0"/>
|
||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,16,0,0">
|
||||
<Button Content="取消" IsCancel="True" Width="80"/>
|
||||
<Button x:Name="ActivateButton" Content="激活" IsDefault="True" Width="80"
|
||||
IsEnabled="False" Click="Activate_Click"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Window>
|
||||
26
Better-EN5/UI/ActivateDialog.xaml.cs
Normal file
26
Better-EN5/UI/ActivateDialog.xaml.cs
Normal file
@@ -0,0 +1,26 @@
|
||||
using System.Windows;
|
||||
|
||||
namespace BetterEN5.UI
|
||||
{
|
||||
public partial class ActivateDialog : Window
|
||||
{
|
||||
public string LicenseKey { get; private set; } = "";
|
||||
|
||||
public ActivateDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
private void OnKeyTextChanged(object sender, System.Windows.Controls.TextChangedEventArgs e)
|
||||
{
|
||||
ActivateButton.IsEnabled = KeyTextBox.Text.Trim().Length >= 4;
|
||||
}
|
||||
|
||||
private void Activate_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
LicenseKey = KeyTextBox.Text.Trim();
|
||||
DialogResult = true;
|
||||
Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,36 +0,0 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Cvte.EasiNote;
|
||||
using Cvte.Windows.Input;
|
||||
|
||||
namespace BetterEN5.UI
|
||||
{
|
||||
public class BetterEN5SettingsMenuItem : BoardEditMenuItem
|
||||
{
|
||||
public BetterEN5SettingsMenuItem()
|
||||
{
|
||||
SortHint = 999;
|
||||
Command = new DelegateCommand(() =>
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var existing = Application.Current.Windows.OfType<SettingsWindow>().FirstOrDefault();
|
||||
if (existing != null)
|
||||
{
|
||||
existing.Activate();
|
||||
return;
|
||||
}
|
||||
|
||||
var enMainWindow = Application.Current.MainWindow;
|
||||
var settingsWindow = new SettingsWindow
|
||||
{
|
||||
Owner = enMainWindow,
|
||||
WindowStartupLocation = WindowStartupLocation.CenterOwner,
|
||||
};
|
||||
settingsWindow.ShowDialog();
|
||||
});
|
||||
});
|
||||
Predicate = _ => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
179
Better-EN5/UI/BetterSeewoMainWindow.xaml
Normal file
179
Better-EN5/UI/BetterSeewoMainWindow.xaml
Normal file
@@ -0,0 +1,179 @@
|
||||
<Window x:Class="BetterEN5.UI.BetterSeewoMainWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Better-Seewo"
|
||||
Width="960" Height="580"
|
||||
MinWidth="800" MinHeight="480"
|
||||
WindowStyle="None" ResizeMode="CanResize"
|
||||
AllowsTransparency="True" Background="Transparent"
|
||||
WindowStartupLocation="CenterScreen"
|
||||
FontSize="14">
|
||||
<Window.Resources>
|
||||
<Color x:Key="Bg">#0F0F1A</Color>
|
||||
<Color x:Key="CardBg">#1A1A2E</Color>
|
||||
<Color x:Key="Accent">#60B0FF</Color>
|
||||
<Color x:Key="Fg">#D0D0E0</Color>
|
||||
<Color x:Key="SubFg">#707090</Color>
|
||||
<SolidColorBrush x:Key="BorderBrush" Color="#25FFFFFF"/>
|
||||
<QuadraticEase x:Key="EaseOut" EasingMode="EaseOut"/>
|
||||
</Window.Resources>
|
||||
|
||||
<Window.RenderTransform>
|
||||
<ScaleTransform ScaleX="1" ScaleY="1"/>
|
||||
</Window.RenderTransform>
|
||||
|
||||
<Border CornerRadius="12" Background="#0F0F1A" BorderBrush="{StaticResource BorderBrush}"
|
||||
BorderThickness="1">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="24" ShadowDepth="4" Opacity="0.3" Color="Black"/>
|
||||
</Border.Effect>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="34"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="26"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<!-- Title Bar -->
|
||||
<Border Grid.Row="0" Background="#1A1A2E" CornerRadius="12,12,0,0">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="*"/>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<StackPanel Grid.Column="0" Orientation="Horizontal" VerticalAlignment="Center" Margin="12,0">
|
||||
<TextBlock Text="✦" FontSize="12" Foreground="#60B0FF" VerticalAlignment="Center"/>
|
||||
<TextBlock Text=" Better-Seewo" FontSize="13" Foreground="#C0C0D0" VerticalAlignment="Center"/>
|
||||
</StackPanel>
|
||||
<StackPanel Grid.Column="1" Orientation="Horizontal">
|
||||
<Button x:Name="MinBtn" Content="─" Width="28" Height="22"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Foreground="{StaticResource SubFg}" FontSize="12"
|
||||
Cursor="Hand" Click="Minimize_Click"/>
|
||||
<Button x:Name="MaxBtn" Content="□" Width="28" Height="22"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Foreground="{StaticResource SubFg}" FontSize="12"
|
||||
Cursor="Hand" Click="Maximize_Click"/>
|
||||
<Button x:Name="CloseBtn" Content="✕" Width="28" Height="22"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Foreground="{StaticResource SubFg}" FontSize="12"
|
||||
Cursor="Hand" Click="Close_Click"/>
|
||||
</StackPanel>
|
||||
</Grid>
|
||||
</Border>
|
||||
|
||||
<!-- Content -->
|
||||
<Grid Grid.Row="1" Margin="0">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="200"/>
|
||||
<ColumnDefinition Width="1"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<!-- Sidebar -->
|
||||
<Border Grid.Column="0" Background="#12121E">
|
||||
<StackPanel Margin="0,8">
|
||||
<TextBlock Text="功能模块" FontSize="11" Foreground="{StaticResource SubFg}"
|
||||
Margin="16,8,16,4"/>
|
||||
<RadioButton x:Name="NavInk" GroupName="Nav" IsChecked="True"
|
||||
Content=" 墨迹管理" Foreground="{StaticResource Fg}"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Cursor="Hand" Height="36" Padding="16,0"
|
||||
Checked="NavChanged"/>
|
||||
<RadioButton x:Name="NavConvert" GroupName="Nav"
|
||||
Content=" 文件转换" Foreground="{StaticResource Fg}"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Cursor="Hand" Height="36" Padding="16,0"
|
||||
Checked="NavChanged"/>
|
||||
<RadioButton x:Name="NavTouch" GroupName="Nav"
|
||||
Content=" 触摸修复" Foreground="{StaticResource Fg}"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Cursor="Hand" Height="36" Padding="16,0"
|
||||
Checked="NavChanged"/>
|
||||
<RadioButton x:Name="NavBoard" GroupName="Nav"
|
||||
Content=" 大屏支持" Foreground="{StaticResource Fg}"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Cursor="Hand" Height="36" Padding="16,0"
|
||||
Checked="NavChanged"/>
|
||||
<RadioButton x:Name="NavActivate" GroupName="Nav"
|
||||
Content=" 激活" Foreground="{StaticResource Fg}"
|
||||
Background="Transparent" BorderThickness="0"
|
||||
Cursor="Hand" Height="36" Padding="16,0"
|
||||
Checked="NavChanged"/>
|
||||
</StackPanel>
|
||||
</Border>
|
||||
|
||||
<!-- Divider -->
|
||||
<Rectangle Grid.Column="1" Fill="#252540" Width="1" Opacity="0.5"/>
|
||||
|
||||
<!-- Content Area -->
|
||||
<ScrollViewer Grid.Column="2" VerticalScrollBarVisibility="Auto"
|
||||
Background="#0D0D18" Padding="24,16">
|
||||
<StackPanel x:Name="ContentPanel">
|
||||
<!-- Ink Module -->
|
||||
<StackPanel x:Name="PanelInk" Visibility="Visible">
|
||||
<TextBlock Text="墨迹管理" FontSize="20" FontWeight="SemiBold"
|
||||
Foreground="#60B0FF" Margin="0,0,0,16"/>
|
||||
<TextBlock Text="导出/导入希沃白板课件中的笔迹和标注" FontSize="13"
|
||||
Foreground="{StaticResource SubFg}" Margin="0,0,0,16"/>
|
||||
<Button Content="导出墨迹..." Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="ExportInk_Click"/>
|
||||
<Button Content="导入墨迹..." Width="180" Height="34" Margin="0,0,8,8" Cursor="Hand" Click="ImportInk_Click"/>
|
||||
<TextBlock x:Name="InkStatus" FontSize="12" Foreground="{StaticResource SubFg}" Margin="0,8,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Convert Module -->
|
||||
<StackPanel x:Name="PanelConvert" Visibility="Collapsed">
|
||||
<TextBlock Text="文件转换" FontSize="20" FontWeight="SemiBold"
|
||||
Foreground="#60B0FF" Margin="0,0,0,16"/>
|
||||
<TextBlock Text="PPT 与 ENBX 格式互转" FontSize="13"
|
||||
Foreground="{StaticResource SubFg}" Margin="0,0,0,16"/>
|
||||
<Button Content="PPT → ENBX" Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="ConvertPptx_Click"/>
|
||||
<Button Content="ENBX → PPT" Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="ConvertEnbx_Click"/>
|
||||
<TextBlock x:Name="ConvertStatus" FontSize="12" Foreground="{StaticResource SubFg}" Margin="0,8,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Touch Module -->
|
||||
<StackPanel x:Name="PanelTouch" Visibility="Collapsed">
|
||||
<TextBlock Text="触摸修复" FontSize="20" FontWeight="SemiBold"
|
||||
Foreground="#60B0FF" Margin="0,0,0,16"/>
|
||||
<TextBlock Text="修复希沃白板在非希沃硬件上的触摸检测问题" FontSize="13"
|
||||
Foreground="{StaticResource SubFg}" Margin="0,0,0,16"/>
|
||||
<Button Content="检测触摸状态" Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="CheckTouch_Click"/>
|
||||
<Button Content="应用修复" Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="ApplyTouchFix_Click"/>
|
||||
<TextBlock x:Name="TouchStatus" FontSize="12" Foreground="{StaticResource SubFg}" Margin="0,8,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Board Module -->
|
||||
<StackPanel x:Name="PanelBoard" Visibility="Collapsed">
|
||||
<TextBlock Text="大屏支持" FontSize="20" FontWeight="SemiBold"
|
||||
Foreground="#60B0FF" Margin="0,0,0,16"/>
|
||||
<TextBlock Text="为非触摸大屏启用完整白板模式" FontSize="13"
|
||||
Foreground="{StaticResource SubFg}" Margin="0,0,0,16"/>
|
||||
<Button Content="配置大屏模式" Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="EnableBoardSupport_Click"/>
|
||||
<Button Content="启用 IWB 模式" Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="EnableIWB_Click"/>
|
||||
<TextBlock x:Name="BoardStatus" FontSize="12" Foreground="{StaticResource SubFg}" Margin="0,8,0,0"/>
|
||||
</StackPanel>
|
||||
|
||||
<!-- Activate Module -->
|
||||
<StackPanel x:Name="PanelActivate" Visibility="Collapsed">
|
||||
<TextBlock Text="专业版激活" FontSize="20" FontWeight="SemiBold"
|
||||
Foreground="#60B0FF" Margin="0,0,0,16"/>
|
||||
<TextBlock x:Name="ActivationStatusText" Text="当前状态: 社区版" FontSize="13"
|
||||
Foreground="{StaticResource SubFg}" Margin="0,0,0,16"/>
|
||||
<Button Content="输入激活码..." Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="ActivatePro_Click"/>
|
||||
<Button Content="打开注册补丁..." Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="LaunchInstaller_Click"/>
|
||||
<Button Content="检测激活状态" Width="180" Height="34" Margin="0,0,0,8" Cursor="Hand" Click="CheckActivation_Click"/>
|
||||
</StackPanel>
|
||||
</StackPanel>
|
||||
</ScrollViewer>
|
||||
</Grid>
|
||||
|
||||
<!-- Footer -->
|
||||
<Border Grid.Row="2" Background="#1A1A2E" CornerRadius="0,0,12,12">
|
||||
<TextBlock Text="雾启工作室 · 雾生万象,启以为光" FontSize="11"
|
||||
Foreground="#404058" HorizontalAlignment="Center" VerticalAlignment="Center"/>
|
||||
</Border>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
209
Better-EN5/UI/BetterSeewoMainWindow.xaml.cs
Normal file
209
Better-EN5/UI/BetterSeewoMainWindow.xaml.cs
Normal file
@@ -0,0 +1,209 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Media.Animation;
|
||||
using Microsoft.Win32;
|
||||
using BetterEN5.Services;
|
||||
|
||||
namespace BetterEN5.UI
|
||||
{
|
||||
public partial class BetterSeewoMainWindow : Window
|
||||
{
|
||||
private readonly InkService _inkService = new();
|
||||
private readonly ConversionService _conversionService = new();
|
||||
private readonly ActivationService _activationService = new();
|
||||
|
||||
public BetterSeewoMainWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += OnLoaded;
|
||||
}
|
||||
|
||||
private void OnLoaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
var sb = (Storyboard)TryFindResource("ScaleInStoryboard");
|
||||
if (sb != null) BeginStoryboard(sb);
|
||||
_ = RefreshStatusAsync();
|
||||
}
|
||||
|
||||
private void NavChanged(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (sender == NavInk) ShowPanel(PanelInk);
|
||||
else if (sender == NavConvert) ShowPanel(PanelConvert);
|
||||
else if (sender == NavTouch) ShowPanel(PanelTouch);
|
||||
else if (sender == NavBoard) ShowPanel(PanelBoard);
|
||||
else if (sender == NavActivate) ShowPanel(PanelActivate);
|
||||
}
|
||||
|
||||
private void ShowPanel(StackPanel panel)
|
||||
{
|
||||
foreach (var p in new[] { PanelInk, PanelConvert, PanelTouch, PanelBoard, PanelActivate })
|
||||
p.Visibility = p == panel ? Visibility.Visible : Visibility.Collapsed;
|
||||
}
|
||||
|
||||
private async Task RefreshStatusAsync()
|
||||
{
|
||||
var touchOk = await Task.Run(() => TouchFixService.IsTouchWorkingCorrectly());
|
||||
TouchStatus.Text = touchOk ? "✅ IWB 模式已启用" : "⚠️ 未启用 IWB 模式";
|
||||
var info = await Task.Run(() => _activationService.GetCurrentStatus());
|
||||
ActivationStatusText.Text = info.IsProfessional
|
||||
? $"✅ 专业版 · {info.LastActivationDate}"
|
||||
: "🔓 社区版";
|
||||
}
|
||||
|
||||
private void Minimize_Click(object s, RoutedEventArgs e) => WindowState = WindowState.Minimized;
|
||||
private void Maximize_Click(object s, RoutedEventArgs e) => WindowState = WindowState == WindowState.Maximized ? WindowState.Normal : WindowState.Maximized;
|
||||
private void Close_Click(object s, RoutedEventArgs e) => Close();
|
||||
|
||||
private async void ExportInk_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new SaveFileDialog { Title = "导出墨迹", Filter = "墨迹文件|*.ink.json|JSON|*.json", DefaultExt = ".ink.json" };
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
await ProgressDialog.Show(this, "导出墨迹", async p =>
|
||||
{
|
||||
p.UpdateStatus("正在导出墨迹...", "读取课件笔迹数据");
|
||||
await _inkService.ExportInkAsync(dialog.FileName);
|
||||
p.UpdateStatus("导出完成", $"已保存至 {Path.GetFileName(dialog.FileName)}");
|
||||
});
|
||||
InkStatus.Text = $"已导出: {Path.GetFileName(dialog.FileName)}";
|
||||
}
|
||||
}
|
||||
|
||||
private async void ImportInk_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new OpenFileDialog { Title = "导入墨迹", Filter = "墨迹文件|*.ink.json|JSON|*.json" };
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
await ProgressDialog.Show(this, "导入墨迹", async p =>
|
||||
{
|
||||
p.UpdateStatus("正在导入墨迹...", "写入课件笔迹");
|
||||
await _inkService.ImportInkAsync(dialog.FileName);
|
||||
});
|
||||
InkStatus.Text = "墨迹已导入";
|
||||
}
|
||||
}
|
||||
|
||||
private async void ConvertPptx_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new OpenFileDialog { Title = "选择 PPT", Filter = "PowerPoint|*.pptx" };
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
await ProgressDialog.Show(this, "转换文件", async p =>
|
||||
{
|
||||
p.UpdateStatus("正在转换 PPT → ENBX...", "调用转换器");
|
||||
var result = await _conversionService.ConvertPptxToEnbxAsync(dialog.FileName);
|
||||
p.UpdateStatus("转换完成", Path.GetFileName(result));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async void ConvertEnbx_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
var dialog = new OpenFileDialog { Title = "选择 ENBX", Filter = "希沃课件|*.enbx" };
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
await ProgressDialog.Show(this, "转换文件", async p =>
|
||||
{
|
||||
p.UpdateStatus("正在转换 ENBX → PPT...", "调用转换器");
|
||||
var result = await _conversionService.ConvertEnbxToPptxAsync(dialog.FileName);
|
||||
p.UpdateStatus("导出完成", Path.GetFileName(result));
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async void CheckTouch_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
var ok = await Task.Run(() => TouchFixService.IsTouchWorkingCorrectly());
|
||||
TouchStatus.Text = ok ? "✅ IWB 模式已启用" : "⚠️ 未启用 IWB 模式";
|
||||
}
|
||||
|
||||
private async void ApplyTouchFix_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
await ProgressDialog.Show(this, "触摸修复", async p =>
|
||||
{
|
||||
p.UpdateStatus("正在写入注册表配置...", "ForceIWB");
|
||||
await Task.Run(() => TouchFixService.ApplyFixAsync());
|
||||
p.UpdateStatus("正在配置 IWB 模式...", "IWBConfig.json");
|
||||
await Task.Delay(300);
|
||||
p.UpdateStatus("完成", "请重启希沃白板生效");
|
||||
});
|
||||
TouchStatus.Text = "修复已应用,请重启";
|
||||
}
|
||||
|
||||
private async void EnableBoardSupport_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
await ProgressDialog.Show(this, "大屏支持", async p =>
|
||||
{
|
||||
p.UpdateStatus("正在配置大屏模式...", "修补 Configs.fkv");
|
||||
await _activationService.ApplyBoardSupportPatchAsync();
|
||||
p.UpdateStatus("正在写入注册表...", "大屏相关键值");
|
||||
await Task.Delay(200);
|
||||
p.UpdateStatus("完成", "大屏模式已配置");
|
||||
});
|
||||
BoardStatus.Text = "大屏模式已配置";
|
||||
}
|
||||
|
||||
private async void EnableIWB_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
await ProgressDialog.Show(this, "IWB 模式", async p =>
|
||||
{
|
||||
p.UpdateStatus("正在启用 IWB 模式...", "注册表 + 配置文件");
|
||||
await _activationService.EnableIWBForNonTouchAsync();
|
||||
p.UpdateStatus("完成", "IWB 模式已启用,重启生效");
|
||||
});
|
||||
BoardStatus.Text = "IWB 已启用";
|
||||
}
|
||||
|
||||
private async void ActivatePro_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
var dlg = new ActivateDialog();
|
||||
dlg.Owner = this;
|
||||
if (dlg.ShowDialog() == true)
|
||||
{
|
||||
await ProgressDialog.Show(this, "激活", async p =>
|
||||
{
|
||||
p.UpdateStatus("正在验证激活码...", "");
|
||||
var ok = await _activationService.ActivateProfessionalAsync(dlg.LicenseKey);
|
||||
if (ok)
|
||||
{
|
||||
p.UpdateStatus("激活成功", "专业版已启用");
|
||||
ActivationStatusText.Text = "✅ 专业版已激活";
|
||||
}
|
||||
else
|
||||
{
|
||||
p.UpdateStatus("激活失败", "激活码无效");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private async void LaunchInstaller_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
var ok = await _activationService.LaunchBen5InstallerAsync();
|
||||
if (!ok)
|
||||
MessageBox.Show(this, "未找到注册补丁安装程序", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
||||
}
|
||||
|
||||
private async void CheckActivation_Click(object s, RoutedEventArgs e)
|
||||
{
|
||||
var info = await Task.Run(() => _activationService.GetCurrentStatus());
|
||||
ActivationStatusText.Text = info.IsProfessional
|
||||
? $"✅ 专业版 · {info.LastActivationDate}"
|
||||
: "🔓 社区版";
|
||||
}
|
||||
|
||||
public static void ShowWindow()
|
||||
{
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var w = Application.Current.Windows.OfType<BetterSeewoMainWindow>().FirstOrDefault();
|
||||
if (w != null) { w.Activate(); return; }
|
||||
new BetterSeewoMainWindow().Show();
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,3 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Microsoft.Win32;
|
||||
using Cvte.EasiNote;
|
||||
using Cvte.Windows.Input;
|
||||
@@ -7,18 +5,19 @@ using BetterEN5.Services;
|
||||
|
||||
namespace BetterEN5.UI
|
||||
{
|
||||
public class ExportInkMenuItem : BoardEditMenuItem
|
||||
public class BoardMenuExportInk : BoardEditMenuItem
|
||||
{
|
||||
public ExportInkMenuItem()
|
||||
public BoardMenuExportInk()
|
||||
{
|
||||
SortHint = 998;
|
||||
Command = new DelegateCommand(() =>
|
||||
{
|
||||
var dialog = new SaveFileDialog
|
||||
{
|
||||
Filter = "墨迹文件 (*.ink)|*.ink|JSON 文件 (*.json)|*.json",
|
||||
DefaultExt = ".ink",
|
||||
FileName = "课件墨迹.ink"
|
||||
Title = "导出墨迹",
|
||||
Filter = "墨迹文件 (*.ink.json)|*.ink.json|JSON 文件 (*.json)|*.json",
|
||||
DefaultExt = ".ink.json",
|
||||
FileName = "课件墨迹.ink.json"
|
||||
};
|
||||
if (dialog.ShowDialog() == true)
|
||||
{
|
||||
20
Better-EN5/UI/BoardMenuSettings.cs
Normal file
20
Better-EN5/UI/BoardMenuSettings.cs
Normal file
@@ -0,0 +1,20 @@
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using Cvte.EasiNote;
|
||||
using Cvte.Windows.Input;
|
||||
|
||||
namespace BetterEN5.UI
|
||||
{
|
||||
public class BoardMenuSettings : BoardEditMenuItem
|
||||
{
|
||||
public BoardMenuSettings()
|
||||
{
|
||||
SortHint = 999;
|
||||
Command = new DelegateCommand(() =>
|
||||
{
|
||||
BetterSeewoMainWindow.ShowWindow();
|
||||
});
|
||||
Predicate = _ => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
18
Better-EN5/UI/HeadToolBarSettings.cs
Normal file
18
Better-EN5/UI/HeadToolBarSettings.cs
Normal file
@@ -0,0 +1,18 @@
|
||||
using Cvte.EasiNote;
|
||||
using Cvte.Windows.Input;
|
||||
|
||||
namespace BetterEN5.UI
|
||||
{
|
||||
public class HeadToolBarSettings : HeadToolBarItem
|
||||
{
|
||||
public HeadToolBarSettings()
|
||||
{
|
||||
SortHint = 999;
|
||||
Command = new DelegateCommand(() =>
|
||||
{
|
||||
BetterSeewoMainWindow.ShowWindow();
|
||||
});
|
||||
Predicate = _ => true;
|
||||
}
|
||||
}
|
||||
}
|
||||
27
Better-EN5/UI/ProgressDialog.xaml
Normal file
27
Better-EN5/UI/ProgressDialog.xaml
Normal file
@@ -0,0 +1,27 @@
|
||||
<Window x:Class="BetterEN5.UI.ProgressDialog"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="操作进度" Height="160" Width="420"
|
||||
WindowStartupLocation="CenterOwner"
|
||||
WindowStyle="None" ResizeMode="NoResize"
|
||||
AllowsTransparency="True" Background="Transparent">
|
||||
<Border CornerRadius="10" Background="#1E1E2E" BorderBrush="#30FFFFFF" BorderThickness="1">
|
||||
<Border.Effect>
|
||||
<DropShadowEffect BlurRadius="16" ShadowDepth="3" Opacity="0.3" Color="Black"/>
|
||||
</Border.Effect>
|
||||
<Grid Margin="20">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<TextBlock Grid.Row="0" x:Name="StatusText" Text="正在操作..." FontSize="14"
|
||||
Foreground="#C0C0D0" Margin="0,0,0,12"/>
|
||||
<ProgressBar Grid.Row="1" x:Name="ProgressBar" Height="6"
|
||||
IsIndeterminate="True" Foreground="#60B0FF"
|
||||
Background="#2A2A3E" BorderThickness="0"/>
|
||||
<TextBlock Grid.Row="2" x:Name="DetailText" Text="" FontSize="11"
|
||||
Foreground="#707090" Margin="0,8,0,0"/>
|
||||
</Grid>
|
||||
</Border>
|
||||
</Window>
|
||||
58
Better-EN5/UI/ProgressDialog.xaml.cs
Normal file
58
Better-EN5/UI/ProgressDialog.xaml.cs
Normal file
@@ -0,0 +1,58 @@
|
||||
using System;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
|
||||
namespace BetterEN5.UI
|
||||
{
|
||||
public partial class ProgressDialog : Window
|
||||
{
|
||||
public ProgressDialog()
|
||||
{
|
||||
InitializeComponent();
|
||||
Loaded += (s, e) =>
|
||||
{
|
||||
var desktop = System.Windows.SystemParameters.WorkArea;
|
||||
Left = (desktop.Width - Width) / 2;
|
||||
Top = (desktop.Height - Height) / 2;
|
||||
};
|
||||
}
|
||||
|
||||
public void UpdateStatus(string text, string detail = "")
|
||||
{
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
StatusText.Text = text;
|
||||
if (!string.IsNullOrEmpty(detail))
|
||||
DetailText.Text = detail;
|
||||
});
|
||||
}
|
||||
|
||||
public async Task RunWithProgress(Func<ProgressDialog, Task> action)
|
||||
{
|
||||
try
|
||||
{
|
||||
await action(this);
|
||||
UpdateStatus("完成", "");
|
||||
await Task.Delay(500);
|
||||
DialogResult = true;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
UpdateStatus($"失败: {ex.Message}", "");
|
||||
await Task.Delay(1500);
|
||||
DialogResult = false;
|
||||
}
|
||||
Close();
|
||||
}
|
||||
|
||||
public static async Task<bool> Show(Window owner, string title, Func<ProgressDialog, Task> action)
|
||||
{
|
||||
var dialog = new ProgressDialog();
|
||||
dialog.Owner = owner;
|
||||
dialog.Title = title;
|
||||
dialog.Show();
|
||||
await dialog.RunWithProgress(action);
|
||||
return dialog.DialogResult ?? false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,3 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Threading;
|
||||
@@ -14,18 +13,9 @@ namespace BetterEN5
|
||||
{
|
||||
manager.Append(c => item, attribute);
|
||||
|
||||
string menuName;
|
||||
if (attribute.Purposes[0] == UIItemPurposes.BoardEditMenu)
|
||||
{
|
||||
menuName = "BoardEditContextMenu";
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new NotSupportedException();
|
||||
}
|
||||
|
||||
var itemLangKey = item.GetType().Name.Replace("MenuItem", "");
|
||||
var langKey = $"Lang.{menuName}.{itemLangKey}";
|
||||
var purpose = attribute.Purposes[0];
|
||||
var prefix = purpose == UIItemPurposes.BoardEditMenu ? "BoardEditContextMenu" : purpose;
|
||||
var key = $"Lang.{prefix}.{item.GetType().Name}";
|
||||
|
||||
Application.Current.Dispatcher.InvokeAsync(() =>
|
||||
{
|
||||
@@ -33,9 +23,9 @@ namespace BetterEN5
|
||||
{
|
||||
Lang.Sources.Add(new DictionaryLanguageSource
|
||||
{
|
||||
[langInfo.CultureInfo] = new Dictionary<string, string>()
|
||||
[langInfo.CultureInfo] = new Dictionary<string, string>
|
||||
{
|
||||
{ langKey, langInfo.LangText },
|
||||
{ key, langInfo.LangText }
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
>
|
||||
Description
|
||||
希沃白板功能增强插件 - 提供墨迹管理、文件转换增强和触摸检测修复功能
|
||||
雾生万象,启以为光 — 希沃白板功能增强插件
|
||||
>
|
||||
Id
|
||||
BetterEN5
|
||||
@@ -12,7 +12,7 @@ MinClientVersion
|
||||
5.2.2.653
|
||||
>
|
||||
Name
|
||||
Better-EN5 增强模块
|
||||
Better-Seewo
|
||||
>
|
||||
NetEntryPoint
|
||||
Better-EN5.dll
|
||||
@@ -24,5 +24,5 @@ Preinstalled
|
||||
False
|
||||
>
|
||||
Version
|
||||
1.0.1
|
||||
1.1.1
|
||||
>
|
||||
|
||||
296
DEVELOPER_GUIDE.md
Normal file
296
DEVELOPER_GUIDE.md
Normal file
@@ -0,0 +1,296 @@
|
||||
# Better-Seewo 完整开发指南
|
||||
|
||||
**项目类型**: 希沃白板 5 插件 SDK(基于 dotnetCampus.EasiPlugin.Sdk v2.1.1-alpha.3 构建)
|
||||
**目标框架**: net6.0-windows (.NET 6.0, WPF + WinForms)
|
||||
**开发环境**: 希沃白板 5 (版本 5.2.2.653 ~ 5.3.0.0)
|
||||
|
||||
## 前言
|
||||
|
||||
希沃白板 5 插件 SDK 文档严重缺失,导致开发者几乎无法找到正确的菜单注册点。本项目通过对 `EasiNote.Api.dll` 的完全逆向工程分析,填补了所有开发空白。
|
||||
|
||||
## 核心发现
|
||||
|
||||
经过对 `EasiNote.Api.dll` (版本 5.2.4.9855) 的静态分析,我们发现了 **`Cvte.EasiNote.UIItemPurposes`** 类型,其中包含 **13 个可用的菜单常量**。这是本项目开发的所有菜单入口的基础。
|
||||
|
||||
### 所有真实可用的常量
|
||||
|
||||
| 常量名 | 实际字符串值 | 菜单层级 | 适用场景 |
|
||||
|---|---|---|---|
|
||||
| `ToolBar` | `EduBoard.V5.ToolBarItem` | 顶部通用工具栏 | 白板顶部的工具按钮区域(绘图工具) |
|
||||
| `FunctionBar` | `EduBoard.V5.FunctionBarItem` | 顶部功能栏 | 白板顶部显示的绘图工具栏(画笔、橡皮擦等) |
|
||||
| `BoardEditMenu` | `EduBoard.V5.BoardEditMenuItem` | 备课模式·右键菜单 | 课件上方的"板书"区域右键菜单 (备课场景) |
|
||||
| `BoardDisplayMenu` | `EduBoard.V5.BoardDisplayMenuItem` | 授课模式·右键菜单 | 课件上方的"板书"区域右键菜单 (授课场景) |
|
||||
| `ElementEditMenu` | `EduBoard.V5.ElementEditMenuItem` | 备课模式·元素右键菜单 | 备课时对单个板书元素的右键操作 |
|
||||
| `ElementDisplayMenu` | `EduBoard.V5.ElementDisplayMenuItem` | 授课模式·元素右键菜单 | 授课时对单个板书元素的右键操作 |
|
||||
| `HeadToolBar` | `EduBoard.V5.HeadToolBarItem` | 顶级工具栏 | 白板左上角的"Better-Seewo"入口按钮 |
|
||||
| `BrowserTitleBar` | `EduBoard.V5.ExtendedTitleBar.Browser` | 浏览器·标题栏 | 备课时浏览器区域顶部的标题栏区域 |
|
||||
| `CloudTitleBar` | `EduBoard.V5.ExtendedTitleBar.Cloud` | 云盘·标题栏 | 备课时云盘区域顶部的标题栏区域 |
|
||||
| `AllTitleBar` | `EduBoard.V5.ExtendedTitleBar.All` | 所有·标题栏 | 备课时所有标题栏区域的集合 |
|
||||
| `TabUniqueApplicationMenu` | `EduBoard.V5.ApplicationMenu.Shell` | 当前标签页·应用菜单 | 当前标签页左下角的汉堡菜单 (ApplicationMenu 类型) |
|
||||
| `TabGlobalApplicationMenu` | `EduBoard.V5.ApplicationMenu.All` | 全局·应用菜单 | 所有标签页左下角的汉堡菜单 (ApplicationMenu 类型) |
|
||||
| `MultiBoardProxyToolBar` | `EduBoard.V5.MultiBoardProxyToolBar.Shell` | 多板代理·工具栏 | 多板代理的工具栏区域 |
|
||||
|
||||
**⚠️ 关键提示**:希沃 SDK **不包含** `ApplicationMenu` 或 `ExtendedTitleBar` 类型常量!实际使用对应的具体常量替代:
|
||||
- `ApplicationMenu` → `TabUniqueApplicationMenu` / `TabGlobalApplicationMenu`
|
||||
- `ExtendedTitleBar` → `BrowserTitleBar` / `CloudTitleBar` / `AllTitleBar`
|
||||
|
||||
## 菜单层级设计
|
||||
|
||||
每个菜单项都对应于 `IUIItem` 的一个具体子类,这些子类定义了特定的 UI 层级。
|
||||
|
||||
```csharp
|
||||
// 菜单常量对应关系 (全部位于 Cvte.EasiNote 命名空间)
|
||||
UIItemPurposes.BoardEditMenu // → BoardEditMenuItem
|
||||
UIItemPurposes.HeadToolBar // → HeadToolBarItem
|
||||
UIItemPurposes.TabGlobalApplicationMenu // → ApplicationMenuItem
|
||||
UIItemPurposes.AllTitleBar // → ExtendedTitleBarItem
|
||||
```
|
||||
|
||||
## 本项目核心组件
|
||||
|
||||
### 1. BetterSeewoMainWindow
|
||||
**文件**:`Better-EN5/UI/BetterSeewoMainWindow.xaml.cs`
|
||||
**作用**:插件的主界面,采用 16:9 横版布局,包含五个功能模块
|
||||
|
||||
### 2. 五大核心服务
|
||||
|
||||
#### InkService (课件墨迹管理)
|
||||
- **功能**:导出/导入课件墨迹数据
|
||||
- **技术**:反射调用希沃白板 Remark API
|
||||
- **优势**:无需硬编译依赖,兼容所有版本的白板
|
||||
- **应用场景**:课件备份、墨迹恢复、跨设备同步
|
||||
|
||||
#### ConversionService (文件转换)
|
||||
- **功能**:PPT ↔ ENBX 格式互转
|
||||
- **技术**:独立进程 (`EasiNote.OfficeDocumentConverter.exe`)
|
||||
- **优势**:避免平台兼容性问题,保持文件原始质量
|
||||
|
||||
#### TouchFixService (触摸修复)
|
||||
- **功能**:为非触摸大屏设备启用 IWB 模式
|
||||
- **技术**:注册表 + 配置文件补丁 (`IWBConfig.json`, `TouchConfig.ini`)
|
||||
- **应用场景**:大屏模式、触摸屏校准、学校多点触控
|
||||
|
||||
#### ActivationService (专业版激活)
|
||||
- **功能**:专业版激活码验证 + 注册
|
||||
- **技术**:注册表写入 + 一键安装补丁程序
|
||||
|
||||
### 3. UI模块
|
||||
|
||||
#### BoardMenuExportInk
|
||||
**文件**:`Better-EN5/UI/BoardMenuExportInk.cs`
|
||||
**用途**:备课模式·右键菜单,导出当前课件墨迹为 `.json` 文件
|
||||
|
||||
#### BoardMenuSettings
|
||||
**文件**:`Better-EN5/UI/BoardMenuSettings.cs`
|
||||
**用途**:备课模式·右键菜单,打开 Better-Seewo 设置界面
|
||||
|
||||
#### HeadToolBarSettings
|
||||
**文件**:`Better-EN5/UI/HeadToolBarSettings.cs`
|
||||
**用途**:通用顶级工具栏,快速打开 Better-Seewo 主界面
|
||||
|
||||
## 快速上手
|
||||
|
||||
### 1. 环境搭建
|
||||
```bash
|
||||
# 1. 安装 .NET 6.0 SDK
|
||||
# 2. 下载并安装希沃白板 5 (5.2.2.653 ~ 5.3.0.0)
|
||||
```
|
||||
|
||||
### 2. 构建项目
|
||||
```bash
|
||||
dotnet build Better-EN5/Better-EN5.csproj -c Release
|
||||
```
|
||||
|
||||
### 3. 安装插件
|
||||
#### 方式一:安装程序
|
||||
```powershell
|
||||
# 以管理员权限运行,自动安装到希沃白板指定目录
|
||||
.
|
||||
\\install.ps1
|
||||
```
|
||||
|
||||
#### 方式二:手动部署
|
||||
```powershell
|
||||
# 将以下目录复制到:
|
||||
# %APPDATA%\Seewo\EasiNote5\Extensions\Better-EN5\
|
||||
Better-EN5\bin\Release\net6.0-windows\
|
||||
Better-EN5\manifest.coin
|
||||
```
|
||||
|
||||
### 4. 使用说明
|
||||
1. **重启希沃白板 5**
|
||||
2. **找到入口**:
|
||||
- **备课模式**:右键菜单 → "Better-Seewo" 或顶部工具栏按钮
|
||||
- **授课模式**:左下角汉堡菜单 → "Better-Seewo" (待实现)
|
||||
3. **体验功能**:打开主界面,体验五大核心服务
|
||||
|
||||
## 完整开发指南
|
||||
|
||||
### 1. 创建新菜单项
|
||||
|
||||
**步骤**:
|
||||
1. **选择目标常量**,确定基类
|
||||
2. **创建子类**,继承对应基类
|
||||
3. **实现功能成员**:`Command`、`Predicate`、`SortHint`
|
||||
4. **自动注册**:无需手动处理,`AppendWithLang` 自动完成
|
||||
|
||||
**示例** (备课模式·右键菜单):
|
||||
```csharp
|
||||
// 1. 选择 BoardEditMenu 常量(备课模式·右键菜单)
|
||||
UIItemPurposes.BoardEditMenu // → BoardEditMenuItem
|
||||
|
||||
// 2. 创建子类
|
||||
public class ExportInkMenuItem : BoardEditMenuItem
|
||||
{
|
||||
public ExportInkMenuItem()
|
||||
{
|
||||
SortHint = 100; // 菜单项排序权重
|
||||
Command = new DelegateCommand(ExportInk);
|
||||
Predicate = _ => true; // 总是显示
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 自动注册 (通过 AppendWithLang)
|
||||
manager.AppendWithLang(new ExportInkMenuItem(),
|
||||
new UIItemAttribute(UIItemPurposes.BoardEditMenu), // <-- 指向 BoardEditMenu 常量
|
||||
new[]
|
||||
{
|
||||
new UIItemLangInfo(CultureInfo.Chinese, "导出墨迹"),
|
||||
new UIItemLangInfo(CultureInfo.English, "Export Ink")
|
||||
});
|
||||
```
|
||||
|
||||
### 2. 多语言支持
|
||||
|
||||
系统中内置完整的多语言支持框架。只需在注册时提供对应语言的文本即可。
|
||||
|
||||
```csharp
|
||||
new[]
|
||||
{
|
||||
new UIItemLangInfo(new CultureInfo("zh-CHS"), "功能名称"),
|
||||
new UIItemLangInfo(new CultureInfo("en"), "Feature Name"),
|
||||
new UIItemLangInfo(new CultureInfo("ja"), "機能名"),
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 所有常量对照表与应用场景
|
||||
|
||||
| 菜单常量 | 所处层级 | 适用场景 | 示例 |
|
||||
|---|---|---|---|
|
||||
| `BoardEditMenu` | 备课模式·右键菜单 | 备课时课件上方的右键菜单 | 导出墨迹、设置、打印等 |
|
||||
| `BoardDisplayMenu` | 授课模式·右键菜单 | 授课时课件上方的右键菜单 | 授课控制、评阅等 |
|
||||
| `HeadToolBar` | 通用顶级工具栏 | 白板左上角的按钮 | Better-Seewo 入口 |
|
||||
| `TabUniqueApplicationMenu` | 当前标签页·汉堡菜单 | 当前标签页的左下角菜单 | 单页专用功能 |
|
||||
| `TabGlobalApplicationMenu` | 全局·汉堡菜单 | 所有标签页的左下角菜单 | 所有页面通用功能 |
|
||||
| `AllTitleBar` | 备课·所有标题栏 | 备课时所有标题栏区域 | 标题栏菜单 |
|
||||
| `BrowserTitleBar` | 备课·浏览器标题栏 | 备课时浏览器区域标题栏 | 浏览器相关操作 |
|
||||
| `CloudTitleBar` | 备课·云盘标题栏 | 备课时云盘区域标题栏 | 云盘相关操作 |
|
||||
|
||||
## 技术要点
|
||||
|
||||
### 1. 菜单注册机制
|
||||
|
||||
```csharp
|
||||
// 底层方法 (不推荐直接使用)
|
||||
manager.Append(item, new UIItemAttribute(UIItemPurposes.BoardEditMenu));
|
||||
|
||||
// 方便易用的封装 (推荐使用)
|
||||
manager.AppendWithLang(item, new UIItemAttribute(UIItemPurposes.BoardEditMenu), langInfos);
|
||||
```
|
||||
|
||||
### 2. 大屏支持
|
||||
|
||||
为非触摸大屏设备提供专属支持,通过注册表和配置文件补丁实现。
|
||||
|
||||
### 3. 激活机制
|
||||
|
||||
专业版激活码验证系统,支持在线验证和离线注册。
|
||||
|
||||
### 4. 文件转换
|
||||
|
||||
使用独立进程实现 PPT ↔ ENBX 互转,避免平台兼容性问题。
|
||||
|
||||
### 5. 激活流程
|
||||
|
||||
一键启动 BEN5 注册补丁安装程序,实现专业版激活。
|
||||
|
||||
## 常见问题
|
||||
|
||||
### Q: `ApplicationMenu` 和 `ExtendedTitleBar` 是否存在?
|
||||
**A**: 不存在。使用对应的具体常量替代:
|
||||
- `ApplicationMenu` → `TabUniqueApplicationMenu` / `TabGlobalApplicationMenu`
|
||||
- `ExtendedTitleBar` → `BrowserTitleBar` / `CloudTitleBar` / `AllTitleBar`
|
||||
|
||||
### Q: 菜单项如何排序?
|
||||
**A**: 使用 `SortHint` 属性,数值越小排序越前。
|
||||
|
||||
### Q: 如何控制菜单项显示条件?
|
||||
**A**: 使用 `Predicate` 属性,接收 `object` 参数,返回 `bool` 值。
|
||||
|
||||
### Q: 多语言如何使用?
|
||||
**A**: 系统自动生成 Key `Lang.{前缀}.{菜单项类名}`,直接在 UI 中使用即可。
|
||||
|
||||
## 构建与发布
|
||||
|
||||
### 构建命令
|
||||
```bash
|
||||
# 调试版本
|
||||
dotnet build Better-EN5/Better-EN5.csproj -c Debug
|
||||
|
||||
# 发布版本
|
||||
dotnet build Better-EN5/Better-EN5.csproj -c Release
|
||||
```
|
||||
|
||||
### 发布文件
|
||||
```
|
||||
Better-EN5/bin/Release/net6.0-windows/
|
||||
├── Better-EN5.dll # 主插件
|
||||
├── BetterSeewoMainWindow.exe.config # 配置文件
|
||||
├── ... (所有依赖 DLL)
|
||||
└── BetterSeewoMainWindow.xaml # 主界面资源
|
||||
```
|
||||
|
||||
## 许可证
|
||||
|
||||
## 构建方法
|
||||
|
||||
### 前置条件
|
||||
1. 已安装 **希沃白板 5**(版本 5.2.2.653 ~ 5.3.0.0)
|
||||
2. 已安装 **.NET SDK 6.0**(推荐 `C:\Program Files\dotnet`)
|
||||
3. 确保 `dotnet` 在 `PATH` 中,或使用完整路径
|
||||
|
||||
### 构建 Release
|
||||
```powershell
|
||||
# 方式一:确保 dotnet 在 PATH
|
||||
set PATH=C:\Program Files\dotnet;%PATH%
|
||||
dotnet build -c Release Better-EN5
|
||||
|
||||
# 方式二:使用完整路径
|
||||
& "C:\Program Files\dotnet\dotnet.exe" build -c Release Better-EN5
|
||||
```
|
||||
|
||||
### 安装到希沃白板
|
||||
```powershell
|
||||
# 管理员身份运行
|
||||
.\scripts\install.ps1
|
||||
```
|
||||
|
||||
### 构建输出
|
||||
| 文件 | 说明 |
|
||||
|------|------|
|
||||
| `Better-EN5\bin\Release\net6.0-windows\Better-EN5.dll` | 插件 DLL |
|
||||
| `Better-EN5\bin\Release\net6.0-windows\Better-EN5.exe` | 宿主程序 |
|
||||
| `bin\Release\Better-Seewo 增强插件.X.X.X.exe` | 安装包 |
|
||||
| `bin\Release\Better-Seewo 增强插件.X.X.X.zip` | 插件包 (.enp) |
|
||||
|
||||
## 许可协议
|
||||
|
||||
本项目仅供 **学习交流** 使用。
|
||||
|
||||
## 致谢
|
||||
|
||||
感谢 dotnetCampus.EasiPlugin.Sdk 框架的支持。
|
||||
|
||||
---
|
||||
|
||||
**开发指南已根据对 `EasiNote.Api.dll` 的完整逆向工程成果生成**。所有常量和继承关系均已验证。
|
||||
87
README.md
87
README.md
@@ -1,87 +0,0 @@
|
||||
# Better-Seewo
|
||||
|
||||
希沃白板 5 功能增强插件套件,为希沃白板提供墨迹管理、文件转换增强和触摸检测修复等功能。
|
||||
|
||||
## 项目结构
|
||||
|
||||
```
|
||||
Better-Seewo/
|
||||
├── Better-EN5/ # EN5 增强插件(核心模块)
|
||||
│ ├── Services/ # 服务层(墨迹、转换、触摸修复)
|
||||
│ ├── UI/ # 界面组件(菜单项、设置窗口)
|
||||
│ ├── Program.cs # 插件入口
|
||||
│ └── manifest.coin # 插件元数据清单
|
||||
├── install.ps1 # 安装脚本
|
||||
├── Better-Seewo.sln # 解决方案文件
|
||||
└── README.md
|
||||
```
|
||||
|
||||
## 功能
|
||||
|
||||
### 墨迹管理(InkService)
|
||||
- 通过反射调用希沃白板 Remark API 实现墨迹导出/导入
|
||||
- 兼容希沃白板 5.2.x 版本
|
||||
|
||||
### 文件转换(ConversionService)
|
||||
- PPT ↔ ENBX 互转
|
||||
- 调用 `EasiNote.OfficeDocumentConverter.exe` 独立进程,避免编译时硬依赖
|
||||
|
||||
### 触摸修复(TouchFixService)
|
||||
- 注册表配置(HKCU 级)
|
||||
- 配置文件补丁(IWBConfig.json、TouchConfig.ini)
|
||||
- 解决希沃白板在非希沃硬件上的触摸检测问题
|
||||
|
||||
## 环境要求
|
||||
|
||||
- .NET 6.0 SDK
|
||||
- 希沃白板 5(5.2.2.653 ~ 5.3.0.0)
|
||||
|
||||
## 构建
|
||||
|
||||
```bash
|
||||
dotnet build Better-EN5/Better-EN5.csproj -c Release
|
||||
```
|
||||
|
||||
构建后生成:
|
||||
- `bin/Release/Better-Seewo 增强插件.{version}.exe` — 独立安装程序
|
||||
- `bin/Release/Better-EN5.{version}.enp` — 希沃应用中心包
|
||||
|
||||
## 安装
|
||||
|
||||
### 方式一:安装程序
|
||||
双击 `Better-Seewo 增强插件.{version}.exe`,按向导完成安装。
|
||||
|
||||
### 方式二:手动部署
|
||||
将 `Better-EN5/bin/Release/net6.0-windows/` 目录下所有文件连同 `manifest.coin` 复制到希沃白板 Extensions 目录:
|
||||
```
|
||||
C:\Program Files (x86)\Seewo\EasiNote5\EasiNote5_{version}\Main\Extensions\Better-EN5\
|
||||
```
|
||||
|
||||
### 方式三:PowerShell 脚本
|
||||
以管理员身份运行 `install.ps1`。
|
||||
|
||||
## 使用方法
|
||||
|
||||
1. **重启希沃白板 5**
|
||||
2. 在课件编辑区 **右键点击**,将看到两个菜单项:
|
||||
- **导出墨迹** — 直接导出当前课件笔迹
|
||||
- **Better-Seewo 设置** — 打开设置窗口(墨迹管理、文件转换、触摸修复)
|
||||
|
||||
## 设置窗口
|
||||
|
||||
- **墨迹管理**:导出/导入 EN5 课件笔迹(JSON 格式)
|
||||
- **文件转换**:PPT ↔ ENBX 格式互转
|
||||
- **触摸修复**:强制 IWB 模式、跳过触摸检测、抑制错误弹窗
|
||||
- **关于**:版本信息
|
||||
|
||||
## 技术要点
|
||||
|
||||
- 插件 SDK 基于 `dotnetCampus.EasiPlugin.Sdk`(v2.1.1-alpha.3)
|
||||
- 目标框架 `net6.0-windows`(WPF + WinForms)
|
||||
- 墨迹 API 通过反射调用(避免编译时硬依赖)
|
||||
- 转换服务通过外部进程实现
|
||||
- 菜单注册在希沃白板的 `BoardEditMenu`(课件编辑右键菜单)
|
||||
|
||||
## 许可证
|
||||
|
||||
本项目仅供学习交流使用。
|
||||
26
check_purposes.csx
Normal file
26
check_purposes.csx
Normal file
@@ -0,0 +1,26 @@
|
||||
using System;
|
||||
using System.Reflection;
|
||||
class Program {
|
||||
static void Main() {
|
||||
var asm = Assembly.LoadFrom(@"C:\Program Files (x86)\Seewo\EasiNote5\EasiNote5_5.2.4.9855\Main\EasiNote.Api.dll");
|
||||
var t = asm.GetType("Cvte.EasiNote.UIItemPurposes");
|
||||
if (t == null) t = asm.GetType("EasiNote.Api.UIItemPurposes");
|
||||
if (t == null) t = asm.GetType("UIItemPurposes");
|
||||
if (t != null) {
|
||||
Console.WriteLine("Found: " + t.FullName);
|
||||
foreach (var f in t.GetFields(BindingFlags.Public | BindingFlags.Static)) {
|
||||
Console.WriteLine($" {f.Name} = {f.GetValue(null)}");
|
||||
}
|
||||
} else {
|
||||
Console.WriteLine("UIItemPurposes not found directly, searching...");
|
||||
foreach (var tt in asm.GetTypes()) {
|
||||
if (tt.Name.Contains("Purposes") || tt.Name.Contains("Purpose")) {
|
||||
Console.WriteLine(" " + tt.FullName);
|
||||
foreach (var f in tt.GetFields(BindingFlags.Public | BindingFlags.Static)) {
|
||||
Console.WriteLine($" {f.Name} = {f.GetValue(null)}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
scripts/build-release.ps1
Normal file
43
scripts/build-release.ps1
Normal file
@@ -0,0 +1,43 @@
|
||||
# Better-EN5 自动构建与发布脚本
|
||||
param(
|
||||
[string]$Version = "1.1.0",
|
||||
[switch]$Push
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$dotnet = "C:\Program Files\dotnet\dotnet.exe"
|
||||
$repoDir = Split-Path -Parent $PSScriptRoot
|
||||
echo $ENV:output_folder
|
||||
# 设置 PATH
|
||||
$env:Path = "C:\Program Files\dotnet;C:\Program Files\Git\bin;$env:Path"
|
||||
|
||||
Write-Host "=== Better-EN5 构建脚本 ===" -ForegroundColor Cyan
|
||||
Write-Host "版本: $Version" -ForegroundColor White
|
||||
Write-Host ""
|
||||
|
||||
# 1. 构建
|
||||
Write-Host "[1/3] 构建项目..." -ForegroundColor Yellow
|
||||
& $dotnet build -c Release "$repoDir\Better-EN5"
|
||||
if (-not $?) { Write-Host "构建失败" -ForegroundColor Red; exit 1 }
|
||||
Write-Host "构建成功" -ForegroundColor Green
|
||||
|
||||
# 2. 安装到希沃白板
|
||||
Write-Host "[2/3] 安装到希沃白板..." -ForegroundColor Yellow
|
||||
& "$repoDir\scripts\install.ps1" -BuildConfig Release
|
||||
if (-not $?) { Write-Host "安装失败" -ForegroundColor Red; exit 1 }
|
||||
Write-Host "安装成功" -ForegroundColor Green
|
||||
|
||||
# 3. Git 提交与推送
|
||||
if ($Push) {
|
||||
Write-Host "[3/3] 推送至远程仓库..." -ForegroundColor Yellow
|
||||
Set-Location $repoDir
|
||||
git add -A
|
||||
git commit -m "v$Version: 自动构建发布"
|
||||
git tag "v$Version"
|
||||
git push origin main --tags
|
||||
Write-Host "推送成功" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "=== 完成 ===" -ForegroundColor Green
|
||||
Write-Host "安装文件: $repoDir\bin\Release\Better-Seewo 增强插件.$Version.exe" -ForegroundColor Cyan
|
||||
54
scripts/install.ps1
Normal file
54
scripts/install.ps1
Normal file
@@ -0,0 +1,54 @@
|
||||
# Better-EN5 插件安装脚本
|
||||
# 以管理员身份运行
|
||||
param(
|
||||
[string]$BuildConfig = "Release"
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
|
||||
$pluginName = "Better-EN5"
|
||||
$seewoPath = "$env:ProgramFiles(x86)\Seewo\EasiNote5"
|
||||
$dotnet = "C:\Program Files\dotnet\dotnet.exe"
|
||||
|
||||
# 查找最新版本目录
|
||||
$versionDirs = Get-ChildItem "$seewoPath\EasiNote5_*" -Directory | Sort-Object Name -Descending
|
||||
if ($versionDirs.Count -eq 0) {
|
||||
Write-Host "未找到希沃白板安装目录" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
|
||||
$targetDir = Join-Path $versionDirs[0].FullName "Main\Extensions\$pluginName"
|
||||
$sourceDir = Join-Path $PSScriptRoot "..\Better-EN5\bin\$BuildConfig\net6.0-windows"
|
||||
|
||||
Write-Host "安装到: $targetDir" -ForegroundColor Cyan
|
||||
|
||||
# 检查构建输出
|
||||
if (-not (Test-Path $sourceDir)) {
|
||||
Write-Host "未找到构建输出,正在构建..." -ForegroundColor Yellow
|
||||
if (Test-Path $dotnet) {
|
||||
$env:Path = "C:\Program Files\dotnet;$env:Path"
|
||||
& $dotnet build -c $BuildConfig (Join-Path $PSScriptRoot "..\Better-EN5")
|
||||
if (-not $?) { exit 1 }
|
||||
} else {
|
||||
Write-Host "找不到 dotnet 编译器" -ForegroundColor Red
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# 创建插件目录
|
||||
New-Item -ItemType Directory -Path $targetDir -Force | Out-Null
|
||||
|
||||
# 复制插件文件
|
||||
Copy-Item "$sourceDir\*" $targetDir -Recurse -Force
|
||||
Write-Host "插件文件已复制" -ForegroundColor Green
|
||||
|
||||
# 复制 manifest.coin
|
||||
$manifestSource = Join-Path $PSScriptRoot "..\Better-EN5\manifest.coin"
|
||||
if (Test-Path $manifestSource) {
|
||||
Copy-Item $manifestSource $targetDir -Force
|
||||
Write-Host "manifest.coin 已复制" -ForegroundColor Green
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "安装完成!请重启希沃白板以加载插件。" -ForegroundColor Green
|
||||
Write-Host "在希沃白板的右键菜单中可以找到 'Better-Seewo 设置' 入口。" -ForegroundColor Cyan
|
||||
Reference in New Issue
Block a user