首页 > CShap > C# 全局快捷键 与接收消息

C# 全局快捷键 与接收消息

2009年10月27日 发表评论 阅读评论

这几天在继续做个Application,用到了 快捷键 ,或者说是 组合键。

费了一天时间来研究这个。在网上找了好多资料都没能成功,连《C#程序开发范例宝典》这本书的第七章第12节的功能快捷键范例都没用,给的源码无法正确应用,让我很失望。
虽然在网上找的那些资料没有能成功运行,但是给我了一些启发,从很多源码中,我找到了以下的结果:

AddMessageFilter (IMessageFilter value)方法 ,

用于添加消息筛选器以便在向目标传送 Windows 消息时监视这些消息。
参数:value : IMessageFilter 接口的实现(就是对象)
警告:向应用程序的消息泵添加消息筛选器会降低性能。

既然接受消息的方法已经找到了,那么接下来就需要一个API来注册快捷键,这个函数为:

[DllImport("user32.dll")]
public static extern UInt32 RegisterHotKey(IntPtr hWnd, UInt32 id, UInt32 fsModifiers, Keys vk);

hWnd:用于接收消息的句柄,一般是this
id:被注册的快捷键的ID,可以设置个ID,但不能重复,推荐用System.Guid.NewGuid()方法获得一个不易被重复的ID.
fsModifiers:快捷键的修饰键(如:Ctrl,Alt或Ctrl+Alt等等),可以使用下面的一些值:

        public const int MOD_ALT = 0x1;        //Alt键,值为1
        public const int MOD_CONTROL = 0x2;    //Ctrl键值为2,如果要用Ctrl+Alt,直接用3就可以了
        public const int MOD_SHIFT = 0x4;      //Shift键值为4

vk:快捷键,如:Keys.A 具体可以查看MSDN的Keys枚举。

===========================================================

接下来还必须要添加一个反注册快捷键的方法:

 [DllImport("user32.dll")]
public static extern UInt32 UnregisterHotKey(IntPtr hWnd, UInt32 id);

hWnd:注册快捷键的窗体句柄。
id:被注册的快捷键的id。(把之前注册快捷键的id放进去就可以了)

刚才用AddMessageFilter方法让消息发给自己的程序,在反注册全部的快捷键后,如果不想让消息再被窗体接收,就该调用 RemoveMessageFilter (IMessageFilter value)

参数: value: IMessageFilter 接口的实现

因为添加消息筛选器会增大系统开销,所以当不再接收消息的时候就要RemoveMessageFilter()。

===========================================================

除此以外,有一个接口:“IMessageFilter”, 我在MSDN中查到:这个接口可以处理消息,这用于是定义消息筛选器的接口。该接口只提供了一个方法PreFilterMessage,作用:在调度消息之前将其筛选出来。

 bool PreFilterMessage (ref Message m)

参数m是程序接收到的消息,消息的Msg 属性如果为0x312 就是快捷键的消息,然后获取消息的WParam 字段,把该字段转换为整型,与设置过的快捷键的id比较,如果有相等,那就可以确定按下了这个快捷键,然后就可以调用相应的方法来实现接下来自己的要做的事。

===========================================================

有了上面的核心解释,就可以了,接下来把完整的代码发出来,以供参考。(源码部分东西是基于网上的摘抄,由于网上的资源比较乱,也不知道原作者了,故在这感谢XXX和XXX)

为方便使用,代码中还添加了一些其他的东西以方便使用(也就是说不是必须的)

 using System;
using System.Collections.Generic;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace Or
{
    public delegate void HotkeyEventHandler(int HotKeyID);
    public class Hotkey : IMessageFilter       //继承这个接口,才能用AddMessageFilter接收消息
    {
        System.Collections.Hashtable keyIDs = new System.Collections.Hashtable();
        IntPtr hWnd;
        public event HotkeyEventHandler OnHotkey;  //方便对快捷键进行处理
        public const int MOD_ALT = 0x1;
        public const int MOD_CONTROL = 0x2;
        public const int MOD_SHIFT = 0x4;
        public const int MOD_WIN = 0x8;
        public const int WM_HOTKEY = 0x312;    //按下快捷键消息的ID

        [DllImport("user32.dll")]
        public static extern UInt32 RegisterHotKey(IntPtr hWnd, UInt32 id, UInt32 fsModifiers, Keys vk);

        [DllImport("user32.dll")]
        public static extern UInt32 UnregisterHotKey(IntPtr hWnd, UInt32 id);

        [DllImport("kernel32.dll")]
        public static extern UInt32 GlobalAddAtom(String lpString);

        [DllImport("kernel32.dll")]
        public static extern UInt32 GlobalDeleteAtom(UInt32 nAtom);

        public Hotkey(IntPtr hWnd)
        {
            this.hWnd = hWnd;
            Application.AddMessageFilter(this);    //这样this才会收到消息
        }
        public int RegisterHotkey(Keys Key, UInt32 KeyModifiers)
        {
            UInt32 hotkeyid = GlobalAddAtom(System.Guid.NewGuid().ToString());
            RegisterHotKey((IntPtr)hWnd, hotkeyid, KeyModifiers, Key);
            keyIDs.Add(hotkeyid, hotkeyid);
            return (int)hotkeyid;
        }
        public void UnregisterHotkeys()
        {
            Application.RemoveMessageFilter(this);
            foreach (UInt32 key in keyIDs.Values)
            {
                UnregisterHotKey(hWnd, key);
                GlobalDeleteAtom(key);
            }
        }
        ///

        /// 消息过滤器
        /// 

        ///
收到的消息
        /// 如果筛选消息并禁止消息被调度,则为true;如果允许消息继续到达下一个筛选器或控件,则为false。

        public bool PreFilterMessage(ref Message m)
        {
            if (m.Msg == WM_HOTKEY)
            {
                if (OnHotkey != null)
                {
                    foreach (UInt32 key in keyIDs.Values)
                    {
                        if ((UInt32)m.WParam == key)
                        {
                            OnHotkey((int)m.WParam);
                            return true;
                        }
                    }
                }
            }
            return false;
        }
    }
}

使用方法:

1.首先在类级别的位置定义Hotkey的一个方法名:

 Hotkey hk;

2.在快捷键注册方法内实例化

         public void HotkeyReg()
        {
            hk = new Hotkey(this.Handle);
            hk.RegisterHotkey(……); //这里选择自己的快捷键设置,方法返回该快捷键的ID
            hk.OnHotkey += new HotkeyEventHandler(hk_OnHotkey);  //绑定方法
        }
        void hk_OnHotkey(int HotKeyID)
        {
            MessageBox.Show(HotKeyID.ToString());
            //在这里添加if语句,用来处理不同的快捷键ID
        }

这是我第一篇技术博文,有问题请指出,有建议请提出,谢谢。正在学习中。。。
Help each other.

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gengzhijun/archive/2009/01/31/3855586.aspx

分类: CShap 标签: , ,
  1. 2009年10月27日17:08 | #1

    很久没有用C#写桌面程序了,不过还是来支持一下`

  2. 2009年10月30日15:56 | #2

    @alswl 呵呵。感谢哦。~~

  1. 本文目前尚无任何 trackbacks 和 pingbacks.

注意: 评论者允许使用'@user空格'的方式将自己的评论通知另外评论者。例如, ABC是本文的评论者之一,则使用'@ABC '(不包括单引号)将会自动将您的评论发送给ABC。使用'@all ',将会将评论发送给之前所有其它评论者。请务必注意user必须和评论者名相匹配(大小写一致)。直接点击评论上方的回复实现此功能