禁用 全局快捷键

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

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         /// <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     hotKeyHandleWindow.Hide();

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

 

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

posted @ 2020-03-24 11:56  唐宋元明清2188  阅读(451)  评论(2编辑  收藏  举报