windows-nt/Source/XPSP1/NT/enduser/speech/sapi/cpl/audiodlg.cpp
2020-09-26 16:20:57 +08:00

515 lines
18 KiB
C++

#include "stdafx.h"
#include "resource.h"
#include <sapi.h>
#include <string.h>
#include "audiodlg.h"
#include <spddkhlp.h>
#include <stdio.h>
/*****************************************************************************
* AudioDlgProc *
*--------------*
* Description:
* DLGPROC for choosing the default audio input/output
****************************************************************** BECKYW ***/
BOOL CALLBACK AudioDlgProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
static CSpUnicodeSupport unicode;
CAudioDlg *pAudioDlg = (CAudioDlg *) unicode.GetWindowLongPtr( hWnd, GWLP_USERDATA );
SPDBG_FUNC( "AudioDlgProc" );
CComPtr<ISpObjectToken> cpToken;
switch (uMsg)
{
case WM_INITDIALOG:
// pAudioDlg comes in on the lParam
pAudioDlg = (CAudioDlg *) lParam;
// Set pAudioDlg to the window long so we can get it later
unicode.SetWindowLongPtr( hWnd, GWLP_USERDATA, lParam );
pAudioDlg->OnInitDialog(hWnd);
break;
case WM_DESTROY:
pAudioDlg->OnDestroy();
break;
case WM_COMMAND:
if ( LOWORD( wParam ) == IDOK )
{
// Determine if there are changes to commit
WCHAR pwszRequestedDefault[ MAX_PATH ];
pwszRequestedDefault[0] = 0;
if ( pAudioDlg->GetRequestedDefaultTokenID( pwszRequestedDefault, MAX_PATH ) )
{
// What kind of changes have been made?
pAudioDlg->m_fChangesToCommit =
(pAudioDlg->m_dstrCurrentDefaultTokenId &&
(0 != wcsicmp( pwszRequestedDefault, pAudioDlg->m_dstrCurrentDefaultTokenId )));
pAudioDlg->m_fChangesSinceLastTime =
(pAudioDlg->m_dstrCurrentDefaultTokenId &&
(0 != wcsicmp( pwszRequestedDefault, pAudioDlg->m_dstrDefaultTokenIdBeforeOK )));
}
if ( pAudioDlg->m_fChangesSinceLastTime )
{
pAudioDlg->m_dstrLastRequestedDefaultTokenId = pwszRequestedDefault;
}
::EndDialog( hWnd, true );
}
else if ( LOWORD( wParam ) == IDCANCEL )
{
// There are no changes to commit
pAudioDlg->m_fChangesSinceLastTime = false;
::EndDialog( hWnd, false );
}
// Handle the volume button
else if ( LOWORD( wParam ) == ID_TTS_VOL )
{
pAudioDlg->GetAudioToken(&cpToken);
CSpDynamicString wszTitle;
CComPtr<ISpObjectWithToken> cpSpObjectWithToken;
HRESULT hr = S_OK;
hr = cpToken->CreateInstance(
NULL, CLSCTX_INPROC_SERVER, IID_ISpObjectWithToken,
(void **)&cpSpObjectWithToken);
if (SUCCEEDED(hr))
{
WCHAR wszTitle[256];
::LoadString(_Module.GetResourceInstance(), IDS_AUDIO_VOLUME, wszTitle, 256);
hr = cpToken->DisplayUI(pAudioDlg->GetHDlg(), wszTitle, SPDUI_AudioVolume, NULL, 0, cpSpObjectWithToken);
}
SPDBG_REPORT_ON_FAIL(hr);
}
// Handle the audio properties button
else if ( LOWORD(wParam) == IDC_AUDIO_PROPERTIES)
{
pAudioDlg->GetAudioToken(&cpToken);
CSpDynamicString wszTitle;
CComPtr<ISpObjectWithToken> cpSpObjectWithToken;
HRESULT hr = S_OK;
hr = cpToken->CreateInstance(
NULL, CLSCTX_INPROC_SERVER, IID_ISpObjectWithToken,
(void **)&cpSpObjectWithToken);
if (SUCCEEDED(hr))
{
WCHAR wszTitle[256];
::LoadString(_Module.GetResourceInstance(), IDS_AUDIO_PROPERTIES, wszTitle, 256);
hr = cpToken->DisplayUI(pAudioDlg->GetHDlg(), wszTitle, SPDUI_AudioProperties, NULL, 0, cpSpObjectWithToken);
}
SPDBG_REPORT_ON_FAIL(hr);
}
// Handle a selection change for the audio device
else if (( IDC_DEFAULT_DEVICE == LOWORD( wParam ) ) &&
( CBN_SELCHANGE == HIWORD( wParam ) ))
{
SPDBG_ASSERT( !pAudioDlg->IsPreferredDevice() );
pAudioDlg->GetAudioToken(&cpToken);
pAudioDlg->UpdateDlgUI(cpToken);
}
// Handle a click to either the preferred or 'this device' radio buttons
else if (HIWORD(wParam) == BN_CLICKED)
{
bool bPreferred;
if( LOWORD(wParam) == IDC_PREFERRED_MM_DEVICE)
{
bPreferred = true;
}
else if(LOWORD(wParam) == IDC_THIS_DEVICE)
{
bPreferred = false;
}
::EnableWindow( ::GetDlgItem(pAudioDlg->GetHDlg(), IDC_DEFAULT_DEVICE), !bPreferred );
pAudioDlg->SetPreferredDevice( bPreferred );
pAudioDlg->GetAudioToken(&cpToken);
pAudioDlg->UpdateDlgUI(cpToken);
}
break;
}
return FALSE;
} /* AudioDlgProc */
/*****************************************************************************
* CAudioDlg::OnInitDialog *
*-------------------------*
* Description:
* Dialog Initialization
****************************************************************** BECKYW ***/
void CAudioDlg::OnInitDialog(HWND hWnd)
{
SPDBG_FUNC( "CAudioDlg::OnInitDialog" );
SPDBG_ASSERT(IsWindow(hWnd));
m_hDlg = hWnd;
// Set the appropriate captions
WCHAR wszCaption[ MAX_LOADSTRING ];
HINSTANCE hInst = _Module.GetResourceInstance();
// Main Window Caption
::LoadString( hInst,
(m_iotype == eINPUT) ? IDS_DEFAULT_SPEECH_INPUT : IDS_DEFAULT_SPEECH_OUTPUT,
wszCaption, MAX_LOADSTRING );
::SendMessage( hWnd, WM_SETTEXT, 0, (LPARAM) wszCaption );
// Group Box Caption
::LoadString( hInst,
(m_iotype == eINPUT) ? IDS_DEFAULT_INPUT : IDS_DEFAULT_OUTPUT,
wszCaption, MAX_LOADSTRING );
::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_AUDIO_GROUPBOX ),
WM_SETTEXT, 0, (LPARAM) wszCaption );
// Preferred Caption
::LoadString( hInst,
(m_iotype == eINPUT) ? IDS_PREFERRED_INPUT : IDS_PREFERRED_OUTPUT,
wszCaption, MAX_LOADSTRING );
::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_PREFERRED_MM_DEVICE ),
WM_SETTEXT, 0, (LPARAM) wszCaption );
// Specific Caption
::LoadString( hInst,
(m_iotype == eINPUT) ? IDS_SPECIFIC_INPUT : IDS_SPECIFIC_OUTPUT,
wszCaption, MAX_LOADSTRING );
::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_THIS_DEVICE ),
WM_SETTEXT, 0, (LPARAM) wszCaption );
// MSAA Specific Caption
::LoadString( hInst,
(m_iotype == eINPUT) ? IDS_SPECIFIC_INPUT2 : IDS_SPECIFIC_OUTPUT2,
wszCaption, MAX_LOADSTRING );
::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_THIS_DEVICE2 ),
WM_SETTEXT, 0, (LPARAM) wszCaption );
// Volume Button
::LoadString( hInst,
IDS_VOLUME,
wszCaption, MAX_LOADSTRING );
::SendMessage( (HWND) ::GetDlgItem( hWnd, ID_TTS_VOL ),
WM_SETTEXT, 0, (LPARAM) wszCaption );
// Properties Button
::LoadString( hInst,
IDS_PROPERTIES,
wszCaption, MAX_LOADSTRING );
::SendMessage( (HWND) ::GetDlgItem( hWnd, IDC_AUDIO_PROPERTIES ),
WM_SETTEXT, 0, (LPARAM) wszCaption );
const WCHAR *pszCategory = (m_iotype == eINPUT) ? SPCAT_AUDIOIN : SPCAT_AUDIOOUT;
const WCHAR *pszMMSysEnum = (m_iotype == eINPUT)
? SPMMSYS_AUDIO_IN_TOKEN_ID
: SPMMSYS_AUDIO_OUT_TOKEN_ID;
HRESULT hr = S_OK;
if ( !m_dstrCurrentDefaultTokenId )
{
hr = SpGetDefaultTokenIdFromCategoryId( pszCategory, &m_dstrCurrentDefaultTokenId );
}
if (SUCCEEDED(hr))
{
// Determine what the initial setting will appear as
if ( m_dstrLastRequestedDefaultTokenId )
{
// An audio change was previously OK'ed
m_dstrDefaultTokenIdBeforeOK = m_dstrLastRequestedDefaultTokenId;
// The current default could be different if the user OK'ed a change
// but did not apply it
m_fChangesToCommit = ( 0 != wcsicmp( m_dstrCurrentDefaultTokenId,
m_dstrDefaultTokenIdBeforeOK ) );
}
else
{
// No audio change was previously OK'ed
if ( !m_dstrDefaultTokenIdBeforeOK )
{
m_dstrDefaultTokenIdBeforeOK = m_dstrCurrentDefaultTokenId;
}
}
if (wcsicmp(m_dstrDefaultTokenIdBeforeOK, pszMMSysEnum) == 0)
{
// This message will cause the check button to be correct.
::SendMessage( ::GetDlgItem(m_hDlg, IDC_PREFERRED_MM_DEVICE), BM_SETCHECK, true, 0L );
// This message will cause the volume button to be enabled or disabled as appropriate
::SendMessage( m_hDlg, WM_COMMAND, MAKELONG( IDC_PREFERRED_MM_DEVICE, BN_CLICKED ),
(LPARAM) ::GetDlgItem( m_hDlg, IDC_PREFERRED_MM_DEVICE ) );
}
else
{
// This message will cause the check button to be correct.
::SendMessage( ::GetDlgItem(m_hDlg, IDC_THIS_DEVICE), BM_SETCHECK, true, 0L );
}
// Initialize the list of audio devices
hr = SpInitTokenComboBox( ::GetDlgItem( hWnd, IDC_DEFAULT_DEVICE ),
(m_iotype == eINPUT) ? SPCAT_AUDIOIN : SPCAT_AUDIOOUT );
}
if (S_OK == hr)
{
if ( BST_CHECKED == ::SendMessage( ::GetDlgItem( m_hDlg, IDC_THIS_DEVICE ), BM_GETCHECK, 0, 0 ) )
{
// Select the appropriate default token ID here by going through the
// stuff in the list and selecting the one whose token ID matches
// m_dstrDefaultTokenIdBeforeOK
int nTokens = (int)::SendDlgItemMessage( m_hDlg, IDC_DEFAULT_DEVICE, CB_GETCOUNT, 0, 0 );
int iItem = 0;
CSpDynamicString dstrTokenId;
bool fFound = false;
for ( iItem = 0;
(iItem < nTokens) && !fFound;
iItem++ )
{
ISpObjectToken *pToken = (ISpObjectToken *) ::SendDlgItemMessage( m_hDlg,
IDC_DEFAULT_DEVICE, CB_GETITEMDATA, iItem, 0 );
HRESULT hr = E_FAIL;
if ( pToken )
{
hr = pToken->GetId(&dstrTokenId);
}
if ( SUCCEEDED( hr ) )
{
fFound = (0 == wcsicmp( m_dstrDefaultTokenIdBeforeOK, dstrTokenId ));
}
dstrTokenId = (WCHAR *) NULL;
}
SPDBG_ASSERT( fFound );
::SendDlgItemMessage( m_hDlg, IDC_DEFAULT_DEVICE, CB_SETCURSEL, iItem - 1, 0 );
// This message will cause the volume button to be enabled or disabled as appropriate
::SendMessage( m_hDlg, WM_COMMAND, MAKELONG( IDC_THIS_DEVICE, BN_CLICKED ),
(LPARAM) ::GetDlgItem( m_hDlg, IDC_THIS_DEVICE ) );
}
::SetCursor( ::LoadCursor( NULL, IDC_ARROW ) );
}
else
{
WCHAR szError[ MAX_LOADSTRING ];
WCHAR szIO[ MAX_LOADSTRING ];
WCHAR szErrorTemplate[ MAX_LOADSTRING ];
::LoadString( _Module.GetResourceInstance(), IDS_NO_DEVICES, szErrorTemplate, sp_countof( szErrorTemplate ) );
::LoadString( _Module.GetResourceInstance(), (eINPUT == m_iotype) ? IDS_INPUT : IDS_OUTPUT, szIO, sp_countof( szIO ) );
swprintf( szError, szErrorTemplate, szIO );
::MessageBox( m_hDlg, szError, NULL, MB_ICONEXCLAMATION | g_dwIsRTLLayout );
if ( FAILED( hr ) )
{
::EndDialog( m_hDlg, -1 );
}
else
{
::EnableWindow( ::GetDlgItem( m_hDlg, IDC_THIS_DEVICE ), FALSE );
::EnableWindow( ::GetDlgItem( m_hDlg, IDC_DEFAULT_DEVICE ), FALSE );
::EnableWindow( ::GetDlgItem( m_hDlg, IDC_PREFERRED_MM_DEVICE ), FALSE );
::EnableWindow( ::GetDlgItem( m_hDlg, IDC_AUDIO_PROPERTIES ), FALSE );
::EnableWindow( ::GetDlgItem( m_hDlg, ID_TTS_VOL ), FALSE );
}
}
} /* CAudioDlg::OnInitDialog */
/*****************************************************************************
* CAudioDlg::OnDestroy *
*----------------------*
* Description:
* Destruction
****************************************************************** BECKYW ***/
void CAudioDlg::OnDestroy()
{
SPDBG_FUNC( "CAudioDlg::OnDestroy" );
SpDestroyTokenComboBox( ::GetDlgItem( m_hDlg, IDC_DEFAULT_DEVICE ) );
} /* CAudioDlg::OnDestroy */
/*****************************************************************************
* CAudioDlg::OnApply *
*--------------------*
* Description:
* Set user specified options
****************************************************************** BECKYW ***/
HRESULT CAudioDlg::OnApply()
{
SPDBG_FUNC( "CAudioDlg::OnApply" );
if ( !m_dstrLastRequestedDefaultTokenId )
{
// nothing to apply
return S_FALSE;
}
HRESULT hr;
CComPtr<ISpObjectTokenCategory> cpCategory;
hr = SpGetCategoryFromId(
m_iotype == eINPUT
? SPCAT_AUDIOIN
: SPCAT_AUDIOOUT,
&cpCategory);
if ( SUCCEEDED( hr ) )
{
hr = cpCategory->SetDefaultTokenId( m_dstrLastRequestedDefaultTokenId );
}
// Next time we bring this up we should show the actual default
m_dstrLastRequestedDefaultTokenId = (WCHAR *) NULL;
m_dstrDefaultTokenIdBeforeOK = (WCHAR *) NULL;
return hr;
} /* CAudioDlg::OnApply */
/*****************************************************************************
* CAudioDlg::GetRequestedDefaultTokenID *
*---------------------------------------*
* Description:
* Looks at the UI and gets the token ID that the user wants to switch
* to. This is returned in pwszNewID.
* Return:
* Number of characters in the ID
****************************************************************** BECKYW ***/
UINT CAudioDlg::GetRequestedDefaultTokenID( WCHAR *pwszNewID, UINT cLength )
{
if ( !pwszNewID )
{
return 0;
}
CComPtr<ISpObjectTokenCategory> cpCategory;
HRESULT hr = SpGetCategoryFromId(
m_iotype == eINPUT
? SPCAT_AUDIOIN
: SPCAT_AUDIOOUT,
&cpCategory);
if (SUCCEEDED(hr))
{
if( ::SendMessage( ::GetDlgItem(m_hDlg, IDC_PREFERRED_MM_DEVICE), BM_GETCHECK, 0, 0L ) == BST_CHECKED )
{
const WCHAR *pwszMMSysAudioID = (m_iotype == eINPUT) ?
SPMMSYS_AUDIO_IN_TOKEN_ID :
SPMMSYS_AUDIO_OUT_TOKEN_ID;
UINT cMMSysAudioIDLength = wcslen( pwszMMSysAudioID );
UINT cRet = __min( cLength - 1, cMMSysAudioIDLength );
wcsncpy( pwszNewID, pwszMMSysAudioID, cRet );
pwszNewID[ cRet ] = 0;
return cRet;
}
else
{
ISpObjectToken *pToken = SpGetCurSelComboBoxToken( ::GetDlgItem( m_hDlg, IDC_DEFAULT_DEVICE ) );
if (pToken)
{
CSpDynamicString dstrTokenId;
hr = pToken->GetId(&dstrTokenId);
if (SUCCEEDED(hr))
{
UINT cIDLength = wcslen( dstrTokenId );
UINT cRet = __min( cLength - 1, cIDLength );
wcsncpy( pwszNewID, dstrTokenId, cRet );
pwszNewID[ cRet ] = 0;
return cRet;
}
}
}
}
// There was an error
return 0;
} /* CAudioDlg::GetRequestedDefaultTokenID */
/*****************************************************************************
* CAudioDlg::GetAudioToken *
*--------------------------*
* Description:
* Returns an interface to the currently selected token. Currently this
* can either be the 'preferred' device in which case, the object is created
* on the fly. Or it can be one from the drop-down list which contains an
* attached token. In this case, it needs to be addref'd so that the returned
* token is consistent regardless of the source inside this function.
*
* NB: This requires the caller to call release on the instance.
*
* Return:
**************************************************************** AGARSIDE ***/
HRESULT CAudioDlg::GetAudioToken(ISpObjectToken **ppToken)
{
HRESULT hr = S_OK;
*ppToken = NULL;
if (IsPreferredDevice())
{
hr = SpGetTokenFromId((this->IsInput())?(SPMMSYS_AUDIO_IN_TOKEN_ID):(SPMMSYS_AUDIO_OUT_TOKEN_ID),
ppToken,
FALSE);
SPDBG_ASSERT(SUCCEEDED(hr));
}
else
{
*ppToken = SpGetCurSelComboBoxToken( GetDlgItem(this->GetHDlg(), IDC_DEFAULT_DEVICE) );
(*ppToken)->AddRef();
}
return S_OK;
}
/*****************************************************************************
* CAudioDlg::UpdateDlgUI *
*------------------------*
* Description:
* Return:
**************************************************************** AGARSIDE ***/
HRESULT CAudioDlg::UpdateDlgUI(ISpObjectToken *pToken)
{
SPDBG_FUNC("CAudioDlg::UpdateDlgUI");
HRESULT hr = S_OK;
BOOL fSupported;
CComPtr<ISpObjectWithToken> cpSpObjectWithToken;
// Get hold of ISpObjectWithToken
hr = pToken->CreateInstance(
NULL, CLSCTX_INPROC_SERVER, IID_ISpObjectWithToken,
(void **)&cpSpObjectWithToken);
// Update volume button status.
fSupported = FALSE;
if (SUCCEEDED(hr))
{
pToken->IsUISupported(SPDUI_AudioVolume, NULL, 0, cpSpObjectWithToken, &fSupported);
::EnableWindow( ::GetDlgItem(this->GetHDlg(), ID_TTS_VOL), fSupported);
}
// Update UI button status.
fSupported = FALSE;
if (SUCCEEDED(hr))
{
pToken->IsUISupported(SPDUI_AudioProperties, NULL, 0, cpSpObjectWithToken, &fSupported);
::EnableWindow( ::GetDlgItem(this->GetHDlg(), IDC_AUDIO_PROPERTIES), fSupported);
}
SPDBG_REPORT_ON_FAIL(hr);
return hr;
}