在给软件添加快捷键时,经常遇到其它软件或者系统已设置的快捷键,导致功能冲突。

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方法 - 外界全局键调用时,调用回调函数

禁用 全局快捷键_快捷键

禁用 全局快捷键_热键_02

1     public class HotKeys
2 {
3 #region 注册快捷键
4
5 /// <summary>
6 /// 注册快捷键
7 /// </summary>
8 /// <param name="modifiers"></param>
9 /// <param name="key"></param>
10 public void Register(int modifiers, Keys key)
11 {
12 Register(IntPtr.Zero, modifiers, key);
13 }
14 /// <summary>
15 /// 注册快捷键
16 /// </summary>
17 /// <param name="hWnd"></param>
18 /// <param name="modifiers"></param>
19 /// <param name="key"></param>
20 /// <param name="callBack"></param>
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 /// <summary>
47 /// 注销快捷键
48 /// </summary>
49 /// <param name="hWnd"></param>
50 /// <param name="modifiers"></param>
51 /// <param name="key"></param>
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 /// <summary>
62 /// 注销快捷键
63 /// </summary>
64 /// <param name="modifiers"></param>
65 /// <param name="key"></param>
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 /// <summary>
76 /// 注销快捷键
77 /// </summary>
78 /// <param name="hWnd"></param>
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 /// <summary>
101 /// 快捷键消息处理
102 /// </summary>
103 /// <param name="msg"></param>
104 /// <param name="wParam">消息Id</param>
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<HotkeyRegisterRecord> _hotkeyRegisterRecords = new List<HotkeyRegisterRecord>();
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

View Code

在上方的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

以上有回调响应,但是也是无感知的。

 

Demo: ​​https://github.com/Kybs0/DiableGlobalShortcuts​

作者:​​唐宋元明清2188​