摘要: 本文通过一个实例,详细讲述了Visual C++的Hot Key控件(CHotKeyCtrl类)的使用方法
关键词:热键 CHotKeyCtrl RegisterHotKey UnregisterHotKey
Windows操作系统提供了许多热键,比如常用的热键:Win+E打开资源管理器,Win+F打开查找对话框,F1打开帮助等等。使用这些热键可以使我们的操作更加方便。那么,怎样在自己的应用程序中添加和使用热键呢?下面以VC++为例来说明。
MFC提供了CHotKeyCtrl类,由 CHotKeyCtrl 类表示的热键控件是一个窗口,显示用户键入的组合键(如 CTRL +S)的文本表示形式。它还维护此键的内部表示形式和一组表示转换状态的标志。热键控件实际上并不设置热键,要靠程序员自己来实现。
应用程序可以按下列两种方法来使用CHotKeyCtrl控件设置热键:
1.通过向将要激活的窗口发送 WM_SETHOTKEY 消息,设置一个用于激活非子窗口的全局热键。
全局热键与特定的非子窗口关联。它使用户得以从系统的任何部分激活窗口。应用程序通过向特定的窗口发送 WM_SETHOTKEY 消息来设置该窗口的全局热键。例如,假如 m_hotkey 是 CHotKeyCtrl 的对象,则可以使用下列代码将控件中指定的热键和主窗口关联起来。
WORD wKey = m_ hotkey.GetHotKey( );
AfxGetMainWnd()->SendMessage( WM_SETHOTKEY,
wKey);
这样,每当用户按全局热键时,指定的窗口就会接收 WM_SYSCOMMAND 消息,该消息将 SC_HOTKEY 指定为命令类型。该消息还激活接收它的窗口。由于该消息不包括按下的确切键的任何信息,使用此方法不能区分可能附加到同一窗口的不同热键。在发送 WM_SETHOTKEY 的应用程序退出之前,热键一直保持有效。
2.通过调用 API 函数 RegisterHotKey() 来设置线程特定的热键。
应用程序使用 RegisterHotKey() 函数设置线程特定的热键。用户按线程特定的热键后,Windows 将 WM_HOTKEY 消息发送到特定线程的消息队列的开始处。WM_HOTKEY消息的结构如下:
idHotKey = (int) wParam;
fuModifiers = (UINT) LOWORD(lParam);
uVirtKey = (UINT) HIWORD(lParam);
下面是两个关键的函数:
BOOL RegisterHotKey( HWND hWnd, int id, UINT fsModifiers, UINT vk );
该函数用于在系统中注册热键。参数hWnd用于指定注册热键的窗口,如果为NULL的话将使热键被注册到该函数的调用线程;id用于指定该热键的标识,在热键消息相应的时候,我们将通过该ID来对不同的热键消息作区分;fsModifiers用于指定修改键,它可以是下面值的组合:
值 |
描述 |
MOD_ALT |
任一Alt键按下 |
MOD_CONTROL |
任一Control键按下 |
MOD_SHIFT |
任一Shift键按下 |
vk的值为指定的虚拟键码。
BOOL UnregisterHotKey( HWND hWnd, int id); //用于在系统中注消热键
该函数的参数和RegisiterHotKey的那两个参数意义大体相同。
有了这两个函数,就可以开始编程了。 下面将通过一个例子(光驱控制程序)详细讲解如何使用CHotKeyCtrl控件。
新建立一个对话框工程cd,添加几个控件(如图1所示)
ID |
标题 |
类型 |
映射变量 |
IDC_TANCHU |
弹出 |
CButton |
m_tanchu |
IDC_GUANBI |
关闭 |
CButton |
m_guanbi |
IDC_HOTKEY1 |
|
CHotKeyCtrl |
m_hotkey |
IDC_SAVE |
保存设置 |
CButton |
|
在VC++6.0中,大多数的窗口消息可以从ClassWizard中找到,但是一些不常用的消息在ClassWizard中并没有封装,WM_HOTKEY就是其中一个,因此用户必须手动添加。方法如下:
在对话框的头文件CCdDlg.h中加入热键处理函数声明:
afx_msg LRESULT OnHotKey(WPARAM wp,LPARAM lp);
在对话框的实现文件CCdDlg.cpp中,找到消息映射的定义处,添加如下的代码:
BEGIN_MESSAGE_MAP(CTestView, CView)
ON_MESSAGE(WM_HOTKEY,OnHotkey) //消息和函数发生关联
END_MESSAGE_MAP()
在对话框的初始化函数OnInitDialog()中添加如下代码,该函数首先用API函数
GetPrivateProfileInt()读取当前目录中的Settings.ini文件中保存的热键值,然后传给SetHotKey() 以设置热键控件
BOOL CCdDlg::OnInitDialog()
{
… …
WORD virtualKey=::GetPrivateProfileInt("热键设置",
"HotkeyVK",0,
".//Settings.ini");
WORD sysKey=::GetPrivateProfileInt("热键设置",
"HotkeySystem",0,
".//Settings.ini");
m_hotkey.SetHotKey(virtualKey, sysKey);
UINT fsModifiers = NULL;
if (sysKey & HOTKEYF_ALT)
fsModifiers = MOD_ALT;
if (sysKey & HOTKEYF_CONTROL)
fsModifiers = MOD_CONTROL;
if (sysKey & HOTKEYF_SHIFT)
fsModifiers = MOD_SHIFT;
RegisterHotKey(m_hWnd,200, fsModifiers, virtualKey); //向系统登记热键
UpdateData(FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
分别双击“保存设置”,“弹出”,“关闭”按扭,添加相应的消息处理函数:
void CCdDlg::OnSave()
{
UpdateData(TRUE);
WORD virtualKey, systemKey;
m_hotkey.GetHotKey(virtualKey, systemKey);
CString strVirtualKey,strSystemKey;
strVirtualKey.Format("%d",virtualKey);
strSystemKey.Format("%d",systemKey);
::WritePrivateProfileString("热键设置",
"HotkeyVK",strVirtualKey,
".//Settings.ini");
::WritePrivateProfileString("热键设置",
"HotkeySystem",strSystemKey,
".//Settings.ini");
//保存设定的热键值到当前目录的Settings.ini文件中
UINT fsModifiers = 0;
if (systemKey & HOTKEYF_ALT)
fsModifiers = MOD_ALT;
if (systemKey & HOTKEYF_CONTROL)
fsModifiers = MOD_CONTROL;
if (systemKey & HOTKEYF_SHIFT)
fsModifiers = MOD_SHIFT;
RegisterHotKey(m_hWnd, 200, fsModifiers, virtualKey); //注册热键
}
void CCdDlg::OnTanchu() //弹出光驱
{
mciSendString("set cdaudio door open",0,0,NULL);
//为了使用此函数应该加入#include
//和#pragma comment(lib,"winmm.lib")
m_btanchu = TRUE; // m_btanchu是在CCdDlg.h中定义的一个BOOL类型的变//量,在构造函数中初始化为 m_btanchu=FALSE;
m_tanchu.EnableWindow(FALSE);
m_guanbi.EnableWindow(TRUE);
}
void CCdDlg::OnGuanbi() //关闭光驱
{
mciSendString("set cdaudio door closed",0,0,NULL);
m_btanchu=FALSE;
m_guanbi.EnableWindow(FALSE);
m_tanchu.EnableWindow(TRUE);
}
现在开始实现OnHotkey()函数,在该函数中处理热键消息,即检查是否是所期望的热键,如果是,则执行相应的操作。
LRESULT CCdDlg::OnHotKey(WPARAM wp,LPARAM lp)
{
if(wp==200)
{
if(m_btanchu)
{
mciSendString("set cdaudio door closed",0,0,NULL);
m_btanchu=FALSE;
m_tanchu.EnableWindow(TRUE);
m_guanbi.EnableWindow(FALSE);
}
else
{
mciSendString("set cdaudio door open",0,0,NULL);
m_btanchu=TRUE;
m_tanchu.EnableWindow(FALSE);
m_guanbi.EnableWindow(TRUE);
}
}
return 0;
}
最后,不要忘了在OnDestroy()函数中注销热键,释放系统资源。
BOOL CCdDlg::DestroyWindow()
{
UnregisterHotKey(m_hWnd,200);
return CDialog::DestroyWindow();
}
好了,到这里,程序的热键功能已经实现了。程序运行后,无论程序在前台或后台运行,只要你按下设定的热键,就会弹出或关闭光驱,你可以自行在自己的热键处理函数中加入需要的代码来完成特定的功能。该程序在WinXP平台上,在Visual C++6.0中调试通过。