Exemplo de vários reconhecedores
Este exemplo demonstra os recursos avançados da API (interface de programação de aplicativo) da Automação de COMPUTADORES MicrosoftTablet usada para reconhecimento de manuscrito .
Isso inclui o seguinte:
- Enumerando os reconhecedores instalados
- Criando um contexto de reconhecedor com um reconhecedor de idioma específico
- Serializando resultados de reconhecimento com uma coleção de traços
- Organizando coleções de traços em uma coleção personalizada dentro do objeto InkDisp
- Serializando objetos de tinta para e recuperando-os de um arquivo ISF (formato serializado à tinta)
- Guias de entrada do reconhecedor de configuração
- Usando o reconhecimento síncrono e assíncrono
Cabeçalhos de tinta
Primeiro, inclua os cabeçalhos para interfaces de Automação de TABLET PC. Eles são instalados com o SDK (Software Development Kit) do Microsoft Windows XP Tablet PC Edition.
#include <msinkaut.h>
#include <msinkaut_i.c>
O arquivo EventSinks.h define as interfaces IInkEventsImpl e IInkRecognitionEventsImpl.
#include "EventSinks.h"
Enumerando os Reconhecedores Instalados
O método LoadMenu do aplicativo preenche o menu Criar Novos Traços com os reconhecedores disponíveis. Um InkRecognizers é criado. Se a propriedade Languages de um objeto InkRecognizers não estiver vazia, o reconhecedor será um reconhecedor de texto e o valor de sua propriedade Name será adicionado ao menu.
// 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)))
...
}
}
Criando um coletor de tinta
O método OnCreate do aplicativo cria um objeto InkCollector , conecta-o à origem do evento e habilita a coleção de tinta.
// 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);
Criando um contexto de reconhecedor
O método CreateRecoContext do aplicativo cria e inicializa um novo contexto de reconhecedor e configura os guias compatíveis com a linguagem associada. O método CreateRecognizerContext do objeto IInkRecognizer cria um objeto IInkRecognizerContext2 para a linguagem. Se necessário, o contexto do reconhecedor antigo será substituído. O contexto está conectado à origem do evento. Por fim, a propriedade Capabilities do contexto do reconhecedor é verificada para qual guia o contexto do reconhecedor dá suporte.
// 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)))
...
Coletando traços e exibindo resultados de reconhecimento
O método OnStroke do aplicativo atualiza os InkStrokes do coletor de tinta, cancela as solicitações de reconhecimento assíncronas existentes e cria uma solicitação de reconhecimento no contexto do reconhecedor.
// 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);
}
O método do OnRecognition
aplicativo envia os resultados da solicitação de reconhecimento para o método da janela de UpdateString
saída.
// Update the output window with the new results
m_wndResults.UpdateString(bstrRecognizedString);
Excluindo traços e resultados de reconhecimento
O método OnClear do aplicativo exclui todos os traços e os resultados de reconhecimento do objeto InkDisp e limpa as janelas. A associação do contexto do reconhecedor com sua coleção InkStrokes é removida.
// 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)))
...
}
Alterando contextos do reconhecedor
O método OnNewStrokes do aplicativo é chamado quando o usuário seleciona um reconhecedor no menu Criar Novos Traços. Os InkStrokes atuais são salvos . Se um reconhecedor de idioma diferente tiver sido selecionado, um novo contexto de reconhecedor será criado. Em seguida, um novo InkStrokes é anexado ao novo contexto do reconhecedor.
// 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;
}
Em seguida, ele chama StartNewStrokeCollection, que cria um InkStrokes vazio e o anexa ao contexto do reconhecedor.
Salvando a coleção Strokes para um contexto de reconhecedor
O método do SaveStrokeCollection
aplicativo verifica um contexto de reconhecedor existente e finaliza o reconhecimento da coleção de traços atual. Em seguida, a coleção InkStrokes é adicionada aos CustomStrokes do objeto de tinta.
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)))
...