文章目录
- 命名空间和类
- 类成员
- 静态成员
- 静态方法
- `GenerateHotkeyId`
- `WndProc`
- `GetWindowHandleAndSource`
- `Register`
- `Unregister`
- 静态方法(外部调用)
- `RegisterHotKey` 和 `UnRegisterHotKey`
- 委托
- `HotKeyCallbackHandler`
- 枚举
- `HotkeyModifiers`
- 应用示例
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Threading;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;
namespace HotKeyModule
{
public static class Hotkey
{
private static readonly Dictionary<int, HotKeyCallbackHandler> keymap = new Dictionary<int, HotKeyCallbackHandler>();
private static int nextHotkeyId = 10;
private static readonly object keymapLock = new object();
private static int GenerateHotkeyId() => Interlocked.Increment(ref nextHotkeyId);
// 窗口消息处理
private static IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
const int WM_HOTKEY = 0x0312;
if (msg == WM_HOTKEY)
{
int hotkeyId = wParam.ToInt32();
if (keymap.TryGetValue(hotkeyId, out var callback))
{
callback();
handled = true;
}
}
return IntPtr.Zero;
}
// 获取窗口句柄和HwndSource
private static (IntPtr hwnd, HwndSource hwndSource) GetWindowHandleAndSource(Window window)
{
var hwnd = new WindowInteropHelper(window).Handle;
var hwndSource = HwndSource.FromHwnd(hwnd) ?? throw new InvalidOperationException("Failed to get HwndSource.");
return (hwnd, hwndSource);
}
// 注册热键
public static void Register(Window window, HotkeyModifiers modifiers, Key key, HotKeyCallbackHandler callback)
{
var (hwnd, hwndSource) = GetWindowHandleAndSource(window);
hwndSource.AddHook(WndProc);
int hotkeyId = GenerateHotkeyId();
uint vk = (uint)KeyInterop.VirtualKeyFromKey(key);
if (!RegisterHotKey(hwnd, hotkeyId, (uint)modifiers, vk))
{
throw new InvalidOperationException("Failed to register hotkey. Ensure the key combination is not already in use.");
}
lock (keymapLock)
{
keymap[hotkeyId] = callback;
}
}
// 注销热键
public static void Unregister(Window window, HotKeyCallbackHandler callback)
{
var (hwnd, _) = GetWindowHandleAndSource(window);
lock (keymapLock)
{
foreach (var kvp in keymap)
{
if (kvp.Value == callback)
{
UnRegisterHotKey(hwnd, kvp.Key);
keymap.Remove(kvp.Key);
break;
}
}
}
}
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool RegisterHotKey(IntPtr hWnd, int id, uint fsModifiers, uint vk);
[DllImport("user32.dll")]
[return: MarshalAs(UnmanagedType.Bool)]
private static extern bool UnRegisterHotKey(IntPtr hWnd, int id);
}
// 热键回调委托
public delegate void HotKeyCallbackHandler();
public enum HotkeyModifiers
{
ALT = 0x0001,
CTRL = 0x0002,
SHIFT = 0x0004,
WIN = 0x0008,
CTRL_ALT = CTRL|ALT,
CTRL_SHIFT = CTRL | SHIFT,
}
}
命名空间和类
代码定义在一个名为 HotKeyModule
的命名空间中,其中包含一个静态类 Hotkey
,用于管理热键的注册和注销。
类成员
静态成员
-
keymap
:- 类型:
Dictionary<int, HotKeyCallbackHandler>
- 用途:存储热键ID和对应的回调函数。
- 类型:
-
nextHotkeyId
:- 类型:
int
- 用途:生成唯一的热键ID。
- 初始值:10
- 类型:
-
keymapLock
:- 类型:
object
- 用途:用于同步访问
keymap
,确保线程安全。
- 类型:
静态方法
GenerateHotkeyId
- 用途:生成唯一的热键ID。
- 实现:使用
Interlocked.Increment
方法原子性地增加nextHotkeyId
,并返回其新的值。
WndProc
- 用途:处理窗口消息,特别是热键消息。
- 参数:
hwnd
:窗口句柄msg
:消息类型wParam
:消息参数lParam
:消息参数handled
:是否处理了消息
- 实现:
- 检查消息类型是否为
WM_HOTKEY
(0x0312)。 - 如果是热键消息,从
wParam
中提取热键ID。 - 在
keymap
中查找对应的回调函数并执行。 - 将
handled
设置为true
,表示消息已处理。
- 检查消息类型是否为
GetWindowHandleAndSource
- 用途:获取窗口句柄和
HwndSource
。 - 参数:
window
:需要处理的Window
对象
- 返回:
hwnd
:窗口句柄hwndSource
:与窗口关联的HwndSource
- 实现:
- 使用
WindowInteropHelper
获取窗口句柄。 - 使用
HwndSource.FromHwnd
获取HwndSource
,如果获取失败则抛出异常。
- 使用
Register
- 用途:注册热键。
- 参数:
window
:需要注册热键的Window
对象modifiers
:热键修饰符(例如CTRL
、ALT
等)key
:热键按键callback
:热键触发时的回调函数
- 实现:
- 调用
GetWindowHandleAndSource
获取窗口句柄和HwndSource
。 - 将
WndProc
注册为窗口消息处理函数。 - 生成唯一的热键ID。
- 将按键转换为虚拟键码。
- 调用
RegisterHotKey
函数注册热键,如果注册失败则抛出异常。 - 将热键ID和回调函数添加到
keymap
中。
- 调用
Unregister
- 用途:注销热键。
- 参数:
window
:需要注销热键的Window
对象callback
:需要注销的回调函数
- 实现:
- 调用
GetWindowHandleAndSource
获取窗口句柄和HwndSource
。 - 升级
keymapLock
,确保线程安全。 - 在
keymap
中查找对应回调函数的热键ID。 - 调用
UnRegisterHotKey
函数注销热键。 - 从
keymap
中移除对应的热键ID和回调函数。
- 调用
静态方法(外部调用)
RegisterHotKey
和 UnRegisterHotKey
- 用途:注册和注销热键的外部调用。
- 参数:
hWnd
:窗口句柄id
:热键IDfsModifiers
:热键修饰符vk
:虚拟键码
- 实现:
- 使用
DllImport
导入user32.dll
中的RegisterHotKey
和UnRegisterHotKey
函数。
- 使用
委托
HotKeyCallbackHandler
- 用途:定义热键回调函数的委托。
- 类型:
public delegate void HotKeyCallbackHandler()
枚举
HotkeyModifiers
- 用途:定义热键修饰符。
- 成员:
ALT
:0x0001CTRL
:0x0002SHIFT
:0x0004WIN
:0x0008CTRL_ALT
:CTRL | ALT
CTRL_SHIFT
:CTRL | SHIFT
应用示例
这段代码是 OnSourceInitialized 方法的重写,用于在窗口的 SourceInitialized 事件触发时注册热键。SourceInitialized 事件在窗口句柄创建后立即触发。
protected override void OnSourceInitialized(EventArgs e)
{
Hotkey.Register(this, HotkeyModifiers.CTRL, Key.D, () =>
{
WindowController.Get<FlowView>().Hide();
WindowController.Get<MainView>().Show();
});
Hotkey.Register(this, HotkeyModifiers.CTRL_ALT, Key.D, () =>
{
Application.Current.Shutdown();
});
}