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" />
+
+
+
+