C ++ Builderの視覚障害者用のText-To-Speechアプリケーションコントロールには、次のコードを使用します(Delphiでも同様の例を使用できる可能性があります)。メインフォームのKeyPreview
プロパティがチェックされ、キーF11プレビューがアクティブな(フォーカスされた)コントロールの発話を開始できるようになっています。コードはそのままで動作しますが、いくつか問題があります。この例はC++Builderコードですが、私が見つけたものから、Delphiは同じ問題に苦しんでおり、私が見つけた解決策は同じです。Delphiソリューションをお持ちの場合は、お気軽に投稿してください。とにかく似ています。
#include <sapi.h>
#include <WTypes.h>
//---------------------------------------------------------------------------
// Speak text string (synchronous function)
//---------------------------------------------------------------------------
bool SpeakText(UnicodeString Text)
{
ISpVoice* pVoice = NULL;
if (FAILED(::CoInitialize(NULL))) return false;
Word Saved8087CW = Default8087CW; // Disable floating point division by zero exception caused by Speak
Set8087CW(0x133f);
HRESULT hr = CoCreateInstance(CLSID_SpVoice, NULL, CLSCTX_ALL, IID_ISpVoice, (void **)&pVoice);
if (SUCCEEDED(hr))
{
//pVoice->SpeakCompleteEvent()
//pVoice->SetSyncSpeakTimeout(1000);
hr = pVoice->Speak(WideString(Text).c_bstr(), SPF_DEFAULT, NULL);
pVoice->Release();
pVoice = NULL;
}
Set8087CW(Saved8087CW);
::CoUninitialize();
return true;
}
//---------------------------------------------------------------------------
void __fastcall TForm1::FormKeyUp(TObject *Sender, WORD &Key, TShiftState Shift)
{
UnicodeString Speaker;
if (Key == VK_F11)
{
if (Screen->ActiveControl->InheritsFrom(__classid(TButton))) { Speaker += "Button, " + static_cast<TButton*>(Screen->ActiveControl)->Caption + "."; }
else if (Screen->ActiveControl->InheritsFrom(__classid(TEdit))) { Speaker += "Edit box, " + static_cast<TEdit*>(Screen->ActiveControl)->Text + "."; }
}
if (Speaker != "") SpeakText(Speaker);
}
//---------------------------------------------------------------------------
問題:
関数を使用して例外をオーバーライドしない場合、pVoice->Speakは浮動小数点のゼロ除算
Set8087CW
を引き起こします。これは、Windows 7(おそらくVistaとWindows 8も)でのみ発生し、同じプログラム(コンパイル済みexe)のWindowsXPでは発生しません。使用せずに解決策はありSet8087CW
ますか?これらの行を削除すると、問題と例外が発生します。私はBCB2010を持っています。関数は同期しており、テキストの読み取りが完了するまで、シャットダウンしたり、制御をプログラムに戻したりすることはありません。これは、長いテキストの場合の問題です。また、プログラムイベントをブロックします。非同期にする方法や、F11キーのステータスを定期的にチェックするイベントを導入する方法はありますか?F11をもう一度押すと、読み取りが停止し、オブジェクトの初期化が解除されますか?たとえば、300ミリ秒ごと(または各単語の後など)にF11キーを押してポーリングし、押された場合は話すのをやめますか?またはスレッドで実行しますか?
SAPIには、さまざまなサイトに書き込むときにメモリリークが発生しますか?
上記のコードはと
OleCheck
の代わりに使用できますか?CoCreateInstance
CoUninitialize
Remy Lebeauによって提案された解決策を探している人のための更新:
SavedCW = Get8087CW();
Set8087CW(SavedCW | 0x4);
hr = pVoice->Speak(WideString(Text).c_bstr(), SPF_DEFAULT | SPF_ASYNC, NULL);
pVoice->WaitUntilDone(-1); // Waits until text is done... if F11 is pressed simply go out of scope and speech will stop
Set8087CW(SavedCW);
CodeRage 4セッションにも詳細な例があります:http://cc.embarcadero.com/item/27264