home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / mfc / advanced / speakn / speakn.cpp < prev    next >
C/C++ Source or Header  |  1998-03-26  |  8KB  |  304 lines

  1. // speakn.cpp : Defines the class behaviors for the SpeakN application.
  2. //
  3. // This is a part of the Microsoft Foundation Classes C++ library.
  4. // Copyright (C) 1992-1998 Microsoft Corporation
  5. // All rights reserved.
  6. //
  7. // This source code is only intended as a supplement to the
  8. // Microsoft Foundation Classes Reference and related
  9. // electronic documentation provided with the library.
  10. // See these sources for detailed information regarding the
  11. // Microsoft Foundation Classes product.
  12.  
  13. #include "stdafx.h"
  14.  
  15. #include "speakn.h"
  16. #include <mmsystem.h>
  17.  
  18. /////////////////////////////////////////////////////////////////////////////
  19. // Sound helpers
  20.  
  21. static void PlaySound(LPCTSTR lpszSound)
  22. {
  23.     HRSRC hRes; // resource handle to wave file
  24.     HGLOBAL hData;
  25.     BOOL bOk = FALSE;
  26.     if ((hRes = ::FindResource(AfxGetResourceHandle(), lpszSound,
  27.       _T("sound"))) != NULL &&
  28.       (hData = ::LoadResource(AfxGetResourceHandle(), hRes)) != NULL)
  29.     {
  30.         // found the resource, play it
  31.         bOk = sndPlaySound((LPCTSTR)::LockResource(hData),
  32.             SND_MEMORY|SND_SYNC|SND_NODEFAULT);
  33.         FreeResource(hData);
  34.     }
  35.     if (!bOk)
  36.     {
  37.         static BOOL bReported = FALSE;
  38.         if (!bReported)
  39.         {
  40.             AfxMessageBox(IDS_CANNOT_PLAY_SOUND);
  41.             bReported = TRUE;       // once please
  42.         }
  43.     }
  44. }
  45.  
  46. inline static void PlaySound(UINT nIDS)
  47.     { PlaySound(MAKEINTRESOURCE(nIDS)); }
  48.  
  49. /////////////////////////////////////////////////////////////////////////////
  50. // CSpeakNDlg
  51.  
  52. CSpeakNDlg::CSpeakNDlg(BOOL bNoPen)
  53.     : CDialog(bNoPen ? IDD_NOPENDIALOG : CSpeakNDlg::IDD)
  54. {
  55.     //{{AFX_DATA_INIT(CSpeakNDlg)
  56.         // NOTE: the ClassWizard will add member initialization here
  57.     //}}AFX_DATA_INIT
  58.  
  59.     m_bNoPen = bNoPen;
  60.     m_lpszNextQuestion = NULL;
  61.     m_bNoAnswerCheck = FALSE;
  62. }
  63.  
  64. BEGIN_MESSAGE_MAP(CSpeakNDlg, CDialog)
  65.     //{{AFX_MSG_MAP(CSpeakNDlg)
  66.     ON_COMMAND(IDC_REPLAY_SOUND, OnReplaySound)
  67.     ON_COMMAND(IDC_GIVE_UP, OnGiveUp)
  68.     ON_COMMAND(IDC_PICTURE, OnReplaySound)
  69.     ON_EN_CHANGE(IDC_INPUT_EDIT, OnUpdateStatus)
  70.     //}}AFX_MSG_MAP
  71. END_MESSAGE_MAP()
  72.  
  73. BOOL CSpeakNDlg::LoadLesson(LPCTSTR lpLessonName)
  74. {
  75.     // load lesson from resource
  76.     HRSRC hRes; // resource handle to lesson data
  77.     HGLOBAL hData;
  78.     if ((hRes = ::FindResource(AfxGetResourceHandle(), lpLessonName,
  79.       _T("lesson"))) == NULL ||
  80.       (hData = ::LoadResource(AfxGetResourceHandle(), hRes)) == NULL)
  81.         return FALSE;
  82.     m_lpszNextQuestion = (LPCSTR)::LockResource(hData);
  83.     return TRUE;
  84. }
  85.  
  86. void CSpeakNDlg::DoDataExchange(CDataExchange* pDX)
  87. {
  88.     CDialog::DoDataExchange(pDX);
  89.     //{{AFX_DATA_MAP(CSpeakNDlg)
  90.     DDX_Control(pDX, IDOK, m_buttonNext);
  91.     //}}AFX_DATA_MAP
  92. }
  93.  
  94.  
  95. BOOL CSpeakNDlg::OnInitDialog()
  96. {
  97.     UpdateData(FALSE); // call DoDataExchange to initialize m_buttonNext
  98.     m_buttonNext.EnableWindow(FALSE);
  99.  
  100.     ASSERT(m_targetWord.IsEmpty());     // not started yet
  101.  
  102.     // set the font of the prompt text to something bigger
  103.     LOGFONT logfont;
  104.     memset(&logfont, 0, sizeof(logfont));
  105.     logfont.lfHeight = 40;
  106.     logfont.lfWeight = FW_BOLD;
  107.     CString szFont;
  108.     szFont.LoadString(IDS_FONT_NAME);           // TrueType font
  109.     lstrcpy(logfont.lfFaceName, szFont);
  110.     VERIFY(m_biggerFont.CreateFontIndirect(&logfont));
  111.     PromptText().SetFont(&m_biggerFont);
  112.     InputEdit().SetFont(&m_biggerFont);
  113.  
  114.     // load the bitmaps for bitmap buttons
  115.     VERIFY(m_replayButton.AutoLoad(IDC_REPLAY_SOUND, this));
  116.     InputEdit().ShowWindow(FALSE);      // start with input disabled
  117.  
  118.     // load initial picture
  119.     VERIFY(m_pictureButton.SubclassDlgItem(IDC_PICTURE, this));
  120.     VERIFY(m_pictureButton.LoadBitmaps(_T("intro"), NULL, NULL));
  121.  
  122.     // Make the dialog visible, and update
  123.     ShowWindow(TRUE);       // SHOW_OPENWINDOW
  124.     UpdateWindow();
  125.  
  126.     PlaySound(IDSOUND_WELCOME);
  127.     AdvanceLesson();
  128.     return FALSE;       // focus already set
  129. }
  130.  
  131. void CSpeakNDlg::OnReplaySound()
  132. {
  133.     InputEdit().SetFocus();
  134.     PlaySound(m_targetRes);
  135. }
  136.  
  137. void CSpeakNDlg::OnOK()
  138. {
  139.     // check results
  140.     CString result;
  141.     InputEdit().GetWindowText(result);
  142.     if (result != m_targetWord)
  143.     {
  144.         PlaySound(IDSOUND_INCORRECT);
  145.         AfxMessageBox(IDS_TRY_AGAIN);
  146.         return;
  147.     }
  148.     PlaySound(IDSOUND_CORRECT);
  149.     AdvanceLesson();
  150. }
  151.  
  152. void CSpeakNDlg::OnGiveUp()
  153. {
  154.     PlaySound(IDSOUND_GIVEUP);
  155.     SetAnswerText(m_targetWord);        // show answer
  156.     OnReplaySound();
  157.     AdvanceLesson();
  158. }
  159.  
  160. void CSpeakNDlg::SetAnswerText(LPCTSTR lpsz)
  161. {
  162.     // setting the window text for an edit control will cause EN_CHANGE
  163.     //  control notifications, so we lock them out while setting the
  164.     //  text programmatically
  165.     ASSERT(!m_bNoAnswerCheck);
  166.     m_bNoAnswerCheck = TRUE;
  167.     InputEdit().SetWindowText(lpsz);
  168.     m_bNoAnswerCheck = FALSE;
  169. }
  170.  
  171. /////////////////////////////////////////////////////////////////////////////
  172. // Advancing to the next lesson
  173.  
  174. void CSpeakNDlg::AdvanceLesson()
  175. {
  176.     if (*m_lpszNextQuestion == '\0')
  177.     {
  178.         // out of questions
  179.         PlaySound(IDSOUND_GOODBYE);
  180.         EndDialog(IDOK);
  181.         return;
  182.     }
  183.  
  184. // The lesson resource consists of several pairs of words (that the user guesses)
  185. // and bitmap resource names.  The words and resource names are stored in the
  186. // resource as ANSI text.  This text must be converted to UNICODE.
  187.  
  188. #ifdef _UNICODE
  189.     TCHAR szT[20];
  190.     int nLen;
  191.     nLen = strlen(m_lpszNextQuestion);
  192.     mbstowcs(szT, m_lpszNextQuestion, nLen);
  193.     szT[nLen] = 0;
  194.     m_targetWord = szT;
  195.     m_lpszNextQuestion += nLen + 1;
  196.  
  197.     nLen = strlen(m_lpszNextQuestion);
  198.     mbstowcs(szT, m_lpszNextQuestion, nLen);
  199.     szT[nLen] = 0;
  200.     m_targetRes = szT;
  201.     m_lpszNextQuestion += nLen + 1;
  202. #else
  203.     m_targetWord = m_lpszNextQuestion;
  204.     m_lpszNextQuestion += m_targetWord.GetLength() + 1;
  205.  
  206.     m_targetRes = m_lpszNextQuestion;
  207.     m_lpszNextQuestion += m_targetRes.GetLength() + 1;
  208. #endif
  209.  
  210.     m_targetWord.MakeUpper();
  211.     m_targetRes.MakeUpper();
  212.  
  213.     PlaySound(IDSOUND_QUESTION);
  214.  
  215.     // draw the picture (bitmap with the same name as the target)
  216.     if (!m_pictureButton.LoadBitmaps(m_targetRes))
  217.     {
  218.         AfxMessageBox(IDS_PICTURE_UNAVAILABLE);
  219.         VERIFY(m_pictureButton.LoadBitmaps(_T("intro"), NULL, NULL));
  220.             // go back to the initial bitmap
  221.     }
  222.     m_pictureButton.Invalidate(TRUE);
  223.  
  224.     SetAnswerText(_T(""));
  225.     InputEdit().ShowWindow(TRUE);
  226.  
  227.     OnUpdateStatus();               // set appropriate face
  228.     OnReplaySound();                // ask question
  229.  
  230.     if (*m_lpszNextQuestion == '\0')
  231.     {
  232.         CString strDone;
  233.         strDone.LoadString(IDS_DONE);
  234.         m_buttonNext.SetWindowText(strDone);
  235.     }
  236. }
  237.  
  238. /////////////////////////////////////////////////////////////////////////////
  239. // Happy face status indicator
  240.  
  241. void CSpeakNDlg::OnUpdateStatus()
  242. {
  243.     CString result;
  244.     InputEdit().GetWindowText(result);
  245.  
  246.     UINT nIDI = IDI_FACE_NEUTRAL;       // default
  247.     if (result == m_targetWord)
  248.     {
  249.         m_buttonNext.EnableWindow();
  250.         nIDI = IDI_FACE_HAPPIER;        // exact match
  251.     }
  252.     else
  253.     {
  254.         m_buttonNext.EnableWindow(FALSE);
  255.         if (result.IsEmpty())
  256.             nIDI = IDI_FACE_NEUTRAL;        // not started yet
  257.         else
  258.         {
  259.             nIDI = (_tcsncmp(m_targetWord, result, _tcslen(result)) == 0?
  260.                 IDI_FACE_HAPPY : IDI_FACE_SAD);
  261.         }
  262.     }
  263.  
  264.     HICON hNew = ::LoadIcon(AfxGetResourceHandle(), MAKEINTRESOURCE(nIDI));
  265.     ASSERT(hNew != NULL);
  266.     ::DestroyIcon(StatusFace().SetIcon(hNew));
  267.     UpdateWindow();                 // draw everything now
  268.  
  269.     if (m_bNoAnswerCheck)
  270.         return;     // don't update
  271.  
  272.     if (nIDI == IDI_FACE_HAPPIER)
  273.     {
  274.         // exact match - automatic advance
  275.         OnReplaySound();
  276.         PlaySound(IDSOUND_CORRECT);
  277.     }
  278. }
  279.  
  280. /////////////////////////////////////////////////////////////////////////////
  281. // CSpeakNApp
  282.  
  283. BOOL CSpeakNApp::InitInstance()
  284. {
  285.     Enable3dControls();
  286.  
  287.     BOOL bNoPen = TRUE;  // no pen-aware controls
  288.  
  289.     // Creates a simple dialog and do it
  290.     CSpeakNDlg mainDlg(bNoPen);
  291.     if (!mainDlg.LoadLesson(_T("SAMPLE1")))
  292.         return FALSE;
  293.     m_pMainWnd = &mainDlg;
  294.     mainDlg.DoModal();
  295.  
  296.     // that's all, quit app
  297.     ::PostQuitMessage(0);
  298.     return TRUE;
  299. }
  300.  
  301. CSpeakNApp NEAR theApp;
  302.  
  303. /////////////////////////////////////////////////////////////////////////////
  304.