v1.1.0: 全面重构UI为Better-Seewo横版主窗口 (Fluent风格+圆角+动画), 新增非触摸大板支持与专业版激活, 更改菜单位置至ApplicationMenu/ExtendedTitleBar

This commit is contained in:
miao-moe
2026-06-28 02:43:22 +08:00
parent fdd3418890
commit 2d35293f7c
20 changed files with 1092 additions and 81 deletions

View File

@@ -7,13 +7,13 @@
<Nullable>enable</Nullable>
<RootNamespace>BetterEN5</RootNamespace>
<AssemblyName>Better-EN5</AssemblyName>
<Version>1.0.1</Version>
<FileVersion>1.0.1</FileVersion>
<Version>1.1.0</Version>
<FileVersion>1.1.0</FileVersion>
<Authors>云汀</Authors>
<Author>云汀</Author>
<Company>云汀</Company>
<Product>Better-Seewo 增强插件</Product>
<Description>希沃白板功能增强插件 - 墨迹管理、文件转换增强、触摸检测修复</Description>
<Description>希沃白板功能增强插件 - 墨迹管理、文件转换增强、触摸检测修复、大屏模式支持、专业版激活</Description>
<UseEasiNote>all</UseEasiNote>
</PropertyGroup>
<ItemGroup>

View File

@@ -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,40 @@ namespace BetterEN5
private async void Run()
{
await Task.Delay(TimeSpan.FromSeconds(3));
TouchFixService.ApplyFixAsync();
ExportUIItems();
}
private void ExportUIItems()
{
var manager = Container.Current.Get<IUIItemManager>();
manager.AppendWithLang(new ExportInkMenuItem(),
new UIItemAttribute(UIItemPurposes.BoardEditMenu), new[]
manager.AppendWithLang(new ApplicationMenuSettings(),
new UIItemAttribute(new[] { "ApplicationMenu" }), new[]
{
new UIItemLangInfo(new CultureInfo("zh-CHS"), "Better-Seewo"),
new UIItemLangInfo(new CultureInfo("en"), "Better-Seewo"),
});
manager.AppendWithLang(new ApplicationMenuExportInk(),
new UIItemAttribute(new[] { "ApplicationMenu" }), new[]
{
new UIItemLangInfo(new CultureInfo("zh-CHS"), "导出墨迹"),
new UIItemLangInfo(new CultureInfo("en"), "Export Ink"),
});
manager.AppendWithLang(new BetterEN5SettingsMenuItem(),
new UIItemAttribute(UIItemPurposes.BoardEditMenu), new[]
manager.AppendWithLang(new HeadToolBarInkImport(),
new UIItemAttribute(new[] { "HeadToolBar" }), new[]
{
new UIItemLangInfo(new CultureInfo("zh-CHS"), "Better-Seewo 设置"),
new UIItemLangInfo(new CultureInfo("en"), "Better-Seewo Settings"),
new UIItemLangInfo(new CultureInfo("zh-CHS"), "导入墨迹"),
new UIItemLangInfo(new CultureInfo("en"), "Import Ink"),
});
manager.AppendWithLang(new ExtendedTitleBarSettings(),
new UIItemAttribute(new[] { "ExtendedTitleBar" }), new[]
{
new UIItemLangInfo(new CultureInfo("zh-CHS"), "Better-Seewo"),
new UIItemLangInfo(new CultureInfo("en"), "Better-Seewo"),
});
}
}

View 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;
}
}
}

View 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; } = "";
}
}

View 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>

View 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();
}
}
}

View File

@@ -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 ApplicationMenuExportInk : HeadToolBarItem
{
public ExportInkMenuItem()
public ApplicationMenuExportInk()
{
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)
{

View File

@@ -0,0 +1,18 @@
using Cvte.EasiNote;
using Cvte.Windows.Input;
namespace BetterEN5.UI
{
public class ApplicationMenuSettings : HeadToolBarItem
{
public ApplicationMenuSettings()
{
SortHint = 999;
Command = new DelegateCommand(() =>
{
BetterSeewoMainWindow.ShowWindow();
});
Predicate = _ => true;
}
}
}

View File

@@ -0,0 +1,150 @@
<UserControl x:Class="BetterEN5.UI.BetterEN5Module"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignWidth="320" d:DesignHeight="600">
<UserControl.Resources>
<Style x:Key="CardBorder" TargetType="Border">
<Setter Property="Background" Value="{Binding ElementName=Root, Path=Resources[CardBackground]}"/>
<Setter Property="BorderBrush" Value="#20FFFFFF"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="10"/>
<Setter Property="Margin" Value="6,4"/>
<Setter Property="Padding" Value="12,10"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="8" ShadowDepth="2" Opacity="0.15" Color="Black"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="ActionButton" TargetType="Button">
<Setter Property="Background" Value="#00FFFFFF"/>
<Setter Property="Foreground" Value="{Binding ElementName=Root, Path=Resources[Foreground]}"/>
<Setter Property="BorderThickness" Value="0"/>
<Setter Property="Cursor" Value="Hand"/>
<Setter Property="Padding" Value="8,6"/>
<Setter Property="FontSize" Value="13"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="BorderBrush" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Button">
<Border x:Name="border" Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}"
CornerRadius="6" Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"
VerticalAlignment="Center"/>
</Border>
<ControlTemplate.Triggers>
<Trigger Property="IsMouseOver" Value="True">
<Setter TargetName="border" Property="Background" Value="#15FFFFFF"/>
</Trigger>
<Trigger Property="IsPressed" Value="True">
<Setter TargetName="border" Property="Background" Value="#30FFFFFF"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Color x:Key="AccentColor">#60B0FF</Color>
<SolidColorBrush x:Key="CardBackground" Color="#1E1E2E"/>
<SolidColorBrush x:Key="Foreground" Color="#E0E0E0"/>
<SolidColorBrush x:Key="AccentBrush" Color="#60B0FF"/>
<SolidColorBrush x:Key="SubText" Color="#909090"/>
</UserControl.Resources>
<Border x:Name="Root" Background="#161625" CornerRadius="0">
<Grid Margin="0">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="#1E1E30" BorderBrush="#30FFFFFF" BorderThickness="0,0,0,1"
CornerRadius="0" Padding="16,14">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="Better-EN5" FontSize="20" FontWeight="Medium"
Foreground="{StaticResource AccentBrush}"/>
<TextBlock Grid.Row="1" Text="希沃白板增强模块" FontSize="12"
Foreground="{StaticResource SubText}" Margin="0,2,0,0"/>
</Grid>
</Border>
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto"
HorizontalScrollBarVisibility="Disabled"
Padding="8,4" Margin="0">
<StackPanel>
<Border Style="{StaticResource CardBorder}">
<StackPanel>
<TextBlock Text="墨迹管理" FontSize="14" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}" Margin="0,0,0,6"/>
<Button Content="📝 导出墨迹..." Style="{StaticResource ActionButton}" Click="ExportInk_Click"/>
<Button Content="📂 导入墨迹..." Style="{StaticResource ActionButton}" Click="ImportInk_Click"/>
<TextBlock x:Name="InkStatus" Text="" FontSize="11" Foreground="{StaticResource SubText}"
Margin="8,4,0,0"/>
</StackPanel>
</Border>
<Border Style="{StaticResource CardBorder}">
<StackPanel>
<TextBlock Text="文件转换" FontSize="14" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}" Margin="0,0,0,6"/>
<Button Content="📄 PPT → ENBX" Style="{StaticResource ActionButton}" Click="ConvertPptx_Click"/>
<Button Content="📄 ENBX → PPT" Style="{StaticResource ActionButton}" Click="ConvertEnbx_Click"/>
<TextBlock x:Name="ConversionStatus" Text="" FontSize="11" Foreground="{StaticResource SubText}"
Margin="8,4,0,0"/>
</StackPanel>
</Border>
<Border Style="{StaticResource CardBorder}">
<StackPanel>
<TextBlock Text="触摸修复" FontSize="14" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}" Margin="0,0,0,6"/>
<Button Content="🔍 检测触摸状态" Style="{StaticResource ActionButton}" Click="CheckTouch_Click"/>
<Button Content="🔧 应用触摸修复" Style="{StaticResource ActionButton}" Click="ApplyTouchFix_Click"/>
<TextBlock x:Name="TouchStatus" Text="" FontSize="11" Foreground="{StaticResource SubText}"
Margin="8,4,0,0"/>
</StackPanel>
</Border>
<Border Style="{StaticResource CardBorder}">
<StackPanel>
<TextBlock Text="大板支持" FontSize="14" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}" Margin="0,0,0,6"/>
<TextBlock Text="为非触摸大屏启用完整白板模式" FontSize="11"
Foreground="{StaticResource SubText}" Margin="0,0,0,6"/>
<Button Content="🖥️ 配置大屏模式" Style="{StaticResource ActionButton}" Click="EnableBoardSupport_Click"/>
<Button Content="💻 启用 IWB 模式" Style="{StaticResource ActionButton}" Click="EnableIWB_Click"/>
<TextBlock x:Name="BoardStatus" Text="" FontSize="11" Foreground="{StaticResource SubText}"
Margin="8,4,0,0"/>
</StackPanel>
</Border>
<Border Style="{StaticResource CardBorder}">
<StackPanel>
<TextBlock Text="专业版 / 激活" FontSize="14" FontWeight="SemiBold"
Foreground="{StaticResource AccentBrush}" Margin="0,0,0,6"/>
<TextBlock x:Name="ActivationStatusText" Text="当前状态: 社区版" FontSize="11"
Foreground="{StaticResource SubText}" Margin="0,0,0,6"/>
<Button Content="🔑 输入激活码..." Style="{StaticResource ActionButton}" Click="ActivatePro_Click"/>
<Button Content="📦 打开注册补丁..." Style="{StaticResource ActionButton}" Click="LaunchInstaller_Click"/>
</StackPanel>
</Border>
</StackPanel>
</ScrollViewer>
<Border Grid.Row="2" Background="#1A1A2E" BorderBrush="#20FFFFFF" BorderThickness="0,1,0,0"
Padding="12,8" CornerRadius="0">
<TextBlock x:Name="FooterText" Text="v1.1.0 · 就绪" FontSize="11"
Foreground="{StaticResource SubText}" TextAlignment="Center"/>
</Border>
</Grid>
</Border>
</UserControl>

View File

@@ -0,0 +1,204 @@
using System;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using Microsoft.Win32;
using BetterEN5.Services;
namespace BetterEN5.UI
{
public partial class BetterEN5Module : UserControl
{
private readonly InkService _inkService = new();
private readonly ConversionService _conversionService = new();
private readonly ActivationService _activationService = new();
public BetterEN5Module()
{
InitializeComponent();
Loaded += OnLoaded;
}
private async void OnLoaded(object sender, RoutedEventArgs e)
{
await RefreshStatusAsync();
}
public async Task RefreshStatusAsync()
{
try
{
var touchOk = await Task.Run(() => TouchFixService.IsTouchWorkingCorrectly());
TouchStatus.Text = touchOk ? "✅ IWB 模式已启用" : "⚠️ 未启用 IWB 模式";
var activationInfo = await Task.Run(() => _activationService.GetCurrentStatus());
ActivationStatusText.Text = activationInfo.IsProfessional
? $"✅ 专业版已激活 | {activationInfo.LastActivationDate}"
: "🔓 社区版 · 点击激活";
}
catch { }
}
private async void ExportInk_Click(object sender, RoutedEventArgs e)
{
var dialog = new SaveFileDialog
{
Title = "导出墨迹",
Filter = "墨迹文件|*.ink.json|JSON 文件|*.json|所有文件|*.*",
DefaultExt = ".ink.json"
};
if (dialog.ShowDialog() == true)
{
try
{
await _inkService.ExportInkAsync(dialog.FileName);
InkStatus.Text = $"✅ 已导出: {Path.GetFileName(dialog.FileName)}";
}
catch (Exception ex)
{
InkStatus.Text = $"❌ 导出失败: {ex.Message}";
}
}
}
private async void ImportInk_Click(object sender, RoutedEventArgs e)
{
var dialog = new OpenFileDialog
{
Title = "导入墨迹",
Filter = "墨迹文件|*.ink.json|JSON 文件|*.json|所有文件|*.*"
};
if (dialog.ShowDialog() == true)
{
try
{
await _inkService.ImportInkAsync(dialog.FileName);
InkStatus.Text = "✅ 墨迹已导入";
}
catch (Exception ex)
{
InkStatus.Text = $"❌ 导入失败: {ex.Message}";
}
}
}
private async void ConvertPptx_Click(object sender, RoutedEventArgs e)
{
var dialog = new OpenFileDialog
{
Title = "选择 PowerPoint 文件",
Filter = "PowerPoint 文件|*.pptx|所有文件|*.*"
};
if (dialog.ShowDialog() == true)
{
try
{
var result = await _conversionService.ConvertPptxToEnbxAsync(dialog.FileName);
ConversionStatus.Text = $"✅ 转换完成: {Path.GetFileName(result)}";
}
catch (Exception ex)
{
ConversionStatus.Text = $"❌ 转换失败: {ex.Message}";
}
}
}
private async void ConvertEnbx_Click(object sender, RoutedEventArgs e)
{
var dialog = new OpenFileDialog
{
Title = "选择希沃白板课件",
Filter = "希沃课件|*.enbx|所有文件|*.*"
};
if (dialog.ShowDialog() == true)
{
try
{
var result = await _conversionService.ConvertEnbxToPptxAsync(dialog.FileName);
ConversionStatus.Text = $"✅ 导出完成: {Path.GetFileName(result)}";
}
catch (Exception ex)
{
ConversionStatus.Text = $"❌ 导出失败: {ex.Message}";
}
}
}
private async void CheckTouch_Click(object sender, RoutedEventArgs e)
{
try
{
var touchOk = await Task.Run(() => TouchFixService.IsTouchWorkingCorrectly());
TouchStatus.Text = touchOk ? "✅ 触摸状态正常" : "⚠️ 触摸可能需要修复";
}
catch (Exception ex)
{
TouchStatus.Text = $"❌ 检测失败: {ex.Message}";
}
}
private async void ApplyTouchFix_Click(object sender, RoutedEventArgs e)
{
try
{
await TouchFixService.ApplyFixAsync();
TouchStatus.Text = "✅ 触摸修复已应用,重启后生效";
}
catch (Exception ex)
{
TouchStatus.Text = $"❌ 修复失败: {ex.Message}";
}
}
private async void EnableBoardSupport_Click(object sender, RoutedEventArgs e)
{
try
{
var ok = await _activationService.ApplyBoardSupportPatchAsync();
BoardStatus.Text = ok ? "✅ 大屏模式已配置" : "❌ 配置失败";
}
catch (Exception ex)
{
BoardStatus.Text = $"❌ 错误: {ex.Message}";
}
}
private async void EnableIWB_Click(object sender, RoutedEventArgs e)
{
try
{
var ok = await _activationService.EnableIWBForNonTouchAsync();
BoardStatus.Text = ok ? "✅ IWB 模式已启用" : "❌ 启用失败";
}
catch (Exception ex)
{
BoardStatus.Text = $"❌ 错误: {ex.Message}";
}
}
private async void ActivatePro_Click(object sender, RoutedEventArgs e)
{
var dialog = new ActivateDialog();
var ownerWindow = Window.GetWindow(this);
if (ownerWindow != null) dialog.Owner = ownerWindow;
if (dialog.ShowDialog() == true)
{
var ok = await _activationService.ActivateProfessionalAsync(dialog.LicenseKey);
ActivationStatusText.Text = ok ? "✅ 激活成功!专业版已启用" : "❌ 激活码无效";
}
}
private async void LaunchInstaller_Click(object sender, RoutedEventArgs e)
{
var ok = await _activationService.LaunchBen5InstallerAsync();
if (!ok)
{
MessageBox.Show("未找到注册补丁安装程序。\n请将 BEN5_Installer.exe 放置于插件目录。",
"提示", MessageBoxButton.OK, MessageBoxImage.Information);
}
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -0,0 +1,108 @@
<Window x:Class="BetterEN5.UI.BetterSeewoMainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:ui="clr-namespace:BetterEN5.UI"
Title="Better-Seewo"
Width="960" Height="640"
MinWidth="720" MinHeight="480"
WindowStyle="None"
ResizeMode="CanResize"
AllowsTransparency="True"
Background="Transparent"
WindowStartupLocation="CenterScreen"
FontSize="14">
<Window.Resources>
<Color x:Key="WindowBackground">#0D0D1A</Color>
<SolidColorBrush x:Key="WindowBorderBrush" Color="#30FFFFFF"/>
<SolidColorBrush x:Key="TitleBarBackground" Color="#1A1A2E"/>
<SolidColorBrush x:Key="TitleBarForeground" Color="#C0C0D0"/>
<SolidColorBrush x:Key="GlowBrush" Color="#40FFFFFF"/>
<Storyboard x:Key="FadeInStoryboard">
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1"
Duration="0:0:0.4" EasingFunction="{StaticResource Easing}"/>
</Storyboard>
<Storyboard x:Key="ScaleInStoryboard">
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" From="0.95" To="1"
Duration="0:0:0.4" EasingFunction="{StaticResource Easing}"/>
<DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" From="0.95" To="1"
Duration="0:0:0.4" EasingFunction="{StaticResource Easing}"/>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0" To="1"
Duration="0:0:0.3" EasingFunction="{StaticResource Easing}"/>
</Storyboard>
<QuadraticEase x:Key="Easing" EasingMode="EaseOut"/>
</Window.Resources>
<Window.RenderTransform>
<ScaleTransform ScaleX="1" ScaleY="1"/>
</Window.RenderTransform>
<Border CornerRadius="12" Background="#0D0D1A" BorderBrush="{StaticResource WindowBorderBrush}"
BorderThickness="1" Padding="0">
<Border.Effect>
<DropShadowEffect BlurRadius="24" ShadowDepth="4" Opacity="0.3" Color="Black"/>
</Border.Effect>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="36"/>
<RowDefinition Height="*"/>
<RowDefinition Height="24"/>
</Grid.RowDefinitions>
<Border Grid.Row="0" Background="{StaticResource TitleBarBackground}"
CornerRadius="12,12,0,0" Padding="0">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Text="Better-Seewo" FontSize="13"
Foreground="{StaticResource TitleBarForeground}"
VerticalAlignment="Center" Margin="14,0,0,0"/>
<StackPanel Grid.Column="1" Orientation="Horizontal" Margin="0,0,6,0">
<Button x:Name="MinimizeButton" Content="─" Width="28" Height="24"
Foreground="{StaticResource TitleBarForeground}"
Background="Transparent" BorderThickness="0"
Cursor="Hand" Click="Minimize_Click"
FontSize="12" FontFamily="Arial"/>
<Button x:Name="MaximizeButton" Content="□" Width="28" Height="24"
Foreground="{StaticResource TitleBarForeground}"
Background="Transparent" BorderThickness="0"
Cursor="Hand" Click="Maximize_Click"
FontSize="12" FontFamily="Arial"/>
<Button x:Name="CloseButton" Content="✕" Width="28" Height="24"
Foreground="{StaticResource TitleBarForeground}"
Background="Transparent" BorderThickness="0"
Cursor="Hand" Click="Close_Click"
FontSize="12" FontFamily="Arial"/>
</StackPanel>
</Grid>
</Border>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="1*" MinWidth="240" MaxWidth="400"/>
<ColumnDefinition Width="1" />
<ColumnDefinition Width="3*"/>
</Grid.ColumnDefinitions>
<Border Grid.Column="0" Background="#12121E">
<ui:BetterEN5Module x:Name="En5Module"/>
</Border>
<Border Grid.Column="1" Background="#252540" Width="1" Opacity="0.5"/>
<Border Grid.Column="2" Background="#0F0F1A">
<ui:ComingSoonModule/>
</Border>
</Grid>
<Border Grid.Row="2" Background="{StaticResource TitleBarBackground}"
CornerRadius="0,0,12,12" Padding="0">
<TextBlock Text="Better-Seewo v1.1.0 · 希沃白板增强插件" FontSize="11"
Foreground="#505060" HorizontalAlignment="Center" VerticalAlignment="Center"/>
</Border>
</Grid>
</Border>
</Window>

View File

@@ -0,0 +1,62 @@
using System;
using System.Linq;
using System.Windows;
using System.Windows.Media.Animation;
namespace BetterEN5.UI
{
public partial class BetterSeewoMainWindow : Window
{
public BetterSeewoMainWindow()
{
InitializeComponent();
Loaded += OnLoaded;
}
private void OnLoaded(object sender, RoutedEventArgs e)
{
var storyboard = (Storyboard)Resources["ScaleInStoryboard"];
BeginStoryboard(storyboard);
}
private void Minimize_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState.Minimized;
}
private void Maximize_Click(object sender, RoutedEventArgs e)
{
WindowState = WindowState == WindowState.Maximized
? WindowState.Normal
: WindowState.Maximized;
}
private void Close_Click(object sender, RoutedEventArgs e)
{
Close();
}
public void RefreshModule()
{
En5Module?.RefreshStatusAsync();
}
public static void ShowWindow()
{
Application.Current.Dispatcher.Invoke(() =>
{
var existing = Application.Current.Windows.OfType<BetterSeewoMainWindow>().FirstOrDefault();
if (existing != null)
{
if (existing.WindowState == WindowState.Minimized)
existing.WindowState = WindowState.Normal;
existing.Activate();
return;
}
var window = new BetterSeewoMainWindow();
window.Show();
});
}
}
}

View File

@@ -0,0 +1,105 @@
<UserControl x:Class="BetterEN5.UI.ComingSoonModule"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" d:DesignWidth="700" d:DesignHeight="600">
<UserControl.Resources>
<Style x:Key="ModuleCard" TargetType="Border">
<Setter Property="Background" Value="#1A1A2E"/>
<Setter Property="BorderBrush" Value="#15FFFFFF"/>
<Setter Property="BorderThickness" Value="1"/>
<Setter Property="CornerRadius" Value="14"/>
<Setter Property="Margin" Value="10,8"/>
<Setter Property="Padding" Value="20"/>
<Setter Property="Effect">
<Setter.Value>
<DropShadowEffect BlurRadius="12" ShadowDepth="3" Opacity="0.12" Color="Black"/>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="PlaceholderIcon" TargetType="TextBlock">
<Setter Property="FontSize" Value="36"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,0,0,8"/>
</Style>
<Style x:Key="PlaceholderTitle" TargetType="TextBlock">
<Setter Property="FontSize" Value="16"/>
<Setter Property="FontWeight" Value="SemiBold"/>
<Setter Property="Foreground" Value="#A0C4FF"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="Margin" Value="0,0,0,4"/>
</Style>
<Style x:Key="PlaceholderDesc" TargetType="TextBlock">
<Setter Property="FontSize" Value="12"/>
<Setter Property="Foreground" Value="#707090"/>
<Setter Property="HorizontalAlignment" Value="Center"/>
<Setter Property="TextWrapping" Value="Wrap"/>
<Setter Property="TextAlignment" Value="Center"/>
</Style>
</UserControl.Resources>
<Border Background="#12121E" CornerRadius="0" Padding="16">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" Text="🚀 更多功能即将到来" FontSize="22" FontWeight="Light"
Foreground="#8080A0" HorizontalAlignment="Center" Margin="0,16,0,4"/>
<TextBlock Grid.Row="1" Text="敬请期待 · Coming Soon" FontSize="13"
Foreground="#505068" HorizontalAlignment="Center" Margin="0,0,0,16"/>
<UniformGrid Grid.Row="2" Columns="2" Margin="0,0,0,0">
<Border Style="{StaticResource ModuleCard}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="🎨" Style="{StaticResource PlaceholderIcon}"/>
<TextBlock Text="自定义皮肤" Style="{StaticResource PlaceholderTitle}"/>
<TextBlock Text="随心更换希沃白板界面主题与配色" Style="{StaticResource PlaceholderDesc}"/>
</StackPanel>
</Border>
<Border Style="{StaticResource ModuleCard}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="📚" Style="{StaticResource PlaceholderIcon}"/>
<TextBlock Text="资源管理器" Style="{StaticResource PlaceholderTitle}"/>
<TextBlock Text="一站式管理课件、图片、音视频资源" Style="{StaticResource PlaceholderDesc}"/>
</StackPanel>
</Border>
<Border Style="{StaticResource ModuleCard}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="📋" Style="{StaticResource PlaceholderIcon}"/>
<TextBlock Text="模板库" Style="{StaticResource PlaceholderTitle}"/>
<TextBlock Text="海量精美课件模板,一键套用" Style="{StaticResource PlaceholderDesc}"/>
</StackPanel>
</Border>
<Border Style="{StaticResource ModuleCard}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="🔌" Style="{StaticResource PlaceholderIcon}"/>
<TextBlock Text="插件市场" Style="{StaticResource PlaceholderTitle}"/>
<TextBlock Text="发现并安装更多社区插件扩展" Style="{StaticResource PlaceholderDesc}"/>
</StackPanel>
</Border>
<Border Style="{StaticResource ModuleCard}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="☁️" Style="{StaticResource PlaceholderIcon}"/>
<TextBlock Text="云同步" Style="{StaticResource PlaceholderTitle}"/>
<TextBlock Text="跨设备课件与设置云端同步" Style="{StaticResource PlaceholderDesc}"/>
</StackPanel>
</Border>
<Border Style="{StaticResource ModuleCard}">
<StackPanel VerticalAlignment="Center">
<TextBlock Text="🤖" Style="{StaticResource PlaceholderIcon}"/>
<TextBlock Text="AI 助手" Style="{StaticResource PlaceholderTitle}"/>
<TextBlock Text="智能备课、AI 生成课件内容" Style="{StaticResource PlaceholderDesc}"/>
</StackPanel>
</Border>
</UniformGrid>
<TextBlock Grid.Row="3" Text="Better-Seewo · 为更好的教学体验" FontSize="12"
Foreground="#404058" HorizontalAlignment="Center" Margin="0,12,0,8"/>
</Grid>
</Border>
</UserControl>

View File

@@ -0,0 +1,12 @@
using System.Windows.Controls;
namespace BetterEN5.UI
{
public partial class ComingSoonModule : UserControl
{
public ComingSoonModule()
{
InitializeComponent();
}
}
}

View File

@@ -0,0 +1,18 @@
using Cvte.EasiNote;
using Cvte.Windows.Input;
namespace BetterEN5.UI
{
public class ExtendedTitleBarSettings : HeadToolBarItem
{
public ExtendedTitleBarSettings()
{
SortHint = 999;
Command = new DelegateCommand(() =>
{
BetterSeewoMainWindow.ShowWindow();
});
Predicate = _ => true;
}
}
}

View File

@@ -0,0 +1,29 @@
using Microsoft.Win32;
using Cvte.EasiNote;
using Cvte.Windows.Input;
using BetterEN5.Services;
namespace BetterEN5.UI
{
public class HeadToolBarInkImport : HeadToolBarItem
{
public HeadToolBarInkImport()
{
SortHint = 900;
Command = new DelegateCommand(() =>
{
var dialog = new OpenFileDialog
{
Title = "导入墨迹",
Filter = "墨迹文件 (*.ink.json)|*.ink.json|JSON 文件 (*.json)|*.json"
};
if (dialog.ShowDialog() == true)
{
var inkService = new InkService();
_ = inkService.ImportInkAsync(dialog.FileName);
}
});
Predicate = _ => true;
}
}
}

View File

@@ -14,17 +14,22 @@ namespace BetterEN5
{
manager.Append(c => item, attribute);
var purpose = attribute.Purposes[0];
string menuName;
if (attribute.Purposes[0] == UIItemPurposes.BoardEditMenu)
if (purpose == UIItemPurposes.BoardEditMenu)
{
menuName = "BoardEditContextMenu";
}
else if (purpose == UIItemPurposes.HeadToolBar)
{
menuName = "HeadToolBar";
}
else
{
throw new NotSupportedException();
menuName = purpose.Replace(".", "_");
}
var itemLangKey = item.GetType().Name.Replace("MenuItem", "");
var itemLangKey = item.GetType().Name.Replace("MenuItem", "").Replace("HeadToolBar", "").Replace("ApplicationMenu", "").Replace("ExtendedTitleBar", "");
var langKey = $"Lang.{menuName}.{itemLangKey}";
Application.Current.Dispatcher.InvokeAsync(() =>

View File

@@ -24,5 +24,5 @@ Preinstalled
False
>
Version
1.0.1
1.1.0
>