在PreTranslateMessage中按Ctrl + C时接收Ctrl + R消息

问题描述:

我有一个MFC对话框应用程序,它处理PreTranslateMessage中的某些消息。我感兴趣的是Ctrl + R。但是,当我点击另一个窗口(Visual Studio 2010中的代码编辑器,nodepad ++等)并使用Ctrl + C(或Ctrl + X)复制某些文本时,我收到了此消息。请注意,它似乎没有发生Ctrl + V,并且可以使用GetKeyState和GetASyncKeyState进行重现。行为非常混乱!要重现,创建在Visual Studio 10基本MFC对话框,添加预翻译为:在PreTranslateMessage中按Ctrl + C时接收Ctrl + R消息

BOOL CPreTranslateTestDlg::PreTranslateMessage(MSG *pMsg) 
{ 
    if (GetKeyState(VK_CONTROL) & 0x8000 && pMsg->wParam == 'R') 
    { 
     return true; 
    } 

    return CDialogEx::PreTranslateMessage(pMsg); 
} 

把断点return true;,启动对话。然后进入你的visual studio代码窗口,并按Ctrl + C一些文本;你的断点会被击中。

关于这可能发生的原因的任何想法?

GetKeyState旨在为您提供一个键的状态,无论您的对话框是否有焦点,所以在您的情况下,它正确指示Ctrl关闭。

其次,你没有检查刚刚发生的消息类型,所以它可能不是keydown等。我怀疑非关键相关的消息正在触发它的wParam值恰好等于'R ”。

我会更改代码,以便检查对话框是否有焦点并使用GetAsyncKeyState来确定R是否已关闭,例如,

BOOL CPreTranslateTestDlg::PreTranslateMessage(MSG *pMsg) 
{ 
    if (GetKeyState(VK_CONTROL) & 0x8000 && 
    GetKeyState(VK_R) & 0x8000 && 
    GetFocus == this) 
    { 
     return true; 
    } 

    return CDialogEx::PreTranslateMessage(pMsg); 
} 

希望这会有所帮助。

我这样做是为了捕捉对话框中的键盘快捷键。

首先,您需要在资源文件中包含一个包含要在对话框中使用的加速器的加速器表。

例如:

IDR_MYDIALOG_ACCEL

IDC_CTRL_R Ctrl+R Virtkey 

在对话框的消息映射,你应该有这样的事情:

BEGIN_MESSAGE_MAP(CMyDialogDlg, CDialog) 
    //{{AFX_MSG_MAP(CMyDialogDlg) 
    ... 
    ON_COMMAND(IDC_CTRL_R, OnMyCtrlRHandler) 
    ON_WM_DESTROY() 
    ... 
    //}}AFX_MSG_MAP 
END_MESSAGE_MAP() 

OnMyCtrlRHandler是将要调用的方法由快捷方式。

装载加速器表的OnInitDialog这样做是:

BOOL CMyDialogDlg::OnInitDialog() 
{ 
    ... 
    m_hAccel = LoadAccelerators (AfxGetResourceHandle(), 
            MAKEINTRESOURCE(IDR_MYDIALOG_ACCEL)); 
    ... 
} 

m_hAccel是类型HACCEL的CMyDialogDlg的成员。

覆盖的PreTranslateMessage这样的:

BOOL CMyDialogDlg::PreTranslateMessage(MSG* pMsg) 
{ 
    if (::TranslateAccelerator(m_hWnd, m_hAccel, pMsg)) 
     return(TRUE); 
    else 
     return CDialog::PreTranslateMessage(pMsg); 
} 

最后宇应该销毁加速器表中的OnDestroy处理程序:

void CMyDialogDlg::OnDestroy() 
{ 
    ... 
    DestroyAcceleratorTable(m_hAccel) ; 
    ... 
}