WPF的热键实现

来源:互联网 发布:知乎 量子通信 骗局 编辑:程序博客网 时间:2024/05/16 05:15

项目开发中,需要实现对于热键的支持,实际上有两种方案来实现,一种是采用WPF的方式,即命令绑定,利用InputBinding实现ICommand的快捷键绑定处理,另一种是调用系统API注册热键的方式.但是如果想要实现全局热键及应用程序级别的热键处理,个人认为第二种方案更为合适.

我的代码中,最初选择的是第一种方案,但是测试过程中发现了一个问题,利用InputBinding的形式来绑定的快捷键处理,作用范围只限于当前的窗口,如果我的程序有很多非模态窗口,显示时,当焦点在不同的窗口切换时,发现快捷键只在定义过InputBinding的窗口中有效.也就是说要想在应用程序级别的范围实现快捷键的响应需要在所有的窗口中去定义InputBinding,然后将其都绑定到同一个Command上.在StackOverflow上,有人提出可以定义Style,在该Style中定义InputBinding,然后将此Style应用于所有的窗口控件中,从而实现应用程序级别的快捷键响应.但是我觉得这样一来程序的耦合性太高了,所以放弃了此种方案.

第二中方案,主要参考了如下文章,主要目的是利用系统级别的API,RegisterHotKey,注册应用程序级别的热键,然后捕获热键消息,定义自己的热键响应函数处理该消息即可.

http://outcoldman.com/en/archive/2010/09/11/register-hotkey-in-system-for-wpf-application/


主要代码如下,首先引入WindowAPI

internal class HotKeyWinApi{    public const int WmHotKey = 0x0312;    [DllImport("user32.dll", SetLastError = true)]    public static extern bool RegisterHotKey(IntPtr hWnd, int id, ModifierKeys fsModifiers, Keys vk);    [DllImport("user32.dll", SetLastError = true)]    public static extern bool UnregisterHotKey(IntPtr hWnd, int id);}

然后定义热键类,负责热键的注册和消息监听

public sealed class HotKey : IDisposable{    public event Action<HotKey> HotKeyPressed;    private readonly int _id;    private bool _isKeyRegistered;    readonly IntPtr _handle;    public HotKey(ModifierKeys modifierKeys, Keys key, Window window)        : this (modifierKeys, key, new WindowInteropHelper(window))    {        Contract.Requires(window != null);    }    public HotKey(ModifierKeys modifierKeys, Keys key, WindowInteropHelper window)        : this(modifierKeys, key, window.Handle)    {        Contract.Requires(window != null);    }    public HotKey(ModifierKeys modifierKeys, Keys key, IntPtr windowHandle)    {        Contract.Requires(modifierKeys != ModifierKeys.None || key != Keys.None);        Contract.Requires(windowHandle != IntPtr.Zero);        Key = key;        KeyModifier = modifierKeys;        _id = GetHashCode();        _handle = windowHandle;        RegisterHotKey();        ComponentDispatcher.ThreadPreprocessMessage += ThreadPreprocessMessageMethod;    }    ~HotKey()    {        Dispose();    }    public Keys Key { get; private set; }    public ModifierKeys KeyModifier { get; private set; }    public void RegisterHotKey()    {        if (Key == Keys.None)            return;        if (_isKeyRegistered)            UnregisterHotKey();        _isKeyRegistered = HotKeyWinApi.RegisterHotKey(_handle, _id, KeyModifier, Key);        if (!_isKeyRegistered)            throw new ApplicationException("Hotkey already in use");    }    public void UnregisterHotKey()    {        _isKeyRegistered = !HotKeyWinApi.UnregisterHotKey(_handle, _id);    }    public void Dispose()    {        ComponentDispatcher.ThreadPreprocessMessage -= ThreadPreprocessMessageMethod;        UnregisterHotKey();    }    private void ThreadPreprocessMessageMethod(ref MSG msg, ref bool handled)    {        if (!handled)        {            if (msg.message == HotKeyWinApi.WmHotKey                && (int)(msg.wParam) == _id)            {                OnHotKeyPressed();                handled = true;            }        }    }    private void OnHotKeyPressed()    {        if (HotKeyPressed != null)            HotKeyPressed(this);    }}


最后使用

public partial class MainWindow : Window{    private HotKey _hotkey;    public MainWindow()    {        InitializeComponent();        Loaded += (s, e) =>                      {                          _hotkey = new HotKey(ModifierKeys.Windows | ModifierKeys.Alt, Keys.Left, this);                          _hotkey.HotKeyPressed += (k) => Console.Beep();                      };    }}



0 0
原创粉丝点击