Ejemplo de varios reconocedores
En este ejemplo se muestran características avanzadas de la interfaz de programación de aplicaciones (API) de MicrosoftTablet PC Automation que se usa para el reconocimiento de escritura a mano .
Incluye lo siguiente:
- Enumeración de los reconocedores instalados
- Creación de un contexto de reconocedor con un reconocedor de lenguaje específico
- Serialización de los resultados del reconocimiento con una colección de trazos
- Organización de colecciones de trazos en una colección personalizada dentro del objeto InkDisp
- Serialización de objetos de entrada de lápiz en y recuperación de ellos desde un archivo de formato serializado de lápiz (ISF)
- Establecimiento de guías de entrada del reconocedor
- Uso del reconocimiento sincrónico y asincrónico
Encabezados de lápiz
En primer lugar, incluya los encabezados para las interfaces de Automatización de PC tablet. Se instalan con el Kit de desarrollo de software (SDK) de Microsoft Windows XP Tablet PC Edition.
#include <msinkaut.h>
#include <msinkaut_i.c>
El archivo EventSinks.h define las interfaces IInkEventsImpl e IInkRecognitionEventsImpl.
#include "EventSinks.h"
Enumeración de los reconocedores instalados
El método LoadMenu de la aplicación rellena el menú Crear nuevos trazos con los reconocedores disponibles. Se crea un inkRecognizers . Si la propiedad Languages de un objeto InkRecognizers no está vacía, el reconocedor es un reconocedor de texto y el valor de su propiedad Name se agrega al menú.
// 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)))
...
}
}
Creación de un recopilador de lápiz
El método OnCreate de la aplicación crea un objeto InkCollector , lo conecta a su origen de eventos y habilita la colección de lápiz.
// 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);
Creación de un contexto de Recognizer
El método CreateRecoContext de la aplicación crea e inicializa un nuevo contexto de reconocedor y configura las guías admitidas por el idioma asociado. El método CreateRecognizerContext del objeto IInkRecognizer Crea un objeto IInkRecognizerContext2 para el lenguaje. Si es necesario, se reemplaza el contexto del reconocedor anterior. El contexto está conectado a su origen de eventos. Por último, la propiedad Capabilities del contexto del reconocedor se comprueba para qué guía el contexto del reconocedor admite.
// 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)))
...
Recopilación de trazos y visualización de resultados de reconocimiento
El método OnStroke de la aplicación actualiza las inkStrokes del recopilador de tinta, cancela las solicitudes de reconocimiento asincrónicas existentes y crea una solicitud de reconocimiento en el contexto del reconocedor.
// 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);
}
El método de OnRecognition
la aplicación envía los resultados de la solicitud de reconocimiento al método de la ventana de UpdateString
salida.
// Update the output window with the new results
m_wndResults.UpdateString(bstrRecognizedString);
Eliminar trazos y resultados de reconocimiento
El método OnClear de la aplicación elimina todos los trazos y resultados de reconocimiento del objeto InkDisp y borra las ventanas. Se quita la asociación del contexto del reconocedor con su colección 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)))
...
}
Cambio de contextos de Reconocedor
Se llama al método OnNewStrokes de la aplicación cuando el usuario selecciona un reconocedor en el menú Crear nuevos trazos. Se guarda inkStrokes actual. Si se ha seleccionado otro reconocedor de idioma, se crea un nuevo contexto de reconocedor. A continuación, se adjunta un nuevo InkStrokes al nuevo contexto del reconocedor.
// 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;
}
A continuación, llama a StartNewStrokeCollection, que crea un InkStrokes vacío y lo adjunta al contexto del reconocedor.
Guardar la colección strokes para un contexto de reconocedor
El método de la SaveStrokeCollection
aplicación comprueba si hay un contexto de reconocedor existente y finaliza el reconocimiento de la colección de trazos actual. A continuación, la colección InkStrokes se agrega a customStrokes del objeto ink.
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)))
...