diff --git a/Project-Aurora/Project-Aurora/Project-Aurora.csproj b/Project-Aurora/Project-Aurora/Project-Aurora.csproj
index d0e70cb25..f3fbedc4e 100644
--- a/Project-Aurora/Project-Aurora/Project-Aurora.csproj
+++ b/Project-Aurora/Project-Aurora/Project-Aurora.csproj
@@ -553,6 +553,9 @@
Control_ROTTombRaider.xaml
+
+ Window_ProcessSelection.xaml
+
@@ -1849,6 +1852,10 @@
Designer
MSBuild:Compile
+
+ MSBuild:Compile
+ Designer
+
Designer
MSBuild:Compile
@@ -2094,4 +2101,4 @@
-->
-
+
\ No newline at end of file
diff --git a/Project-Aurora/Project-Aurora/Settings/Control_Settings.xaml b/Project-Aurora/Project-Aurora/Settings/Control_Settings.xaml
index 902ca8747..a3dcb9f7d 100644
--- a/Project-Aurora/Project-Aurora/Settings/Control_Settings.xaml
+++ b/Project-Aurora/Project-Aurora/Settings/Control_Settings.xaml
@@ -132,9 +132,8 @@
-
+
-
diff --git a/Project-Aurora/Project-Aurora/Settings/Control_Settings.xaml.cs b/Project-Aurora/Project-Aurora/Settings/Control_Settings.xaml.cs
index 1d00a6406..d8692fe76 100644
--- a/Project-Aurora/Project-Aurora/Settings/Control_Settings.xaml.cs
+++ b/Project-Aurora/Project-Aurora/Settings/Control_Settings.xaml.cs
@@ -405,13 +405,9 @@ private void load_excluded_listbox()
private void excluded_add_Click(object sender, RoutedEventArgs e)
{
- if (!String.IsNullOrWhiteSpace(this.excluded_process_name.Text))
- {
- if (!Global.Configuration.excluded_programs.Contains(this.excluded_process_name.Text))
- {
- Global.Configuration.excluded_programs.Add(this.excluded_process_name.Text);
- }
- }
+ Window_ProcessSelection dialog = new Window_ProcessSelection();
+ if (dialog.ShowDialog() == true && !String.IsNullOrWhiteSpace(dialog.ChosenExecutable)) // do not need to check if dialog is already in excluded_programs since it is a Set and only contains unique items by definition
+ Global.Configuration.excluded_programs.Add(dialog.ChosenExecutable);
load_excluded_listbox();
}
@@ -967,30 +963,6 @@ private void volume_overlay_dim_color_SelectedColorChanged(object sender, Routed
}
}
- private async void excluded_process_name_DropDownOpened(object sender, EventArgs e)
- {
- excluded_process_name.ItemsSource = new string[] { "Working..." };
-
- HashSet processes = new HashSet();
- await System.Threading.Tasks.Task.Run(() =>
- {
-
- foreach (var p in Process.GetProcesses())
- {
- try
- {
- processes.Add(Path.GetFileName(p.MainModule.FileName));
- }
- catch (Exception exc)
- {
-
- }
- }
-
- });
- excluded_process_name.ItemsSource = processes.ToArray();
- }
-
private void btnShowBitmapWindow_Click(object sender, RoutedEventArgs e)
{
if (winBitmapView == null)
diff --git a/Project-Aurora/Project-Aurora/Settings/Window_ProcessSelection.xaml b/Project-Aurora/Project-Aurora/Settings/Window_ProcessSelection.xaml
new file mode 100644
index 000000000..3d9b453a3
--- /dev/null
+++ b/Project-Aurora/Project-Aurora/Settings/Window_ProcessSelection.xaml
@@ -0,0 +1,94 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Project-Aurora/Project-Aurora/Settings/Window_ProcessSelection.xaml.cs b/Project-Aurora/Project-Aurora/Settings/Window_ProcessSelection.xaml.cs
new file mode 100644
index 000000000..7a6066f1b
--- /dev/null
+++ b/Project-Aurora/Project-Aurora/Settings/Window_ProcessSelection.xaml.cs
@@ -0,0 +1,148 @@
+using Microsoft.Win32;
+using System;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Drawing;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace Aurora.Settings {
+ public partial class Window_ProcessSelection : Window {
+
+ public Window_ProcessSelection() {
+ InitializeComponent();
+
+ // Scan running processes and add them to a list
+ List processList = new List();
+ foreach (var p in Process.GetProcesses())
+ try {
+ // Get the exe name
+ string name = System.IO.Path.GetFileName(p.MainModule.FileName);
+ // Check if we've already got an exe by that name, if not add it
+ if (!processList.Any(x => x.Name == name))
+ processList.Add(new RunningProcess {
+ Name = name,
+ Icon = System.Drawing.Icon.ExtractAssociatedIcon(p.MainModule.FileName)
+ });
+ } catch { }
+
+ // Sort the list, set the ListBox control to use that list
+ RunningProcessList.ItemsSource = processList.OrderBy(p => p.Name);
+ RunningProcessList.SelectedIndex = 0;
+
+ // CollectionViewSorce to provide search/filter feature
+ CollectionViewSource.GetDefaultView(RunningProcessList.ItemsSource).Filter = RunningProcessFilterPredicate;
+ RunningProcessListFilterText.Focus();
+ }
+
+ /// The exe that the user has selected to exclude.
+ public string ChosenExecutable { get; private set; } = "";
+
+ ///
+ /// Handler for the browse button on the custom exe path tab. Sets
+ ///
+ ///
+ ///
+ private void BrowseButton_Click(object sender, RoutedEventArgs e) {
+ OpenFileDialog dialog = new OpenFileDialog() {
+ AddExtension = true,
+ Filter = "Executable files (*.exe)|*.exe",
+ Multiselect = false
+ };
+ if (dialog.ShowDialog() == true) // requires "== true" because ShowDialog is a bool?, so doing "if (dialog.ShowDialog())" is invalid
+ ProcessBrowseResult.Text = dialog.FileName;
+ }
+
+ ///
+ /// Updates the running process filter when the textbox is changed.
+ ///
+ private void RunningListFilter_TextChanged(object sender, TextChangedEventArgs e) {
+ CollectionViewSource.GetDefaultView(RunningProcessList.ItemsSource).Refresh();
+ if (RunningProcessList.SelectedIndex == -1)
+ RunningProcessList.SelectedIndex = 0;
+ }
+
+ ///
+ /// Method that makes Up/Down arrow keys when focussed on the RunningListFilter change the selection of the running list element.
+ /// This means you don't have to click on the item when you are typing in a filter.
+ /// We do not need to handle Enter key here as it is done by setting the OK button "IsDefault" to true.
+ ///
+ private void RunningProcessListFilterText_KeyDown(object sender, KeyEventArgs e) {
+ if (e.Key == Key.Up)
+ RunningProcessList.SelectedIndex = Math.Max(RunningProcessList.SelectedIndex - 1, 0);
+ else if (e.Key == Key.Down)
+ RunningProcessList.SelectedIndex = RunningProcessList.SelectedIndex + 1; // Automatically clamped
+ }
+
+ ///
+ /// Filter that is run on each item in the running process list (List<RunningProcess>) and returns a bool
+ /// indicating whether it should appear on the list.
+ ///
+ private bool RunningProcessFilterPredicate(object item) {
+ return ((RunningProcess)item).Name.IndexOf(RunningProcessListFilterText.Text, StringComparison.InvariantCultureIgnoreCase) >= 0;
+ }
+
+ ///
+ /// Handler for when the confimation button is clicked. Handles closing and informing the result of the dialog.
+ ///
+ private void OkayButton_Click(object sender, RoutedEventArgs e) {
+ // If the user is on the running process list tab
+ if (MainTabControl.SelectedIndex == 0) {
+ if (RunningProcessList.SelectedItem == null) return; // Cannot OK if there is no item selected
+ ChosenExecutable = ((RunningProcess)RunningProcessList.SelectedItem).Name;
+
+ // Else if user is on browse tab
+ } else {
+ string exe = ProcessBrowseResult.Text;
+ if (String.IsNullOrWhiteSpace(exe)) return; // Cannot OK if there is no text entered
+ // Get just the exe name,
+ ChosenExecutable = exe.Substring(exe.LastIndexOfAny(new[] { '/', '\\' }) + 1);
+ }
+
+ // Close the window and set result as successful
+ DialogResult = true;
+ Close();
+ }
+
+ ///
+ /// Handler for when the cancel button is clicked. Closes the window.
+ ///
+ private void CancelButton_Click(object sender, RoutedEventArgs e) {
+ DialogResult = false;
+ Close();
+ }
+ }
+
+
+ ///
+ /// Converts an Icon into a WPF-compatible BitmapSource.
+ ///
+ class IconToImageConverter : IValueConverter {
+ public object Convert(object value, Type targetType, object parameter, CultureInfo culture) {
+ Icon ico = (Icon)value;
+ // Taken from https://stackoverflow.com/a/51438725/1305670
+ return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(ico.Handle, Int32Rect.Empty, BitmapSizeOptions.FromEmptyOptions());
+ }
+
+ public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture) => null;
+ }
+
+ ///
+ /// Container for a Running Process definition.
+ ///
+ struct RunningProcess {
+ public string Name { get; set; }
+ public Icon Icon { get; set; }
+ }
+}