Compartilhar via


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)))
            ...