在给软件添加快捷键时,经常遇到其它软件或者系统已设置的快捷键,导致功能冲突。
HotKey函数
下面介绍一个user32.dll的RegisterHotKey以及UnregisterHotKey热键处理的函数
注册热键 RegisterHotKey function
BOOL RegisterHotKey(
HWND hWnd, //响应热键的窗口句柄,如果为空,则注册到调用线程上
Int id, //热键的唯一标识
UINT fsModifiers, //热键的辅助按键
UINT vk //热键的键值
);
解除注册热键UnregisterHotKey function
BOOL WINAPI UnregisterHotKey(
HWND hWnd,//热键注册的窗口
int id//要解除注册的热键ID
);
添加热键注册和注销函数
流程:
Register方法 - 注册user32.dll函数RegisterHotKey以禁用全局键,并在缓存内添加禁用记录
ProcessHotKey方法 - 外界全局键调用时,调用回调函数
1 public class HotKeys 2 { 3 #region 注册快捷键 4 5 ///6 /// 注册快捷键 7 /// 8 /// 9 /// 10 public void Register(int modifiers, Keys key) 11 { 12 Register(IntPtr.Zero, modifiers, key); 13 } 14 /// 15 /// 注册快捷键 16 /// 17 /// 18 /// 19 /// 20 /// 21 public void Register(IntPtr hWnd, int modifiers, Keys key, HotKeyCallBackHanlder callBack = null) 22 { 23 var registerRecord = _hotkeyRegisterRecords.FirstOrDefault(i => i.IntPtr == hWnd && i.Modifiers == modifiers && i.Key == key); 24 if (registerRecord != null) 25 { 26 UnregisterHotKey(hWnd, registerRecord.Id); 27 _hotkeyRegisterRecords.Remove(registerRecord); 28 } 29 int id = registerId++; 30 if (!RegisterHotKey(hWnd, id, modifiers, key)) 31 throw new Exception("注册失败!"); 32 _hotkeyRegisterRecords.Add(new HotkeyRegisterRecord() 33 { 34 Id = id, 35 IntPtr = hWnd, 36 Modifiers = modifiers, 37 Key = key, 38 CallBack = callBack 39 }); 40 } 41 42 #endregion 43 44 #region 注销快捷键 45 46 /// 47 /// 注销快捷键 48 /// 49 /// 50 /// 51 /// 52 public void UnRegister(IntPtr hWnd, int modifiers, Keys key) 53 { 54 var registerRecord = _hotkeyRegisterRecords.FirstOrDefault(i => i.IntPtr == hWnd && i.Modifiers == modifiers && i.Key == key); 55 if (registerRecord != null) 56 { 57 UnregisterHotKey(hWnd, registerRecord.Id); 58 _hotkeyRegisterRecords.Remove(registerRecord); 59 } 60 } 61 /// 62 /// 注销快捷键 63 /// 64 /// 65 /// 66 public void UnRegister(int modifiers, Keys key) 67 { 68 var registerRecord = _hotkeyRegisterRecords.FirstOrDefault(i => i.IntPtr == IntPtr.Zero && i.Modifiers == modifiers && i.Key == key); 69 if (registerRecord != null) 70 { 71 UnregisterHotKey(IntPtr.Zero, registerRecord.Id); 72 _hotkeyRegisterRecords.Remove(registerRecord); 73 } 74 } 75 /// 76 /// 注销快捷键 77 /// 78 /// 79 public void UnRegister(IntPtr hWnd) 80 { 81 var registerRecords = _hotkeyRegisterRecords.Where(i => i.IntPtr == hWnd); 82 //注销所有 83 foreach (var registerRecord in registerRecords) 84 { 85 UnregisterHotKey(hWnd, registerRecord.Id); 86 _hotkeyRegisterRecords.Remove(registerRecord); 87 } 88 } 89 90 #endregion 91 92 #region 快捷键消息处理 93 94 // 快捷键消息处理 95 public void ProcessHotKey(Message message) 96 { 97 ProcessHotKey(message.Msg, message.WParam); 98 } 99 100 /// 101 /// 快捷键消息处理 102 /// 103 /// 104 /// 消息Id 105 public void ProcessHotKey(int msg, IntPtr wParam) 106 { 107 if (msg == 0x312) 108 { 109 int id = wParam.ToInt32(); 110 var registerRecord = _hotkeyRegisterRecords.FirstOrDefault(i => i.Id == id); 111 registerRecord?.CallBack?.Invoke(); 112 } 113 } 114 115 #endregion 116 117 #region MyRegion 118 119 //引入系统API 120 [DllImport("user32.dll")] 121 static extern bool RegisterHotKey(IntPtr hWnd, int id, int modifiers, Keys vk); 122 [DllImport("user32.dll")] 123 static extern bool UnregisterHotKey(IntPtr hWnd, int id); 124 125 //标识-区分不同的快捷键 126 int registerId = 10; 127 //添加key值注册字典,后续调用时有回调处理函数 128 private readonly List _hotkeyRegisterRecords = new List (); 129 public delegate void HotKeyCallBackHanlder(); 130 131 #endregion 132 133 } 134 135 public class HotkeyRegisterRecord 136 { 137 public IntPtr IntPtr { get; set; } 138 public int Modifiers { get; set; } 139 public Keys Key { get; set; } 140 public int Id { get; set; } 141 public HotKeys.HotKeyCallBackHanlder CallBack { get; set; } 142 } 143 //组合控制键 144 public enum HotkeyModifiers 145 { 146 Alt = 1, 147 Control = 2, 148 Shift = 4, 149 Win = 8 150 }
在上方的HotKeys类中,注册方法Register提供了一个回调函数,后续监听到外界全局键时,可以通知回调函数处理。
参数WParam,是窗口响应时快捷键值,在winform和WPF窗口消息函数中都是有的。
另,组合快捷键内部枚举类HotkeyModifiers,枚举值来自官网文档WM_HOTKEY message
无感知禁用全局快捷键
比如:禁用Ctrl+Alt+1、Ctrl+Alt+2、Ctrl+Alt+3、Ctrl+Alt+4(Windows桌面图标大小的调节快捷键)
1 HotKeys hotKeys = new HotKeys(); 2 hotKeys.Register((int)HotkeyModifiers.Control, Keys.N); 3 hotKeys.Register((int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D1); 4 hotKeys.Register((int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D2); 5 hotKeys.Register((int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D3); 6 hotKeys.Register((int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D4);
注:
- 窗口句柄参数,如果提供空的话,则注册到调用线程上。
- Keys类型在system.windows.Forms程序集下,如果是WPF的Key,可以使用KeyInterop将Wpf键值类型转换为Winform键值再调用此函数。
无感知禁用全局快捷键后回调
如果禁用全局快捷键的同时,外界触发快捷键时需要此程序回调处理,可以添加窗口消息处理:
1. 新建一个类HotKeyHandleWindow,继承自Window
- 窗口样式 - 高宽为0,窗口样式None
- 添加热键注册的调用
- 添加WndProc,处理窗口消息
1 public class HotKeyHandleWindow : Window 2 { 3 private readonly HotKeys _hotKeys = new HotKeys(); 4 public HotKeyHandleWindow() 5 { 6 WindowStyle = WindowStyle.None; 7 Width = 0; 8 Height = 0; 9 Loaded += (s, e) => 10 { 11 //这里注册了Ctrl+Alt+1 快捷键 12 _hotKeys.Register(new WindowInteropHelper(this).Handle, 13 (int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D1, CallBack); 14 }; 15 } 16 protected override void OnSourceInitialized(EventArgs e) 17 { 18 base.OnSourceInitialized(e); 19 var hwndSource = PresentationSource.FromVisual(this) as HwndSource; 20 hwndSource?.AddHook(new HwndSourceHook(WndProc)); 21 } 22 public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled) 23 { 24 //窗口消息处理函数 25 _hotKeys.ProcessHotKey(msg, wParam); 26 return hwnd; 27 } 28 //按下快捷键时被调用的方法 29 public void CallBack() 30 { 31 } 32 }
2. 调用窗口类:
1 var hotKeyHandleWindow = new HotKeyHandleWindow(); 2 hotKeyHandleWindow.Show(); 3 hotKeyHandleWindow.Hide();
以上有回调响应,但是也是无感知的。
Demo: https://github.com/Kybs0/DiableGlobalShortcuts