Initial reassign of hotkeys

This commit is contained in:
Peter Kirmeier 2023-05-29 20:48:46 +02:00
parent ce2d9772f6
commit 637cc46e7e
3 changed files with 79 additions and 43 deletions

View file

@ -39,6 +39,12 @@ namespace SystemTrayMenu.Helpers
Key GetKey(); Key GetKey();
} }
/// <summary>
/// Gets or sets a value indicating whether hotkeys are enabled
/// (e.g. during user configuration dialog).
/// </summary>
internal static bool IsEnabled { get; set; } = true;
/// <summary> /// <summary>
/// Registers a global hotkey. /// Registers a global hotkey.
/// Function is thread safe. /// Function is thread safe.
@ -57,9 +63,9 @@ namespace SystemTrayMenu.Helpers
{ {
foreach (var reg in Registrations) foreach (var reg in Registrations)
{ {
if (id < reg.Id) if (id <= reg.Id)
{ {
id = reg.Id; id = reg.Id + 1; // TODO: Rework to re-use gaps
} }
} }
@ -102,7 +108,7 @@ namespace SystemTrayMenu.Helpers
/// <returns>true: Success or false: Failure.</returns> /// <returns>true: Success or false: Failure.</returns>
internal static bool Unregister(IHotkeyRegistration? registration) internal static bool Unregister(IHotkeyRegistration? registration)
{ {
if (registration == null || registration is not HotkeyRegistration reg || Registrations.Contains(reg)) if (registration == null || registration is not HotkeyRegistration reg || !Registrations.Contains(reg))
{ {
return true; return true;
} }
@ -120,6 +126,61 @@ namespace SystemTrayMenu.Helpers
return true; return true;
} }
internal static bool Reassign(IHotkeyRegistration? registration, ModifierKeys modifiers, Key key)
{
if (registration == null || registration is not HotkeyRegistration reg || !Registrations.Contains(reg))
{
return false;
}
if (modifiers == reg.Modifiers && key == reg.Key)
{
return true; // Yes, nothing changed, but we return true as requested key is properly registered even when unchanged.
}
int virtualKeyCode = KeyInterop.VirtualKeyFromKey(key);
int id = 0;
lock (CriticalSectionLock)
{
foreach (var regs in Registrations)
{
if (id <= regs.Id)
{
id = reg.Id + 1; // TODO: Rework to re-use gaps
}
}
if (!NativeMethods.User32RegisterHotKey(HWnd.Handle, id, (uint)modifiers, (uint)virtualKeyCode))
{
string errorHint = NativeMethods.GetLastErrorHint();
throw new InvalidOperationException(Translator.GetText("Could not register the hot key.") + " (" + errorHint + ")");
}
// In case unregister failes, unfortunately registration remains
// but will not trigger anything as we change our hotkey registration.
// However, this means the hotkey keeps being registered with this application
// and the key combination will not be availalbe for re-registration till app restart.
// TODO: Decide how to handle this? Restart App? Try keep old registartion and not update it?
if (!NativeMethods.User32UnregisterHotKey(HWnd.Handle, reg.Id))
{
Log.Info("Hotkey registration cannot unregister key " + reg.Modifiers.ToString() + " with modifiers " + reg.Modifiers.ToString());
}
reg.Id = id;
reg.Modifiers = modifiers;
reg.Key = key;
}
return true;
}
internal static bool Reassign(IHotkeyRegistration? registration, string hotKeyString)
{
var (modifiers, key) = ParseKeysAndModifiersFromString(hotKeyString);
return Reassign(registration, modifiers, key);
}
// TODO: Instead of searching for the registration, it should be passed to the caller instead. // TODO: Instead of searching for the registration, it should be passed to the caller instead.
// Only this ensures caller and registrator are talking about the SAME registration. // Only this ensures caller and registrator are talking about the SAME registration.
internal static IHotkeyRegistration? FindRegistration(string hotKeyString) internal static IHotkeyRegistration? FindRegistration(string hotKeyString)
@ -316,7 +377,7 @@ namespace SystemTrayMenu.Helpers
const int WmHotkey = 0x0312; const int WmHotkey = 0x0312;
// check if we got a hot key pressed. // check if we got a hot key pressed.
if (msg == WmHotkey) if (msg == WmHotkey && IsEnabled)
{ {
ModifierKeys modifiers = (ModifierKeys)((int)lParam & 0xFFFF); ModifierKeys modifiers = (ModifierKeys)((int)lParam & 0xFFFF);
int virtualKeyCode = ((int)lParam >> 16) & 0xFFFF; int virtualKeyCode = ((int)lParam >> 16) & 0xFFFF;
@ -346,7 +407,7 @@ namespace SystemTrayMenu.Helpers
{ {
public event Action<IHotkeyRegistration>? KeyPressed; public event Action<IHotkeyRegistration>? KeyPressed;
internal int Id { get; init; } internal int Id { get; set; }
internal ModifierKeys Modifiers { get; set; } internal ModifierKeys Modifiers { get; set; }

View file

@ -25,7 +25,7 @@ namespace SystemTrayMenu.UserInterface
private readonly IList<int> needNonAltGrModifier = new List<int>(); private readonly IList<int> needNonAltGrModifier = new List<int>();
// These variables store the current hotkey and modifier(s) // These variables store the current hotkey and modifier(s)
private IHotkeyRegistration? hotkeyHandle; private IHotkeyRegistration? hotkeyRegistration;
private Key hotkey = Key.None; private Key hotkey = Key.None;
private ModifierKeys modifiers = ModifierKeys.None; private ModifierKeys modifiers = ModifierKeys.None;
private Action? handler; private Action? handler;
@ -48,11 +48,7 @@ namespace SystemTrayMenu.UserInterface
PreviewKeyDown += HandlePreviewKeyDown; PreviewKeyDown += HandlePreviewKeyDown;
PreviewTextInput += HandlePreviewTextInput; PreviewTextInput += HandlePreviewTextInput;
GotFocus += (_, _) => GotFocus += (_, _) => GlobalHotkeys.IsEnabled = false;
{
UnregisterHotKey();
Reassigning = true;
};
LostFocus += (_, _) => LostFocus += (_, _) =>
{ {
#if TODO // HOTKEY #if TODO // HOTKEY
@ -66,18 +62,14 @@ namespace SystemTrayMenu.UserInterface
/// </summary> /// </summary>
/// <returns>Whether the hotkeys could be registered to the users content. This also applies if conflicts arise and the user decides to ignore these (i.e. not to register the conflicting hotkey).</returns> /// <returns>Whether the hotkeys could be registered to the users content. This also applies if conflicts arise and the user decides to ignore these (i.e. not to register the conflicting hotkey).</returns>
RegisterHotkeys(false); RegisterHotkeys(false);
#else
ReregisterHotKey();
#endif #endif
Reassigning = false; GlobalHotkeys.IsEnabled = true;
}; };
PopulateModifierLists(); PopulateModifierLists();
SetHotkeyRegistration((IHotkeyRegistration?)null); SetHotkeyRegistration((IHotkeyRegistration?)null);
} }
internal bool Reassigning { get; private set; }
public static string HotkeyToString(ModifierKeys modifierKeyCode, Key key) public static string HotkeyToString(ModifierKeys modifierKeyCode, Key key)
{ {
StringBuilder hotkeyString = new(); StringBuilder hotkeyString = new();
@ -112,11 +104,11 @@ namespace SystemTrayMenu.UserInterface
/// <param name="registration">Registration interface.</param> /// <param name="registration">Registration interface.</param>
internal void SetHotkeyRegistration(IHotkeyRegistration? registration) internal void SetHotkeyRegistration(IHotkeyRegistration? registration)
{ {
hotkeyHandle = registration; hotkeyRegistration = registration;
if (hotkeyHandle != null) if (hotkeyRegistration != null)
{ {
hotkey = hotkeyHandle.GetKey(); hotkey = hotkeyRegistration.GetKey();
modifiers = hotkeyHandle.GetModifierKeys(); modifiers = hotkeyRegistration.GetModifierKeys();
Background = Brushes.LightGreen; Background = Brushes.LightGreen;
} }
else else
@ -140,12 +132,7 @@ namespace SystemTrayMenu.UserInterface
/// Change the hotkey to given combination. /// Change the hotkey to given combination.
/// </summary> /// </summary>
/// <param name="hotkeyString">Hotkey combination string.</param> /// <param name="hotkeyString">Hotkey combination string.</param>
internal void ChangeHotkey(string hotkeyString) internal void ChangeHotkey(string hotkeyString) => Reassign(hotkeyRegistration, hotkeyString);
{
hotkey = KeyFromString(hotkeyString);
modifiers = ModifierKeysFromString(hotkeyString);
Redraw(true);
}
/// <summary> /// <summary>
/// Register a hotkey. /// Register a hotkey.
@ -164,7 +151,7 @@ namespace SystemTrayMenu.UserInterface
try try
{ {
hotkeyHandle = Register(modifiers, key); hotkeyRegistration = Register(modifiers, key);
} }
catch (InvalidOperationException ex) catch (InvalidOperationException ex)
{ {
@ -174,26 +161,12 @@ namespace SystemTrayMenu.UserInterface
} }
this.handler = handler; this.handler = handler;
hotkeyHandle.KeyPressed += (_) => handler.Invoke(); hotkeyRegistration.KeyPressed += (_) => handler.Invoke();
Background = Brushes.LightGreen; Background = Brushes.LightGreen;
return 1; return 1;
} }
private void ReregisterHotKey()
{
if (handler != null)
{
RegisterHotKey(modifiers, hotkey, handler);
}
}
private void UnregisterHotKey()
{
Unregister(hotkeyHandle);
hotkeyHandle = null;
}
/// <summary> /// <summary>
/// Clears the current hotkey and resets the TextBox. /// Clears the current hotkey and resets the TextBox.
/// </summary> /// </summary>
@ -354,6 +327,7 @@ namespace SystemTrayMenu.UserInterface
{ {
modifiers = Keyboard.Modifiers; modifiers = Keyboard.Modifiers;
hotkey = e.Key; hotkey = e.Key;
Reassign(hotkeyRegistration, modifiers, hotkey);
Redraw(false); Redraw(false);
} }
} }

View file

@ -14,6 +14,7 @@ namespace SystemTrayMenu.UserInterface
using System.Windows.Input; using System.Windows.Input;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using Microsoft.Win32; using Microsoft.Win32;
using SystemTrayMenu.Helpers;
using SystemTrayMenu.Properties; using SystemTrayMenu.Properties;
using SystemTrayMenu.UserInterface.FolderBrowseDialog; using SystemTrayMenu.UserInterface.FolderBrowseDialog;
using SystemTrayMenu.Utilities; using SystemTrayMenu.Utilities;
@ -445,7 +446,7 @@ namespace SystemTrayMenu.UserInterface
private void HandlePreviewKeyDown(object sender, KeyEventArgs e) private void HandlePreviewKeyDown(object sender, KeyEventArgs e)
{ {
if (e.Key == Key.Escape && !textBoxHotkey.Reassigning) if (e.Key == Key.Escape && GlobalHotkeys.IsEnabled)
{ {
Close(); Close();
} }