Based on the implementation of the dialog box in the dialog box to capture the WM_KEYDOWN message

  • 2020-04-01 23:30:43
  • OfStack

In dialog programs, we often use child controls on the dialog to respond to commands to handle events. If we want the dialog (the parent window of the child control) class to respond to our keydown message, we can respond to the WM_KEYDOWN message with the ClassWizard. When the program runs, we press the keypad, but the dialog doesn't respond. This is because in the dialog box procedure, some particular message, key message, for example, they are Windows inside the dialog process (i.e. in the base class finished processing, interested readers can view the MFC source code), or is sent to the child controls for processing, so we can't capture button in the dialog class.

Now that we know how this works, we can find the underlying function that handles the keystroke message, and then override it in the subclass to handle the keystroke message in the dialog program. In MFC, it is the virtual function BOOL ProcessMessageFilter(int code, LPMSG LPMSG) that filters or responds to specific Windows messages in menus and dialogs. Next, we will demonstrate the capture of WM_KEYDOWN message by a dialog-based application.

The first step: Create a new project, select the MFC AppWizard (exe), the project name is WinSun, click ok, go to the next step, select Dialog based, click Finish.

The second step: Right-click on the CWinSunApp class, select Add Member Varialbe, Add a variable of type HWND, variable name m_hwndDlg public.

The code is as follows:


WinSun.h
class CWinSunApp : public CWinApp
{
public:
       HWND m_hwndDlg;
       CWinSunApp();
 
// Overrides
       // ClassWizard generated virtual function overrides
       //{{AFX_VIRTUAL(CWinSunApp)
       public:
       virtual BOOL InitInstance();
       //}}AFX_VIRTUAL
 
// Implementation
 
       //{{AFX_MSG(CWinSunApp)
              // NOTE - the ClassWizard will add and remove member functions here.
              //    DO NOT EDIT what you see in these blocks of generated code !
       //}}AFX_MSG
       DECLARE_MESSAGE_MAP()
};

Step 3: Add the following code to the InitInstance() function in the winsun.cpp (CWinSunApp class) file:

WinSun.cpp
BOOL CWinSunApp::InitInstance()
{
       AfxEnableControlContainer();
 
       // Standard initialization
       // If you are not using these features and wish to reduce the size
       //  of your final executable, you should remove from the following
       //  the specific initialization routines you do not need.
 
#ifdef _AFXDLL
       Enable3dControls();                     // Call this when using MFC in a shared DLL
#else
       Enable3dControlsStatic();      // Call this when linking to MFC statically
#endif
 
       CWinSunDlg dlg;
       m_pMainWnd = &dlg;
       int nResponse = dlg.DoModal();
       if (nResponse == IDOK)
       {
              // TODO: Place code here to handle when the dialog is
              //  dismissed with OK
       }
       else if (nResponse == IDCANCEL)
       {
              // TODO: Place code here to handle when the dialog is
              //  dismissed with Cancel
       }
 
       // Since the dialog has been closed, return FALSE so that we exit the
       //  application, rather than start the application's message pump.
       m_hwndDlg=NULL;
       return FALSE;
}

Step 4: Right-click on the CWinSunApp class, select Add Virtual Function, in the left column, select ProcessMessageFilter, on the right button select Add and Edit, and then Add the following code:

WinSun.cpp
BOOL CWinSunApp::ProcessMessageFilter(int code, LPMSG lpMsg)
{
       // TODO: Add your specialized code here and/or call the base class
       if(m_hwndDlg!=NULL)
       {
              //Determine if the message is sent from the dialog box or its child controls, and we process it. sunxin
              if((lpMsg->hwnd==m_hwndDlg) || ::IsChild(m_hwndDlg,lpMsg->hwnd))
              {
                     //If the message is WM_KEYDOWN, we pop up a message box. sunxin
                     if(lpMsg->message==WM_KEYDOWN)
                     {
                            AfxMessageBox(" capture WM_KEYDOWN Message successful! ");
                     }
              }
       }
       return CWinApp::ProcessMessageFilter(code, lpMsg);
}

Step 5: Add the following code to the OnInitialDialog() function in WinSunDlg. CPP (CWinSunDlg class) :

WinSunDlg.cpp
BOOL CWinSunDlg::OnInitDialog()
{
       CDialog::OnInitDialog();
 
       // Add "About..." menu item to system menu.
 
       // IDM_ABOUTBOX must be in the system command range.
       ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
       ASSERT(IDM_ABOUTBOX < 0xF000);
 
       CMenu* pSysMenu = GetSystemMenu(FALSE);
       if (pSysMenu != NULL)
       {
              CString strAboutMenu;
              strAboutMenu.LoadString(IDS_ABOUTBOX);
              if (!strAboutMenu.IsEmpty())
              {
                     pSysMenu->AppendMenu(MF_SEPARATOR);
                     pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
              }
       }
 
       // Set the icon for this dialog.  The framework does this automatically
       //  when the application's main window is not a dialog
       SetIcon(m_hIcon, TRUE);                  // Set big icon
       SetIcon(m_hIcon, FALSE);          // Set small icon
      
       // TODO: Add extra initialization here
//Passes the handle to the dialog box into the CWinSunApp class. sunxin
       ((CWinSunApp*)AfxGetApp())->m_hwndDlg=m_hWnd;
       return TRUE;  // return TRUE  unless you set the focus to a control
}

Step 6: After the dialog window is destroyed, the variable m_hwndDlg in the CWinSunApp class is set to NULL. For this reason, we right-click on the CWinSunDlg class, select Add Windows Message Handler, select WM_DESTROY in the left column, select Add and Edit on the right button, and then Add the following code:

WinSunDlg.cpp
void CWinSunDlg::OnDestroy()
{
       CDialog::OnDestroy();
      
       // TODO: Add your message handler code here
       ((CWinSunApp*)AfxGetApp())->m_hwndDlg=NULL;
}

Now that our work is done, we can press Ctrl+F5 to run the program and see what we want.


Related articles: