@@ -1 +1 @@
|
||||
1.7.1.0
|
||||
1.7.2.0
|
||||
|
||||
@@ -49,5 +49,5 @@ using System.Windows;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.7.1.14")]
|
||||
[assembly: AssemblyFileVersion("1.7.1.14")]
|
||||
[assembly: AssemblyVersion("1.7.2.0")]
|
||||
[assembly: AssemblyFileVersion("1.7.2.0")]
|
||||
|
||||
@@ -845,9 +845,31 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
progressCallback?.Invoke(100, $"多线程下载完成({threadCount}线程)");
|
||||
|
||||
FileInfo fileInfo = new FileInfo(destinationPath);
|
||||
if (fileInfo.Length != totalSize)
|
||||
{
|
||||
LogHelper.WriteLogToFile($"AutoUpdate | 文件大小校验失败,本地:{fileInfo.Length},服务器:{totalSize}", LogHelper.LogType.Error);
|
||||
File.Delete(destinationPath);
|
||||
progressCallback?.Invoke(0, "文件大小校验失败,已删除损坏文件");
|
||||
return false;
|
||||
}
|
||||
if (destinationPath.EndsWith(".zip", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
try
|
||||
{
|
||||
System.IO.Compression.ZipFile.OpenRead(destinationPath).Dispose();
|
||||
}
|
||||
catch
|
||||
{
|
||||
LogHelper.WriteLogToFile("AutoUpdate | ZIP文件解压测试失败,文件可能已损坏", LogHelper.LogType.Error);
|
||||
File.Delete(destinationPath);
|
||||
progressCallback?.Invoke(0, "ZIP文件解压测试失败,已删除损坏文件");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
// 理论上不会到这里
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
using System.Diagnostics;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows.Forms;
|
||||
using System.Drawing;
|
||||
|
||||
namespace Ink_Canvas.Helpers
|
||||
{
|
||||
@@ -96,22 +94,14 @@ namespace Ink_Canvas.Helpers
|
||||
}
|
||||
}
|
||||
|
||||
public static int GetTaskbarHeight(Screen screen, double dpiScaleY)
|
||||
public static double GetTaskbarHeight(System.Windows.Forms.Screen screen, double dpiScaleY)
|
||||
{
|
||||
// 优先用工作区和屏幕区的差值法,兼容多屏
|
||||
int height = 0;
|
||||
if (screen.Bounds.Height > screen.WorkingArea.Height)
|
||||
{
|
||||
// 任务栏在上下
|
||||
height = screen.Bounds.Height - screen.WorkingArea.Height;
|
||||
}
|
||||
else if (screen.Bounds.Width > screen.WorkingArea.Width)
|
||||
{
|
||||
// 任务栏在左右
|
||||
height = screen.Bounds.Width - screen.WorkingArea.Width;
|
||||
}
|
||||
// 考虑DPI缩放
|
||||
return (int)(height / dpiScaleY);
|
||||
// 获取工作区和屏幕高度的差值
|
||||
var workingArea = screen.WorkingArea;
|
||||
var bounds = screen.Bounds;
|
||||
int taskbarHeight = bounds.Height - workingArea.Height;
|
||||
// 考虑 DPI 缩放
|
||||
return taskbarHeight / dpiScaleY;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -618,6 +618,13 @@
|
||||
FontSize="26" />
|
||||
</GroupBox.Header>
|
||||
<ui:SimpleStackPanel Spacing="6">
|
||||
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
|
||||
<TextBlock Foreground="#fafafa" Text="窗口无焦点模式" VerticalAlignment="Center"
|
||||
FontSize="14" Margin="0,0,16,0" />
|
||||
<ui:ToggleSwitch OnContent="" OffContent="" Name="ToggleSwitchNoFocusMode"
|
||||
IsOn="False" FontFamily="Microsoft YaHei UI" FontWeight="Bold"
|
||||
Toggled="ToggleSwitchNoFocusMode_Toggled" />
|
||||
</ui:SimpleStackPanel>
|
||||
<ui:ToggleSwitch OnContent="" OffContent=""
|
||||
Name="ToggleSwitchIsAutoUpdate" Header="自动检查更新"
|
||||
FontFamily="Microsoft YaHei UI"
|
||||
|
||||
@@ -19,6 +19,7 @@ using System.Reflection;
|
||||
using Brushes = System.Windows.Media.Brushes;
|
||||
using Point = System.Windows.Point;
|
||||
using System.Collections.Generic;
|
||||
using iNKORE.UI.WPF.Modern.Controls;
|
||||
|
||||
namespace Ink_Canvas {
|
||||
public partial class MainWindow : Window {
|
||||
@@ -28,44 +29,7 @@ namespace Ink_Canvas {
|
||||
private System.Windows.Controls.Canvas currentCanvas = null;
|
||||
private AutoUpdateHelper.UpdateLineGroup AvailableLatestLineGroup = null;
|
||||
|
||||
// Win32 API声明和常量(用于无焦点窗口)
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
private const int GWL_EXSTYLE = -20;
|
||||
private const int WS_EX_NOACTIVATE = 0x08000000;
|
||||
[DllImport("user32.dll")]
|
||||
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
|
||||
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
|
||||
private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
|
||||
private const uint SWP_NOSIZE = 0x0001;
|
||||
private const uint SWP_NOMOVE = 0x0002;
|
||||
private const uint SWP_NOACTIVATE = 0x0010;
|
||||
private const uint SWP_SHOWWINDOW = 0x0040;
|
||||
|
||||
// 新增:设置窗口置顶并兼容无焦点
|
||||
private void SetTopmostWithNoActivate(bool topmost)
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(this).Handle;
|
||||
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
// 先移除 WS_EX_NOACTIVATE
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_NOACTIVATE);
|
||||
// 设置 Topmost
|
||||
this.Topmost = topmost;
|
||||
// 使用SetWindowPos确保无焦点置顶
|
||||
if (topmost)
|
||||
{
|
||||
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0, SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW);
|
||||
}
|
||||
// 再加回 WS_EX_NOACTIVATE
|
||||
exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
|
||||
}
|
||||
|
||||
|
||||
#region Window Initialization
|
||||
|
||||
@@ -204,14 +168,12 @@ namespace Ink_Canvas {
|
||||
BlackBoardRightSidePageListScrollViewer.ReleaseTouchCapture(e.TouchDevice);
|
||||
e.Handled = true;
|
||||
};
|
||||
// 初始化无焦点模式开关
|
||||
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
|
||||
ApplyNoFocusMode();
|
||||
}
|
||||
|
||||
protected override void OnSourceInitialized(EventArgs e)
|
||||
{
|
||||
base.OnSourceInitialized(e);
|
||||
// 设置窗口为无焦点且置顶(不会抢占焦点且始终在最前)
|
||||
SetTopmostWithNoActivate(true);
|
||||
}
|
||||
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -435,6 +397,9 @@ namespace Ink_Canvas {
|
||||
|
||||
// 初始化插件系统
|
||||
InitializePluginSystem();
|
||||
// 确保开关和设置同步
|
||||
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
|
||||
ApplyNoFocusMode();
|
||||
}
|
||||
|
||||
private void SystemEventsOnDisplaySettingsChanged(object sender, EventArgs e) {
|
||||
@@ -1378,5 +1343,35 @@ namespace Ink_Canvas {
|
||||
BorderSettings.Visibility = Visibility.Visible;
|
||||
BorderSettingsMask.Visibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
|
||||
[DllImport("user32.dll")]
|
||||
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
|
||||
private const int GWL_EXSTYLE = -20;
|
||||
private const int WS_EX_NOACTIVATE = 0x08000000;
|
||||
|
||||
private void ApplyNoFocusMode()
|
||||
{
|
||||
var hwnd = new WindowInteropHelper(this).Handle;
|
||||
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
|
||||
if (Settings.Advanced.IsNoFocusMode)
|
||||
{
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_NOACTIVATE);
|
||||
}
|
||||
}
|
||||
|
||||
private void ToggleSwitchNoFocusMode_Toggled(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (!isLoaded) return;
|
||||
var toggle = sender as ToggleSwitch;
|
||||
Settings.Advanced.IsNoFocusMode = toggle != null && toggle.IsOn;
|
||||
SaveSettingsToFile();
|
||||
ApplyNoFocusMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,9 @@ namespace Ink_Canvas {
|
||||
// 在类中添加字段
|
||||
private bool wasFloatingBarFoldedWhenEnterSlideShow = false;
|
||||
|
||||
// 新增:用于控制WPS强制关闭提示只弹一次
|
||||
private static bool hasShownWpsForceCloseWarning = false;
|
||||
|
||||
private void BtnCheckPPT_Click(object sender, RoutedEventArgs e) {
|
||||
try {
|
||||
pptApplication =
|
||||
@@ -1473,21 +1476,8 @@ namespace Ink_Canvas {
|
||||
|
||||
if (!allSaved)
|
||||
{
|
||||
// 弹窗提示用户
|
||||
bool userContinue = false;
|
||||
Application.Current.Dispatcher.Invoke(() =>
|
||||
{
|
||||
var result = MessageBox.Show(
|
||||
"检测到有未保存的WPS文档,强制关闭可能导致数据丢失。是否继续?",
|
||||
"警告", MessageBoxButton.YesNo, MessageBoxImage.Warning);
|
||||
userContinue = (result == MessageBoxResult.Yes);
|
||||
});
|
||||
if (!userContinue)
|
||||
{
|
||||
LogHelper.WriteLogToFile("用户取消了强制关闭WPS进程", LogHelper.LogType.Trace);
|
||||
StopWppProcessCheckTimer();
|
||||
return;
|
||||
}
|
||||
// 直接跳过弹窗,自动继续
|
||||
LogHelper.WriteLogToFile("检测到有未保存的WPS文档,但已取消弹窗提示,自动继续。", LogHelper.LogType.Trace);
|
||||
}
|
||||
|
||||
// 立即结束WPP进程
|
||||
@@ -1579,6 +1569,7 @@ namespace Ink_Canvas {
|
||||
public bool IsMaximized { get; set; }
|
||||
public ForegroundWindowInfo.RECT Rect { get; set; }
|
||||
public uint ProcessId { get; set; }
|
||||
public string ProcessName { get; set; } // 新增
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1656,6 +1647,15 @@ namespace Ink_Canvas {
|
||||
GetWindowThreadProcessId(hWnd, out processId);
|
||||
windowInfo.ProcessId = processId;
|
||||
|
||||
// 新增:获取进程名
|
||||
windowInfo.ProcessName = "";
|
||||
try
|
||||
{
|
||||
var proc = System.Diagnostics.Process.GetProcessById((int)processId);
|
||||
windowInfo.ProcessName = proc.ProcessName.ToLower();
|
||||
}
|
||||
catch { }
|
||||
|
||||
return windowInfo;
|
||||
}
|
||||
|
||||
@@ -1667,58 +1667,30 @@ namespace Ink_Canvas {
|
||||
if (string.IsNullOrEmpty(windowInfo.Title) && string.IsNullOrEmpty(windowInfo.ClassName))
|
||||
return false;
|
||||
|
||||
// 检查窗口标题
|
||||
var title = windowInfo.Title.ToLower();
|
||||
var className = windowInfo.ClassName.ToLower();
|
||||
var processName = windowInfo.ProcessName ?? "";
|
||||
|
||||
// WPS相关关键词(扩展版)
|
||||
var wpsKeywords = new[]
|
||||
{
|
||||
"wps", "演示文稿", "presentation", "powerpoint", "ppt", "pptx",
|
||||
"kingsoft", "金山", "office", "幻灯片", "slide", "presentation",
|
||||
"wpp", "wps演示", "wps presentation", "wps office", "kingsoft office"
|
||||
};
|
||||
// WPS相关关键词
|
||||
var wpsKeywords = new[] { "wps", "wpp", "kingsoft", "金山", "wps演示", "wps presentation", "wps office", "kingsoft office" };
|
||||
// 微软Office相关进程名
|
||||
var msOfficeProcess = new[] { "powerpnt", "excel", "word", "onenote", "outlook", "microsoftoffice", "office" };
|
||||
|
||||
// 检查标题是否包含WPS相关关键词
|
||||
// 只要进程名是微软Office,直接排除
|
||||
if (msOfficeProcess.Any(keyword => processName.Contains(keyword)))
|
||||
return false;
|
||||
|
||||
// 只要进程名是WPS/WPP/Kingsoft,直接通过
|
||||
if (wpsKeywords.Any(keyword => processName.Contains(keyword)))
|
||||
return true;
|
||||
|
||||
// 标题或类名包含WPS相关关键词
|
||||
bool hasWpsTitle = wpsKeywords.Any(keyword => title.Contains(keyword));
|
||||
|
||||
// 检查类名是否包含WPS相关关键词
|
||||
bool hasWpsClass = wpsKeywords.Any(keyword => className.Contains(keyword));
|
||||
bool isWpsClass = className.Contains("wps") || className.Contains("kingsoft") || className.Contains("wpp");
|
||||
bool hasValidSize = (windowInfo.Rect.Right - windowInfo.Rect.Left) > 0 && (windowInfo.Rect.Bottom - windowInfo.Rect.Top) > 0;
|
||||
|
||||
// 检查是否为WPS特有的窗口类名
|
||||
bool isWpsClass = className.Contains("wps") ||
|
||||
className.Contains("kingsoft") ||
|
||||
className.Contains("presentation") ||
|
||||
className.Contains("powerpoint") ||
|
||||
className.Contains("wpp") ||
|
||||
className.Contains("office");
|
||||
|
||||
// 检查窗口是否有有效尺寸(排除0尺寸窗口)
|
||||
bool hasValidSize = (windowInfo.Rect.Right - windowInfo.Rect.Left) > 0 &&
|
||||
(windowInfo.Rect.Bottom - windowInfo.Rect.Top) > 0;
|
||||
|
||||
// 检查窗口是否可见且不是最小化状态
|
||||
bool isActiveWindow = windowInfo.IsVisible && !windowInfo.IsMinimized;
|
||||
|
||||
// 检查是否为前台窗口
|
||||
bool isForegroundWindow = windowInfo.Handle == GetForegroundWindow();
|
||||
|
||||
// 综合判断是否为WPS窗口
|
||||
bool isWpsWindow = (hasWpsTitle || hasWpsClass || isWpsClass) && hasValidSize;
|
||||
|
||||
// 如果是前台窗口且包含相关关键词,更可能是WPS窗口
|
||||
if (isForegroundWindow && (hasWpsTitle || hasWpsClass))
|
||||
{
|
||||
isWpsWindow = true;
|
||||
}
|
||||
|
||||
if (isWpsWindow)
|
||||
{
|
||||
var windowType = isForegroundWindow ? "前台" : (isActiveWindow ? "活跃" : "后台");
|
||||
LogHelper.WriteLogToFile($"确认WPS窗口: 标题='{windowInfo.Title}', 类名='{windowInfo.ClassName}', 类型={windowType}, 尺寸={windowInfo.Rect.Right - windowInfo.Rect.Left}x{windowInfo.Rect.Bottom - windowInfo.Rect.Top}", LogHelper.LogType.Trace);
|
||||
}
|
||||
|
||||
return isWpsWindow;
|
||||
return (hasWpsTitle || hasWpsClass || isWpsClass) && hasValidSize;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -1954,9 +1926,15 @@ namespace Ink_Canvas {
|
||||
try
|
||||
{
|
||||
var pname = process.ProcessName.ToLower();
|
||||
// 只允许WPS/WPP相关进程,排除PowerPoint及微软Office
|
||||
if ((pname.Contains("wps") || pname.Contains("wpp") || pname.Contains("presentation"))
|
||||
// 排除PowerPoint官方进程
|
||||
&& !pname.Contains("powerpnt"))
|
||||
&& !pname.Contains("powerpnt")
|
||||
&& !pname.Contains("office")
|
||||
&& !pname.Contains("onenote")
|
||||
&& !pname.Contains("excel")
|
||||
&& !pname.Contains("word")
|
||||
&& !pname.Contains("outlook")
|
||||
&& !pname.Contains("microsoft"))
|
||||
{
|
||||
wpsProcesses.Add(process);
|
||||
LogHelper.WriteLogToFile($"发现WPS进程: {process.ProcessName} (PID: {process.Id})", LogHelper.LogType.Trace);
|
||||
|
||||
@@ -105,8 +105,8 @@ namespace Ink_Canvas {
|
||||
timerDisplayDate.Interval = 1000 * 60 * 60 * 1;
|
||||
timerDisplayDate.Start();
|
||||
timerKillProcess.Start();
|
||||
nowTimeVM.nowDate = DateTime.Now.ToShortDateString().ToString();
|
||||
nowTimeVM.nowTime = DateTime.Now.ToShortTimeString().ToString();
|
||||
nowTimeVM.nowDate = DateTime.Now.ToString("yyyy/M/d");
|
||||
nowTimeVM.nowTime = DateTime.Now.ToString("HH:mm");
|
||||
}
|
||||
|
||||
private async Task TimerDisplayTime_ElapsedAsync()
|
||||
@@ -115,12 +115,12 @@ namespace Ink_Canvas {
|
||||
// 只更新时间,日期由原有逻辑定时更新即可
|
||||
Dispatcher.Invoke(() =>
|
||||
{
|
||||
nowTimeVM.nowTime = now.ToShortTimeString();
|
||||
nowTimeVM.nowTime = now.ToString("HH:mm");
|
||||
});
|
||||
}
|
||||
|
||||
private void TimerDisplayDate_Elapsed(object sender, ElapsedEventArgs e) {
|
||||
nowTimeVM.nowDate = DateTime.Now.ToShortDateString().ToString();
|
||||
nowTimeVM.nowDate = DateTime.Now.ToString("yyyy/M/d");
|
||||
}
|
||||
|
||||
private void TimerKillProcess_Elapsed(object sender, ElapsedEventArgs e) {
|
||||
|
||||
@@ -49,5 +49,5 @@ using System.Windows;
|
||||
// You can specify all the values or you can default the Build and Revision Numbers
|
||||
// by using the '*' as shown below:
|
||||
// [assembly: AssemblyVersion("1.0.*")]
|
||||
[assembly: AssemblyVersion("1.7.1.14")]
|
||||
[assembly: AssemblyFileVersion("1.7.1.14")]
|
||||
[assembly: AssemblyVersion("1.7.2.0")]
|
||||
[assembly: AssemblyFileVersion("1.7.2.0")]
|
||||
|
||||
@@ -437,6 +437,9 @@ namespace Ink_Canvas
|
||||
|
||||
[JsonProperty("isAutoBackupBeforeUpdate")]
|
||||
public bool IsAutoBackupBeforeUpdate { get; set; } = true;
|
||||
|
||||
[JsonProperty("isNoFocusMode")]
|
||||
public bool IsNoFocusMode { get; set; } = true;
|
||||
}
|
||||
|
||||
public class InkToShape
|
||||
|
||||
+31
-1
@@ -1 +1,31 @@
|
||||
1. 更新了自动更新
|
||||
1. 改进端点吸附
|
||||
2. 新增自定义浮动栏图标
|
||||
3. 新增自定义点名背景
|
||||
4. 新增退出收纳模式自动进入批注选项
|
||||
5. 改进自动更新
|
||||
6. 改进进程检测
|
||||
7. 改进设置侧边栏
|
||||
8. 修复PPT联动模块
|
||||
9. 修复使用正方形预设时多出来一条直线
|
||||
10. 新增白板自定义调色盘
|
||||
11. 改进手掌擦逻辑
|
||||
12. 新增并改进了插件功能
|
||||
13. 修复大量触摸问题
|
||||
14. 改进橡皮
|
||||
15. 新增设置配置备份功能
|
||||
16. 新增墨迹全屏保存功能
|
||||
17. 修复win7下的自动更新不可用的问题
|
||||
18. 改进墨迹打开功能
|
||||
19. 改进插件功能及启动台插件
|
||||
20. 改进墨迹平滑方案
|
||||
21. 改进窗口无焦点
|
||||
22. 修复白板页面预览不可触摸的问题
|
||||
23. 新增插入图片功能
|
||||
24. 新增侧边栏退出放映按钮
|
||||
25. 新增退出PPT自动恢复收纳模式
|
||||
26. 新增PPT自动回到首页
|
||||
27. 新增查杀鸿合屏幕书写后进入批注
|
||||
28. 修复浮动栏高度计算
|
||||
29. 修复墨迹错页
|
||||
30. 改进直线拉直
|
||||
31. 改进白板时间显示
|
||||
|
||||
Reference in New Issue
Block a user