refactor:迁移设置

This commit is contained in:
PrefacedCorg
2026-04-19 08:35:22 +08:00
parent 4dd56a4e5d
commit 12c7fb1713
11 changed files with 651 additions and 564 deletions
@@ -0,0 +1,48 @@
using IWshRuntimeLibrary;
using System;
using System.IO;
using File = System.IO.File;
namespace Ink_Canvas.Windows.SettingsViews.Helpers
{
public static class AutoStartHelper
{
public static bool StartAutomaticallyCreate(string exeName)
{
try
{
var shell = new WshShell();
var shortcut = (IWshShortcut)shell.CreateShortcut(
Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\" + exeName + ".lnk");
shortcut.TargetPath = System.Windows.Forms.Application.ExecutablePath;
shortcut.WorkingDirectory = Environment.CurrentDirectory;
shortcut.WindowStyle = 1;
shortcut.Description = exeName + "_Ink";
shortcut.Save();
return true;
}
catch (Exception) { }
return false;
}
public static bool StartAutomaticallyDel(string exeName)
{
try
{
File.Delete(Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\" + exeName +
".lnk");
return true;
}
catch (Exception) { }
return false;
}
public static bool IsAutoStartEnabled(string exeName)
{
return File.Exists(
Environment.GetFolderPath(Environment.SpecialFolder.Startup) + "\\" + exeName + ".lnk");
}
}
}
@@ -0,0 +1,475 @@
using System;
using System.Linq;
using System.Reflection;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Media = System.Windows.Media;
namespace Ink_Canvas.Windows.SettingsViews.Helpers
{
public static class MainWindowSettingsHelper
{
private static MainWindow GetMainWindow()
{
return Application.Current.MainWindow as MainWindow;
}
public static void InvokeMainWindowMethod(string methodName, params object[] parameters)
{
try
{
var mainWindow = GetMainWindow();
if (mainWindow == null) return;
var method = mainWindow.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (method != null)
{
method.Invoke(mainWindow, parameters);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"调用 MainWindow 方法 {methodName} 失败: {ex.Message}");
}
}
public static void InvokeToggleSwitchToggled(string toggleSwitchName, bool isOn)
{
try
{
var mainWindow = GetMainWindow();
if (mainWindow == null) return;
var toggleSwitch = mainWindow.FindName(toggleSwitchName);
if (toggleSwitch == null)
{
var property = mainWindow.GetType().GetProperty(toggleSwitchName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (property != null && property.PropertyType.Name.Contains("ToggleSwitch"))
{
var isOnProperty = property.PropertyType.GetProperty("IsOn");
if (isOnProperty != null)
{
var toggleSwitchInstance = property.GetValue(mainWindow);
if (toggleSwitchInstance != null)
{
isOnProperty.SetValue(toggleSwitchInstance, isOn);
}
}
}
var toggledMethodName = toggleSwitchName + "_Toggled";
InvokeMainWindowMethod(toggledMethodName, null, new RoutedEventArgs());
NotifySettingsPanelsSyncState(toggleSwitchName);
return;
}
var toggleSwitchType = toggleSwitch.GetType();
var isOnProp = toggleSwitchType.GetProperty("IsOn");
if (isOnProp != null)
{
isOnProp.SetValue(toggleSwitch, isOn);
}
var toggledMethodName2 = toggleSwitchName + "_Toggled";
InvokeMainWindowMethod(toggledMethodName2, toggleSwitch, new RoutedEventArgs());
NotifySettingsPanelsSyncState(toggleSwitchName);
NotifyThemeUpdateIfNeeded(toggleSwitchName);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"调用 ToggleSwitch {toggleSwitchName} 失败: {ex.Message}");
}
}
public static void InvokeComboBoxSelectionChanged(string comboBoxName, object selectedItem)
{
try
{
var mainWindow = GetMainWindow();
if (mainWindow == null) return;
var comboBox = mainWindow.FindName(comboBoxName) as System.Windows.Controls.ComboBox;
if (comboBox != null)
{
comboBox.SelectedItem = selectedItem;
var selectionChangedMethodName = comboBoxName + "_SelectionChanged";
InvokeMainWindowMethod(selectionChangedMethodName, comboBox, new System.Windows.Controls.SelectionChangedEventArgs(
System.Windows.Controls.Primitives.Selector.SelectionChangedEvent,
new System.Collections.IList[0],
new System.Collections.IList[0]));
}
NotifySettingsPanelsSyncState(comboBoxName);
NotifyThemeUpdateIfNeeded(comboBoxName);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"调用 ComboBox {comboBoxName} 失败: {ex.Message}");
}
}
public static void InvokeSliderValueChanged(string sliderName, double value)
{
try
{
var mainWindow = GetMainWindow();
if (mainWindow == null) return;
var slider = mainWindow.FindName(sliderName) as System.Windows.Controls.Slider;
if (slider != null)
{
var oldValue = slider.Value;
slider.Value = value;
var valueChangedMethodName = sliderName + "_ValueChanged";
InvokeMainWindowMethod(valueChangedMethodName, slider,
new System.Windows.RoutedPropertyChangedEventArgs<double>(oldValue, value));
}
NotifySettingsPanelsSyncState(sliderName);
NotifyThemeUpdateIfNeeded(sliderName);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"调用 Slider {sliderName} 失败: {ex.Message}");
}
}
public static void InvokeCheckBoxCheckedChanged(string checkBoxName, bool isChecked)
{
try
{
var mainWindow = GetMainWindow();
if (mainWindow == null) return;
var checkBox = mainWindow.FindName(checkBoxName) as System.Windows.Controls.CheckBox;
if (checkBox != null)
{
checkBox.IsChecked = isChecked;
var methodNames = new[]
{
checkBoxName + "_IsCheckChanged",
checkBoxName + "_IsCheckChange",
checkBoxName + "_Checked",
checkBoxName + "_Unchecked"
};
foreach (var methodName in methodNames)
{
var method = mainWindow.GetType().GetMethod(methodName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (method != null)
{
InvokeMainWindowMethod(methodName, checkBox, new RoutedEventArgs());
break;
}
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"调用 CheckBox {checkBoxName} 失败: {ex.Message}");
}
}
public static void UpdateSettingSafely(Action action, string eventHandlerName = null, string controlName = null, params object[] eventHandlerParams)
{
try
{
if (!string.IsNullOrEmpty(eventHandlerName))
{
var mainWindow = GetMainWindow();
if (mainWindow != null)
{
var method = mainWindow.GetType().GetMethod(eventHandlerName, BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (method != null)
{
method.Invoke(mainWindow, eventHandlerParams);
if (!string.IsNullOrEmpty(controlName))
{
NotifySettingsPanelsSyncState(controlName);
}
return;
}
}
}
action?.Invoke();
MainWindow.SaveSettingsToFile();
if (!string.IsNullOrEmpty(controlName))
{
NotifySettingsPanelsSyncState(controlName);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"更新设置失败: {ex.Message}");
}
}
public static void UpdateSettingDirectly(Action action, string controlName = null)
{
try
{
action?.Invoke();
MainWindow.SaveSettingsToFile();
if (!string.IsNullOrEmpty(controlName))
{
NotifySettingsPanelsSyncState(controlName);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"直接更新设置失败: {ex.Message}");
}
}
public static void InvokeTextBoxTextChanged(string textBoxName, string text)
{
try
{
var mainWindow = GetMainWindow();
if (mainWindow == null) return;
var textBox = mainWindow.FindName(textBoxName) as System.Windows.Controls.TextBox;
if (textBox != null)
{
textBox.Text = text;
var textChangedMethodName = textBoxName + "_TextChanged";
InvokeMainWindowMethod(textChangedMethodName, textBox, new System.Windows.Controls.TextChangedEventArgs(
System.Windows.Controls.Primitives.TextBoxBase.TextChangedEvent,
System.Windows.Controls.UndoAction.None));
}
NotifySettingsPanelsSyncState(textBoxName);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"调用 TextBox {textBoxName} 失败: {ex.Message}");
}
}
public static void NotifySettingsPanelsSyncState(string controlName)
{
try
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
foreach (Window window in Application.Current.Windows)
{
if (window.GetType().Name == "SettingsWindow")
{
SyncAllPanels(window);
break;
}
}
}), System.Windows.Threading.DispatcherPriority.Background);
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"通知设置面板同步状态失败: {ex.Message}");
}
}
private static void SyncAllPanels(Window settingsWindow)
{
try
{
var pageProperties = settingsWindow.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance)
.Where(p => p.PropertyType.Name.EndsWith("Page") &&
p.PropertyType.IsSubclassOf(typeof(System.Windows.Controls.Page)));
foreach (var pageProp in pageProperties)
{
try
{
var page = pageProp.GetValue(settingsWindow) as System.Windows.Controls.Page;
if (page != null)
{
var loadMethod = page.GetType().GetMethod("LoadSettings",
BindingFlags.Public | BindingFlags.Instance);
if (loadMethod != null)
{
loadMethod.Invoke(page, null);
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"同步页面 {pageProp.Name} 状态失败: {ex.Message}");
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"同步所有页面状态失败: {ex.Message}");
}
}
public static void NotifyThemeUpdateIfNeeded(string controlName)
{
try
{
if (string.IsNullOrEmpty(controlName)) return;
var themeRelatedControls = new[]
{
"ComboBoxTheme",
"ToggleSwitchEnableTrayIcon",
"ComboBoxFloatingBarImg",
"ComboBoxUnFoldBtnImg",
"ComboBoxSplashScreenStyle",
"ToggleSwitchEnableSplashScreen",
"ViewboxFloatingBarScaleTransformValueSlider",
"ViewboxFloatingBarOpacityValueSlider",
"ViewboxFloatingBarOpacityInPPTValueSlider",
"UnFoldBtnImg",
"FloatingBarImg",
"Theme"
};
bool isThemeRelated = false;
string controlNameLower = controlName.ToLower();
foreach (var themeControl in themeRelatedControls)
{
string themeControlLower = themeControl.ToLower();
if (controlNameLower.Contains(themeControlLower) ||
themeControlLower.Contains(controlNameLower) ||
controlNameLower == themeControlLower)
{
isThemeRelated = true;
break;
}
}
if (isThemeRelated)
{
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
{
NotifySettingsWindowThemeUpdate();
}), System.Windows.Threading.DispatcherPriority.Background);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"通知主题更新失败: {ex.Message}");
}
}
private static void NotifySettingsWindowThemeUpdate()
{
try
{
foreach (Window window in Application.Current.Windows)
{
if (window.GetType().Name == "SettingsWindow")
{
var applyThemeMethod = window.GetType().GetMethod("ApplyTheme",
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
if (applyThemeMethod != null)
{
applyThemeMethod.Invoke(window, null);
}
break;
}
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine($"通知设置窗口主题更新失败: {ex.Message}");
}
}
public static void ForceUpdateAllPanelsTheme()
{
NotifySettingsWindowThemeUpdate();
}
public static void InvokeComboBoxSelectionChangedWithThemeCheck(string comboBoxName, object selectedItem)
{
InvokeComboBoxSelectionChanged(comboBoxName, selectedItem);
NotifyThemeUpdateIfNeeded(comboBoxName);
}
public static void InvokeToggleSwitchToggledWithThemeCheck(string toggleSwitchName, bool isOn)
{
InvokeToggleSwitchToggled(toggleSwitchName, isOn);
NotifyThemeUpdateIfNeeded(toggleSwitchName);
}
public static void EnableTouchSupportForControls(DependencyObject parent)
{
if (parent == null) return;
for (int i = 0; i < Media.VisualTreeHelper.GetChildrenCount(parent); i++)
{
var child = Media.VisualTreeHelper.GetChild(parent, i);
if (child is Border border)
{
if (border.Tag != null || border.Cursor == Cursors.Hand)
{
border.IsManipulationEnabled = true;
border.TouchDown += (s, e) =>
{
var touchPoint = e.GetTouchPoint(border);
var mouseEvent = new MouseButtonEventArgs(Mouse.PrimaryDevice, Environment.TickCount, MouseButton.Left)
{
RoutedEvent = UIElement.MouseLeftButtonDownEvent,
Source = border
};
border.RaiseEvent(mouseEvent);
border.CaptureTouch(e.TouchDevice);
e.Handled = true;
};
border.TouchUp += (s, e) =>
{
border.ReleaseTouchCapture(e.TouchDevice);
e.Handled = true;
};
}
}
else if (child is Button button)
{
button.IsManipulationEnabled = true;
}
else if (child is ComboBox comboBox)
{
comboBox.IsManipulationEnabled = true;
}
else if (child is Slider slider)
{
slider.IsManipulationEnabled = true;
}
else if (child is TextBox textBox)
{
textBox.IsManipulationEnabled = true;
}
else if (child is CheckBox checkBox)
{
checkBox.IsManipulationEnabled = true;
}
else if (child is RadioButton radioButton)
{
radioButton.IsManipulationEnabled = true;
}
EnableTouchSupportForControls(child);
}
}
}
}
@@ -0,0 +1,31 @@
using Newtonsoft.Json;
using System;
using System.IO;
using ProcessProtectionManager = Ink_Canvas.Helpers.ProcessProtectionManager;
namespace Ink_Canvas.Windows.SettingsViews.Helpers
{
public static class SettingsManager
{
public static Settings Settings { get; set; } = new Settings();
public static string SettingsFileName { get; } = Path.Combine("Configs", "Settings.json");
public static void SaveSettingsToFile()
{
var text = JsonConvert.SerializeObject(Settings, Formatting.Indented);
try
{
string configsDir = Path.Combine(App.RootPath, "Configs");
if (!Directory.Exists(configsDir))
{
ProcessProtectionManager.WithWriteAccess(configsDir, () => Directory.CreateDirectory(configsDir));
}
var path = App.RootPath + SettingsFileName;
ProcessProtectionManager.WithWriteAccess(path, () => File.WriteAllText(path, text));
}
catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
}
}
}
@@ -0,0 +1,29 @@
using System.Windows;
using System.Windows.Controls;
namespace Ink_Canvas.Windows.SettingsViews.Helpers
{
public class TopMostModeSelectionItem
{
}
public class TopMostModeButtonItem
{
public string ButtonHeader { get; set; }
public string ButtonContent { get; set; }
public bool RestartAsAdmin { get; set; }
}
public class TopMostModeTemplateSelector : DataTemplateSelector
{
public DataTemplate SelectionTemplate { get; set; }
public DataTemplate ButtonTemplate { get; set; }
public override DataTemplate SelectTemplate(object item, DependencyObject container)
{
if (item is TopMostModeSelectionItem) return SelectionTemplate;
if (item is TopMostModeButtonItem) return ButtonTemplate;
return null;
}
}
}
@@ -0,0 +1,463 @@
using System;
using System.Runtime.InteropServices;
using System.Security.Principal;
using System.Windows;
using System.Windows.Interop;
using System.Windows.Threading;
using Ink_Canvas.Helpers;
namespace Ink_Canvas.Windows.SettingsViews.Helpers
{
public static class WindowSettingsHelper
{
#region Win32 API
[DllImport("user32.dll")]
private static extern int GetWindowLong(IntPtr hWnd, int nIndex);
[DllImport("user32.dll")]
private static extern int SetWindowLong(IntPtr hWnd, int nIndex, int dwNewLong);
[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 IntPtr GetForegroundWindow();
[DllImport("user32.dll")]
private static extern uint GetWindowThreadProcessId(IntPtr hWnd, out uint lpdwProcessId);
[DllImport("user32.dll")]
private static extern bool IsWindow(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool IsWindowVisible(IntPtr hWnd);
[DllImport("user32.dll")]
private static extern bool IsIconic(IntPtr hWnd);
[DllImport("UIAccessDLL_x86.dll", EntryPoint = "PrepareUIAccess", CallingConvention = CallingConvention.Cdecl)]
private static extern Int32 PrepareUIAccessX86();
[DllImport("UIAccessDLL_x64.dll", EntryPoint = "PrepareUIAccess", CallingConvention = CallingConvention.Cdecl)]
private static extern Int32 PrepareUIAccessX64();
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr SetWindowsHookEx(int idHook, LowLevelKeyboardProc lpfn, IntPtr hMod, uint dwThreadId);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnhookWindowsHookEx(IntPtr hhk);
[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode, IntPtr wParam, IntPtr lParam);
[DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern IntPtr GetModuleHandle(string lpModuleName);
[DllImport("kernel32.dll")]
private static extern uint GetCurrentProcessId();
private const int GWL_EXSTYLE = -20;
private const int WS_EX_NOACTIVATE = 0x08000000;
private const int WS_EX_TOPMOST = 0x00000008;
private const int WH_KEYBOARD_LL = 13;
private static readonly IntPtr HWND_TOPMOST = new IntPtr(-1);
private static readonly IntPtr HWND_NOTOPMOST = new IntPtr(-2);
private const uint SWP_NOMOVE = 0x0002;
private const uint SWP_NOSIZE = 0x0001;
private const uint SWP_NOACTIVATE = 0x0010;
private const uint SWP_SHOWWINDOW = 0x0040;
private const uint SWP_NOOWNERZORDER = 0x0200;
private delegate IntPtr LowLevelKeyboardProc(int nCode, IntPtr wParam, IntPtr lParam);
#endregion
#region Keyboard Hook
private static LowLevelKeyboardProc _keyboardProc;
private static IntPtr _keyboardHookId = IntPtr.Zero;
private static IntPtr KeyboardHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
return CallNextHookEx(_keyboardHookId, nCode, wParam, lParam);
}
public static void InstallKeyboardHook()
{
if (_keyboardHookId == IntPtr.Zero)
{
_keyboardProc = KeyboardHookProc;
_keyboardHookId = SetWindowsHookEx(WH_KEYBOARD_LL, _keyboardProc,
GetModuleHandle(null), 0);
if (_keyboardHookId == IntPtr.Zero)
{
LogHelper.WriteLogToFile("安装低级键盘钩子失败", LogHelper.LogType.Error);
}
}
}
public static void UninstallKeyboardHook()
{
if (_keyboardHookId != IntPtr.Zero)
{
UnhookWindowsHookEx(_keyboardHookId);
_keyboardHookId = IntPtr.Zero;
_keyboardProc = null;
}
}
#endregion
#region Timer Callbacks
public static Action OnStopKillProcessTimer { get; set; }
public static Action OnStartKillProcessTimer { get; set; }
#endregion
#region Topmost Maintenance Timer
private static DispatcherTimer _topmostMaintenanceTimer;
private static bool _isTopmostMaintenanceEnabled;
private static Window _maintainedWindow;
#endregion
#region PPT Only Mode
private static DispatcherTimer _pptOnlyVisibilityProbeTimer;
private static Window _pptModeWindow;
private const int PptOnlyVisibilityProbeIntervalMs = 800;
public static Action<bool> OnPptOnlyModeChanged { get; set; }
public static void ApplyPptOnlyMode(Window window, bool isEnabled)
{
try
{
SettingsManager.Settings.ModeSettings.IsPPTOnlyMode = isEnabled;
SettingsManager.SaveSettingsToFile();
if (isEnabled)
{
window.Hide();
LogHelper.WriteLogToFile("已切换到仅PPT模式,主窗口已隐藏", LogHelper.LogType.Event);
EnsurePptOnlyVisibilityProbeTimer(window);
}
else
{
StopPptOnlyVisibilityProbeTimer();
window.Show();
LogHelper.WriteLogToFile("已切换到正常模式,主窗口已显示", LogHelper.LogType.Event);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"切换模式时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
private static void EnsurePptOnlyVisibilityProbeTimer(Window window)
{
try
{
if (!SettingsManager.Settings.ModeSettings.IsPPTOnlyMode)
{
StopPptOnlyVisibilityProbeTimer();
return;
}
_pptModeWindow = window;
if (_pptOnlyVisibilityProbeTimer == null)
{
_pptOnlyVisibilityProbeTimer = new DispatcherTimer
{
Interval = TimeSpan.FromMilliseconds(PptOnlyVisibilityProbeIntervalMs)
};
_pptOnlyVisibilityProbeTimer.Tick += PptOnlyVisibilityProbeTimer_Tick;
}
if (!_pptOnlyVisibilityProbeTimer.IsEnabled)
_pptOnlyVisibilityProbeTimer.Start();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"仅PPT可见性探测计时器启动失败: {ex.Message}", LogHelper.LogType.Warning);
}
}
private static void StopPptOnlyVisibilityProbeTimer()
{
try
{
_pptOnlyVisibilityProbeTimer?.Stop();
}
catch { }
}
private static void PptOnlyVisibilityProbeTimer_Tick(object sender, EventArgs e)
{
OnPptOnlyModeChanged?.Invoke(true);
}
#endregion
#region Window Settings Methods
public static bool IsTemporarilyDisablingNoFocusMode { get; set; }
public static void ApplyNoFocusMode(Window window)
{
var hwnd = new WindowInteropHelper(window).Handle;
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
bool shouldBeNoFocus = !IsTemporarilyDisablingNoFocusMode && SettingsManager.Settings.Advanced.IsNoFocusMode;
if (shouldBeNoFocus)
{
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_NOACTIVATE);
InstallKeyboardHook();
}
else
{
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_NOACTIVATE);
UninstallKeyboardHook();
}
}
public static void SetWindowMode(Window window)
{
if (SettingsManager.Settings.Advanced.WindowMode)
{
window.WindowState = WindowState.Normal;
window.Left = 0.0;
window.Top = 0.0;
window.Height = SystemParameters.PrimaryScreenHeight;
window.Width = SystemParameters.PrimaryScreenWidth;
}
else
{
window.WindowState = WindowState.Maximized;
}
}
public static void ApplyAlwaysOnTop(Window window)
{
try
{
var hwnd = new WindowInteropHelper(window).Handle;
if (SettingsManager.Settings.Advanced.IsAlwaysOnTop)
{
window.Topmost = true;
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
if (SettingsManager.Settings.Advanced.IsNoFocusMode && !SettingsManager.Settings.Advanced.EnableUIAccessTopMost)
{
StartTopmostMaintenance(window);
}
else
{
StopTopmostMaintenance();
}
}
else
{
SetWindowPos(hwnd, HWND_NOTOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle & ~WS_EX_TOPMOST);
StopTopmostMaintenance();
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用窗口置顶失败: {ex.Message}", LogHelper.LogType.Error);
}
}
public static void ApplyUIAccessTopMost(Window window)
{
try
{
if (SettingsManager.Settings.Advanced.EnableUIAccessTopMost && SettingsManager.Settings.Advanced.IsAlwaysOnTop)
{
var identity = WindowsIdentity.GetCurrent();
var principal = new WindowsPrincipal(identity);
if (principal.IsInRole(WindowsBuiltInRole.Administrator))
{
try
{
OnStopKillProcessTimer?.Invoke();
if (App.watchdogProcess != null && !App.watchdogProcess.HasExited)
{
App.watchdogProcess.Kill();
App.watchdogProcess = null;
}
App.StartWatchdogIfNeeded();
if (Environment.Is64BitProcess)
{
PrepareUIAccessX64();
}
else
{
PrepareUIAccessX86();
}
OnStartKillProcessTimer?.Invoke();
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"启用UIA置顶功能时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
else
{
LogHelper.WriteLogToFile("UIA置顶功能需要管理员权限", LogHelper.LogType.Warning);
}
}
else
{
LogHelper.WriteLogToFile("UIA置顶功能已禁用", LogHelper.LogType.Trace);
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"应用UIA置顶功能时出错: {ex.Message}", LogHelper.LogType.Error);
}
}
public static void SetTopmostBasedOnSettings(Window window, bool shouldBeTopmost)
{
if (SettingsManager.Settings.Advanced.IsAlwaysOnTop)
{
window.Topmost = true;
ApplyAlwaysOnTop(window);
}
else
{
window.Topmost = shouldBeTopmost;
if (!shouldBeTopmost)
{
ApplyAlwaysOnTop(window);
}
}
}
public static void PauseTopmostMaintenance()
{
if (_topmostMaintenanceTimer != null && _isTopmostMaintenanceEnabled)
{
_topmostMaintenanceTimer.Stop();
}
}
public static void ResumeTopmostMaintenance(Window window)
{
if (SettingsManager.Settings.Advanced.IsAlwaysOnTop &&
SettingsManager.Settings.Advanced.IsNoFocusMode &&
!SettingsManager.Settings.Advanced.EnableUIAccessTopMost)
{
if (_topmostMaintenanceTimer != null && !_isTopmostMaintenanceEnabled)
{
_topmostMaintenanceTimer.Start();
_isTopmostMaintenanceEnabled = true;
}
}
}
private static void StartTopmostMaintenance(Window window)
{
if (SettingsManager.Settings.Advanced.EnableUIAccessTopMost) return;
if (_isTopmostMaintenanceEnabled) return;
_maintainedWindow = window;
if (_topmostMaintenanceTimer == null)
{
_topmostMaintenanceTimer = new DispatcherTimer();
_topmostMaintenanceTimer.Interval = TimeSpan.FromMilliseconds(500);
_topmostMaintenanceTimer.Tick += TopmostMaintenanceTimer_Tick;
}
_topmostMaintenanceTimer.Start();
_isTopmostMaintenanceEnabled = true;
LogHelper.WriteLogToFile("启动置顶维护定时器", LogHelper.LogType.Trace);
}
private static void StopTopmostMaintenance()
{
if (_topmostMaintenanceTimer != null && _isTopmostMaintenanceEnabled)
{
_topmostMaintenanceTimer.Stop();
_isTopmostMaintenanceEnabled = false;
LogHelper.WriteLogToFile("停止置顶维护定时器", LogHelper.LogType.Trace);
}
}
private static void TopmostMaintenanceTimer_Tick(object sender, EventArgs e)
{
try
{
if (SettingsManager.Settings.Advanced.EnableUIAccessTopMost)
{
StopTopmostMaintenance();
return;
}
if (!SettingsManager.Settings.Advanced.IsAlwaysOnTop || !SettingsManager.Settings.Advanced.IsNoFocusMode)
{
StopTopmostMaintenance();
return;
}
var window = _maintainedWindow;
if (window == null) return;
var hwnd = new WindowInteropHelper(window).Handle;
if (hwnd == IntPtr.Zero) return;
if (!IsWindow(hwnd) || !IsWindowVisible(hwnd) || IsIconic(hwnd)) return;
var foregroundWindow = GetForegroundWindow();
if (foregroundWindow != hwnd)
{
GetWindowThreadProcessId(foregroundWindow, out uint processId);
var currentProcessId = GetCurrentProcessId();
if (processId == currentProcessId) return;
SetWindowPos(hwnd, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOMOVE | SWP_NOSIZE | SWP_NOACTIVATE | SWP_SHOWWINDOW | SWP_NOOWNERZORDER);
int exStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
if ((exStyle & WS_EX_TOPMOST) == 0)
{
SetWindowLong(hwnd, GWL_EXSTYLE, exStyle | WS_EX_TOPMOST);
}
}
}
catch (Exception ex)
{
LogHelper.WriteLogToFile($"置顶维护定时器出错: {ex.Message}", LogHelper.LogType.Error);
}
}
#endregion
}
}