From 4c6580868f18cb31b3cd47eb6459c02f4846e9b3 Mon Sep 17 00:00:00 2001 From: zggsong Date: Tue, 12 Mar 2024 15:02:14 +0800 Subject: [PATCH] fix: main window follow mouse problem #32 --- src/STranslate.Util/CommonUtil.cs | 14 ++- .../ViewModels/NotifyIconViewModel.cs | 113 +++++++++++++----- .../Views/Preference/CommonPage.xaml | 8 +- src/STranslate/Views/ScreenshotView.xaml.cs | 4 +- 4 files changed, 94 insertions(+), 45 deletions(-) diff --git a/src/STranslate.Util/CommonUtil.cs b/src/STranslate.Util/CommonUtil.cs index 8bbd68e9..e0c12d10 100644 --- a/src/STranslate.Util/CommonUtil.cs +++ b/src/STranslate.Util/CommonUtil.cs @@ -389,18 +389,24 @@ public static Dictionary GetEnumList() /// 获取鼠标位置 /// /// - public static Point GetMousePositionWindowsForms() + public static Tuple GetPositionInfos() { + //获取未进行缩放的position信息 var ms = System.Windows.Forms.Control.MousePosition; - var screen = WpfScreenHelper.Screen.AllScreens.FirstOrDefault(s => s.WpfBounds.Contains(new Point(ms.X, ms.Y))); + //原始数据是否在原始分辨率的屏幕内 + var screen = WpfScreenHelper.Screen.AllScreens.FirstOrDefault(s => s.Bounds.Contains(new Point(ms.X, ms.Y))); if (screen != null) { + //获取缩放比例 double dpiScale = screen.ScaleFactor; - return new Point(ms.X / dpiScale, ms.Y / dpiScale); + //获取处理后的屏幕数据 + var bounds = screen.WpfBounds; + //返回处理后的数据 + return new(new Point(ms.X / dpiScale, ms.Y / dpiScale), bounds); } - return new Point(ms.X, ms.Y); + throw new ArgumentNullException(); } /// diff --git a/src/STranslate/ViewModels/NotifyIconViewModel.cs b/src/STranslate/ViewModels/NotifyIconViewModel.cs index ef743c71..17f1a63c 100644 --- a/src/STranslate/ViewModels/NotifyIconViewModel.cs +++ b/src/STranslate/ViewModels/NotifyIconViewModel.cs @@ -116,7 +116,7 @@ private void InputTranslate(Window view) Singleton.Instance.SingleTranslateCancelCommand.Execute(null); Singleton.Instance.TranslateCancelCommand.Execute(null); Clear(); - ShowAndActive(view); + ShowAndActive(view, Singleton.Instance.CurrentConfig?.IsFollowMouse ?? false); } [RelayCommand] @@ -139,7 +139,7 @@ private void CrossWordTranslate(Window view) Clear(); Singleton.Instance.InputContent = content; - ShowAndActive(view); + ShowAndActive(view, Singleton.Instance.CurrentConfig?.IsFollowMouse ?? false); Singleton.Instance.TranslateCommand.Execute(null); } @@ -177,7 +177,7 @@ private void QRCode(object obj) internal void QRCodeHandler() { ScreenshotView view = new(); - ShowAndActive(view, false); + ShowAndActive(view); view.BitmapCallback += ( bitmap => @@ -185,7 +185,7 @@ internal void QRCodeHandler() //显示OCR窗口 OCRView? view = Application.Current.Windows.OfType().FirstOrDefault(); view ??= new OCRView(); - ShowAndActive(view, false); + ShowAndActive(view); //显示截图 var bs = BitmapUtil.ConvertBitmap2BitmapSource(bitmap); @@ -223,7 +223,7 @@ private void OCR(object obj) internal void OCRHandler() { ScreenshotView view = new(); - ShowAndActive(view, false); + ShowAndActive(view); view.BitmapCallback += ( bitmap => @@ -231,7 +231,7 @@ internal void OCRHandler() //显示OCR窗口 OCRView? view = Application.Current.Windows.OfType().FirstOrDefault(); view ??= new OCRView(); - ShowAndActive(view, false); + ShowAndActive(view); //显示截图 var bs = BitmapUtil.ConvertBitmap2BitmapSource(bitmap); @@ -269,7 +269,7 @@ private void SilentOCR(object? obj) internal void SilentOCRHandler() { ScreenshotView view = new(); - ShowAndActive(view, false); + ShowAndActive(view); view.BitmapCallback += ( bitmap => @@ -323,7 +323,7 @@ private void ScreenShotTranslate(object obj) internal void ScreenShotHandler() { ScreenshotView view = new(); - ShowAndActive(view, false); + ShowAndActive(view); view.BitmapCallback += ( bitmap => @@ -337,7 +337,7 @@ internal void ScreenShotHandler() Clear(); MainView view = Application.Current.Windows.OfType().FirstOrDefault()!; - ShowAndActive(view); + ShowAndActive(view, Singleton.Instance.CurrentConfig?.IsFollowMouse ?? false); var bytes = BitmapUtil.ConvertBitmap2Bytes(bitmap); @@ -401,23 +401,18 @@ internal void Clear() Singleton.Instance.Clear(); } - private void ShowAndActive(Window view, bool canFollowMouse = true) + private void ShowAndActive(Window view, bool canFollowMouse = false) { - if ((Singleton.Instance.CurrentConfig?.IsFollowMouse ?? false) && canFollowMouse) - { - Point mouseLocation = CommonUtil.GetMousePositionWindowsForms(); - view.Left = mouseLocation.X; - view.Top = mouseLocation.Y; - } - if (view.WindowState == WindowState.Minimized) - { - view.WindowState = WindowState.Normal; // Restore the window if it was minimized. - } - if (!view.Topmost) // Ensure the window is topmost if it's not already. + if (canFollowMouse) { - view.Topmost = true; // Temporarily make the window topmost. - view.Topmost = false; // Then set it back to normal state, this is a trick to bring it to the front. + var position = FollowMouseHandler(view); + + view.Left = position.Item1; + view.Top = position.Item2; } + + SpecialWindowActiveHandler(view); + if (view is MainView mview) { mview.ViewAnimation(); @@ -443,21 +438,21 @@ private void ShowAndActive(Window view, bool canFollowMouse = true) [RelayCommand] private void OpenPreference() { - PreferenceView? window = Application.Current.Windows.OfType().FirstOrDefault(); - window ??= new PreferenceView(); - window.UpdateNavigation(); + PreferenceView? view = Application.Current.Windows.OfType().FirstOrDefault(); + view ??= new PreferenceView(); + view.UpdateNavigation(); - ShowAndActive(window, false); + ShowAndActive(view); } [RelayCommand] private void OpenHistory() { - PreferenceView? window = Application.Current.Windows.OfType().FirstOrDefault(); - window ??= new PreferenceView(); - window.UpdateNavigation(PerferenceType.History); + PreferenceView? view = Application.Current.Windows.OfType().FirstOrDefault(); + view ??= new PreferenceView(); + view.UpdateNavigation(PerferenceType.History); - ShowAndActive(window, false); + ShowAndActive(view); } [RelayCommand] @@ -477,7 +472,7 @@ private void ClipboardMonitor(Window view) { IsClipboardMonitor = !IsClipboardMonitor; IsEnabledClipboardMonitor = IsClipboardMonitor ? ConstStr.TAGTRUE : ConstStr.TAGFALSE; - + if (IsClipboardMonitor) { // 开始监听剪贴板变化 @@ -519,7 +514,7 @@ private void ClipboardChanged(string content, Window view) Clear(); Singleton.Instance.InputContent = content; - ShowAndActive(view); + ShowAndActive(view, Singleton.Instance.CurrentConfig?.IsFollowMouse ?? false); Singleton.Instance.TranslateCommand.Execute(null); } @@ -563,5 +558,57 @@ private void Exit() Application.Current.Shutdown(); } + + /// + /// 跟随鼠标处理 + /// + /// + /// + private Tuple FollowMouseHandler(Window view) + { + var infos = CommonUtil.GetPositionInfos(); + var position = infos.Item1; + var bounds = infos.Item2; + var left = position.X; + var top = position.Y; + + //保持页面在屏幕上方三分之一处 + if ((top - bounds.Top) * 3 > bounds.Height) + { + top = bounds.Height / 3 + bounds.Top; + } + + //如果当前高度不足以容纳最大高度的内容,则使用最大高度为窗口Top值 + if (bounds.Height - top + bounds.Top < view.MaxHeight) + { + top = bounds.Height - view.MaxHeight + bounds.Top - 48; + } + + //右侧不超出当前屏幕区域 + if (left + view.Width > (bounds.Left + bounds.Width)) + { + left = bounds.Left + bounds.Width - view.Width; + } + return new Tuple(left, top); + } + + /// + /// 特定情况下窗口无法激活的问题 + /// 1. 主窗口非置顶并且设置页面已经存在时激活设置页面 + /// 2. 设置页面最小化再激活 + /// + /// + private void SpecialWindowActiveHandler(Window view) + { + if (view.WindowState == WindowState.Minimized) + { + view.WindowState = WindowState.Normal; // Restore the window if it was minimized. + } + if (!view.Topmost) // Ensure the window is topmost if it's not already. + { + view.Topmost = true; // Temporarily make the window topmost. + view.Topmost = false; // Then set it back to normal state, this is a trick to bring it to the front. + } + } } } diff --git a/src/STranslate/Views/Preference/CommonPage.xaml b/src/STranslate/Views/Preference/CommonPage.xaml index 42a7e98e..7b82ceb9 100644 --- a/src/STranslate/Views/Preference/CommonPage.xaml +++ b/src/STranslate/Views/Preference/CommonPage.xaml @@ -106,7 +106,6 @@ HorizontalAlignment="Right" ItemsSource="{Binding ProxyMethodList}" SelectedValue="{Binding ProxyMethod, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" /> - @@ -117,7 +116,6 @@ HorizontalAlignment="Right" Placeholder="请输入IP地址" Text="{Binding ProxyIp, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" /> - @@ -127,7 +125,6 @@ Placeholder="请输入端口号" PreviewKeyDown="AcceptOnlyNumber" Text="{Binding ProxyPort, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}" /> - @@ -150,7 +147,6 @@ - @@ -227,8 +223,8 @@ - - + + diff --git a/src/STranslate/Views/ScreenshotView.xaml.cs b/src/STranslate/Views/ScreenshotView.xaml.cs index 9eef5c8a..f21dc2de 100644 --- a/src/STranslate/Views/ScreenshotView.xaml.cs +++ b/src/STranslate/Views/ScreenshotView.xaml.cs @@ -18,10 +18,10 @@ public ScreenshotView() _rectangle = new(); var ms = System.Windows.Forms.Control.MousePosition; - var screen = WpfScreenHelper.Screen.AllScreens.FirstOrDefault(screen => screen.WpfBounds.Contains(new Point(ms.X, ms.Y))); + var screen = WpfScreenHelper.Screen.AllScreens.FirstOrDefault(screen => screen.Bounds.Contains(new Point(ms.X, ms.Y))); if (screen == null) { - Log.LogService.Logger.Error("恶性BUG,未获取到屏幕数据"); + Log.LogService.Logger.Error("未获取到屏幕数据"); return; }