Voice Command Enabling Your Software

IBM and Dragon have made quite a splash with their voice software enabling users to dictate text to their computers and use voice to control applications. This article presents an MFC class based on the Microsoft Speech SDK which will enable you to make your application work with these engines to accept voice commands.

To use this class you must have a copy of the Microsoft Speech SDK version 3 or above. I believe this is available on MSDN. It is also available from Microsoft's web site.

These classes basically wrap the IVoiceCmd COM interface. They are specifically designed to simplify the interface so you can put speech into your applications with minimum effort. They also provide some features above and beyond the SDK including a built in "What can I say?" command and confirmation prompts. My CDialog and CScrollView derived classes show how you can also voice enable windows built in message boxes. If you wish to use this feature you will need to create similar classes for CView, CFormView etc. I leave this as an exercise for the reader.

The CCommandMenu Class

Before I leap into code I will outline each of the public methods on the CCommandMenu class which does most of the hard work.

   static CCommandMenu* CreateWindowCommandMenu(CWnd* pWnd, const CString& sVerify = "Do It",
   const CString& sWhatCanISay = "What Can I Say", const DWORD dwVerifyTimeout = 3000,
   CWnd* pMessageTarget = NULL);

This method is the only way in which a CCommandMenu object can be created. It returns NULL if it cannot be created. The most typical reason it fails is that a suitable engine has not been installed on the users machine. The parameters are ...

  • pWnd - This is the window that the commands are associated with. It must be a top level window. Do not pass a CView derived class here. If you are voice enabling a view class then you must pass in the CMainFrame class here. The commands in this menu will only be available when this window is the active window.
  • sVerify - This is the phrase the user must say after a voice command that requires confirmation to confirm the computer has heard the command correctly.
  • sWhatCanISay - This is the phrase the user can use to query the computer for what voice commands the computer can understand.
  • dwVerifyTimeout - This is the number of milliseconds the computer allows for the user to confirm their command before it just assumes it heard you wrong.
  • pMessageTarget - This is the window to send notifications to. If this parameter is NULL then notifications are sent to pWnd. If you are voice enabling a view and want the view to receove the voice messages then pass a pointer to the view here. If you are voice enabling a dialog then this can be NULL.
   BOOL Deactivate(void);
   BOOL Activate(void);

These methods activate and deactivate the command menu. If you are adding several voice commands to the menu then you will find it runs faster if you deactivate the menu before the first add and then re-activate it after the last add.


   BOOL Add(const CString& sCmd, const DWORD dwID, const BOOL fConfirmation,
 const CPoint& ptConfirmationPromptPos, const BOOL fSendWM_COMMAND);


This method adds a voice command that your window is listening for. The parameters are ...

  • sCmd - This is the word or phrase the computer will listen for. To help the reliability of the voice command recognition it is recommended that you make the commands as distinctly sounding as possible without confusing your users.
  • dwID - This is an identifier for your command. It must be unique otherwise you won't be able to tell which command was spoken. If fSendWM_COMMAND is TRUE then it must be the control id of the button or menu you want to receive the WM_COMMAND message.
  • fConfirmation - If this is true then the user will be prompted to confirm their command before the command is executed. This should be used for any command that does anything that is not reversable.
  • ptConfirmationPromptPos - This is a point relative to the window where the confirmation prompt tooltip should be displayed.
  • fSendWM_COMMAND - If this is true then the voice command notification is sent to your window via a WM_COMMAND message. This simplifies you coding on the window but requires you have a button for each voice command.
   BOOL Remove(const CString& sCmd);
   BOOL Remove(const DWORD dwID);

These methods remove a voice command from the menu.

   BOOL RemoveAll(void);

This method removes all voice commands from the menu.

   BOOL EnableItem(const DWORD dwID, const BOOL fEnable);
   BOOL EnableItem(const CString& sCmd, const BOOL fEnable);

These methods are used to enable and disable voice commands. When a voice command is disabled it will not appear on the "What can I say?" list.

   static BOOL IsAvailable(void);

This method can be called at any time to see if voice input is available on this machine.

Sample Project

Now that we understand the CVoiceCommand class it is time to add some voice commands to a project. Our sample project is a very simple dialog based project.

Step 1

In order to use this class you project needs to have the appropriate OLE code inserted. This may be already there but it may not.

In stdafx.h check that the following include statement is present

#include <afxdisp.h>        // MFC OLE automation classes

In your applications InitInstance check you are initialising the COM libraries

	// Initialize OLE libraries
	if (!AfxOleInit())
	{
		AfxMessageBox("OLE did not initialise.");
		return FALSE;
	}

Step 2

We must change the class from which our CSampleDialog is derived. By default this was CDialog and we need to change it to CVoiceCommandDialog. A simple search and replace in the SampleDlg.h and SampleDlg.cpp files does the trick.

Step 3

In our dialog box constructor we can override some of the default settings used for message boxes.

   // enable voice input
   SetVoiceEnabled(TRUE);

   // enable voice input on message boxes
   SetMessageBoxVerify(TRUE);

Step 4

Now we need to add some voice commands. This is most easily done in the OnInitDialog member funtion. Don't forget to check the m_pVoiceCmd is not NULL before using it.

   if (m_pVoiceCmd != NULL)
   {
      m_pVoiceCmd->Deactivate();
      m_pVoiceCmd->Add("Close", m_Close.GetDlgCtrlID(), TRUE, CPoint(0,0), TRUE);
      m_pVoiceCmd->Add("Message box", m_MessageBox.GetDlgCtrlID(), TRUE, CPoint(0,0), TRUE);
      m_pVoiceCmd->Add("Up", 1, FALSE, CPoint(0,0), FALSE);
      m_pVoiceCmd->Add("Down", 2, FALSE, CPoint(0,0), FALSE);
      m_pVoiceCmd->Activate();
   }
   else
   {
      MessageBox("Voice command not available.", "Warning", MB_OK);
   }

Step 5

We need to add a message handler to receive the command notifications

BEGIN_MESSAGE_MAP(CSampleDlg, CVoiceCommandDialog)
   ON_COMMAND_CONFIRMED()

and insert it's definition in the dialogs header file

   afx_msg LONG OnCommandConfirmed(UINT, LONG);
   DECLARE_MESSAGE_MAP()

and then actually write the handler

afx_msg LONG CSampleDlg::OnCommandConfirmed(UINT dwID, LONG lUnused)
{
   UpdateData(FALSE);

   switch(dwID)
   {
   case 1:
      if (m_Edit < 10)
      {
         m_Edit++;
      }
      break;
   case 2:
      if (m_Edit > 0)
      {
         m_Edit--;
      }
      break;
   default:
      ASSERT(FALSE);
      break;
   }

   UpdateData(FALSE);
   return 0;
}

Step 6

Lastly don't forget to add my source files to your project so it will link correctly...

  • SpeachInput.CPP
  • TimerWindow.CPP
  • Tip.CPP
  • VoiceCommandDialog.CPP

... And that is all there is to it.

Download source - 60 KB