Beispiel für mehrere Erkennungen
Dieses Beispiel veranschaulicht die erweiterten Features der MicrosoftTablet PC Automation-API (Application Programming Interface), die für die Handschrifterkennung verwendet wird.
Dies umfasst Folgendes:
- Auflisten der installierten Erkennungen
- Erstellen eines Erkennungskontexts mit einer bestimmten Spracherkennung
- Serialisieren von Erkennungsergebnissen mit einer Strichsammlung
- Organisieren von Strichauflistungen in einer benutzerdefinierten Auflistung innerhalb des InkDisp-Objekts
- Serialisieren von Freihandobjekten in und Abrufen aus einer ISF-Datei (Ink Serialized Format)
- Festlegen von Eingabehandlinien für die Erkennung
- Verwenden der synchronen und asynchronen Erkennung
Freihandheader
Schließen Sie zunächst die Header für Tablet PC Automation-Schnittstellen ein. Diese werden mit dem Microsoft Windows XP Tablet PC Edition Software Development Kit (SDK) installiert.
#include <msinkaut.h>
#include <msinkaut_i.c>
Die Datei EventSinks.h definiert die Schnittstellen IInkEventsImpl und IInkRecognitionEventsImpl.
#include "EventSinks.h"
Auflisten der installierten Erkennungen
Die LoadMenu-Methode der Anwendung füllt das Menü Neue Striche erstellen mit den verfügbaren Erkennungen auf. Ein InkRecognizers wird erstellt. Wenn die Languages-Eigenschaft eines InkRecognizers-Objekts nicht leer ist, ist die Erkennung eine Texterkennung, und der Wert der Name-Eigenschaft wird dem Menü hinzugefügt.
// 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)))
...
}
}
Erstellen eines Freihandsammlers
Die OnCreate-Methode der Anwendung erstellt ein InkCollector-Objekt , stellt eine Verbindung mit seiner Ereignisquelle her und aktiviert die Freihandsammlung.
// 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);
Erstellen eines Erkennungskontexts
Die CreateRecoContext-Methode der Anwendung erstellt und initialisiert einen neuen Erkennungskontext und richtet die leitfäden ein, die von der zugeordneten Sprache unterstützt werden. Die CreateRecognizerContext-Methode des IInkRecognizer-Objekts erstellt ein IInkRecognizerContext2-Objekt für die Sprache. Bei Bedarf wird der alte Erkennungskontext ersetzt. Der Kontext ist mit seiner Ereignisquelle verbunden. Schließlich wird die Capabilities-Eigenschaft des Erkennungskontexts überprüft, welche Führungslinien der Erkennungskontext unterstützt.
// 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)))
...
Sammeln von Strichen und Anzeigen von Erkennungsergebnissen
Die OnStroke-Methode der Anwendung aktualisiert die InkStrokes des Freihandsammlers, bricht vorhandene asynchrone Erkennungsanforderungen ab und erstellt eine Erkennungsanforderung für den Erkennungskontext.
// 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);
}
Die -Methode der OnRecognition
Anwendung sendet die Ergebnisse der Erkennungsanforderung an die -Methode des Ausgabefensters UpdateString
.
// Update the output window with the new results
m_wndResults.UpdateString(bstrRecognizedString);
Löschen von Strichen und Erkennungsergebnissen
Die OnClear-Methode der Anwendung löscht alle Striche und Erkennungsergebnisse aus dem InkDisp-Objekt und löscht die Fenster. Die Zuordnung des Erkennungskontexts zur InkStrokes-Auflistung wird entfernt.
// 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)))
...
}
Ändern von Erkennungskontexten
Die OnNewStrokes-Methode der Anwendung wird aufgerufen, wenn der Benutzer im Menü Neue Striche erstellen eine Erkennung auswählt. Die aktuellen InkStrokes werden gespeichert. Wenn eine andere Spracherkennung ausgewählt wurde, wird ein neuer Erkennungskontext erstellt. Anschließend wird ein neues InkStrokes an den neuen Erkennungskontext angefügt.
// 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;
}
Anschließend wird StartNewStrokeCollection aufgerufen, wodurch eine leere InkStrokes erstellt und an den Erkennungskontext angefügt wird.
Speichern der Strokes-Auflistung für einen Erkennungskontext
Die -Methode der SaveStrokeCollection
Anwendung sucht nach einem vorhandenen Erkennungskontext und schließt die Erkennung der aktuellen Strichauflistung ab. Anschließend wird die InkStrokes-Auflistung den CustomStrokes des Freihandobjekts hinzugefügt.
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)))
...