diff --git a/BetterGenshinImpact/View/PickerWindow.xaml b/BetterGenshinImpact/View/PickerWindow.xaml index 1cf76084..2d43c943 100644 --- a/BetterGenshinImpact/View/PickerWindow.xaml +++ b/BetterGenshinImpact/View/PickerWindow.xaml @@ -1,37 +1,183 @@  - + WindowStartupLocation="CenterScreen" + Background="#FF1E1E1E"> + + + + + + + - - - + + + + + + + - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - + \ No newline at end of file diff --git a/BetterGenshinImpact/View/PickerWindow.xaml.cs b/BetterGenshinImpact/View/PickerWindow.xaml.cs index b7cc0448..20f33cd4 100644 --- a/BetterGenshinImpact/View/PickerWindow.xaml.cs +++ b/BetterGenshinImpact/View/PickerWindow.xaml.cs @@ -7,71 +7,160 @@ using System.Windows; using System.Windows.Input; using System.Windows.Interop; using Vanara.PInvoke; +using System.Windows.Media; +using System.Collections.Generic; +using System.Windows.Media.Imaging; +using System.Runtime.InteropServices; namespace BetterGenshinImpact.View; public partial class PickerWindow : Window { private static readonly string[] _ignoreProcesses = ["applicationframehost", "shellexperiencehost", "systemsettings", "winstore.app", "searchui"]; - + private bool _isSelected = false; public PickerWindow() { InitializeComponent(); this.InitializeDpiAwareness(); Loaded += OnLoaded; } + public class CapturableWindow + { + public string Name { get; set; } + public string ProcessName { get; set; } + + public IntPtr Handle { get; set; } + public ImageSource Icon { get; set; } + } private void OnLoaded(object sender, RoutedEventArgs e) { FindWindows(); } - public IntPtr PickCaptureTarget(IntPtr hWnd) + public bool PickCaptureTarget(IntPtr hWnd,out IntPtr PickedWindow) { new WindowInteropHelper(this).Owner = hWnd; ShowDialog(); - - return ((CapturableWindow?)WindowList.SelectedItem)?.Handle ?? IntPtr.Zero; + if(!_isSelected) + { + PickedWindow = IntPtr.Zero; + return false; + } + PickedWindow = ((CapturableWindow?)WindowList.SelectedItem)?.Handle ?? IntPtr.Zero; + return true; } private unsafe void FindWindows() { var wih = new WindowInteropHelper(this); + var windows = new List(); + User32.EnumWindows((hWnd, lParam) => { - // ignore invisible windows - if (!User32.IsWindowVisible(hWnd)) + if (!User32.IsWindowVisible(hWnd) || wih.Handle == hWnd) return true; - // ignore untitled windows var title = new StringBuilder(1024); _ = User32.GetWindowText(hWnd, title, title.Capacity); if (string.IsNullOrWhiteSpace(title.ToString())) return true; - // ignore me - if (wih.Handle == hWnd) - return true; - _ = User32.GetWindowThreadProcessId(hWnd, out var processId); - - // ignore by process name var process = Process.GetProcessById((int)processId); if (_ignoreProcesses.Contains(process.ProcessName.ToLower())) return true; - WindowList.Items.Add(new CapturableWindow + // 获取窗口图标 + var icon = GetWindowIcon((IntPtr)hWnd); + + windows.Add(new CapturableWindow { Handle = (IntPtr)hWnd, - Name = $"{title} ({process.ProcessName}.exe)" + Name = title.ToString(), + ProcessName = process.ProcessName, + Icon = icon }); return true; }, IntPtr.Zero); + + WindowList.ItemsSource = windows; + } + private ImageSource GetWindowIcon(IntPtr hWnd) + { + try + { + const int ICON_BIG = 1; // WM_GETICON large icon constant + const int ICON_SMALL = 0; // WM_GETICON small icon constant + const int GCL_HICON = -14; // GetClassLong index for icon + + // 尝试获取窗口大图标 + var iconHandle = User32.SendMessage(hWnd, User32.WindowMessage.WM_GETICON, (IntPtr)ICON_BIG, IntPtr.Zero); + + if (iconHandle == IntPtr.Zero) + { + // 尝试获取窗口小图标 + iconHandle = User32.SendMessage(hWnd, User32.WindowMessage.WM_GETICON, (IntPtr)ICON_SMALL, IntPtr.Zero); + } + + if (iconHandle == IntPtr.Zero) + { + // 尝试获取窗口类图标 + iconHandle = User32.GetClassLong(hWnd, GCL_HICON); + } + + if (iconHandle != IntPtr.Zero) + { + return Imaging.CreateBitmapSourceFromHIcon( + iconHandle, + Int32Rect.Empty, + BitmapSizeOptions.FromEmptyOptions()); + } + } + catch (Exception ex) + { + Debug.WriteLine($"获取窗口图标失败: {ex.Message}"); + } + + // 如果获取失败,返回一个默认图标或null + return null; + } + private bool IsGenshinWindow(string windowName) + { + // 判断是否包含原神相关的进程名 TODO:更加健壮的判断 + return windowName == "原神"; + } + + private bool AskIsThisGenshinImpact(string windowName) + { + var res = MessageBox.Question( + $""" + 这看起来不像是原神,确定要选择这个窗口吗? + + 当前选择的窗口:{windowName} + """, + "确认选择", + MessageBoxButton.YesNo, + MessageBoxResult.No + ); + return res == MessageBoxResult.Yes; } private void WindowsOnMouseDoubleClick(object sender, MouseButtonEventArgs e) { + var selectedWindow = WindowList.SelectedItem as CapturableWindow; + if (selectedWindow == null) return; + + // 如果不是原神窗口,询问用户是否确认 + if (!IsGenshinWindow(selectedWindow.Name)) + { + if (!AskIsThisGenshinImpact(selectedWindow.Name)) + { + return; + } + } + _isSelected = true; Close(); } } diff --git a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs index 604cfed6..bb7613d6 100644 --- a/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs +++ b/BetterGenshinImpact/ViewModel/Pages/HomePageViewModel.cs @@ -139,29 +139,42 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware, IVi private void OnStartCaptureTest() { var picker = new PickerWindow(); - var hWnd = picker.PickCaptureTarget(new WindowInteropHelper(UIDispatcherHelper.MainWindow).Handle); - if (hWnd != IntPtr.Zero) + + if (picker.PickCaptureTarget(new WindowInteropHelper(UIDispatcherHelper.MainWindow).Handle, out var hWnd)) { - var captureWindow = new CaptureTestWindow(); - captureWindow.StartCapture(hWnd, Config.CaptureMode.ToCaptureMode()); - captureWindow.Show(); + if (hWnd != IntPtr.Zero) + { + var captureWindow = new CaptureTestWindow(); + captureWindow.StartCapture(hWnd, Config.CaptureMode.ToCaptureMode()); + captureWindow.Show(); + } + else + { + MessageBox.Error("选择的窗体句柄为空"); + } } + + } [RelayCommand] private void OnManualPickWindow() { var picker = new PickerWindow(); - var hWnd = picker.PickCaptureTarget(new WindowInteropHelper(UIDispatcherHelper.MainWindow).Handle); - if (hWnd != IntPtr.Zero) + if(picker.PickCaptureTarget(new WindowInteropHelper(UIDispatcherHelper.MainWindow).Handle,out var hWnd)) { - _hWnd = hWnd; - Start(hWnd); - } - else - { - MessageBox.Error("选择的窗体句柄为空!"); + if (hWnd != IntPtr.Zero) + { + _hWnd = hWnd; + Start(hWnd); + } + else + { + MessageBox.Error("选择的窗体句柄为空!"); + } + } + } [RelayCommand] @@ -181,8 +194,13 @@ public partial class HomePageViewModel : ObservableObject, INavigationAware, IVi var hWnd = SystemControl.FindGenshinImpactHandle(); if (hWnd == IntPtr.Zero) { - if (Config.GenshinStartConfig.LinkedStartEnabled && !string.IsNullOrEmpty(Config.GenshinStartConfig.InstallPath)) + if (Config.GenshinStartConfig.LinkedStartEnabled) { + if (string.IsNullOrEmpty(Config.GenshinStartConfig.InstallPath)) + { + MessageBox.Error("没有找到原神的安装路径"); + return; + } hWnd = await SystemControl.StartFromLocalAsync(Config.GenshinStartConfig.InstallPath); if (hWnd != IntPtr.Zero) { diff --git a/View/PickerWindow.xaml b/View/PickerWindow.xaml new file mode 100644 index 00000000..0519ecba --- /dev/null +++ b/View/PickerWindow.xaml @@ -0,0 +1 @@ + \ No newline at end of file