このサンプルでは、 手書き 認識に使用される MicrosoftTablet PC Automation アプリケーション プログラミング インターフェイス (API) の高度な機能を示します。
含まれる内容は次のとおりです。
- インストールされている認識エンジンの列挙
- 特定の言語 認識エンジン を使用して認識エンジン コンテキストを作成する
- ストローク コレクションを使用した認識結果のシリアル化
- InkDisp オブジェクト内のカスタム コレクションにストローク コレクションを整理する
- インク オブジェクトをシリアル化し、インク シリアル化形式 (ISF) ファイルから取得する
- 認識エンジン入力ガイドの設定
- 同期認識と非同期認識の使用
インク ヘッダー
最初に、タブレット PC オートメーション インターフェイスのヘッダーを含めます。 これらは、Microsoft Windows XP Tablet PC Edition Software Development Kit (SDK) と共にインストールされます。
#include <msinkaut.h>
#include <msinkaut_i.c>
EventSinks.h ファイルは、IInkEventsImpl インターフェイスと IInkRecognitionEventsImpl インターフェイスを定義します。
#include "EventSinks.h"
インストールされている認識エンジンの列挙
アプリケーションの LoadMenu メソッドは、[新しいストロークの作成] メニューに使用可能な認識エンジンを設定します。 InkRecognizers が作成されます。 InkRecognizers オブジェクトの Languages プロパティが空でない場合、認識エンジンはテキスト認識エンジンであり、Name プロパティの値がメニューに追加されます。
// Create the enumerator for the installed recognizers
hr = m_spIInkRecognizers.CoCreateInstance(CLSID_InkRecognizers);
...
// Filter out non-language recognizers by checking for
// the languages supported by the recognizer - there is not
// any if it is a gesture or object recognizer.
CComVariant vLanguages;
if (SUCCEEDED(spIInkRecognizer->get_Languages(&vLanguages)))
{
if ((VT_ARRAY == (VT_ARRAY & vLanguages.vt)) // it should be an array
&& (NULL != vLanguages.parray)
&& (0 < vLanguages.parray->rgsabound[0].cElements)) // with at least one element
{
// This is a language recognizer. Add its name to the menu.
CComBSTR bstrName;
if (SUCCEEDED(spIInkRecognizer->get_Name(&bstrName)))
...
}
}
インク コレクターの作成
アプリケーションの OnCreate メソッドは InkCollector オブジェクトを作成し、それをそのイベント ソースに接続し、インクコレクションを有効にします。
// Create an ink collector object.
hr = m_spIInkCollector.CoCreateInstance(CLSID_InkCollector);
// Establish a connection to the collector's event source.
hr = IInkCollectorEventsImpl<CMultiRecoApp>::DispEventAdvise(m_spIInkCollector);
// Enable ink input in the m_wndInput window
hr = m_spIInkCollector->put_hWnd((long)m_wndInput.m_hWnd);
hr = m_spIInkCollector->put_Enabled(VARIANT_TRUE);
認識エンジン コンテキストの作成
アプリケーションの CreateRecoContext メソッドは、新しい認識エンジン コンテキストを作成して初期化し、関連付けられている言語でサポートされているガイドを設定します。 IInkRecognizer オブジェクトの CreateRecognizerContext メソッドは、言語の IInkRecognizerContext2 オブジェクトを作成します。 必要に応じて、古い認識エンジン コンテキストが置き換えられます。 コンテキストは、そのイベント ソースに接続されています。 最後に、認識エンジン コンテキストの Capabilities プロパティがチェックされ、認識エンジン コンテキストがサポートするガイドが表示されます。
// Create a recognizer context
CComPtr<IInkRecognizerContext2> spNewContext;
if (FAILED(pIInkRecognizer2->CreateRecognizerContext(&spNewContext)))
return false;
// Replace the current context with the new one
if (m_spIInkRecoContext != NULL)
{
// Close the connection to the recognition events source
IInkRecognitionEventsImpl<CMultiRecoApp>::DispEventUnadvise(m_spIInkRecoContext);
}
m_spIInkRecoContext.Attach(spNewContext.Detach());
// Establish a connection with the recognizer context's event source
if (FAILED(IInkRecognitionEventsImpl<CMultiRecoApp>::DispEventAdvise(m_spIInkRecoContext)))
...
// Set the guide if it's supported by the recognizer and has been created
int cRows = 0, cColumns = 0;
InkRecognizerCapabilities dwCapabilities = IRC_DontCare;
if (SUCCEEDED(pIInkRecognizer->get_Capabilities(&dwCapabilities)))
...
ストロークの収集と認識結果の表示
アプリケーションの OnStroke メソッドは、インク コレクターの InkStrokes を更新し、既存の非同期認識要求を取り消し、認識エンジン コンテキストで認識要求を作成します。
// Add the new stroke to the current collection
hr = m_spIInkStrokes->Add(pIInkStroke);
if (SUCCEEDED(hr))
{
// Cancel the previous background recognition requests
// which have not been processed yet
m_spIInkRecoContext->StopBackgroundRecognition();
// Ask the context to update the recognition results with newly added strokes
// When the results are ready, the recognizer context returns them
// through the corresponding event RecognitionWithAlternates
CComVariant vCustomData;
m_spIInkRecoContext->BackgroundRecognize(vCustomData);
}
アプリケーションの OnRecognition メソッドは、認識要求の結果を出力ウィンドウの UpdateString メソッドに送信します。
// Update the output window with the new results
m_wndResults.UpdateString(bstrRecognizedString);
ストロークと認識結果の削除
アプリケーションの OnClear メソッドは、 InkDisp オブジェクトからすべてのストロークと認識結果を削除し、ウィンドウをクリアします。 認識エンジン コンテキストと InkStrokes コレクションの 関連付けが削除されます。
// Detach the current stroke collection from the recognizer context and release it
if (m_spIInkRecoContext != NULL)
m_spIInkRecoContext->putref_Strokes(NULL);
m_spIInkStrokes.Release();
// Clear the custom strokes collection
if (m_spIInkCustomStrokes != NULL)
m_spIInkCustomStrokes->Clear();
// Delete all strokes from the Ink object
// Passing NULL as a stroke collection pointer means asking to delete all strokes
m_spIInkDisp->DeleteStrokes(NULL);
// Get a new stroke collection from the ink object
...
// Ask for an empty collection by passing an empty variant
if (SUCCEEDED(m_spIInkDisp->CreateStrokes(v, &m_spIInkStrokes)))
{
// Attach it to the recognizer context
if (FAILED(m_spIInkRecoContext->putref_Strokes(m_spIInkStrokes)))
...
}
認識エンジン コンテキストの変更
アプリケーションの OnNewStrokes メソッドは、ユーザーが [新しいストロークの作成] メニューで認識エンジンを選択すると呼び出されます。 現在の InkStrokes が保存されます。 別の言語認識エンジンが選択されている場合は、新しい認識エンジン コンテキストが作成されます。 次に、新しい InkStrokes が新しい認識エンジン コンテキストにアタッチされます。
// Save the current stroke collection if there is any
if (m_spIInkRecoContext != NULL)
{
// Cancel the previous background recognition requests
// which have not been processed yet
m_spIInkRecoContext->StopBackgroundRecognition();
// Let the context know that there'll be no more input
// for the attached stroke collection
m_spIInkRecoContext->EndInkInput();
// Add the stroke collection to the Ink object's CustomStrokes collection
SaveStrokeCollection();
}
...
// If a different recognizer was selected, create a new recognizer context
// Else, reuse the same recognizer context
if (wID != m_nCmdRecognizer)
{
// Get a pointer to the recognizer object from the recognizer collection
CComPtr<IInkRecognizer> spIInkRecognizer;
if ((m_spIInkRecognizers == NULL)
|| FAILED(m_spIInkRecognizers->Item(wID - ID_RECOGNIZER_FIRST,
&spIInkRecognizer))
|| (false == CreateRecoContext(spIInkRecognizer)))
{
// restore the cursor
::SetCursor(hCursor);
return 0;
}
// Update the status bar
m_bstrCurRecoName.Empty();
spIInkRecognizer->get_Name(&m_bstrCurRecoName);
UpdateStatusBar();
// Store the selected recognizer's command id
m_nCmdRecognizer = wID;
}
次に、StartNewStrokeCollection を呼び出します。これにより、空の InkStrokes が作成され、認識エンジン コンテキストにアタッチされます。
認識エンジン コンテキストの Strokes コレクションを保存する
アプリケーションの メソッドは、既存の SaveStrokeCollection 認識エンジン コンテキストをチェックし、現在の strokes コレクションの認識を終了します。 次に、 InkStrokes コレクションが Ink オブジェクトの CustomStrokes に追加されます。
if (m_spIInkRecoContext != NULL)
{
if (SUCCEEDED(m_spIInkStrokes->get_Count(&lCount)) && 0 != lCount)
{
CComPtr<IInkRecognitionResult> spIInkRecoResult;
InkRecognitionStatus RecognitionStatus;
if (SUCCEEDED(m_spIInkRecoContext->Recognize(&RecognitionStatus, &spIInkRecoResult)))
{
if (SUCCEEDED(spIInkRecoResult->SetResultOnStrokes()))
{
CComBSTR bstr;
spIInkRecoResult->get_TopString(&bstr);
m_wndResults.UpdateString(bstr);
}
...
}
}
// Detach the stroke collection from the old recognizer context
m_spIInkRecoContext->putref_Strokes(NULL);
}
// Now add it to the ink's custom strokes collection
// Each item (stroke collection) of the custom strokes must be identified
// by a unique string. Here we generate a GUID for this.
if ((0 != lCount) && (m_spIInkCustomStrokes != NULL))
{
GUID guid;
WCHAR szGuid[40]; // format: "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}"
if (SUCCEEDED(::CoCreateGuid(&guid))
&& (::StringFromGUID2(guid, szGuid, countof(szGuid)) != 0))
{
CComBSTR bstrGuid(szGuid);
if (FAILED(m_spIInkCustomStrokes->Add(bstrGuid, m_spIInkStrokes)))
...