C# 禁用 全局快捷键

Posted dotNET跨平台

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C# 禁用 全局快捷键相关的知识,希望对你有一定的参考价值。

本文经原作者授权以原创方式二次分享,欢迎转载、分享。

原文作者:唐宋元明清

原文地址:https://www.cnblogs.com/kybs0/p/12558056.html

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

HotKey函数

  • 下面介绍一个user32.dllRegisterHotKey以及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,是窗口响应时快捷键值,在winformWPF窗口消息函数中都是有的。

  • 另,组合快捷键内部枚举类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程序集下,如果是WPFKey,可以使用KeyInteropWpf键值类型转换为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

以上是关于C# 禁用 全局快捷键的主要内容,如果未能解决你的问题,请参考以下文章

禁用 全局快捷键

C# WinForm如何实现全局快捷键?

在 KDE 中禁用全局 Ctrl-Alt-L 热键

禁用alt键临时c#

在WPF中使用全局快捷键

在录制按键时抑制全局窗口快捷方式