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

HotKey函数

  • 下面介绍一个​​user32.dll​​的​​RegisterHotKey​​以及​​UnregisterHotKey​​热键处理的函数;
  • 注册热键 RegisterHotKey function [1];
BOOL RegisterHotKey(
HWND hWnd, //响应热键的窗口句柄,如果为空,则注册到调用线程上
Int id, //热键的唯一标识
UINT fsModifiers, //热键的辅助按键
UINT vk //热键的键值
);
  • 解除注册热键UnregisterHotKey function [2];
BOOL WINAPI UnregisterHotKey( 
HWND hWnd,//热键注册的窗口
int id//要解除注册的热键ID
);

添加热键注册和注销函数

​Register​​​方法 -  注册​​user32.dll​​​函数​​RegisterHotKey​​以禁用全局键,并在缓存内添加禁用记录;

​ProcessHotKey​​方法 - 外界全局键调用时,调用回调函数;

public class HotKeys
{
#region 注册快捷键

/// <summary>
/// 注册快捷键
/// </summary>
/// <param name="modifiers"></param>
/// <param name="key"></param>
public void Register(int modifiers, Keys key)
{
Register(IntPtr.Zero, modifiers, key);
}
/// <summary>
/// 注册快捷键
/// </summary>
/// <param name="hWnd"></param>
/// <param name="modifiers"></param>
/// <param name="key"></param>
/// <param name="callBack"></param>
public void Register(IntPtr hWnd, int modifiers, Keys key, HotKeyCallBackHanlder callBack = null)
{
var registerRecord = _hotkeyRegisterRecords.FirstOrDefault(i => i.IntPtr == hWnd && i.Modifiers == modifiers && i.Key == key);
if (registerRecord != null)
{
UnregisterHotKey(hWnd, registerRecord.Id);
_hotkeyRegisterRecords.Remove(registerRecord);
}
int id = registerId++;
if (!RegisterHotKey(hWnd, id, modifiers, key))
throw new Exception("注册失败!");
_hotkeyRegisterRecords.Add(new HotkeyRegisterRecord()
{
Id = id,
IntPtr = hWnd,
Modifiers = modifiers,
Key = key,
CallBack = callBack
});
}

#endregion

#region 注销快捷键

/// <summary>
/// 注销快捷键
/// </summary>
/// <param name="hWnd"></param>
/// <param name="modifiers"></param>
/// <param name="key"></param>
public void UnRegister(IntPtr hWnd, int modifiers, Keys key)
{
var registerRecord = _hotkeyRegisterRecords.FirstOrDefault(i => i.IntPtr == hWnd && i.Modifiers == modifiers && i.Key == key);
if (registerRecord != null)
{
UnregisterHotKey(hWnd, registerRecord.Id);
_hotkeyRegisterRecords.Remove(registerRecord);
}
}
/// <summary>
/// 注销快捷键
/// </summary>
/// <param name="modifiers"></param>
/// <param name="key"></param>
public void UnRegister(int modifiers, Keys key)
{
var registerRecord = _hotkeyRegisterRecords.FirstOrDefault(i => i.IntPtr == IntPtr.Zero && i.Modifiers == modifiers && i.Key == key);
if (registerRecord != null)
{
UnregisterHotKey(IntPtr.Zero, registerRecord.Id);
_hotkeyRegisterRecords.Remove(registerRecord);
}
}
/// <summary>
/// 注销快捷键
/// </summary>
/// <param name="hWnd"></param>
public void UnRegister(IntPtr hWnd)
{
var registerRecords = _hotkeyRegisterRecords.Where(i => i.IntPtr == hWnd);
//注销所有
foreach (var registerRecord in registerRecords)
{
UnregisterHotKey(hWnd, registerRecord.Id);
_hotkeyRegisterRecords.Remove(registerRecord);
}
}

#endregion

#region 快捷键消息处理

// 快捷键消息处理
public void ProcessHotKey(Message message)
{
ProcessHotKey(message.Msg, message.WParam);
}

/// <summary>
/// 快捷键消息处理
/// </summary>
/// <param name="msg"></param>
/// <param name="wParam">消息Id</param>
public void ProcessHotKey(int msg, IntPtr wParam)
{
if (msg == 0x312)
{
int id = wParam.ToInt32();
var registerRecord = _hotkeyRegisterRecords.FirstOrDefault(i => i.Id == id);
registerRecord?.CallBack?.Invoke();
}
}

#endregion

#region MyRegion

//引入系统API
[DllImport("user32.dll")]
static extern bool RegisterHotKey(IntPtr hWnd, int id, int modifiers, Keys vk);
[DllImport("user32.dll")]
static extern bool UnregisterHotKey(IntPtr hWnd, int id);

//标识-区分不同的快捷键
int registerId = 10;
//添加key值注册字典,后续调用时有回调处理函数
private readonly List<HotkeyRegisterRecord> _hotkeyRegisterRecords = new List<HotkeyRegisterRecord>();
public delegate void HotKeyCallBackHanlder();

#endregion

}

public class HotkeyRegisterRecord
{
public IntPtr IntPtr { get; set; }
public int Modifiers { get; set; }
public Keys Key { get; set; }
public int Id { get; set; }
public HotKeys.HotKeyCallBackHanlder CallBack { get; set; }
}
//组合控制键
public enum HotkeyModifiers
{
Alt = 1,
Control = 2,
Shift = 4,
Win = 8
}
  • 在上方的​​HotKeys​​类中,注册方法​​Register​​提供了一个回调函数,后续监听到外界全局键时,可以通知回调函数处理。
  • 参数​​WParam​​,是窗口响应时快捷键值,在​​winform​​和​​WPF​​窗口消息函数中都是有的。
  • 另,组合快捷键内部枚举类​​HotkeyModifiers​​,枚举值来自官网文档​​WM_HOTKEY message​​;

无感知禁用全局快捷键

比如:

  • 禁用​​Ctrl+Alt+1、Ctrl+Alt+2、Ctrl+Alt+3、Ctrl+Alt+4(Windows桌面图标大小的调节快捷键​​);
    HotKeys hotKeys = new HotKeys();
hotKeys.Register((int)HotkeyModifiers.Control, Keys.N);
hotKeys.Register((int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D1);
hotKeys.Register((int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D2);
hotKeys.Register((int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D3);
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​​,处理窗口消息;
public class HotKeyHandleWindow : Window
{
private readonly HotKeys _hotKeys = new HotKeys();
public HotKeyHandleWindow()
{
WindowStyle = WindowStyle.None;
Width = 0;
Height = 0;
Loaded += (s, e) =>
{
//这里注册了Ctrl+Alt+1 快捷键
_hotKeys.Register(new WindowInteropHelper(this).Handle,
(int)HotkeyModifiers.Control + (int)HotkeyModifiers.Alt, Keys.D1, CallBack);
};
}
protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
var hwndSource = PresentationSource.FromVisual(this) as HwndSource;
hwndSource?.AddHook(new HwndSourceHook(WndProc));
}
public IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
//窗口消息处理函数
_hotKeys.ProcessHotKey(msg, wParam);
return hwnd;
}
//按下快捷键时被调用的方法
public void CallBack()
{
}
}

2)调用窗口类;

var hotKeyHandleWindow = new HotKeyHandleWindow();
hotKeyHandleWindow.Show();
hotKeyHandleWindow.Hide();

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

源码下载[3]

参考资料

[1]

RegisterHotKey function : ​https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-registerhotkey?redirectedfrom=MSDN​

[2]

UnregisterHotKey function : ​https://docs.microsoft.com/zh-cn/windows/win32/api/winuser/nf-winuser-unregisterhotkey​

[3]

源码下载: ​https://github.com/Kybs0/DiableGlobalShortcuts​