128 lines
4.0 KiB
C#
128 lines
4.0 KiB
C#
using System;
|
|
using System.Runtime.InteropServices;
|
|
using System.Windows.Input;
|
|
using System.Windows.Interop;
|
|
|
|
namespace TodoList.Services
|
|
{
|
|
public class GlobalShortcutService : IDisposable
|
|
{
|
|
private const int HOTKEY_ID = 9000;
|
|
|
|
public const uint MOD_ALT = 0x0001;
|
|
public const uint MOD_CONTROL = 0x0002;
|
|
public const uint MOD_SHIFT = 0x0004;
|
|
public const uint MOD_WIN = 0x0008;
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
|
|
|
|
[DllImport("user32.dll")]
|
|
private static extern bool UnregisterHotKey(IntPtr hWnd, int id);
|
|
|
|
private IntPtr _windowHandle;
|
|
private HwndSource _source;
|
|
private Action _onHotKeyPressed;
|
|
private bool _isRegistered;
|
|
|
|
public void Register(IntPtr windowHandle, Action onHotKeyPressed, uint modifiers, uint key)
|
|
{
|
|
// If already registered, unregister first (to support updating)
|
|
if (_isRegistered)
|
|
{
|
|
UnregisterHotKey(_windowHandle, HOTKEY_ID);
|
|
_source?.RemoveHook(HwndHook);
|
|
_isRegistered = false;
|
|
}
|
|
|
|
_windowHandle = windowHandle;
|
|
_onHotKeyPressed = onHotKeyPressed;
|
|
|
|
_source = HwndSource.FromHwnd(_windowHandle);
|
|
if (_source == null) return; // Should not happen if handle is valid
|
|
|
|
_source.AddHook(HwndHook);
|
|
|
|
if (RegisterHotKey(_windowHandle, HOTKEY_ID, modifiers, key))
|
|
{
|
|
_isRegistered = true;
|
|
}
|
|
else
|
|
{
|
|
System.Diagnostics.Debug.WriteLine("Failed to register hotkey.");
|
|
}
|
|
}
|
|
|
|
public void UpdateShortcut(uint modifiers, uint key)
|
|
{
|
|
if (_windowHandle != IntPtr.Zero && _onHotKeyPressed != null)
|
|
{
|
|
// Re-register with new keys
|
|
Register(_windowHandle, _onHotKeyPressed, modifiers, key);
|
|
}
|
|
}
|
|
|
|
private IntPtr HwndHook(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
|
|
{
|
|
const int WM_HOTKEY = 0x0312;
|
|
if (msg == WM_HOTKEY)
|
|
{
|
|
if (wParam.ToInt32() == HOTKEY_ID)
|
|
{
|
|
_onHotKeyPressed?.Invoke();
|
|
handled = true;
|
|
}
|
|
}
|
|
return IntPtr.Zero;
|
|
}
|
|
|
|
public void Unregister()
|
|
{
|
|
if (_isRegistered)
|
|
{
|
|
_source?.RemoveHook(HwndHook);
|
|
UnregisterHotKey(_windowHandle, HOTKEY_ID);
|
|
_isRegistered = false;
|
|
}
|
|
}
|
|
|
|
public void Dispose()
|
|
{
|
|
Unregister();
|
|
}
|
|
|
|
public static uint GetModifier(string modifiers)
|
|
{
|
|
uint mod = 0;
|
|
if (string.IsNullOrEmpty(modifiers)) return mod;
|
|
|
|
var parts = modifiers.Split(',');
|
|
foreach (var part in parts)
|
|
{
|
|
var p = part.Trim();
|
|
if (p.Equals("Control", StringComparison.OrdinalIgnoreCase)) mod |= MOD_CONTROL;
|
|
if (p.Equals("Alt", StringComparison.OrdinalIgnoreCase)) mod |= MOD_ALT;
|
|
if (p.Equals("Shift", StringComparison.OrdinalIgnoreCase)) mod |= MOD_SHIFT;
|
|
if (p.Equals("Windows", StringComparison.OrdinalIgnoreCase)) mod |= MOD_WIN;
|
|
}
|
|
return mod;
|
|
}
|
|
|
|
public static uint GetKey(string key)
|
|
{
|
|
if (Enum.TryParse<Key>(key, out var k))
|
|
{
|
|
return (uint)KeyInterop.VirtualKeyFromKey(k);
|
|
}
|
|
// Fallback for simple letters if Key enum doesn't match directly (though it should for A-Z)
|
|
if (key.Length == 1)
|
|
{
|
|
char c = char.ToUpper(key[0]);
|
|
if (c >= 'A' && c <= 'Z') return (uint)c;
|
|
if (c >= '0' && c <= '9') return (uint)c;
|
|
}
|
|
return 0x41; // Default 'A'
|
|
}
|
|
}
|
|
}
|