Files
2025-05-21 21:20:08 +03:00

346 lines
10 KiB
C++

/******************************************************************************
* coffee.cpp
* Contains entry point for the coffee tutorial application, as
* well as implementation of all application features.
*
*
* Copyright (c) Microsoft Corporation. All rights reserved.
*
* The source code supplied here is intended as a sample, so some
* error handling, etc. has been omitted for the sake of clarity.
******************************************************************************/
#include "stdafx.h"
#include <sphelper.h> // Contains definitions of SAPI functions
#include "common.h" // Contains common defines
#include "coffee.h" // Forward declarations and constants
#include "cofgram.h" // This header is created by the grammar
// compiler and has our rule ids
/******************************************************************************
* WinMain *
*---------*
* Description:
* coffee entry point.
*
* Return:
* exit code
******************************************************************************/
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
// Register the main window class
MyRegisterClass(hInstance, WndProc);
// Initialize pane handler state
g_fpCurrentPane = EntryPaneProc;
// Only continue if COM is successfully initialized
if ( SUCCEEDED( CoInitialize( NULL ) ) )
{
// Perform application initialization:
if (!InitInstance( hInstance, nCmdShow ))
{
return FALSE;
}
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
CoUninitialize();
}
return msg.wParam;
}
/******************************************************************************
* WndProc *
*---------*
* Description:
* Main window procedure.
*
******************************************************************************/
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_CREATE:
// Try to initialize, quit with error message if we can't
if ( FAILED( InitSAPI( hWnd ) ) )
{
const iMaxTitleLength = 64;
TCHAR tszBuf[ MAX_PATH ];
LoadString( g_hInst, IDS_FAILEDINIT, tszBuf, MAX_PATH );
TCHAR tszName[ iMaxTitleLength ];
LoadString( g_hInst, IDS_APP_TITLE, tszName, iMaxTitleLength );
MessageBox( hWnd, tszBuf, tszName, MB_OK|MB_ICONWARNING );
return( -1 );
}
break;
// This is our application defined window message to let us know that a
// speech recognition event has occurred.
case WM_RECOEVENT:
ProcessRecoEvent( hWnd );
break;
case WM_ERASEBKGND:
EraseBackground( (HDC) wParam );
return ( 1 );
case WM_GETMINMAXINFO:
{
LPMINMAXINFO lpMM = (LPMINMAXINFO) lParam;
lpMM->ptMaxSize.x = MINMAX_WIDTH;
lpMM->ptMaxSize.y = MINMAX_HEIGHT;
lpMM->ptMinTrackSize.x = MINMAX_WIDTH;
lpMM->ptMinTrackSize.y = MINMAX_HEIGHT;
lpMM->ptMaxTrackSize.x = MINMAX_WIDTH;
lpMM->ptMaxTrackSize.y = MINMAX_HEIGHT;
return ( 0 );
}
// Release remaining SAPI related COM references before application exits
case WM_DESTROY:
KillTimer( hWnd, 0 );
CleanupGDIObjects();
CleanupSAPI();
PostQuitMessage(0);
break;
default:
{
_ASSERTE( g_fpCurrentPane );
// Send unhandled messages to pane specific procedure for potential action
LRESULT lRet = (*g_fpCurrentPane)(hWnd, message, wParam, lParam);
if ( 0 == lRet )
{
lRet = DefWindowProc(hWnd, message, wParam, lParam);
}
return ( lRet );
}
}
return ( 0 );
}
/******************************************************************************
* InitSAPI *
*----------*
* Description:
* Called once to get SAPI started.
*
******************************************************************************/
HRESULT InitSAPI( HWND hWnd )
{
HRESULT hr = S_OK;
CComPtr<ISpAudio> cpAudio;
while ( 1 )
{
// create a recognition engine
hr = g_cpEngine.CoCreateInstance(CLSID_SpSharedRecognizer);
if ( FAILED( hr ) )
{
break;
}
// create the command recognition context
hr = g_cpEngine->CreateRecoContext( &g_cpRecoCtxt );
if ( FAILED( hr ) )
{
break;
}
// Let SR know that window we want it to send event information to, and using
// what message
hr = g_cpRecoCtxt->SetNotifyWindowMessage( hWnd, WM_RECOEVENT, 0, 0 );
if ( FAILED( hr ) )
{
break;
}
// Tell SR what types of events interest us. Here we only care about command
// recognition.
hr = g_cpRecoCtxt->SetInterest( SPFEI(SPEI_RECOGNITION), SPFEI(SPEI_RECOGNITION) );
if ( FAILED( hr ) )
{
break;
}
// Load our grammar, which is the compiled form of simple.xml bound into this executable as a
// user defined ("SRGRAMMAR") resource type.
hr = g_cpRecoCtxt->CreateGrammar(GRAMMARID1, &g_cpCmdGrammar);
if (FAILED(hr))
{
break;
}
hr = g_cpCmdGrammar->LoadCmdFromResource(NULL, MAKEINTRESOURCEW(IDR_CMD_CFG),
L"SRGRAMMAR", MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL),
SPLO_DYNAMIC);
if ( FAILED( hr ) )
{
break;
}
// Set rules to active, we are now listening for commands
hr = g_cpCmdGrammar->SetRuleState(NULL, NULL, SPRS_ACTIVE );
if ( FAILED( hr ) )
{
break;
}
break;
}
// if we failed and have a partially setup SAPI, close it all down
if ( FAILED( hr ) )
{
CleanupSAPI();
}
return ( hr );
}
/******************************************************************************
* CleanupSAPI *
*----------------*
* Description:
* Called to close down SAPI COM objects we have stored away.
*
******************************************************************************/
void CleanupSAPI( void )
{
// Release grammar, if loaded
if ( g_cpCmdGrammar )
{
g_cpCmdGrammar.Release();
}
// Release recognition context, if created
if ( g_cpRecoCtxt )
{
g_cpRecoCtxt->SetNotifySink(NULL);
g_cpRecoCtxt.Release();
}
// Release recognition engine instance, if created
if ( g_cpEngine )
{
g_cpEngine.Release();
}
}
/******************************************************************************
* ProcessRecoEvent *
*------------------*
* Description:
* Called to when reco event message is sent to main window procedure.
* In the case of a recognition, it extracts result and calls ExecuteCommand.
*
******************************************************************************/
void ProcessRecoEvent( HWND hWnd )
{
CSpEvent event; // Event helper class
// Loop processing events while there are any in the queue
while (event.GetFrom(g_cpRecoCtxt) == S_OK)
{
// Look at recognition event only
switch (event.eEventId)
{
case SPEI_RECOGNITION:
ExecuteCommand(event.RecoResult(), hWnd);
break;
}
}
}
/******************************************************************************
* ExecuteCommand *
*----------------*
* Description:
* Called to Execute commands that have been identified by the speech engine.
*
******************************************************************************/
void ExecuteCommand(ISpPhrase *pPhrase, HWND hWnd)
{
SPPHRASE *pElements;
// Get the phrase elements, one of which is the rule id we specified in
// the grammar. Switch on it to figure out which command was recognized.
if (SUCCEEDED(pPhrase->GetPhrase(&pElements)))
{
switch ( pElements->Rule.ulId )
{
case VID_Navigation:
{
switch( pElements->pProperties->vValue.ulVal )
{
case VID_Counter:
PostMessage( hWnd, WM_GOTOCOUNTER, NULL, NULL );
break;
}
}
break;
}
// Free the pElements memory which was allocated for us
::CoTaskMemFree(pElements);
}
}
/******************************************************************************
* EntryPaneProc *
*---------------*
* Description:
* Handles messages specifically for the entry pane.
*
******************************************************************************/
LRESULT EntryPaneProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_GOTOCOUNTER:
// Set the right message handler and repaint
g_fpCurrentPane = CounterPaneProc;
PostMessage( hWnd, WM_INITPANE, NULL, NULL );
InvalidateRect( hWnd, NULL, TRUE );
return ( 1 );
case WM_PAINT:
EntryPanePaint( hWnd );
return ( 1 );
}
return ( 0 );
}
/******************************************************************************
* CounterPaneProc *
*-----------------*
* Description:
* Handles messages specifically for the counter (order) pane.
*
******************************************************************************/
LRESULT CounterPaneProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch ( message )
{
case WM_PAINT:
CounterPanePaint( hWnd, g_szCounterDisplay );
return ( 1 );
case WM_INITPANE:
LoadString( g_hInst, IDS_PLEASEORDER, g_szCounterDisplay, MAX_LOADSTRING );
return ( 1 );
}
return ( 0 );
}