Search code examples
mfcacceleratorkey

Handling accelerator in a dialog


What step am I missing?

I have an accelerator table:

Accelerator Table

I have added a member variable to my app class:

HACCEL m_hAccel;

I have added the following override:

BOOL CMeetingScheduleAssistantApp::ProcessMessageFilter(int code, LPMSG lpMsg)
{
    if (m_hAccel)
    {
        if (::TranslateAccelerator(m_pMainWnd->m_hWnd, m_hAccel, lpMsg))
        {
            AfxMessageBox(_T("Found"));
            return(TRUE);
        }
    }

    return CWinAppEx::ProcessMessageFilter(code, lpMsg);
}

I am only using the popup message box for debugging and it confirms that the key press is being detected.

My menu resource is setup correctly:

Menu

So my menu is operation with menu handlers. And I have set up the program to load the accelerator table. If I press, for example Ctrl+Shift+X whilst it is detected by the accelerator table why doesn't my popup dialog actually process it?

I should point out that my main app dialog displays one of two editors. So when a editor is displayed I load the accelerator table for that editor.

What step am I missing? Why is the dialog not processing the accelerator?

Update

I found this answer How to make child control handle accelerator command of parent CView.

I found that if I add a HACCEL directly to my popup dialog and then just use PreTranslateMessage:

if (m_hAccelTable)
{
    if (::TranslateAccelerator(GetSafeHwnd(), m_hAccelTable, pMsg))
        return TRUE;
}

It works.


Solution

  • For keyboard accelerators in dialogs I do this:

    In OnInitDialog

    BOOL CMyDlg::OnInitDialog()
    {
       ...
       m_hAccel = LoadAccelerators ( AfxGetResourceHandle(), MAKEINTRESOURCE(IDR_DLGACCEL));
       ...
    }
    

    PreTranslateMessage

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

    In OnDestroy

    void CMyDlg::OnDestroy()
    {
      ...
      VERIFY(DestroyAcceleratorTable(m_hAccel)) ;
      CDialog::OnDestroy();
    }
    

    Message map:

    BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
      ...
      ON_COMMAND(IDC_SOMECOMMANDID, OnDoSomething)
      ON_UPDATE_COMMAND_UI(IDC_SOMECOMMANDID, OnUpdateDoSomething)
      ...
    END_MESSAGE_MAP()
    

    Command handlers

    void CMyDlg::OnUpdateDoSomething(CCmdUI* pCmdUI) 
    {
      ...
      pCmdUI->Enable(...) ;
    }
    
    void CMyDlg::OnDoSomething() 
    {
      ...
    }
    

    Accelerator table in .rc file

    IDR_DLGACCEL ACCELERATORS
    BEGIN
        "A",            IDC_SOMECOMMANDID,         VIRTKEY, CONTROL, NOINVERT  // Ctrl+A
        ...
    END
    

    That's all.