程序的所谓热键,简单点来说就它的快捷键,特别适合去激活后台运行或已隐藏了窗口程序,为达同种目的,程序也可以弄个dll安装全局钩子,可当你理解了热键之后便会发现这种钩子方法可谓笨又烦。。。
对于热键,及将几个特殊键组合在一起,由系统封装之后向程序发送WM_HOTKEY消息,接下来就是程序员的事了。为了让自己的程序能收到特定的热键消息,首先要向系统注册自定义热键,直接调用API RegisterHotKey( HWND hWnd,int id, UINT fsModifiers, UINT vk );其中fsModifiers可以是MOD_ALT、CONTROL、KEYUP、SHIFT、WIN(ENTER)的组合,然后与vk一起组成热键,hwnd当然指明是谁要注册,而id一看就知道是热键的身份证了。接下来就可相应WM_HOTKEY消息了,如
void xxxx::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
if(!IsWindowVisible())
{
OnShellnotifyBegin();
}
CDialog::OnHotKey(nHotKeyId, nKey1, nKey2);
}
这种方法最简明了当了,可程序往往要求我们要与用户打交道,就是要能让用户手动设置热键,当我想到这个问题时我立马想到了在对话框上放两个个combo box,然后在一个得下拉列表中列出前面参数fsModifiers的可能组合项在,另一个放VK,乖乖,幸亏没试过......微软早就为我们想好,就是控件CHotKeyCtrl,这个控件很简单,就是给出个与CEdit很类似的输入框让用户直接往里输热键,当然它也是通用控件,有这一般的创建准则,这里直接在对话框拖一个,然后给它关联个CHotKeyCtrl的对象,如m_hotKey,然后就是对它的初始化,msdn推荐在对话框的初始化函数搞定,不错的建议:
m_hotKey.SetHotKey(m_wVirtualKeyCode,m_wModifiers);
它的参数是对话框的成员变量
WORD m_wVirtualKeyCode,m_wModifiers;//存放热键
在对话框的构造函数或初始化函数中
m_wVirtualKeyCode=VK_F2;
m_wModifiers=HOTKEYF_ALT;//默认alt+F2
之所以不用常量直接对它初始化,是因为我要用户能动态改变热键,每次修改的值都是放在这两个变量的
然后再对话框的ONOK函数中对热键进行存储和注册,这些都是要手动的,不要天真的以为
UpdateData(TRUE);就能搞定了,笑了。。
m_hotKey.GetHotKey(m_wVirtualKeyCode,m_wModifiers);//存储热键
接下来就是要注册热键了,这一点MSDN给出了两个方法,一个是通过发送WM_SETHOTKEY给需要热键的窗口(一般是对话框的父窗口),在OK中如此实现
WORD wKeyAndShift = m_HotKeyCtrl.GetHotKey( );
pMainWnd->SendMessage( WM_SETHOTKEY, wKeyAndShift );
然后pMainWnd响应WM_SYSCOMMAND消息
另一个就是上面提到的api注册,这个更简单明了,直接在上面的存储热键后
RegisterHotKey(AfxGetMainWnd()->m_hWnd,1,m_wModifiers,m_wVirtualKeyCode);
到此,在理论上来说,这个动态设置热键的工作已经完成了,可当你真的去设置一个之后,你会发现按那个热键,程序根本一点反应都没有,这种境况下是最郁闷的了,在仔细研读msdn后你发现其实你的做法是相当精确地,通过调试你很可能会发现上面的函数是返回非零的,热键已注册成功。。。。微软又要被我怀疑了~~
于是我猜测,是不是这个RegisterHotKey中的参数与CHotKey的GetHotKey()返回的不一致呢,于是我调出了这几个MODIFIERS的定义
#define HOTKEYF_SHIFT 0x01
#define HOTKEYF_CONTROL 0x02
#define HOTKEYF_ALT 0x04
#ifdef _MAC
#define HOTKEYF_EXT 0x80
#else
#define HOTKEYF_EXT 0x08
//上面的是CHotKeyCtrl对几个热键的定义,下面的是Api函数中引用的定义
#define MOD_ALT 0x0001
#define MOD_CONTROL 0x0002
#define MOD_SHIFT 0x0004
#define MOD_WIN 0x0008
仔细看下,是不是发觉他们很不一致呢,alt与shift的定义刚好相反!这就是问题所在了,难怪当我通过控件设置热键为Alt+F2时起作用的偏偏是Shift+F2了,微软太不厚道了。。。
解决方法:
//热键控件与registerhotkey不同!转化下
if ((m_wModifiers & HOTKEYF_ALT) && !(m_wModifiers & HOTKEYF_SHIFT) )//Shift->ALt
{
m_wModifiers&=~HOTKEYF_ALT;
m_wModifiers|=MOD_ALT;
RegisterHotKey(AfxGetMainWnd()->m_hWnd,1,m_wModifiers,m_wVirtualKeyCode);
//在恢复到CHotKeyCtrl,以便下次显示
m_wModifiers|=HOTKEYF_ALT;
m_wModifiers&=~MOD_ALT;
}
else if (!(m_wModifiers & HOTKEYF_ALT) && (m_wModifiers & HOTKEYF_SHIFT))//Alt->Shift
{
m_wModifiers&=~HOTKEYF_SHIFT;
m_wModifiers|=MOD_SHIFT;
RegisterHotKey(AfxGetMainWnd()->m_hWnd,1,m_wModifiers,m_wVirtualKeyCode);
m_wModifiers|=HOTKEYF_SHIFT;
m_wModifiers&=~MOD_SHIFT;
}
else
RegisterHotKey(AfxGetMainWnd()->m_hWnd,1,m_wModifiers,m_wVirtualKeyCode);
问题解决了!。。。有时微软真是让人又爱又恨。。。。