VC系统热键的注册 (转载)
本文来自:http://cool02.cn/ablog/post/2009031869..html
使用系统热键可以这么进行,假设我们在 CTestHotkeyDlg 这个类进行热键测试。
A. 首先是注册系统热键 RegisterHotKey
BOOL RegisterHotKey(HWND hWnd, int id, UINT fsModifiers, UINT vk);
hWnd : 指定响应该热键的窗体
id : 指定响应该事件的 id
fsModifiers : 指定组合键。这个值可以由 MOD_ALT MOD_CONTROL MOD_SHIFT MOD_WIN 中的一个或几个组成。
vk : 指定热键的虚拟键值。如A
例如在本例中注册一个 Ctrl+Alt+Q 的热键。在 CTestHotkeyDlg特定的地方中调用:
RegisterHotKey(this->m_hWnd, 0x1998, MOD_CTRL | MOD_ALT, Q);
B. 接着响应并实现系统热键消息 WM_HOTKEY
添加消息映射 ON_MESSAGE(WM_HOTKEY,OnHotKey) 并实现函数 OnHotKey
LRESULT CHotKeyTestDlg::OnHotKey(WPARAM wParam, LPARAM lParam)
{
MessageBox("You press Ctrl+Alt+Q");
return 0;
}
C. 最后,可别忘了在程序结束时撤销注册的热键 UnRegisterHotKey
void CHotKeyTestDlg::OnDestroy()
{
CDialog::OnDestroy();
UnregisterHotKey(this->m_hWnd,1000);
}
到此系统热键的工作全部完成。
最好不要直接用0x1998, 0x1220等数,以防止热键冲突
ATOM m_atom1,m_atom2; //保存全局原子
ATOM TmpID=GlobalFindAtom("my first hotkey");
if TmpID=0 then //查找全局原子.如果返回值不为0,则说明这个全局原子已经被注册;
m_atom1 = GlobalAddAtom("my first hotkey");
m_atom2 = GlobalAddAtom("my second hotkey");
BOOL m_isKeyRegistered;
m_isKeyRegistered = RegisterHotKey(GetSafeHwnd(),m_atom1, MOD_CONTROL|MOD_SHIFT, 0x4e);
ASSERT(m_isKeyRegistered != FALSE); //调试时用(当前热键已经被注册时会返回失败)
// 注册第二个始终不行
if(RegisterHotKey(GetSafeHwnd(), m_atom2, MOD_CONTROL, 0x4d) == FALSE)
{
MessageBox("error", NULL, MB_OK);
}
在不需要热键时,比如程序退出时
GlobalDeleteAtom(m_atom1);
GlobalDeleteAtom(m_atom2);
热键一般是有Ctrl+其他键位或Alt+其他键位或Ctrl+Alt+其他键位构成。关于如何建立自己的热键,
下面就有详细的说明:
1:要定义一个热键(组合键)即必须先为热键赋于一个自定义的ID,用来给系统标识该热键。注意,
自定义的ID(int型)必须是唯一的,既不能与系统的其他ID相冲突。
2 运用函数RegisterHotKey
(
HWND hWnd, // 接收WM_HOTKEY的窗口句柄
int id, // hot key的ID号.
UINT fsModifiers, // 响应那个热键.
UINT vk // 与热键配合的键虚位码
)
当配合建为a(A) —z(Z),
和 0 — 9时,伴随建虚伪码可以用诸如a,0的形式代替。hWnd 为接受热键的窗口句柄,可以用
GetSafeHwnd()函数获得。自定义热键ID对于一个线程来讲一般设在0x0000 到0xBFFF(49151)之间,对于一个
DLL来讲其值一般设在0xC000(49152) 到0xBFFF(49151)之间。
fsModifiers可取如下值
MOD_ALT ;MOD_CONTROL ;MOD_SHIFT ;MOD_WIN 或他们的组合(中间用|连接)
3 定义热键的同时一般也要自定义热键相应的响应函数,其定义方法如下:
(1):先在某个类的头文件的其他消息响应函数的声明处按照相应的格式加上如下语句
afx_msg long OnHotKey(WPARAM wParam,LPARAM lParam);//wParam一般为热键消息的ID
(2): 在相应类的.cpp文件的消息映射宏BEGIN_MESSAGE_MAP 和END_MESSAGE_MAP之间加上同其他消息
响应宏声明相同格式的自定义消息响应宏ON_MESSAGE(WM_HOTKEY,OnHotKey)
(3):然后就运用RegisterHotKey(...)函数定义快捷键。并在相应的消息响应函数OnHotKey(...)中加
如相应的处理代码。注意消息响应函数一定要有返回值,其可以使HRESULT,int ,long等数据类
型。
(4): 用完后不要忘了在OnDestory(...)函数或OnCancel(...)中解除函数登记,释放系统资源。此时
要调用函数 bool UnregisterHotKey(hWnd,VK(ID));
4 相应的例子如:
[程序实现]
建立名为My的对话框工程.本例要用到RegisterHotKey()实现Alt+D的快捷键组合功能.在调用该函数后你的进程会在ALT+D按下时比系统先得到通知.你需要处理的消息是WM_HOTKEY.
如下:
在MyDlg.h中:
class CMyDlg : public CDialog
{
// Construction
public:
int m_nHotKeyID;//为你自己定义的一个hot key的ID值,在整个程序唯一.
........
protected:
HICON m_hIcon;
// Generated message map functions
//{{AFX_MSG(CMyDlg)
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
afx_msg LONG OnHotKey(WPARAM wParam,LPARAM lParam);//手动加入.
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
在MyDlg.cpp中:
#define VK_D 68
..............
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
//{{AFX_MSG_MAP(CHotKey1Dlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDOK, OnRegisterHotKey)
ON_BN_CLICKED(IDCANCEL, OnUnregisterHotKey)
ON_MESSAGE(WM_HOTKEY,OnHotKey) //手动加入.
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
BOOL CMyDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
m_nHotKeyID=0;
BOOL m_isKeyRegistered = RegisterHotKey(GetSafeHwnd(),m_nHotKeyID,MOD_ALT,VK_D);
ASSERT(m_isKeyRegistered != FALSE);
return TRUE; // return TRUE unless you set the focus to a control
}
在取消按钮的事件函数中加入:
void CMyDlg::OnCancel()
{
BOOL m_iskeyUnregistered = UnregisterHotKey(GetSafeHwnd(), m_nHotKeyID);
ASSERT(m_iskeyUnregistered != FALSE);
CDialog::OnCancel();
}
处理截到的组合键,并处理:
LONG CMyDlg::OnHotKey(WPARAM wParam,LPARAM lParam) //wParam一般为热键消息的ID
{
AfxMessageBox("你按下了组合键:Alt+D");
//加入相关代码.
return 0;
}
一、热键注册的步骤
1、热键消息处理函数的声明
在头文件中加入如下代码:
afx_msg LRESULT OnHotKey(WPARAM wParam,LPARAM lParam);
2、添加消息映射
BEGIN_MESSAGE_MAP(CWndSnapDlg, CDialog)
......
ON_MESSAGE(WM_HOTKEY,OnHotKey) //手动加入
END_MESSAGE_MAP()
3、消息处理函数的实现
LRESULT CWndSnapDlg::OnHotKey(WPARAM wParam,LPARAM lParam)
{
//wParam是注册热键的ID,lParam是关于按键的信息
if(wParam==1000)
{
.........
}
......
return 0;
}
4、在初始化时进行热键注册
注册热键的函数原型如下:
BOOL RegisterHotKey( HWND hWnd, // handle to window int id, // hot key identifier UINT fsModifiers, // key-modifier options UINT vk // virtual-key code );
例如要注册热键Ctrl+Shift+A,则注册代码如下:
RegisterHotKey(m_hWnd,1000,MOD_CONTROL | MOD_SHIFT,A);
5、热键的注销
在程序退出之前要记着注销这些注册热键,注销热键的函数如下:
BOOL UnregisterHotKey( HWND hWnd, // handle to window int id // hot key identifier );
则注销上面注册的热键Ctrl+Shift+A的代码为:
UnregisterHotKey(m_hWnd,1000);二、需要注意的问题
1、我一开始编这个程序的时候,每次按下Ctrl+Shift+A时,消息处理函数OnHotKey(WPARAM wParam,LPARAM lParam)确实被调用了,但是wParam和lParam两个参数传进来的值却总是不对,后来才发现,是我在声明消息处理函数时,在函数前面加上了CALLBACK这个调用约定。所以,一定要注意,千万不要加调用约定修饰。
2、我看很多资料都说如果注册热键Ctrl+Shift+A和Ctrl+Shift+a的话,只要在上面的基础上多加一个注册函数即可:
RegisterHotKey(m_hWnd,2000,MOD_CONTROL | MOD_SHIFT,a);但是我在调试的时候发现,不管按下的是Ctrl+Shift+A还是Ctrl+Shift+a,消息处理函数传入的wParam这个参数始终是1000,而且,当我把注册Ctrl+Shift+a的代码删掉时,现象和以前一样。经过不断的调试,我发现,只要注册了包含大写字母的热键后,在运行时按下小写字母的按钮时同样实现按下大写字母时的功能,而且,注册时必须注册大写字母,如果只注册包含小写字母的热键是没有用的。