yanjinhua

V1

2022/08/17阅读:17主题:蓝莹

C# 禁用 全局快捷键

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

原文作者:唐宋元明清

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

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

HotKey函数

  • 下面介绍一个user32.dllRegisterHotKey以及UnregisterHotKey热键处理的函数;

BOOL RegisterHotKey(
   HWND hWnd, //响应热键的窗口句柄,如果为空,则注册到调用线程上
   Int id, //热键的唯一标识
   UINT fsModifiers, //热键的辅助按键
   UINT vk //热键的键值
)
;
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 { getset; }
        public int Modifiers { getset; }
        public Keys Key { getset; }
        public int Id { getset; }
        public HotKeys.HotKeyCallBackHanlder CallBack { getset; }
    }
    //组合控制键
    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(thisas 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();

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

源码下载

分类:

后端

标签:

C#

作者介绍

yanjinhua
V1