diff --git a/Ink Canvas/Helpers/GlobalHotkeyManager.cs b/Ink Canvas/Helpers/GlobalHotkeyManager.cs index e0516650..7dea1ec1 100644 --- a/Ink Canvas/Helpers/GlobalHotkeyManager.cs +++ b/Ink Canvas/Helpers/GlobalHotkeyManager.cs @@ -567,6 +567,36 @@ namespace Ink_Canvas.Helpers } } + /// + /// 刷新多屏相关设置(开关和跟随鼠标策略)。 + /// + public void RefreshMultiScreenSettings() + { + try + { + var advanced = MainWindow.Settings.Advanced; + _isMultiScreenMode = advanced.EnableMultiScreenSupport && ScreenDetectionHelper.HasMultipleScreens(); + _enableScreenSpecificHotkeys = _isMultiScreenMode; + + if (_isMultiScreenMode) + { + _currentScreen = advanced.FollowMouseForScreenSelection + ? Screen.FromPoint(Control.MousePosition) + : ScreenDetectionHelper.GetWindowScreen(_mainWindow); + } + else + { + _currentScreen = ScreenDetectionHelper.GetPrimaryScreen(); + } + + RefreshHotkeysForCurrentScreen(); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"刷新多屏设置时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + /// /// 获取当前屏幕信息 /// @@ -624,13 +654,15 @@ namespace Ink_Canvas.Helpers { try { - // 检测是否有多个屏幕 - _isMultiScreenMode = ScreenDetectionHelper.HasMultipleScreens(); + var advanced = MainWindow.Settings.Advanced; + _isMultiScreenMode = advanced.EnableMultiScreenSupport && ScreenDetectionHelper.HasMultipleScreens(); + _enableScreenSpecificHotkeys = _isMultiScreenMode; if (_isMultiScreenMode) { - // 获取当前窗口所在的屏幕 - _currentScreen = ScreenDetectionHelper.GetWindowScreen(_mainWindow); + _currentScreen = advanced.FollowMouseForScreenSelection + ? Screen.FromPoint(Control.MousePosition) + : ScreenDetectionHelper.GetWindowScreen(_mainWindow); // 监听窗口位置变化事件 _mainWindow.LocationChanged += OnWindowLocationChanged; @@ -688,6 +720,9 @@ namespace Ink_Canvas.Helpers if (!_isMultiScreenMode || !_enableScreenSpecificHotkeys) return; + if (MainWindow.Settings.Advanced.FollowMouseForScreenSelection) + return; + var newScreen = ScreenDetectionHelper.GetWindowScreen(_mainWindow); if (newScreen != null && newScreen != _currentScreen) { @@ -800,9 +835,16 @@ namespace Ink_Canvas.Helpers if (!_isMultiScreenMode || !_enableScreenSpecificHotkeys) return; - // 检查鼠标是否在当前窗口所在的屏幕上 var mousePosition = Control.MousePosition; - var currentScreen = Screen.FromPoint(mousePosition); + var mouseScreen = Screen.FromPoint(mousePosition); + + if (MainWindow.Settings.Advanced.FollowMouseForScreenSelection && + mouseScreen != null && + mouseScreen != _currentScreen) + { + _currentScreen = mouseScreen; + RefreshHotkeysForCurrentScreen(); + } // 无论屏幕是否变化,都检查热键状态 // 这样可以确保热键状态始终与当前上下文保持一致 diff --git a/Ink Canvas/MainWindow.xaml.cs b/Ink Canvas/MainWindow.xaml.cs index 9f784e4e..1c393a4f 100644 --- a/Ink Canvas/MainWindow.xaml.cs +++ b/Ink Canvas/MainWindow.xaml.cs @@ -2547,6 +2547,22 @@ namespace Ink_Canvas } } + /// + /// 应用多屏设置到全局热键管理器。 + /// + public void ApplyMultiScreenSettings() + { + try + { + _globalHotkeyManager?.RefreshMultiScreenSettings(); + RefreshFloatingBarScreenFollowState(); + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"应用多屏设置时出错: {ex.Message}", LogHelper.LogType.Error); + } + } + /// /// 打开快捷键设置窗口 /// diff --git a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs index c8fe6b0a..8e4dd813 100644 --- a/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs +++ b/Ink Canvas/MainWindow_cs/MW_FloatingBarIcons.cs @@ -204,6 +204,10 @@ namespace Ink_Canvas /// 用于记录上次在PPT中的坐标 /// private Point pointPPT = new Point(-1, -1); + private DispatcherTimer _floatingBarScreenFollowTimer; + private string _lastFloatingBarScreenDeviceName; + private string _lastCanvasScreenDeviceName; + private bool _isRebuildingCanvasForScreen; /// /// 浮动工具栏移动事件处理 @@ -1733,8 +1737,7 @@ namespace Ink_Canvas dpiScaleY = source.CompositionTarget.TransformToDevice.M22; } - var windowHandle = new WindowInteropHelper(this).Handle; - var screen = Screen.FromHandle(windowHandle); + var screen = GetFloatingBarTargetScreen(); double screenWidth, screenHeight; double toolbarHeight; if (Settings.Advanced.IsEnableAvoidFullScreenHelper && PosXCaculatedWithTaskbarHeight) @@ -1889,8 +1892,7 @@ namespace Ink_Canvas dpiScaleY = source.CompositionTarget.TransformToDevice.M22; } - var windowHandle = new WindowInteropHelper(this).Handle; - var screen = Screen.FromHandle(windowHandle); + var screen = GetFloatingBarTargetScreen(); double screenWidth, screenHeight; double toolbarHeight; if (Settings.Advanced.IsEnableAvoidFullScreenHelper) @@ -2008,8 +2010,7 @@ namespace Ink_Canvas dpiScaleY = source.CompositionTarget.TransformToDevice.M22; } - var windowHandle = new WindowInteropHelper(this).Handle; - var screen = Screen.FromHandle(windowHandle); + var screen = GetFloatingBarTargetScreen(); double screenWidth = screen.Bounds.Width / dpiScaleX, screenHeight = screen.Bounds.Height / dpiScaleY; // 仅计算Windows任务栏高度,不考虑其他程序对工作区的影响 var toolbarHeight = ForegroundWindowInfo.GetTaskbarHeight(screen, dpiScaleY); @@ -2104,6 +2105,203 @@ namespace Ink_Canvas } } + private Screen GetFloatingBarTargetScreen() + { + try + { + if (Settings.Advanced.EnableMultiScreenSupport && + Settings.Advanced.FollowMouseForScreenSelection && + ScreenDetectionHelper.HasMultipleScreens()) + { + var mouseScreen = Screen.FromPoint(System.Windows.Forms.Control.MousePosition); + if (mouseScreen != null) + { + return mouseScreen; + } + } + + var windowHandle = new WindowInteropHelper(this).Handle; + return Screen.FromHandle(windowHandle); + } + catch + { + return Screen.PrimaryScreen; + } + } + + private Screen GetCurrentFloatingBarScreen() + { + try + { + if (ViewboxFloatingBar == null || !IsLoaded) + { + return null; + } + + var center = ViewboxFloatingBar.PointToScreen(new Point( + Math.Max(0, ViewboxFloatingBar.ActualWidth / 2), + Math.Max(0, ViewboxFloatingBar.ActualHeight / 2))); + return Screen.FromPoint(new System.Drawing.Point((int)center.X, (int)center.Y)); + } + catch + { + return null; + } + } + + internal void RefreshFloatingBarScreenFollowState() + { + try + { + var enableFollow = Settings.Advanced.EnableMultiScreenSupport && + Settings.Advanced.FollowMouseForScreenSelection && + ScreenDetectionHelper.HasMultipleScreens(); + + if (!enableFollow) + { + _floatingBarScreenFollowTimer?.Stop(); + _lastFloatingBarScreenDeviceName = null; + return; + } + + if (_floatingBarScreenFollowTimer == null) + { + _floatingBarScreenFollowTimer = new DispatcherTimer + { + Interval = TimeSpan.FromMilliseconds(350) + }; + _floatingBarScreenFollowTimer.Tick += FloatingBarScreenFollowTimer_Tick; + } + + _lastFloatingBarScreenDeviceName = GetCurrentFloatingBarScreen()?.DeviceName; + _lastCanvasScreenDeviceName = _lastFloatingBarScreenDeviceName; + + if (!_floatingBarScreenFollowTimer.IsEnabled) + { + _floatingBarScreenFollowTimer.Start(); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"刷新浮动栏多屏跟随状态失败: {ex.Message}", LogHelper.LogType.Warning); + } + } + + private void FloatingBarScreenFollowTimer_Tick(object sender, EventArgs e) + { + try + { + if (!Settings.Advanced.EnableMultiScreenSupport || + !Settings.Advanced.FollowMouseForScreenSelection || + !ScreenDetectionHelper.HasMultipleScreens()) + { + _floatingBarScreenFollowTimer?.Stop(); + _lastFloatingBarScreenDeviceName = null; + return; + } + + if (currentMode == 1 || isDragDropInEffect || ViewboxFloatingBar.Visibility != Visibility.Visible) + { + return; + } + + var mouseScreen = Screen.FromPoint(System.Windows.Forms.Control.MousePosition); + var currentFloatingBarScreen = GetCurrentFloatingBarScreen(); + + if (mouseScreen == null || currentFloatingBarScreen == null) + { + return; + } + + if (mouseScreen.DeviceName == currentFloatingBarScreen.DeviceName) + { + _lastFloatingBarScreenDeviceName = currentFloatingBarScreen.DeviceName; + return; + } + + if (mouseScreen.DeviceName == _lastFloatingBarScreenDeviceName) + { + return; + } + + _lastFloatingBarScreenDeviceName = mouseScreen.DeviceName; + RebuildCanvasOnTargetScreen(mouseScreen); + + if (BtnPPTSlideShowEnd.Visibility == Visibility.Visible) + { + PureViewboxFloatingBarMarginAnimationInPPTMode(); + } + else + { + PureViewboxFloatingBarMarginAnimationInDesktopMode(); + } + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"浮动栏跨屏跟随失败: {ex.Message}", LogHelper.LogType.Warning); + } + } + + private void RebuildCanvasOnTargetScreen(Screen targetScreen) + { + try + { + if (targetScreen == null || _isRebuildingCanvasForScreen) + { + return; + } + + if (_lastCanvasScreenDeviceName == targetScreen.DeviceName) + { + return; + } + + _isRebuildingCanvasForScreen = true; + + double dpiScaleX = 1, dpiScaleY = 1; + var source = PresentationSource.FromVisual(this); + if (source?.CompositionTarget != null) + { + dpiScaleX = source.CompositionTarget.TransformToDevice.M11; + dpiScaleY = source.CompositionTarget.TransformToDevice.M22; + } + + // 先移动主窗口到目标屏,确保画布承载区域切换到新屏幕。 + MainWindow.MoveWindow( + new WindowInteropHelper(this).Handle, + targetScreen.Bounds.X, + targetScreen.Bounds.Y, + targetScreen.Bounds.Width, + targetScreen.Bounds.Height, + true); + + // 重新铺设画布尺寸,强制触发布局刷新。 + inkCanvas.Width = targetScreen.Bounds.Width / dpiScaleX; + inkCanvas.Height = targetScreen.Bounds.Height / dpiScaleY; + inkCanvas.InvalidateMeasure(); + inkCanvas.InvalidateArrange(); + inkCanvas.UpdateLayout(); + + if (GridInkCanvasSelectionCover != null) + { + GridInkCanvasSelectionCover.Width = inkCanvas.Width; + GridInkCanvasSelectionCover.Height = inkCanvas.Height; + GridInkCanvasSelectionCover.InvalidateMeasure(); + GridInkCanvasSelectionCover.InvalidateArrange(); + } + + _lastCanvasScreenDeviceName = targetScreen.DeviceName; + } + catch (Exception ex) + { + LogHelper.WriteLogToFile($"在新屏重建画布失败: {ex.Message}", LogHelper.LogType.Warning); + } + finally + { + _isRebuildingCanvasForScreen = false; + } + } + /// /// 光标图标点击事件处理 /// diff --git a/Ink Canvas/MainWindow_cs/MW_Settings.cs b/Ink Canvas/MainWindow_cs/MW_Settings.cs index 2dde6a73..95cfada4 100644 --- a/Ink Canvas/MainWindow_cs/MW_Settings.cs +++ b/Ink Canvas/MainWindow_cs/MW_Settings.cs @@ -823,6 +823,8 @@ namespace Ink_Canvas Settings.Advanced.IsEnableForceFullScreen = false; Settings.Advanced.IsEnableDPIChangeDetection = false; Settings.Advanced.IsEnableResolutionChangeDetection = false; + Settings.Advanced.EnableMultiScreenSupport = true; + Settings.Advanced.FollowMouseForScreenSelection = true; Settings.Appearance.IsEnableDisPlayNibModeToggler = false; Settings.Appearance.IsColorfulViewboxFloatingBar = false; diff --git a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs index 8f83f083..3f076a39 100644 --- a/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs +++ b/Ink Canvas/MainWindow_cs/MW_SettingsToLoad.cs @@ -618,6 +618,8 @@ namespace Ink_Canvas ViewboxFloatingBarMarginAnimation(100, true); } + RefreshFloatingBarScreenFollowState(); + } /// diff --git a/Ink Canvas/Resources/Settings.cs b/Ink Canvas/Resources/Settings.cs index de4bd12d..79abcaa5 100644 --- a/Ink Canvas/Resources/Settings.cs +++ b/Ink Canvas/Resources/Settings.cs @@ -731,6 +731,12 @@ namespace Ink_Canvas [JsonProperty("windowMode")] public bool WindowMode { get; set; } = true; + + [JsonProperty("enableMultiScreenSupport")] + public bool EnableMultiScreenSupport { get; set; } = true; + + [JsonProperty("followMouseForScreenSelection")] + public bool FollowMouseForScreenSelection { get; set; } = true; } public class InkToShape diff --git a/Ink Canvas/Windows/SettingsViews/Pages/WindowPage.xaml b/Ink Canvas/Windows/SettingsViews/Pages/WindowPage.xaml index 40d73773..e84ac544 100644 --- a/Ink Canvas/Windows/SettingsViews/Pages/WindowPage.xaml +++ b/Ink Canvas/Windows/SettingsViews/Pages/WindowPage.xaml @@ -57,6 +57,21 @@ SwitchName="ToggleSwitchAvoidFullScreen" Toggled="ToggleSwitchAvoidFullScreen_Toggled" /> + + + +