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();
}
/// <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>
/// Registers a global hotkey.
/// Function is thread safe.
@ -57,9 +63,9 @@ namespace SystemTrayMenu.Helpers
{
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>
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;
}
@ -120,6 +126,61 @@ namespace SystemTrayMenu.Helpers
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.
// Only this ensures caller and registrator are talking about the SAME registration.
internal static IHotkeyRegistration? FindRegistration(string hotKeyString)
@ -316,7 +377,7 @@ namespace SystemTrayMenu.Helpers
const int WmHotkey = 0x0312;
// check if we got a hot key pressed.
if (msg == WmHotkey)
if (msg == WmHotkey && IsEnabled)
{
ModifierKeys modifiers = (ModifierKeys)((int)lParam & 0xFFFF);
int virtualKeyCode = ((int)lParam >> 16) & 0xFFFF;
@ -346,7 +407,7 @@ namespace SystemTrayMenu.Helpers
{
public event Action<IHotkeyRegistration>? KeyPressed;
internal int Id { get; init; }
internal int Id { get; set; }
internal ModifierKeys Modifiers { get; set; }

View file

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

View file

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