天天看点

VS2010 MFC中设置HotKey

       1.首先建立一个基于对话框的MFC程序,我这里建立的项目名为“Testlili”。

  2.然后“项目”--“类向导”--“消息”,选择类名为“CTestliliDlg”,找到WM_HOTKEY消息添加,添加后“现有处理程序”的框框下就会多出一个“OnHotKey”。

  3.在“BOOL ×××::OnInitDialog()”函数中加入注册热键的代码,比如注册一个Ctrl+X的热键:

      ATOM HotKeyId=GlobalAddAtom(L"Chun_ge")- 0xC000; //取得热键唯一标识符

      //GetSafeHwnd();取得本程序的窗口句柄  

      RegisterHotKey(GetSafeHwnd(),HotKeyId,MOD_ALT①,'X'②);   

       RegisterHotKey(GetSafeHwnd(),HotKeyId,NULL,VK_F10);       

        当然还可以像上面这样把①中的参数NULL掉,②中的参数用虚拟键代码比如此处的按键是F10。这样设置后实现的就是单热键。顺带一提RegisterHotKey()函数是系统API这样设置后的热键是全局热键,也就是当我们的窗户最小化或者处于未激活状态下按下设置的热键也会执行回调函数中的代码,而不是像下面的方法设置的那样是局部热键,一旦我们的程序处于未激活状态按下热键就不会有反应。

①:参数3可以叠加,比如MOD_CONTROL|MOD_ALT,加上②处的参数4组合起来就是热键Ctrl+Alt+X

  注册热键的函数:

  BOOL WINAPI RegisterHotKey(

  __in_opt HWND hWnd,

  __in int id,

  __in UINT fsModifiers,

  __in UINT vk

  );

  参数1:为窗口的句柄

  参数2:定义热键的标识符。调用线程中的其他热键,不能使用同样的标识符。应用程序必须定义一个0X0000-0xBFFF范围的值。一个共享的动态链接库(DLL)必须定义一个范围为0xC000-0xFFFF的值(GlobalAddAtom函数返回该范围)。为了避免与其他动态链接库定义的热键冲突,一个DLL必须使用GlobalAddAtom函数获得热键的标识符。

  参数3:定义为了产生WM_HOTKEY消息而必须与由nVirtKey参数定义的键一起按下的键。

  该参数可以是如下值的组合:

  键                               值                 含意

      MOD_ALT                0x0001         按下的可以是任一(左边或者右边的)Alt键。

    MOD_SHIFT            0x0004         按下的可以是任一(左边或者右边的)Shift键。

  MOD_WIN              0x0008         按下的可以是任一(左边或者右边的)Windows徽标键。

  MOD_NOREPEAT   0x4000         更改热键行为,以便键盘自动重复不会产生多个热键通知。

  MOD_CONTROL     0x0002          按下的可以是任意一个Ctrl键(左边或者右边的)。

  参数4:定义热键的虚拟键码。

  4.在OnHotKey函数中添加触发热键后要执行的代码:

void CEternityDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值

	if (nHotKeyId==HotKeyId) //这个If不加也行
	{
	MessageBox(L"春哥纯爷们");
	}

	CDialogEx::OnHotKey(nHotKeyId, nKey1, nKey2);
}
           

          5.如果有2个以上热键:

BOOL ×××::OnInitDialog()
{

	HotKeyId=GlobalAddAtom(L"Chun_ge")- 0xC000; //取得热键唯一标识符

	HotKeyId2=GlobalAddAtom(L"Zeng_ge")- 0xC000;

	RegisterHotKey(GetSafeHwnd(),HotKeyId,NULL,VK_F10);  //热键F10

	RegisterHotKey(GetSafeHwnd(),HotKeyId2,NULL,VK_F11); //再注册一个F11

}


void CNeverDlg::OnHotKey(UINT nHotKeyId, UINT nKey1, UINT nKey2)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值


	if (nHotKeyId==HotKeyId) //如果有1个以上热键可以用这个方法来选择  
	{  //F10热键
		MessageBox(L"春哥纯爷们");  
	} 

	else if (nHotKeyId==HotKeyId2)
	{ //F11热键
		MessageBox(L"铁血真汉子");

	}

	CDialogEx::OnHotKey(nHotKeyId, nKey1, nKey2);
}
           

  然后编译运行,当按下Alt+X组合键时就会弹出一个消息框。当然为了严谨还可以用类向导添加OnDestroy()消息:

void CGhostDlg::OnDestroy()
{
	CDialogEx::OnDestroy();

	// TODO: 在此处添加消息处理程序代码

	UnregisterHotKey(GetSafeHwnd(),HotKeyId);

}
           

这样在MFC程序退出时就会注销热键

关于MFC对话框程序不能响应OnKeyDown和OnChar函数的一些说明

(1)现象

  在MFC的对话框中,映射了WM_CHAR和WM_KEYDOWN消息响应函数后,还是不能响应OnKeyDown和OnChar。需要说明的是WM_CHAR消息响应的是键盘上的数字键和A~Z的字母键,WM_KEYDOWN消息响应的是除了数字键和字母键以外的那些键盘按键比如Esc键,回车键,空格键什么的。

(2)原因

  因为MFC在进行设计的时候,这两个消息被对话框上的控件截获了,不能到达这两个消息响应函数,对于OnKeyDown来说,只要把对话框上的控件都删除了,就可以接收到WM_KEYDOWN消息,但是还是接收不到WM_CHAR消息。

(3)解决

  方法1:重载PreTranslateMessage这个虚函数;在里面加上SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam);这一句后,对话框的OnKeyDown和OnChar函数就生效了。

  方法2:在PreTranslateMessage虚函数里直接处理WM_KEYDOWN或WM_CHAR。

    eg:对话框屏蔽esc键

    BOOL Cmfc_testDlg::PreTranslateMessage(MSG* pMsg)

    {

      // TODO: 在此添加专用代码和/或调用基类

      if(pMsg->message == WM_KEYDOWN)

      {

        if(pMsg->wParam == VK_ESCAPE)

          return TRUE;

      }

return CDialogEx::PreTranslateMessage(pMsg);

}

(4)执行顺序

  三个消息的执行顺序为WM_KEYDOWN、WM_CHAR、WM_KEYUP

(5)关于PreTranslateMessage()函数

  PreTranslateMessage是消息在送给TranslateMessage函数之前被调用的,绝大多数窗口的消息都要通过这里,比较常用,当你需要在 MFC之前处理某些消息时,常常要在这里添加代码。通过重载这个函数,我们可以改变MFC的消息控制流程,甚至可以作一个全新的控制流出来。

  前面说了绝大多数窗口的消息都可以通过这个虚函数进行控制,这个绝大数其实是只有穿过消息队列的消息才受PreTranslateMessage ()影响,采用SendMessage()或其他类似的方式向窗口直接发送的而不经过消息队列的消息根本不会理睬PreTranslateMessage()的存在,故切记SendMessage 发送的消息是不能用PreTranslate来截取的,应该重写WindowProc窗口过程来响应消息!

(6)SendMessage()和PostMessage()

  SendMessage函数发送的消息会直接发送到窗口过程而不经过消息队列,且直到消息处理完成后,SendMessage才返回。函数返回值指定 消息处理的结果,依赖于所发送的消息。

  PostMessage函数将一个消息寄送到指定窗口的消息队列里,不等待线程处理消息就立刻返回。函数执行成功返回TRUE,否则返回 FALSE。

LRESULT WINAPI SendMessage( 

HWND hWnd, //窗口句柄

UINT Msg, //消息值

WPARAM wParam,//消息附加信息 

LPARAM lParam //消息附加信息 

);

BOOL WINAPI PostMessage( 

HWND hWnd, 

UINT Msg, 

WPARAM wParam, 

LPARAM lParam 

); 

(6)对话框特殊按键消息的处理

  默认情况下对话框响应Enter键的处理是调用基类的OnOK()函数,Esc键会调用基类的OnCancel()函数,这两个函数都是虚函数,故要 对Enter或Esc键做相应处理的话可以重写这两个函数。

  单击对话框标题栏上的关闭按钮时会先后产生WM_CLOSE消息,故需要对标题栏关闭按钮按下做处理的时候可以在WM_CLOSE消息的消息响应函数中进行。

键盘消息介绍

系统消息:

    ALT,F1,——F24等,是由系统内部处理的,程序本身就存在,比如F1是帮助键。

    WM_SYSKEYDOWN

    WM_SYSKEYUP

    WM_SYSCHAR

非系统消息:

    是由我们自己加上去的,

    WM_KEYDOWN

    WM_KEYUP

    WM_CHAR

虚拟键代码

符号形式             十六进制形式        说明

VK_LBUTTON           01             鼠标左键

VK_RBUTTON            02             鼠标右键

VK_CANCEL             03          Control-break 过程

VK_MBUTTON          04                  鼠标中键

VK_BACK                 08           BACKSPACE 键

VK_TAB                    09              TAB 键

VK_CLEAR               0C                CLEAR 键

VK_RETURN              0D            ENTER 键

VK_SHIFT                 10                 SHIFT 键

VK_CONTROL         11                 CTRL 键

VK_MENU                 12                   ALT 键

VK_PAUSE               13                PAUSE 键

VK_CAPITAL             14                CAPS LOCK 键

VK_ESCAPE            1B            ESC 键

VK_SPACE               20                SPACEBAR

VK_PRIOR                21                PAGE UP 键

VK_NEXT                 22                PAGE DOWN 键

VK_END                   23                  END 键

VK_HOME                24             HOME 键

VK_LEFT                 25               LEFT ARROW 键

VK_UP                      26               UP ARROW 键

VK_RIGHT                27               RIGHT ARROW 键

VK_DOWN                28               DOWN ARROW 键

VK_SELECT              29              SELECT 键

VK_EXECUTE          2B                 EXECUTE 键

VK_SNAPSHOT        2C                    PRINT SCREEN键(用于Windows 3.0及以后版本)

VK_INSERT              2D                   INS 键

VK_DELETE            2E                         DEL 键

VK_HELP                 2F                         HELP键

VK_LWIN                 5B                  Left Windows 键 (Microsoft自然键盘)

VK_RWIN                 5C                Right Windows 键 (Microsoft自然键盘)

VK_APPS                5D                  Applications 键 (Microsoft自然键盘)

VK_NUMPAD0         60                 数字小键盘上的 0 键

VK_NUMPAD1         61                    数字小键盘上的 1 键

VK_NUMPAD2         62                 数字小键盘上的 2 键

VK_NUMPAD3         63                 数字小键盘上的 3 键

VK_NUMPAD4         64                 数字小键盘上的 4 键

VK_NUMPAD5         65                   数字小键盘上的 5 键

VK_NUMPAD6        66                数字小键盘上的 6 键

VK_NUMPAD7        67               数字小键盘上的 7 键

VK_NUMPAD8          68               数字小键盘上的 8 键

VK_NUMPAD9         69               数字小键盘上的 9 键

VK_MULTIPLY          6A              Multiply 键

VK_ADD                   6B                 Add键

VK_SEPARATOR           6C           Separator 键

VK_SUBTRACT             6D              Subtract 键

VK_DECIMAL              6E               Decimal 键

VK_DIVIDE               6F               数字小键盘 / 键

VK_F1                    70               F1 键

VK_F2                    71                  F2 键

VK_F3                    72                   F3 键

VK_F4                    73                   F4 键

VK_F5                     74               F5 键

VK_F6                    75                  F6 键

VK_F7                    76                 F7 键

VK_F8                    77                  F8 键

VK_F9                    78                  F9 键

VK_F10                 79                 F10 键

VK_F11                 7A                 F11 键

VK_F12                 7B                 F12 键

VK_F13                 7C               F13 键

VK_F14                 7D               F14 键

VK_F15                 7 E                   F15 键

VK_F16                 7F                F16 键

VK_F17                80H               F17 键

VK_F18                81H              F18 键

VK_F19                82H               F19 键

VK_F20               83H            F20 键

VK_F21               84H             F21 键

VK_F22                85H             F22 键

VK_F23               86H            F23 键

VK_F24                 87H            F24 键

VK_NUMLOCK         90            NUM LOCK 键

VK_SCROLL         91             SCROLL LOCK 键

VK_ATTN              F6              Attn 键

VK_CRSEL          F7               CrSel 键

VK_EXSEL           F8             ExSel 键

VK_EREOF          F9              Erase EOF 键

VK_PLAY            FA           Play 键

VK_ZOOM           FB             Zoom 键

VK_OEM_CLEAR     FE         Clear 键

如何设置单键快捷键(热键)

下面为这个按钮添加快捷键ctrl+o。左下角切换到“资源视图”,然后项目名上右键>添加>资源

VS2010 MFC中设置HotKey
VS2010 MFC中设置HotKey
VS2010 MFC中设置HotKey

其中IDR_ACCELERATOR1 为加速键资源ID,在它上面右键>属性,打开“快捷键节点”窗口,可以在这个窗口中修改这个ID,这个ID在后面的代码中会用到

VS2010 MFC中设置HotKey

此时窗口中间是快捷键编辑窗口,点击其中一行则右侧显示这一行响应的编辑器,注意右侧窗口的标题

VS2010 MFC中设置HotKey

切换到“类视图”,在CTestDlg上右键>添加>添加变量

VS2010 MFC中设置HotKey

CTestDlg的构造函数中添加加速键初始化代码,注意LoadAccelerators()参数中的IDR_ACCELERATOR1要和之前提到的加速键资源ID要一样

CTestDlg::CTestDlg(CWnd* pParent /*=NULL*/)  
    : CDialogEx(CTestDlg::IDD, pParent)  
{  
    m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);  
    //加速键初始化  
    hAccKey=LoadAccelerators(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDR_ACCELERATOR1));  
}  
           

为CTestDlg类添加PreTranslateMessage虚函数,项目>类向导

VS2010 MFC中设置HotKey

BOOL CTestDlg::PreTranslateMessage(MSG* pMsg)

{  
    if(TranslateAccelerator(m_hWnd,hAccKey,pMsg)){  
        return true;  
    }  
  
    return CDialogEx::PreTranslateMessage(pMsg);  
} 
           

Ctrl+F5,程序运行起来之后点击Ctrl+o就会弹出对话框,和点击“打开”效果一样。

下面通过响应键盘消息的方式让这个程序对按下字母a也响应“打开”事件。

项目>类向导

VS2010 MFC中设置HotKey
void CTestDlg::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)  
{  
    if('a' == nChar){  
        MessageBox(L"春哥纯爷们");  
    }  
    CDialogEx::OnChar(nChar, nRepCnt, nFlags);  
}  
           

但是这样是不能响应按键消息的,因为对话框程序中键盘消息会被拦截。还需要在刚才的PreTranslateMessage(MSG*pMsg)函数中用SendMessage重新发送键盘消息。修改之后的PreTranslateMessage(MSG*pMsg)函数如下:

BOOL CkeysDlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类

	SendMessage(pMsg->message,pMsg->wParam,pMsg->lParam);

	return 0;


	//return CDialogEx::PreTranslateMessage(pMsg);
}
           

编译后启动,我们按下a键就会弹出:

VS2010 MFC中设置HotKey

参考文章:http://blog.csdn.net/xing_yufei/article/details/8573774

参考文章:http://blog.csdn.net/whereyougo/article/details/38407339

示例工程: http://download.csdn.net/download/l198738655/9986530

单热键示例工程:http://download.csdn.net/download/l198738655/10265598