From d25af927216c2561efe8ff352f26d4234d720eb7 Mon Sep 17 00:00:00 2001
From: Doriel Rivalet <100863878+DorielRivalet@users.noreply.github.com>
Date: Fri, 18 Oct 2024 15:37:35 -0300
Subject: [PATCH] feat: add hotkeys window
closes #375
---
MHFZ_Overlay/App.config | 9 ++
MHFZ_Overlay/MHFZ_Overlay.csproj | 36 +++----
.../Services/Hotkey/HotkeySettings.cs | 94 ++++++++++++++++++
MHFZ_Overlay/Settings.Designer.cs | 36 +++++++
MHFZ_Overlay/Settings.settings | 9 ++
.../Views/Windows/HotkeySettingsWindow.xaml | 53 ++++++++++
.../Windows/HotkeySettingsWindow.xaml.cs | 98 +++++++++++++++++++
MHFZ_Overlay/Views/Windows/MainWindow.xaml | 5 +
MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs | 36 ++++++-
README.md | 2 +-
10 files changed, 354 insertions(+), 24 deletions(-)
create mode 100644 MHFZ_Overlay/Services/Hotkey/HotkeySettings.cs
create mode 100644 MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml
create mode 100644 MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml.cs
diff --git a/MHFZ_Overlay/App.config b/MHFZ_Overlay/App.config
index 51b382b6..76e0a0c0 100644
--- a/MHFZ_Overlay/App.config
+++ b/MHFZ_Overlay/App.config
@@ -1044,6 +1044,15 @@
True
+
+ Shift + F1
+
+
+ Shift + F5
+
+
+ Shift + F6
+
diff --git a/MHFZ_Overlay/MHFZ_Overlay.csproj b/MHFZ_Overlay/MHFZ_Overlay.csproj
index 3fb4ff83..f2c69f46 100644
--- a/MHFZ_Overlay/MHFZ_Overlay.csproj
+++ b/MHFZ_Overlay/MHFZ_Overlay.csproj
@@ -2001,44 +2001,44 @@
-
+
-
+
-
+
-
-
-
+
+
+
-
-
-
+
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
+
+
all
runtime; build; native; contentfiles; analyzers; buildtransitive
-
-
-
-
-
-
+
+
+
+
+
+
-
+
diff --git a/MHFZ_Overlay/Services/Hotkey/HotkeySettings.cs b/MHFZ_Overlay/Services/Hotkey/HotkeySettings.cs
new file mode 100644
index 00000000..8b029615
--- /dev/null
+++ b/MHFZ_Overlay/Services/Hotkey/HotkeySettings.cs
@@ -0,0 +1,94 @@
+namespace MHFZ_Overlay.Services.Hotkey;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+// HotkeySettings.cs
+public class HotkeySettings
+{
+ public string OpenSettings { get; set; } = "Shift + F1";
+ public string RestartProgram { get; set; } = "Shift + F5";
+ public string CloseProgram { get; set; } = "Shift + F6";
+}
+
+public class HotkeyManager : IDisposable
+{
+ private readonly Dictionary _hotkeyActions = new();
+ private HotkeySettings _settings;
+ private readonly GlobalHotKey _globalHotKey;
+
+ public HotkeyManager()
+ {
+ _globalHotKey = new GlobalHotKey();
+ LoadSettings();
+ }
+
+
+ public void LoadSettings()
+ {
+ var s = (Settings)System.Windows.Application.Current.TryFindResource("Settings");
+
+ // Load from user settings or create default
+ _settings = new HotkeySettings
+ {
+ OpenSettings = s.OpenSettingsHotkey ?? "Shift + F1",
+ RestartProgram = s.RestartProgramHotkey ?? "Shift + F5",
+ CloseProgram = s.CloseProgramHotkey ?? "Shift + F6"
+ };
+ }
+
+ public void SaveSettings()
+ {
+ var s = (Settings)System.Windows.Application.Current.TryFindResource("Settings");
+
+ s.OpenSettingsHotkey = _settings.OpenSettings;
+ s.RestartProgramHotkey = _settings.RestartProgram;
+ s.CloseProgramHotkey = _settings.CloseProgram;
+ s.Save();
+ }
+
+ public void RegisterHotkeys(Action openSettings, Action restart, Action close)
+ {
+ // Store the actions
+ _hotkeyActions["OpenSettings"] = openSettings;
+ _hotkeyActions["RestartProgram"] = restart;
+ _hotkeyActions["CloseProgram"] = close;
+
+ // Register hotkeys using existing GlobalHotKey class
+ GlobalHotKey.RegisterHotKey(_settings.OpenSettings, openSettings);
+ GlobalHotKey.RegisterHotKey(_settings.RestartProgram, restart);
+ GlobalHotKey.RegisterHotKey(_settings.CloseProgram, close);
+ }
+
+ public void UpdateHotkey(string action, string newHotkey)
+ {
+ // Update the settings
+ switch (action)
+ {
+ case "OpenSettings":
+ _settings.OpenSettings = newHotkey;
+ break;
+ case "RestartProgram":
+ _settings.RestartProgram = newHotkey;
+ break;
+ case "CloseProgram":
+ _settings.CloseProgram = newHotkey;
+ break;
+ }
+
+ SaveSettings();
+
+ // Re-register the hotkey if we have an action for it
+ if (_hotkeyActions.TryGetValue(action, out var hotkeyAction))
+ {
+ GlobalHotKey.RegisterHotKey(newHotkey, hotkeyAction);
+ }
+ }
+
+ public void Dispose()
+ {
+ _globalHotKey?.Dispose();
+ }
+}
diff --git a/MHFZ_Overlay/Settings.Designer.cs b/MHFZ_Overlay/Settings.Designer.cs
index 2657a844..d2dbaa39 100644
--- a/MHFZ_Overlay/Settings.Designer.cs
+++ b/MHFZ_Overlay/Settings.Designer.cs
@@ -4162,5 +4162,41 @@ public bool EnableAchievementsTracking {
this["EnableAchievementsTracking"] = value;
}
}
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Shift + F1")]
+ public string OpenSettingsHotkey {
+ get {
+ return ((string)(this["OpenSettingsHotkey"]));
+ }
+ set {
+ this["OpenSettingsHotkey"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Shift + F5")]
+ public string RestartProgramHotkey {
+ get {
+ return ((string)(this["RestartProgramHotkey"]));
+ }
+ set {
+ this["RestartProgramHotkey"] = value;
+ }
+ }
+
+ [global::System.Configuration.UserScopedSettingAttribute()]
+ [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
+ [global::System.Configuration.DefaultSettingValueAttribute("Shift + F6")]
+ public string CloseProgramHotkey {
+ get {
+ return ((string)(this["CloseProgramHotkey"]));
+ }
+ set {
+ this["CloseProgramHotkey"] = value;
+ }
+ }
}
}
diff --git a/MHFZ_Overlay/Settings.settings b/MHFZ_Overlay/Settings.settings
index 17bf6b45..3d979bad 100644
--- a/MHFZ_Overlay/Settings.settings
+++ b/MHFZ_Overlay/Settings.settings
@@ -1037,5 +1037,14 @@
True
+
+ Shift + F1
+
+
+ Shift + F5
+
+
+ Shift + F6
+
\ No newline at end of file
diff --git a/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml b/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml
new file mode 100644
index 00000000..e1660d73
--- /dev/null
+++ b/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml
@@ -0,0 +1,53 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ Press hotkey combination to set. Press Escape to clear. Each hotkey must include at least one modifier (Ctrl, Alt, Shift, or Win).
+
+
+
+
+
+
+
+
+
diff --git a/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml.cs b/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml.cs
new file mode 100644
index 00000000..2a3f98ac
--- /dev/null
+++ b/MHFZ_Overlay/Views/Windows/HotkeySettingsWindow.xaml.cs
@@ -0,0 +1,98 @@
+namespace MHFZ_Overlay.Views.Windows;
+using System;
+using System.Collections.Generic;
+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.Shapes;
+using MHFZ_Overlay.Services.Hotkey;
+using Wpf.Ui.Controls;
+
+// HotkeySettingsWindow.xaml.cs
+public partial class HotkeySettingsWindow : FluentWindow
+{
+ private readonly HotkeyManager _hotkeyManager;
+ private readonly Dictionary _originalHotkeys = new();
+
+ public HotkeySettingsWindow(HotkeyManager hotkeyManager)
+ {
+ this.InitializeComponent();
+ _hotkeyManager = hotkeyManager;
+ LoadCurrentHotkeys();
+ }
+
+ private void LoadCurrentHotkeys()
+ {
+ var s = (Settings)System.Windows.Application.Current.TryFindResource("Settings");
+
+ this.OpenSettingsHotkey.Text = s.OpenSettingsHotkey;
+ this.RestartProgramHotkey.Text = s.RestartProgramHotkey;
+ this.CloseProgramHotkey.Text = s.CloseProgramHotkey;
+
+ // Store original values for cancellation
+ _originalHotkeys[this.OpenSettingsHotkey] = s.OpenSettingsHotkey;
+ _originalHotkeys[this.RestartProgramHotkey] = s.RestartProgramHotkey;
+ _originalHotkeys[this.CloseProgramHotkey] = s.CloseProgramHotkey;
+ }
+
+ private void Hotkey_PreviewKeyDown(object sender, KeyEventArgs e)
+ {
+ e.Handled = true;
+ var textBox = (System.Windows.Controls.TextBox)sender;
+
+ var key = e.Key == Key.System ? e.SystemKey : e.Key;
+ if (key == Key.Escape)
+ {
+ textBox.Text = _originalHotkeys[textBox];
+ return;
+ }
+
+ var modifiers = new List();
+ if (Keyboard.Modifiers.HasFlag(ModifierKeys.Control))
+ modifiers.Add("Ctrl");
+ if (Keyboard.Modifiers.HasFlag(ModifierKeys.Shift))
+ modifiers.Add("Shift");
+ if (Keyboard.Modifiers.HasFlag(ModifierKeys.Alt))
+ modifiers.Add("Alt");
+ if (Keyboard.Modifiers.HasFlag(ModifierKeys.Windows))
+ modifiers.Add("Win");
+
+ if (key != Key.LeftCtrl && key != Key.RightCtrl &&
+ key != Key.LeftAlt && key != Key.RightAlt &&
+ key != Key.LeftShift && key != Key.RightShift &&
+ key != Key.LWin && key != Key.RWin)
+ {
+ if (modifiers.Count == 0)
+ {
+ System.Windows.MessageBox.Show("Hotkey must include at least one modifier (Ctrl, Alt, Shift, or Win)",
+ "Invalid Hotkey", System.Windows.MessageBoxButton.OK, MessageBoxImage.Warning);
+ return;
+ }
+
+ var hotkeyString = string.Join(" + ", modifiers.Concat(new[] { key.ToString() }));
+ textBox.Text = hotkeyString;
+ }
+ }
+
+ private void SaveButton_Click(object sender, RoutedEventArgs e)
+ {
+ _hotkeyManager.UpdateHotkey("OpenSettings", this.OpenSettingsHotkey.Text);
+ _hotkeyManager.UpdateHotkey("RestartProgram", this.RestartProgramHotkey.Text);
+ _hotkeyManager.UpdateHotkey("CloseProgram", this.CloseProgramHotkey.Text);
+ DialogResult = true;
+ Close();
+ }
+
+ private void CancelButton_Click(object sender, RoutedEventArgs e)
+ {
+ DialogResult = false;
+ Close();
+ }
+}
diff --git a/MHFZ_Overlay/Views/Windows/MainWindow.xaml b/MHFZ_Overlay/Views/Windows/MainWindow.xaml
index 1375d664..09d48635 100644
--- a/MHFZ_Overlay/Views/Windows/MainWindow.xaml
+++ b/MHFZ_Overlay/Views/Windows/MainWindow.xaml
@@ -40,6 +40,11 @@
x:Name="MainWindowNotifyIcon">
+
+
+
+
+
diff --git a/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs b/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs
index 7c40f887..f7d1d1c1 100644
--- a/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs
+++ b/MHFZ_Overlay/Views/Windows/MainWindow.xaml.cs
@@ -128,10 +128,28 @@ private void CreateSystemTrayIcon()
_mainWindowNotifyIcon = this.MainWindowNotifyIcon;
}
+ // Add method to open hotkey settings
+ private void OpenHotkeySettings()
+ {
+ var settingsWindow = new HotkeySettingsWindow(_hotkeyManager);
+ settingsWindow.Owner = this; // Make it a child window of MainWindow
+ settingsWindow.WindowStartupLocation = WindowStartupLocation.CenterOwner;
+ settingsWindow.ShowDialog();
+ }
+
+ // Ensure proper cleanup. TODO test
+ protected override void OnClosed(EventArgs e)
+ {
+ base.OnClosed(e);
+ _hotkeyManager?.Dispose();
+ }
+
private void NotifyIcon_Click(object sender, RoutedEventArgs e) => this.OpenConfigButton_Key();
private void OptionSettings_Click(object sender, RoutedEventArgs e) => this.OpenConfigButton_Key();
+ private void OptionHotkeys_Click(object sender, RoutedEventArgs e) => this.OpenHotkeySettings();
+
private void OptionHelp_Click(object sender, RoutedEventArgs e) => OpenLink("https://github.com/DorielRivalet/mhfz-overlay/blob/main/FAQ.md");
private void OptionDocumentation_Click(object sender, RoutedEventArgs e) => OpenLink("https://github.com/DorielRivalet/mhfz-overlay/tree/main/docs");
@@ -270,6 +288,9 @@ private void OptionDatabaseFolder_Click(object sender, RoutedEventArgs e)
private double? xOffset { get; set; }
+ private readonly HotkeyManager _hotkeyManager;
+
+
///
/// Initializes a new instance of the class.
///
@@ -281,6 +302,8 @@ public MainWindow()
// Start the stopwatch
stopwatch.Start();
+ _hotkeyManager = new HotkeyManager();
+
var splashScreen = new SplashScreen("../../Assets/Icons/png/loading.png");
splashScreen.Show(false);
@@ -304,9 +327,12 @@ public MainWindow()
ViewModels.Windows.AddressModel.ValidateGameFolder();
this.DataContext = this.DataLoader.Model;
- GlobalHotKey.RegisterHotKey("Shift + F1", () => this.OpenConfigButton_Key());
- GlobalHotKey.RegisterHotKey("Shift + F5", () => ReloadButton_Key());
- GlobalHotKey.RegisterHotKey("Shift + F6", () => CloseButton_Key());
+ // Replace your existing hotkey registration with this:
+ _hotkeyManager.RegisterHotkeys(
+ () => this.OpenConfigButton_Key(),
+ () => this.ReloadButton_Key(),
+ () => this.CloseButton_Key()
+ );
DiscordService.InitializeDiscordRPC();
this.CheckGameState();
@@ -1624,7 +1650,7 @@ private void OpenConfigButton_Click(object sender, RoutedEventArgs e)
private void CloseButton_Click(object sender, RoutedEventArgs e) => ApplicationService.HandleShutdown();
// https://stackoverflow.com/questions/4773632/how-do-i-restart-a-wpf-application
- private static void ReloadButton_Key() => ApplicationService.HandleRestart();
+ private void ReloadButton_Key() => ApplicationService.HandleRestart();
private void OpenConfigButton_Key()
{
@@ -1665,7 +1691,7 @@ private void OpenConfigButton_Key()
}
}
- private static void CloseButton_Key() => ApplicationService.HandleShutdown();
+ private void CloseButton_Key() => ApplicationService.HandleShutdown();
private void MainGrid_MouseMove(object sender, MouseEventArgs e) => DoDragDrop(this.movingObject);
diff --git a/README.md b/README.md
index 4e2073c1..3dd6578f 100644
--- a/README.md
+++ b/README.md
@@ -125,7 +125,7 @@ We strongly recommend that you verify the authenticity and integrity of the soft
- `Shift+F5` Restart Overlay.
- `Shift+F6` Exit.
-As an alternative to hotkeys, you can use the system tray options by right-clicking the icon.
+As an alternative to hotkeys, you can use the system tray options by right-clicking the icon. You can change the hotkeys by opening the Hotkeys window, found in the system tray menu.
![System Tray options](./demo/systemtray.png)