这几天在继续做个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);
}
}
/// <summary>
/// 消息过滤器
/// </summary>
/// <param name="m">收到的消息</param>
/// <returns>如果筛选消息并禁止消息被调度,则为true;如果允许消息继续到达下一个筛选器或控件,则为false。</returns>
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.
!Or
2009-1-31 2:05:56