#include "stdafx.h" #include "resource.h" #include #include #include "audiodlg.h" #include #include /***************************************************************************** * 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 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 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 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 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 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 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; }