2
votes

I have an MFC dialog application that processes certain messages in PreTranslateMessage. One of the ones I'm interested in is Ctrl+R. However, I am receiving this message when I click on another window (the code editor in Visual Studio 2010, notepad++, etc) and copy some text with Ctrl+C (or Ctrl+X). Note that it doesn't seem to happen with Ctrl+V, and is reproducable using both GetKeyState and GetASyncKeyState. The behavior is very confusing! To reproduce, create a basic MFC dialog in Visual Studio 10, add pretranslate as:

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

    return CDialogEx::PreTranslateMessage(pMsg);
}

put a breakpoint on return true;, launch the dialog. Then go to your Visual Studio Code window, and Ctrl+C some text; your breakpoint will be hit.

Any ideas on why this might be happening?

2

2 Answers

5
votes

GetKeyState is designed to give you the status of a key regardless of whether your dialog has focus, so in your case it's correctly indicating that Ctrl is down.

Secondly, you're not checking the type of message that's just occurred, so it may not be a keydown etc. I suspect that a non-key-related message is being triggered whose wParam value just happens to equal 'R'.

I would change the code so that you check your dialog has focus and use GetAsyncKeyState to determine if R is down too, e.g.

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

    return CDialogEx::PreTranslateMessage(pMsg);
}

Hope this helps.

0
votes

I do this for catching keyboard shortcuts in dialogs.

First of all you need to have an accelerator table containting the accelerator(s) you want to use in your dialog, in your resource file.

For example:

IDR_MYDIALOG_ACCEL

IDC_CTRL_R    Ctrl+R    Virtkey

In the message map of the dialog you should have something like this:

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 is the method that will be invoked by the shortcut.

Loading the accelerator table is done in OnInitDialog like this:

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

m_hAccel being a member of CMyDialogDlg of type HACCEL.

Override PretranslateMessage like this:

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

Finally you should destroy the accelerator table in the OnDestroy handler:

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