This commit is contained in:
2025-09-13 15:34:50 +08:00
parent 9628d1b27f
commit 13594371bb
6 changed files with 1922 additions and 0 deletions
@@ -0,0 +1,393 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using Ink_Canvas.Helpers;
namespace Ink_Canvas
{
/// <summary>
/// 悬浮窗拦截管理器
/// </summary>
public class FloatingWindowInterceptorManager : IDisposable
{
#region
private FloatingWindowInterceptor _interceptor;
private bool _isInitialized;
private bool _disposed;
private FloatingWindowInterceptorSettings _settings;
#endregion
#region
public event EventHandler<FloatingWindowInterceptor.WindowInterceptedEventArgs> WindowIntercepted;
public event EventHandler<FloatingWindowInterceptor.WindowRestoredEventArgs> WindowRestored;
#endregion
#region
public bool IsEnabled => _interceptor != null && _settings != null && _settings.IsEnabled;
public bool IsRunning => _interceptor != null && _isInitialized;
#endregion
#region
/// <summary>
/// 初始化拦截器
/// </summary>
public void Initialize(FloatingWindowInterceptorSettings settings)
{
if (_isInitialized) return;
try
{
_settings = settings ?? new FloatingWindowInterceptorSettings();
_interceptor = new FloatingWindowInterceptor();
// 订阅事件
_interceptor.WindowIntercepted += OnWindowIntercepted;
_interceptor.WindowRestored += OnWindowRestored;
// 应用配置
ApplySettings();
_isInitialized = true;
// 如果设置了自动启动,则启动拦截器
if (_settings.AutoStart && _settings.IsEnabled)
{
Start();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化悬浮窗拦截器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 启动拦截器
/// </summary>
public void Start()
{
if (!_isInitialized || _settings == null) return;
if (_interceptor == null) return;
try
{
_interceptor.Start(_settings.ScanIntervalMs);
LogHelper.WriteLogToFile("悬浮窗拦截器已启动", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动悬浮窗拦截器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 停止拦截器
/// </summary>
public void Stop()
{
if (_interceptor == null) return;
try
{
_interceptor.Stop();
LogHelper.WriteLogToFile("悬浮窗拦截器已停止", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"停止悬浮窗拦截器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 设置拦截规则
/// </summary>
public void SetInterceptRule(FloatingWindowInterceptor.InterceptType type, bool enabled)
{
if (_interceptor == null || _settings == null) return;
try
{
_interceptor.SetInterceptRule(type, enabled);
// 更新设置
var ruleName = type.ToString();
if (_settings.InterceptRules.ContainsKey(ruleName))
{
_settings.InterceptRules[ruleName] = enabled;
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置拦截规则失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 获取拦截规则
/// </summary>
public FloatingWindowInterceptor.InterceptRule GetInterceptRule(FloatingWindowInterceptor.InterceptType type)
{
return _interceptor?.GetInterceptRule(type);
}
/// <summary>
/// 获取所有拦截规则
/// </summary>
public Dictionary<FloatingWindowInterceptor.InterceptType, FloatingWindowInterceptor.InterceptRule> GetAllRules()
{
return _interceptor?.GetAllRules() ?? new Dictionary<FloatingWindowInterceptor.InterceptType, FloatingWindowInterceptor.InterceptRule>();
}
/// <summary>
/// 手动扫描一次
/// </summary>
public void ScanOnce()
{
if (_interceptor == null) return;
try
{
_interceptor.ScanOnce();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"手动扫描失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 调试:列出所有可见窗口
/// </summary>
public void DebugListAllWindows()
{
if (_interceptor == null)
{
LogHelper.WriteLogToFile("拦截器未初始化,无法进行调试", LogHelper.LogType.Warning);
return;
}
try
{
LogHelper.WriteLogToFile("开始调试扫描所有可见窗口...", LogHelper.LogType.Event);
// 直接调用扫描方法,在扫描过程中会输出调试信息
_interceptor.ScanOnce();
LogHelper.WriteLogToFile("调试扫描完成,请查看日志文件获取详细信息", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"调试列出窗口失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 恢复所有被拦截的窗口
/// </summary>
public void RestoreAllWindows()
{
if (_interceptor == null) return;
try
{
_interceptor.RestoreAllWindows();
LogHelper.WriteLogToFile("已恢复所有被拦截的窗口", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"恢复窗口失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 应用设置
/// </summary>
public void ApplySettings()
{
if (_interceptor == null || _settings == null) return;
try
{
// 应用拦截规则设置
foreach (var kvp in _settings.InterceptRules)
{
if (Enum.TryParse<FloatingWindowInterceptor.InterceptType>(kvp.Key, out var type))
{
_interceptor.SetInterceptRule(type, kvp.Value);
}
}
// 如果启用了拦截器,则启动
if (_settings.IsEnabled && !IsRunning)
{
Start();
}
// 如果禁用了拦截器,则停止
else if (!_settings.IsEnabled && IsRunning)
{
Stop();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用设置失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 更新扫描间隔
/// </summary>
public void UpdateScanInterval(int intervalMs)
{
if (_interceptor == null || _settings == null) return;
try
{
_settings.ScanIntervalMs = intervalMs;
// 如果正在运行,重启以应用新间隔
if (IsRunning)
{
Stop();
Start();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新扫描间隔失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 获取拦截统计信息
/// </summary>
public InterceptStatistics GetStatistics()
{
if (_interceptor == null || _settings == null) return new InterceptStatistics();
try
{
var rules = GetAllRules();
var enabledRules = rules.Count(r => r.Value.IsEnabled);
var totalRules = rules.Count;
return new InterceptStatistics
{
TotalRules = totalRules,
EnabledRules = enabledRules,
IsRunning = IsRunning,
ScanIntervalMs = _settings.ScanIntervalMs
};
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"获取统计信息失败: {ex.Message}", LogHelper.LogType.Error);
return new InterceptStatistics();
}
}
#endregion
#region
private void OnWindowIntercepted(object sender, FloatingWindowInterceptor.WindowInterceptedEventArgs e)
{
try
{
// 记录日志
LogHelper.WriteLogToFile($"拦截窗口: {e.WindowTitle} ({e.InterceptType})", LogHelper.LogType.Event);
// 显示通知(如果启用)
if (_settings != null && _settings.ShowNotifications)
{
ShowNotification($"已拦截悬浮窗: {e.Rule.Description}");
}
// 触发事件
WindowIntercepted?.Invoke(this, e);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理窗口拦截事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void OnWindowRestored(object sender, FloatingWindowInterceptor.WindowRestoredEventArgs e)
{
try
{
// 记录日志
LogHelper.WriteLogToFile($"恢复窗口: {e.InterceptType}", LogHelper.LogType.Event);
// 触发事件
WindowRestored?.Invoke(this, e);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理窗口恢复事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
private void ShowNotification(string message)
{
try
{
// 这里可以集成系统通知或自定义通知
// 暂时使用调试输出
System.Diagnostics.Debug.WriteLine($"通知: {message}");
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"显示通知失败: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
#region
public class InterceptStatistics
{
public int TotalRules { get; set; }
public int EnabledRules { get; set; }
public bool IsRunning { get; set; }
public int ScanIntervalMs { get; set; }
}
#endregion
#region IDisposable
public void Dispose()
{
if (_disposed) return;
try
{
Stop();
_interceptor?.Dispose();
_interceptor = null;
_isInitialized = false;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"释放悬浮窗拦截器失败: {ex.Message}", LogHelper.LogType.Error);
}
finally
{
_disposed = true;
}
}
#endregion
}
}
@@ -0,0 +1,775 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
namespace Ink_Canvas.Helpers
{
/// <summary>
/// 悬浮窗拦截器 - 检测和隐藏指定的悬浮窗
/// </summary>
public class FloatingWindowInterceptor : IDisposable
{
#region Windows API Declarations
[DllImport("user32.dll")]
private static extern bool EnumWindows(EnumWindowsProc enumProc, IntPtr lParam);
[DllImport("user32.dll")]
private static extern IntPtr GetWindowThreadProcessId(IntPtr hWnd, out uint processId);
[DllImport("user32.dll")]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll")]
private static extern int GetClassName(IntPtr hWnd, StringBuilder lpClassName, int nMaxCount);
[DllImport("user32.dll")]
private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern IntPtr GetWindow(IntPtr hWnd, uint uCmd);
[DllImport("user32.dll")]
private static extern uint GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndInsertAfter, int X, int Y, int cx, int cy, uint uFlags);
[DllImport("user32.dll")]
private static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool GetWindowRect(IntPtr hWnd, out ForegroundWindowInfo.RECT lpRect);
[DllImport("kernel32.dll")]
private static extern IntPtr OpenProcess(uint dwDesiredAccess, bool bInheritHandle, uint dwProcessId);
[DllImport("kernel32.dll")]
private static extern bool CloseHandle(IntPtr hObject);
[DllImport("kernel32.dll")]
private static extern int GetProcessImageFileName(IntPtr hProcess, StringBuilder lpImageFileName, int nSize);
private delegate bool EnumWindowsProc(IntPtr hWnd, IntPtr lParam);
private const int SW_HIDE = 0;
private const int SW_SHOW = 1;
private const int SW_MINIMIZE = 6;
private const int SW_RESTORE = 9;
private const int GWL_EXSTYLE = -20;
private const uint WS_EX_TOOLWINDOW = 0x00000080;
private const uint WS_EX_APPWINDOW = 0x00040000;
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOZORDER = 0x0004;
private const uint SWP_HIDEWINDOW = 0x0080;
private const uint PROCESS_QUERY_INFORMATION = 0x0400;
private const uint PROCESS_VM_READ = 0x0010;
#endregion
#region
/// <summary>
/// 拦截规则类型
/// </summary>
public enum InterceptType
{
/// <summary>
/// 希沃白板3 桌面悬浮窗
/// </summary>
SeewoWhiteboard3Floating,
/// <summary>
/// 希沃白板5 桌面悬浮窗
/// </summary>
SeewoWhiteboard5Floating,
/// <summary>
/// 希沃白板5C 桌面悬浮窗
/// </summary>
SeewoWhiteboard5CFloating,
/// <summary>
/// 希沃品课教师端 桌面悬浮窗
/// </summary>
SeewoPincoSideBarFloating,
/// <summary>
/// 希沃品课教师端 画笔悬浮窗(包括PPT控件)
/// </summary>
SeewoPincoDrawingFloating,
/// <summary>
/// 希沃PPT小工具
/// </summary>
SeewoPPTFloating,
/// <summary>
/// AiClass 桌面悬浮窗
/// </summary>
AiClassFloating,
/// <summary>
/// 鸿合屏幕书写
/// </summary>
HiteAnnotationFloating,
/// <summary>
/// 畅言智慧课堂 桌面悬浮窗
/// </summary>
ChangYanFloating,
/// <summary>
/// 畅言智慧课堂 PPT悬浮窗
/// </summary>
ChangYanPptFloating,
/// <summary>
/// 天喻教育云互动课堂 桌面悬浮窗(包括PPT控件)
/// </summary>
IntelligentClassFloating,
/// <summary>
/// 希沃桌面 画笔悬浮窗
/// </summary>
SeewoDesktopAnnotationFloating,
/// <summary>
/// 希沃桌面 侧栏悬浮窗
/// </summary>
SeewoDesktopSideBarFloating
}
/// <summary>
/// 拦截规则
/// </summary>
public class InterceptRule
{
public InterceptType Type { get; set; }
public string ProcessName { get; set; }
public string WindowTitlePattern { get; set; }
public string ClassNamePattern { get; set; }
public bool IsEnabled { get; set; }
public bool RequiresAdmin { get; set; }
public string Description { get; set; }
}
#endregion
#region
private readonly Dictionary<InterceptType, InterceptRule> _interceptRules;
private readonly Dictionary<IntPtr, InterceptType> _interceptedWindows;
private readonly Timer _scanTimer;
private readonly Dispatcher _dispatcher;
private bool _isRunning;
private bool _disposed;
#endregion
#region
public event EventHandler<WindowInterceptedEventArgs> WindowIntercepted;
public event EventHandler<WindowRestoredEventArgs> WindowRestored;
#endregion
#region
public FloatingWindowInterceptor()
{
_interceptRules = new Dictionary<InterceptType, InterceptRule>();
_interceptedWindows = new Dictionary<IntPtr, InterceptType>();
_dispatcher = Dispatcher.CurrentDispatcher;
InitializeRules();
_scanTimer = new Timer(ScanForWindows, null, Timeout.Infinite, Timeout.Infinite);
}
#endregion
#region
private void InitializeRules()
{
// 希沃白板3 桌面悬浮窗
_interceptRules[InterceptType.SeewoWhiteboard3Floating] = new InterceptRule
{
Type = InterceptType.SeewoWhiteboard3Floating,
ProcessName = "EasiNote3",
WindowTitlePattern = "",
ClassNamePattern = "",
IsEnabled = true,
RequiresAdmin = false,
Description = "希沃白板3 桌面悬浮窗"
};
// 希沃白板5 桌面悬浮窗
_interceptRules[InterceptType.SeewoWhiteboard5Floating] = new InterceptRule
{
Type = InterceptType.SeewoWhiteboard5Floating,
ProcessName = "EasiNote5",
WindowTitlePattern = "",
ClassNamePattern = "",
IsEnabled = true,
RequiresAdmin = false,
Description = "希沃白板5 桌面悬浮窗"
};
// 希沃白板5C 桌面悬浮窗
_interceptRules[InterceptType.SeewoWhiteboard5CFloating] = new InterceptRule
{
Type = InterceptType.SeewoWhiteboard5CFloating,
ProcessName = "EasiNote5C",
WindowTitlePattern = "希沃白板",
ClassNamePattern = "EasiNote5C",
IsEnabled = true,
RequiresAdmin = false,
Description = "希沃白板5C 桌面悬浮窗"
};
// 希沃品课教师端 桌面悬浮窗
_interceptRules[InterceptType.SeewoPincoSideBarFloating] = new InterceptRule
{
Type = InterceptType.SeewoPincoSideBarFloating,
ProcessName = "SeewoPinco",
WindowTitlePattern = "品课",
ClassNamePattern = "SeewoPinco",
IsEnabled = true,
RequiresAdmin = false,
Description = "希沃品课教师端 桌面悬浮窗"
};
// 希沃品课教师端 画笔悬浮窗
_interceptRules[InterceptType.SeewoPincoDrawingFloating] = new InterceptRule
{
Type = InterceptType.SeewoPincoDrawingFloating,
ProcessName = "SeewoPinco",
WindowTitlePattern = "画笔",
ClassNamePattern = "SeewoPinco",
IsEnabled = true,
RequiresAdmin = false,
Description = "希沃品课教师端 画笔悬浮窗(包括PPT控件)"
};
// 希沃PPT小工具
_interceptRules[InterceptType.SeewoPPTFloating] = new InterceptRule
{
Type = InterceptType.SeewoPPTFloating,
ProcessName = "SeewoPPT",
WindowTitlePattern = "希沃PPT",
ClassNamePattern = "SeewoPPT",
IsEnabled = true,
RequiresAdmin = false,
Description = "希沃PPT小工具"
};
// AiClass 桌面悬浮窗
_interceptRules[InterceptType.AiClassFloating] = new InterceptRule
{
Type = InterceptType.AiClassFloating,
ProcessName = "AiClass",
WindowTitlePattern = "AiClass",
ClassNamePattern = "AiClass",
IsEnabled = true,
RequiresAdmin = false,
Description = "AiClass 桌面悬浮窗"
};
// 鸿合屏幕书写
_interceptRules[InterceptType.HiteAnnotationFloating] = new InterceptRule
{
Type = InterceptType.HiteAnnotationFloating,
ProcessName = "HiteAnnotation",
WindowTitlePattern = "鸿合",
ClassNamePattern = "HiteAnnotation",
IsEnabled = true,
RequiresAdmin = false,
Description = "鸿合屏幕书写"
};
// 畅言智慧课堂 桌面悬浮窗
_interceptRules[InterceptType.ChangYanFloating] = new InterceptRule
{
Type = InterceptType.ChangYanFloating,
ProcessName = "ChangYan",
WindowTitlePattern = "畅言",
ClassNamePattern = "ChangYan",
IsEnabled = true,
RequiresAdmin = true,
Description = "畅言智慧课堂 桌面悬浮窗"
};
// 畅言智慧课堂 PPT悬浮窗
_interceptRules[InterceptType.ChangYanPptFloating] = new InterceptRule
{
Type = InterceptType.ChangYanPptFloating,
ProcessName = "ChangYanPPT",
WindowTitlePattern = "畅言PPT",
ClassNamePattern = "ChangYanPPT",
IsEnabled = true,
RequiresAdmin = true,
Description = "畅言智慧课堂 PPT悬浮窗"
};
// 天喻教育云互动课堂 桌面悬浮窗
_interceptRules[InterceptType.IntelligentClassFloating] = new InterceptRule
{
Type = InterceptType.IntelligentClassFloating,
ProcessName = "IntelligentClass",
WindowTitlePattern = "天喻",
ClassNamePattern = "IntelligentClass",
IsEnabled = true,
RequiresAdmin = false,
Description = "天喻教育云互动课堂 桌面悬浮窗(包括PPT控件)"
};
// 希沃桌面 画笔悬浮窗
_interceptRules[InterceptType.SeewoDesktopAnnotationFloating] = new InterceptRule
{
Type = InterceptType.SeewoDesktopAnnotationFloating,
ProcessName = "SeewoDesktop",
WindowTitlePattern = "希沃桌面",
ClassNamePattern = "SeewoDesktop",
IsEnabled = true,
RequiresAdmin = false,
Description = "希沃桌面 画笔悬浮窗"
};
// 希沃桌面 侧栏悬浮窗
_interceptRules[InterceptType.SeewoDesktopSideBarFloating] = new InterceptRule
{
Type = InterceptType.SeewoDesktopSideBarFloating,
ProcessName = "SeewoDesktop",
WindowTitlePattern = "希沃桌面",
ClassNamePattern = "SeewoDesktop",
IsEnabled = true,
RequiresAdmin = true,
Description = "希沃桌面 侧栏悬浮窗"
};
// 测试规则 - 拦截所有小窗口
_interceptRules[InterceptType.SeewoWhiteboard3Floating] = new InterceptRule
{
Type = InterceptType.SeewoWhiteboard3Floating,
ProcessName = "", // 空字符串表示匹配所有进程
WindowTitlePattern = "",
ClassNamePattern = "",
IsEnabled = false, // 默认关闭,需要手动开启
RequiresAdmin = false,
Description = "测试规则 - 拦截所有小窗口"
};
}
#endregion
#region
/// <summary>
/// 启动拦截器
/// </summary>
public void Start(int scanIntervalMs = 5000)
{
if (_isRunning) return;
_isRunning = true;
_scanTimer.Change(0, scanIntervalMs);
}
/// <summary>
/// 停止拦截器
/// </summary>
public void Stop()
{
if (!_isRunning) return;
_isRunning = false;
_scanTimer.Change(Timeout.Infinite, Timeout.Infinite);
}
/// <summary>
/// 设置拦截规则
/// </summary>
public void SetInterceptRule(InterceptType type, bool enabled)
{
if (_interceptRules.ContainsKey(type))
{
_interceptRules[type].IsEnabled = enabled;
}
}
/// <summary>
/// 获取拦截规则
/// </summary>
public InterceptRule GetInterceptRule(InterceptType type)
{
return _interceptRules.ContainsKey(type) ? _interceptRules[type] : null;
}
/// <summary>
/// 获取所有拦截规则
/// </summary>
public Dictionary<InterceptType, InterceptRule> GetAllRules()
{
return new Dictionary<InterceptType, InterceptRule>(_interceptRules);
}
/// <summary>
/// 手动扫描一次
/// </summary>
public void ScanOnce()
{
ScanForWindows(null);
}
/// <summary>
/// 恢复所有被拦截的窗口
/// </summary>
public void RestoreAllWindows()
{
var windowsToRestore = new List<IntPtr>(_interceptedWindows.Keys);
foreach (var hWnd in windowsToRestore)
{
RestoreWindow(hWnd);
}
}
/// <summary>
/// 恢复指定窗口
/// </summary>
public bool RestoreWindow(IntPtr hWnd)
{
if (!_interceptedWindows.ContainsKey(hWnd)) return false;
if (IsWindow(hWnd))
{
ShowWindow(hWnd, SW_RESTORE);
_interceptedWindows.Remove(hWnd);
WindowRestored?.Invoke(this, new WindowRestoredEventArgs
{
WindowHandle = hWnd,
InterceptType = _interceptedWindows[hWnd]
});
return true;
}
_interceptedWindows.Remove(hWnd);
return false;
}
#endregion
#region
private void ScanForWindows(object state)
{
if (!_isRunning) return;
try
{
EnumWindows(EnumWindowsCallback, IntPtr.Zero);
}
catch (Exception ex)
{
// 记录错误但不中断扫描
LogHelper.WriteLogToFile($"扫描窗口时发生错误: {ex.Message}", LogHelper.LogType.Error);
}
}
private bool EnumWindowsCallback(IntPtr hWnd, IntPtr lParam)
{
try
{
// 基本检查
if (!IsWindow(hWnd) || !IsWindowVisible(hWnd)) return true;
// 检查是否已经被拦截
if (_interceptedWindows.ContainsKey(hWnd)) return true;
// 获取窗口信息
var windowInfo = GetWindowInfo(hWnd);
if (windowInfo == null) return true;
// 输出调试信息到日志
LogHelper.WriteLogToFile($"检测到窗口: '{windowInfo.WindowTitle}' | 进程: '{windowInfo.ProcessName}' | 类名: '{windowInfo.ClassName}'", LogHelper.LogType.Event);
// 检查窗口样式,过滤掉系统窗口和主窗口
var exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
var style = GetWindowLong(hWnd, -16); // GWL_STYLE
// 跳过工具窗口
if ((exStyle & WS_EX_TOOLWINDOW) != 0)
{
LogHelper.WriteLogToFile($"跳过工具窗口: {windowInfo.WindowTitle}", LogHelper.LogType.Event);
return true;
}
// 跳过主窗口(有标题栏和系统菜单的窗口)
const uint WS_CAPTION = 0x00C00000;
const uint WS_SYSMENU = 0x00080000;
if ((style & WS_CAPTION) != 0 && (style & WS_SYSMENU) != 0)
{
LogHelper.WriteLogToFile($"跳过主窗口: {windowInfo.WindowTitle}", LogHelper.LogType.Event);
return true;
}
// 检查窗口大小,跳过过大的窗口
var rect = new ForegroundWindowInfo.RECT();
GetWindowRect(hWnd, out rect);
var width = rect.Right - rect.Left;
var height = rect.Bottom - rect.Top;
if (width > 600 || height > 400)
{
LogHelper.WriteLogToFile($"跳过大窗口 ({width}x{height}): {windowInfo.WindowTitle}", LogHelper.LogType.Event);
return true;
}
// 检查是否匹配拦截规则
foreach (var rule in _interceptRules.Values)
{
if (!rule.IsEnabled) continue;
if (MatchesRule(windowInfo, rule))
{
LogHelper.WriteLogToFile($"匹配规则 '{rule.Description}',开始拦截窗口: {windowInfo.WindowTitle}", LogHelper.LogType.Event);
InterceptWindow(hWnd, rule);
break;
}
}
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理窗口时发生错误: {ex.Message}", LogHelper.LogType.Error);
return true;
}
}
private WindowInfo GetWindowInfo(IntPtr hWnd)
{
try
{
// 获取进程ID
GetWindowThreadProcessId(hWnd, out uint processId);
if (processId == 0) return null;
// 获取进程信息
var process = Process.GetProcessById((int)processId);
if (process == null) return null;
// 获取窗口标题
var titleBuilder = new StringBuilder(256);
GetWindowText(hWnd, titleBuilder, titleBuilder.Capacity);
// 获取窗口类名
var classBuilder = new StringBuilder(256);
GetClassName(hWnd, classBuilder, classBuilder.Capacity);
return new WindowInfo
{
Handle = hWnd,
ProcessId = processId,
ProcessName = process.ProcessName,
WindowTitle = titleBuilder.ToString(),
ClassName = classBuilder.ToString(),
Process = process
};
}
catch
{
return null;
}
}
private bool MatchesRule(WindowInfo windowInfo, InterceptRule rule)
{
try
{
// 检查进程名(如果指定了进程名)
if (!string.IsNullOrEmpty(rule.ProcessName))
{
if (!windowInfo.ProcessName.ToLower().Contains(rule.ProcessName.ToLower()))
{
return false;
}
}
// 检查窗口标题(如果指定了模式)
if (!string.IsNullOrEmpty(rule.WindowTitlePattern))
{
if (!windowInfo.WindowTitle.ToLower().Contains(rule.WindowTitlePattern.ToLower()))
{
return false;
}
}
// 检查类名(如果指定了模式)
if (!string.IsNullOrEmpty(rule.ClassNamePattern))
{
if (!windowInfo.ClassName.ToLower().Contains(rule.ClassNamePattern.ToLower()))
{
return false;
}
}
// 如果所有检查都通过,就认为是目标窗口
return true;
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"匹配规则时发生错误: {ex.Message}", LogHelper.LogType.Error);
return false;
}
}
private void InterceptWindow(IntPtr hWnd, InterceptRule rule)
{
try
{
// 使用多种方法隐藏窗口
// 方法1:移动到屏幕外
SetWindowPos(hWnd, IntPtr.Zero, -2000, -2000, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOZORDER | SWP_HIDEWINDOW);
// 方法2:最小化窗口
ShowWindow(hWnd, SW_MINIMIZE);
// 方法3:隐藏窗口
ShowWindow(hWnd, SW_HIDE);
// 记录拦截的窗口
_interceptedWindows[hWnd] = rule.Type;
LogHelper.WriteLogToFile($"成功拦截窗口: {GetWindowTitle(hWnd)}", LogHelper.LogType.Event);
// 触发事件
WindowIntercepted?.Invoke(this, new WindowInterceptedEventArgs
{
WindowHandle = hWnd,
InterceptType = rule.Type,
Rule = rule,
WindowTitle = GetWindowTitle(hWnd)
});
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"拦截窗口时发生错误: {ex.Message}", LogHelper.LogType.Error);
}
}
private string GetWindowTitle(IntPtr hWnd)
{
try
{
var titleBuilder = new StringBuilder(256);
GetWindowText(hWnd, titleBuilder, titleBuilder.Capacity);
return titleBuilder.ToString();
}
catch
{
return "Unknown";
}
}
private bool IsMainWindow(IntPtr hWnd)
{
try
{
// 检查是否有父窗口
var parent = GetWindow(hWnd, 4); // GW_OWNER
if (parent != IntPtr.Zero) return false;
// 检查窗口样式
var style = GetWindowLong(hWnd, -16); // GWL_STYLE
var exStyle = GetWindowLong(hWnd, GWL_EXSTYLE);
// 主窗口通常有 WS_CAPTION 和 WS_SYSMENU
const uint WS_CAPTION = 0x00C00000;
const uint WS_SYSMENU = 0x00080000;
const uint WS_MINIMIZEBOX = 0x00020000;
const uint WS_MAXIMIZEBOX = 0x00010000;
if ((style & WS_CAPTION) != 0 && (style & WS_SYSMENU) != 0)
{
return true; // 这可能是主窗口
}
// 检查窗口大小,主窗口通常比较大
var rect = new ForegroundWindowInfo.RECT();
GetWindowRect(hWnd, out rect);
var width = rect.Right - rect.Left;
var height = rect.Bottom - rect.Top;
// 如果窗口很大,可能是主窗口
if (width > 800 && height > 600)
{
return true;
}
return false;
}
catch
{
return false;
}
}
#endregion
#region
private class WindowInfo
{
public IntPtr Handle { get; set; }
public uint ProcessId { get; set; }
public string ProcessName { get; set; }
public string WindowTitle { get; set; }
public string ClassName { get; set; }
public Process Process { get; set; }
}
#endregion
#region
public class WindowInterceptedEventArgs : EventArgs
{
public IntPtr WindowHandle { get; set; }
public InterceptType InterceptType { get; set; }
public InterceptRule Rule { get; set; }
public string WindowTitle { get; set; }
}
public class WindowRestoredEventArgs : EventArgs
{
public IntPtr WindowHandle { get; set; }
public InterceptType InterceptType { get; set; }
}
#endregion
#region IDisposable
public void Dispose()
{
if (_disposed) return;
Stop();
_scanTimer?.Dispose();
// 恢复所有被拦截的窗口
RestoreAllWindows();
_disposed = true;
}
#endregion
}
}
+249
View File
@@ -2745,6 +2745,255 @@
</ui:SimpleStackPanel>
<TextBlock Name="TextBlockFileAssociationStatus" Text=""
Foreground="#a1a1aa" FontSize="12" Margin="0,4,0,0" />
<!-- 悬浮窗拦截功能 -->
<Line HorizontalAlignment="Center" X1="0" Y1="0" X2="400" Y2="0" Stroke="#3f3f46"
StrokeThickness="1" Margin="0,8,0,8" />
<TextBlock Text="悬浮窗拦截" FontWeight="Bold" Foreground="#fafafa"
FontSize="16" Margin="0,8,0,8" />
<TextBlock Text="自动检测并隐藏教育软件的悬浮窗,保持桌面整洁"
TextWrapping="Wrap" Foreground="#a1a1aa" Margin="0,0,0,8" />
<!-- 主控制开关 -->
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,0,0,8">
<TextBlock Foreground="#fafafa" Text="启用悬浮窗拦截" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
<ui:ToggleSwitch OnContent="" OffContent=""
Name="ToggleSwitchFloatingWindowInterceptorEnabled" IsOn="False"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchFloatingWindowInterceptorEnabled_Toggled" />
</ui:SimpleStackPanel>
<!-- 拦截规则网格 -->
<Grid Name="FloatingWindowInterceptorGrid" Margin="4,0" Visibility="Collapsed">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
<!-- 希沃白板3 -->
<ui:SimpleStackPanel Grid.Row="0" Grid.Column="0" Orientation="Vertical">
<Image Source="/Resources/Icons-png/EasiNote3.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="希沃白板3" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchSeewoWhiteboard3Floating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchSeewoWhiteboard3Floating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 希沃白板5 -->
<ui:SimpleStackPanel Grid.Row="0" Grid.Column="1" Orientation="Vertical">
<Image Source="/Resources/Icons-png/EasiNote.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="希沃白板5" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchSeewoWhiteboard5Floating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchSeewoWhiteboard5Floating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 希沃白板5C -->
<ui:SimpleStackPanel Grid.Row="0" Grid.Column="2" Orientation="Vertical">
<Image Source="/Resources/Icons-png/EasiNote5C.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="希沃白板5C" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchSeewoWhiteboard5CFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchSeewoWhiteboard5CFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 希沃品课 -->
<ui:SimpleStackPanel Grid.Row="0" Grid.Column="3" Orientation="Vertical">
<Image Source="/Resources/Icons-png/SeewoPinco.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="希沃品课" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchSeewoPincoSideBarFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchSeewoPincoSideBarFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 希沃品课画笔 -->
<ui:SimpleStackPanel Grid.Row="1" Grid.Column="0" Orientation="Vertical">
<Image Source="/Resources/Icons-png/SeewoPinco.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="希沃品课画笔" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchSeewoPincoDrawingFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchSeewoPincoDrawingFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 希沃PPT小工具 -->
<ui:SimpleStackPanel Grid.Row="1" Grid.Column="1" Orientation="Vertical">
<Image Source="/Resources/Icons-png/PPTTools.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="希沃PPT小工具" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchSeewoPPTFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchSeewoPPTFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- AiClass -->
<ui:SimpleStackPanel Grid.Row="1" Grid.Column="2" Orientation="Vertical">
<Image Source="/Resources/Icons-png/AiClass.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="AiClass" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchAiClassFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchAiClassFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 鸿合屏幕书写 -->
<ui:SimpleStackPanel Grid.Row="1" Grid.Column="3" Orientation="Vertical">
<Image Source="/Resources/Icons-png/HiteAnnotation.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="鸿合屏幕书写" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchHiteAnnotationFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchHiteAnnotationFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 畅言智慧课堂 -->
<ui:SimpleStackPanel Grid.Row="2" Grid.Column="0" Orientation="Vertical">
<Image Source="/Resources/Icons-png/ChangYan.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="畅言智慧课堂" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchChangYanFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchChangYanFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 畅言PPT -->
<ui:SimpleStackPanel Grid.Row="2" Grid.Column="1" Orientation="Vertical">
<Image Source="/Resources/Icons-png/ChangYanPPT.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="畅言PPT" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchChangYanPptFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchChangYanPptFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 天喻教育云 -->
<ui:SimpleStackPanel Grid.Row="2" Grid.Column="2" Orientation="Vertical">
<Image Source="/Resources/Icons-png/IntelligentClass.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="天喻教育云" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchIntelligentClassFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchIntelligentClassFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 希沃桌面画笔 -->
<ui:SimpleStackPanel Grid.Row="2" Grid.Column="3" Orientation="Vertical">
<Image Source="/Resources/Icons-png/SeewoDesktop.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="希沃桌面画笔" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchSeewoDesktopAnnotationFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchSeewoDesktopAnnotationFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
<!-- 希沃桌面侧栏 -->
<ui:SimpleStackPanel Grid.Row="3" Grid.Column="0" Orientation="Vertical">
<Image Source="/Resources/Icons-png/SeewoDesktop.png" Margin="0,0,0,4"
Width="42" Height="42" HorizontalAlignment="Center" />
<TextBlock Foreground="#fafafa" Text="希沃桌面侧栏" HorizontalAlignment="Center"
FontSize="14" Margin="0,0,0,4" />
<ui:ToggleSwitch OnContent="" OffContent="" MinWidth="0"
HorizontalAlignment="Center"
Name="ToggleSwitchSeewoDesktopSideBarFloating" IsOn="True"
FontFamily="Microsoft YaHei UI" FontWeight="Bold"
Toggled="ToggleSwitchSeewoDesktopSideBarFloating_Toggled"
Width="40" />
</ui:SimpleStackPanel>
</Grid>
<!-- 控制按钮 -->
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left" Margin="0,8,0,8">
<Button Name="BtnFloatingWindowInterceptorStart" Content="启动拦截"
Padding="12,6" Margin="0,0,8,0" Click="BtnFloatingWindowInterceptorStart_Click"
Background="#FF28A745" Foreground="White" BorderBrush="#FF1E7E34"
FontFamily="Microsoft YaHei UI" FontSize="12" />
<Button Name="BtnFloatingWindowInterceptorStop" Content="停止拦截"
Padding="12,6" Margin="0,0,8,0" Click="BtnFloatingWindowInterceptorStop_Click"
Background="#FFDC3545" Foreground="White" BorderBrush="#FFBD2130"
FontFamily="Microsoft YaHei UI" FontSize="12" />
<Button Name="BtnFloatingWindowInterceptorScan" Content="手动扫描"
Padding="12,6" Margin="0,0,8,0" Click="BtnFloatingWindowInterceptorScan_Click"
Background="#FF17A2B8" Foreground="White" BorderBrush="#FF138496"
FontFamily="Microsoft YaHei UI" FontSize="12" />
<Button Name="BtnFloatingWindowInterceptorRestore" Content="恢复所有窗口"
Padding="12,6" Margin="0,0,8,0" Click="BtnFloatingWindowInterceptorRestore_Click"
Background="#FF6C757D" Foreground="White" BorderBrush="#FF5A6268"
FontFamily="Microsoft YaHei UI" FontSize="12" />
<Button Name="BtnFloatingWindowInterceptorDebug" Content="调试列出窗口"
Padding="12,6" Margin="0,0,8,0" Click="BtnFloatingWindowInterceptorDebug_Click"
Background="#FF6F42C1" Foreground="White" BorderBrush="#FF5A2D91"
FontFamily="Microsoft YaHei UI" FontSize="12" />
<Button Name="BtnFloatingWindowInterceptorTest" Content="测试拦截"
Padding="12,6" Click="BtnFloatingWindowInterceptorTest_Click"
Background="#FFE83E8C" Foreground="White" BorderBrush="#FFC2185B"
FontFamily="Microsoft YaHei UI" FontSize="12" />
</ui:SimpleStackPanel>
<!-- 状态信息 -->
<TextBlock Name="TextBlockFloatingWindowInterceptorStatus" Text="拦截器未启动"
Foreground="#a1a1aa" FontSize="12" Margin="0,4,0,0" />
<ui:SimpleStackPanel Orientation="Horizontal" HorizontalAlignment="Left">
<TextBlock Foreground="#fafafa" Text="清屏时自动截图" VerticalAlignment="Center"
FontSize="14" Margin="0,0,16,0" />
+6
View File
@@ -50,6 +50,9 @@ namespace Ink_Canvas
// 墨迹渐隐管理器
private InkFadeManager _inkFadeManager;
// 悬浮窗拦截管理器
private FloatingWindowInterceptorManager _floatingWindowInterceptorManager;
// 设置面板相关状态
private bool userChangedNoFocusModeInSettings;
@@ -534,6 +537,9 @@ namespace Ink_Canvas
// 初始化剪贴板监控
InitializeClipboardMonitoring();
// 初始化悬浮窗拦截管理器
InitializeFloatingWindowInterceptor();
// 初始化全局快捷键管理器
InitializeGlobalHotkeyManager();
@@ -0,0 +1,463 @@
using Ink_Canvas.Helpers;
using iNKORE.UI.WPF.Modern.Controls;
using System;
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas
{
public partial class MainWindow : Window
{
#region
/// <summary>
/// 初始化悬浮窗拦截管理器
/// </summary>
private void InitializeFloatingWindowInterceptor()
{
try
{
_floatingWindowInterceptorManager = new FloatingWindowInterceptorManager();
// 订阅事件
_floatingWindowInterceptorManager.WindowIntercepted += OnFloatingWindowIntercepted;
_floatingWindowInterceptorManager.WindowRestored += OnFloatingWindowRestored;
// 初始化拦截器
_floatingWindowInterceptorManager.Initialize(Settings.Automation.FloatingWindowInterceptor);
// 加载UI状态
LoadFloatingWindowInterceptorUI();
LogHelper.WriteLogToFile("悬浮窗拦截管理器初始化完成", LogHelper.LogType.Event);
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"初始化悬浮窗拦截管理器失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 加载悬浮窗拦截UI状态
/// </summary>
private void LoadFloatingWindowInterceptorUI()
{
try
{
if (!isLoaded) return;
// 设置主开关状态
ToggleSwitchFloatingWindowInterceptorEnabled.IsOn = Settings.Automation.FloatingWindowInterceptor.IsEnabled;
// 设置各个拦截规则的状态
foreach (var kvp in Settings.Automation.FloatingWindowInterceptor.InterceptRules)
{
var toggleName = $"ToggleSwitch{kvp.Key}";
var toggle = FindName(toggleName) as ToggleSwitch;
if (toggle != null)
{
toggle.IsOn = kvp.Value;
}
}
// 更新UI可见性
UpdateFloatingWindowInterceptorUI();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"加载悬浮窗拦截UI状态失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 更新悬浮窗拦截UI
/// </summary>
private void UpdateFloatingWindowInterceptorUI()
{
try
{
var isEnabled = Settings.Automation.FloatingWindowInterceptor.IsEnabled;
FloatingWindowInterceptorGrid.Visibility = isEnabled ? Visibility.Visible : Visibility.Collapsed;
// 更新状态文本
if (_floatingWindowInterceptorManager != null)
{
var stats = _floatingWindowInterceptorManager.GetStatistics();
TextBlockFloatingWindowInterceptorStatus.Text = stats.IsRunning
? $"拦截器运行中 - 已启用 {stats.EnabledRules}/{stats.TotalRules} 个规则"
: "拦截器未启动";
}
else
{
TextBlockFloatingWindowInterceptorStatus.Text = "拦截器未初始化";
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"更新悬浮窗拦截UI失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 窗口被拦截事件处理
/// </summary>
private void OnFloatingWindowIntercepted(object sender, FloatingWindowInterceptor.WindowInterceptedEventArgs e)
{
try
{
// 在UI线程中更新状态
Dispatcher.BeginInvoke(new Action(() =>
{
UpdateFloatingWindowInterceptorUI();
}));
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理窗口拦截事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 窗口被恢复事件处理
/// </summary>
private void OnFloatingWindowRestored(object sender, FloatingWindowInterceptor.WindowRestoredEventArgs e)
{
try
{
// 在UI线程中更新状态
Dispatcher.BeginInvoke(new Action(() =>
{
UpdateFloatingWindowInterceptorUI();
}));
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"处理窗口恢复事件失败: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
#region
/// <summary>
/// 主开关切换事件
/// </summary>
private void ToggleSwitchFloatingWindowInterceptorEnabled_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
try
{
Settings.Automation.FloatingWindowInterceptor.IsEnabled = ToggleSwitchFloatingWindowInterceptorEnabled.IsOn;
if (_floatingWindowInterceptorManager != null)
{
if (Settings.Automation.FloatingWindowInterceptor.IsEnabled)
{
_floatingWindowInterceptorManager.Start();
}
else
{
_floatingWindowInterceptorManager.Stop();
}
}
UpdateFloatingWindowInterceptorUI();
SaveSettingsToFile();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换悬浮窗拦截主开关失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 希沃白板3拦截开关
/// </summary>
private void ToggleSwitchSeewoWhiteboard3Floating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoWhiteboard3Floating, ToggleSwitchSeewoWhiteboard3Floating.IsOn);
}
/// <summary>
/// 希沃白板5拦截开关
/// </summary>
private void ToggleSwitchSeewoWhiteboard5Floating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoWhiteboard5Floating, ToggleSwitchSeewoWhiteboard5Floating.IsOn);
}
/// <summary>
/// 希沃白板5C拦截开关
/// </summary>
private void ToggleSwitchSeewoWhiteboard5CFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoWhiteboard5CFloating, ToggleSwitchSeewoWhiteboard5CFloating.IsOn);
}
/// <summary>
/// 希沃品课侧栏拦截开关
/// </summary>
private void ToggleSwitchSeewoPincoSideBarFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoPincoSideBarFloating, ToggleSwitchSeewoPincoSideBarFloating.IsOn);
}
/// <summary>
/// 希沃品课画笔拦截开关
/// </summary>
private void ToggleSwitchSeewoPincoDrawingFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoPincoDrawingFloating, ToggleSwitchSeewoPincoDrawingFloating.IsOn);
}
/// <summary>
/// 希沃PPT小工具拦截开关
/// </summary>
private void ToggleSwitchSeewoPPTFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoPPTFloating, ToggleSwitchSeewoPPTFloating.IsOn);
}
/// <summary>
/// AiClass拦截开关
/// </summary>
private void ToggleSwitchAiClassFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.AiClassFloating, ToggleSwitchAiClassFloating.IsOn);
}
/// <summary>
/// 鸿合屏幕书写拦截开关
/// </summary>
private void ToggleSwitchHiteAnnotationFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.HiteAnnotationFloating, ToggleSwitchHiteAnnotationFloating.IsOn);
}
/// <summary>
/// 畅言智慧课堂拦截开关
/// </summary>
private void ToggleSwitchChangYanFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.ChangYanFloating, ToggleSwitchChangYanFloating.IsOn);
}
/// <summary>
/// 畅言PPT拦截开关
/// </summary>
private void ToggleSwitchChangYanPptFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.ChangYanPptFloating, ToggleSwitchChangYanPptFloating.IsOn);
}
/// <summary>
/// 天喻教育云拦截开关
/// </summary>
private void ToggleSwitchIntelligentClassFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.IntelligentClassFloating, ToggleSwitchIntelligentClassFloating.IsOn);
}
/// <summary>
/// 希沃桌面画笔拦截开关
/// </summary>
private void ToggleSwitchSeewoDesktopAnnotationFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoDesktopAnnotationFloating, ToggleSwitchSeewoDesktopAnnotationFloating.IsOn);
}
/// <summary>
/// 希沃桌面侧栏拦截开关
/// </summary>
private void ToggleSwitchSeewoDesktopSideBarFloating_Toggled(object sender, RoutedEventArgs e)
{
if (!isLoaded) return;
SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoDesktopSideBarFloating, ToggleSwitchSeewoDesktopSideBarFloating.IsOn);
}
/// <summary>
/// 设置拦截规则
/// </summary>
private void SetInterceptRule(FloatingWindowInterceptor.InterceptType type, bool enabled)
{
try
{
if (_floatingWindowInterceptorManager != null)
{
_floatingWindowInterceptorManager.SetInterceptRule(type, enabled);
}
// 更新设置
var ruleName = type.ToString();
if (Settings.Automation.FloatingWindowInterceptor.InterceptRules.ContainsKey(ruleName))
{
Settings.Automation.FloatingWindowInterceptor.InterceptRules[ruleName] = enabled;
}
SaveSettingsToFile();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"设置拦截规则失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 启动拦截按钮点击
/// </summary>
private void BtnFloatingWindowInterceptorStart_Click(object sender, RoutedEventArgs e)
{
try
{
if (_floatingWindowInterceptorManager != null)
{
_floatingWindowInterceptorManager.Start();
UpdateFloatingWindowInterceptorUI();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启动悬浮窗拦截失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 停止拦截按钮点击
/// </summary>
private void BtnFloatingWindowInterceptorStop_Click(object sender, RoutedEventArgs e)
{
try
{
if (_floatingWindowInterceptorManager != null)
{
_floatingWindowInterceptorManager.Stop();
UpdateFloatingWindowInterceptorUI();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"停止悬浮窗拦截失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 手动扫描按钮点击
/// </summary>
private void BtnFloatingWindowInterceptorScan_Click(object sender, RoutedEventArgs e)
{
try
{
if (_floatingWindowInterceptorManager != null)
{
_floatingWindowInterceptorManager.ScanOnce();
UpdateFloatingWindowInterceptorUI();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"手动扫描失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 恢复所有窗口按钮点击
/// </summary>
private void BtnFloatingWindowInterceptorRestore_Click(object sender, RoutedEventArgs e)
{
try
{
if (_floatingWindowInterceptorManager != null)
{
_floatingWindowInterceptorManager.RestoreAllWindows();
UpdateFloatingWindowInterceptorUI();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"恢复所有窗口失败: {ex.Message}", LogHelper.LogType.Error);
}
}
/// <summary>
/// 调试列出窗口按钮点击
/// </summary>
private void BtnFloatingWindowInterceptorDebug_Click(object sender, RoutedEventArgs e)
{
try
{
if (_floatingWindowInterceptorManager != null)
{
// 更新状态显示
TextBlockFloatingWindowInterceptorStatus.Text = "正在调试扫描窗口...";
_floatingWindowInterceptorManager.DebugListAllWindows();
// 更新状态显示
TextBlockFloatingWindowInterceptorStatus.Text = "调试扫描完成,请查看日志文件";
LogHelper.WriteLogToFile("用户点击了调试列出窗口按钮", LogHelper.LogType.Event);
}
else
{
LogHelper.WriteLogToFile("拦截器管理器未初始化", LogHelper.LogType.Warning);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"调试列出窗口失败: {ex.Message}", LogHelper.LogType.Error);
TextBlockFloatingWindowInterceptorStatus.Text = "调试扫描失败";
}
}
/// <summary>
/// 测试拦截按钮点击
/// </summary>
private void BtnFloatingWindowInterceptorTest_Click(object sender, RoutedEventArgs e)
{
try
{
if (_floatingWindowInterceptorManager != null)
{
// 更新状态显示
TextBlockFloatingWindowInterceptorStatus.Text = "正在测试拦截功能...";
// 启用测试规则
_floatingWindowInterceptorManager.SetInterceptRule(FloatingWindowInterceptor.InterceptType.SeewoWhiteboard3Floating, true);
// 执行一次扫描
_floatingWindowInterceptorManager.ScanOnce();
// 更新状态显示
TextBlockFloatingWindowInterceptorStatus.Text = "测试拦截完成,请查看日志文件";
LogHelper.WriteLogToFile("用户点击了测试拦截按钮", LogHelper.LogType.Event);
}
else
{
LogHelper.WriteLogToFile("拦截器管理器未初始化", LogHelper.LogType.Warning);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"测试拦截失败: {ex.Message}", LogHelper.LogType.Error);
TextBlockFloatingWindowInterceptorStatus.Text = "测试拦截失败";
}
}
#endregion
}
}
+36
View File
@@ -456,6 +456,42 @@ namespace Ink_Canvas
[JsonProperty("isAutoEnterAnnotationAfterKillHite")]
public bool IsAutoEnterAnnotationAfterKillHite { get; set; }
[JsonProperty("floatingWindowInterceptor")]
public FloatingWindowInterceptorSettings FloatingWindowInterceptor { get; set; } = new FloatingWindowInterceptorSettings();
}
public class FloatingWindowInterceptorSettings
{
[JsonProperty("isEnabled")]
public bool IsEnabled { get; set; } = false;
[JsonProperty("scanIntervalMs")]
public int ScanIntervalMs { get; set; } = 5000;
[JsonProperty("interceptRules")]
public Dictionary<string, bool> InterceptRules { get; set; } = new Dictionary<string, bool>
{
{ "SeewoWhiteboard3Floating", true },
{ "SeewoWhiteboard5Floating", true },
{ "SeewoWhiteboard5CFloating", true },
{ "SeewoPincoSideBarFloating", true },
{ "SeewoPincoDrawingFloating", true },
{ "SeewoPPTFloating", true },
{ "AiClassFloating", true },
{ "HiteAnnotationFloating", true },
{ "ChangYanFloating", true },
{ "ChangYanPptFloating", true },
{ "IntelligentClassFloating", true },
{ "SeewoDesktopAnnotationFloating", true },
{ "SeewoDesktopSideBarFloating", true }
};
[JsonProperty("autoStart")]
public bool AutoStart { get; set; } = false;
[JsonProperty("showNotifications")]
public bool ShowNotifications { get; set; } = true;
}
public class Advanced