Udostępnij przez


Przykład z wieloma rozpoznawaczami

W tym przykładzie przedstawiono zaawansowane funkcje interfejsu programowania aplikacji (API) microsoftTablet PC Automation używanego do rozpoznawania pisma ręcznego.

Obejmuje ona następujące elementy:

  • Wyliczanie zainstalowanych rozpoznawaczy
  • Tworzenie kontekstu rozpoznawania za pomocą dedykowanego systemu rozpoznawania języka.
  • Serializowanie wyników rozpoznawania za pomocą kolekcji gestów
  • Organizowanie kolekcji pociągnięć w niestandardowym zbiorze w obiekcie InkDisp
  • Serializowanie obiektów pisma odręcznego i pobieranie ich z pliku formatu odręcznego (ISF)
  • Ustawianie przewodników wejściowych rozpoznawania
  • Używanie synchronicznego i asynchronicznego rozpoznawania

Nagłówki atramentu

Najpierw dołącz nagłówki dla interfejsów automatyzacji komputerów tabletowych. Są one instalowane przy użyciu zestawu Microsoft Windows XP Tablet PC Development Kit (SDK).

#include <msinkaut.h>
#include <msinkaut_i.c>

Plik EventSinks.h definiuje interfejsy IInkEventsImpl i IInkRecognitionEventsImpl.

#include "EventSinks.h"

Wyliczanie zainstalowanych rozpoznawaczy

Metoda LoadMenu aplikacji wypełnia menu Create New Strokes (Tworzenie nowych pociągnięć) dostępnymi funkcjami rozpoznawania. Zostanie utworzona InkRecognizers. Jeśli właściwość Languages obiektu InkRecognizers nie jest pusta, to rozpoznawanie jest rozpoznawaniem tekstu , a wartość jego właściwości Name zostanie dodana do 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)))
                ...
        }
    }

Tworzenie kolektora atramentu

Metoda OnCreate aplikacji tworzy obiekt InkCollector, łączy go ze źródłem zdarzeń i włącza zbieranie tuszu.

// 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);

Tworzenie kontekstu rozpoznawania

Metoda CreateRecoContext aplikacji tworzy i inicjuje nowy kontekst rozpoznawania oraz konfiguruje przewodniki obsługiwane przez skojarzony język. Metoda IInkRecognizer obiektu CreateRecognizerContext tworzy obiekt IInkRecognizerContext2 dla określonego języka. W razie potrzeby stary kontekst rozpoznawania jest zastępowany. Kontekst jest połączony ze źródłem zdarzeń. Na koniec sprawdzana jest właściwość Capabilities kontekstu rozpoznawania, dla którego kontekst rozpoznawania zapewnia wsparcie.

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

Zbieranie pociągnięć i wyświetlanie wyników rozpoznawania

Metoda OnStroke aplikacji aktualizuje InkStrokes modułu zbierającego pisma odręcznego, anuluje istniejące żądania rozpoznawania asynchronicznego i tworzy żądanie rozpoznawania w kontekście rozpoznawania.

// 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);
}

Metoda OnRecognition aplikacji wysyła wyniki żądania rozpoznawania do metody UpdateString okna danych wyjściowych.

// Update the output window with the new results
m_wndResults.UpdateString(bstrRecognizedString);

Usuwanie pociągnięć i wyników rozpoznawania tekstu

Metoda OnClear aplikacji usuwa wszystkie pociągnięcia i wyniki rozpoznawania z obiektu InkDisp i czyści okna. Powiązanie kontekstu rozpoznawania z kolekcją InkStrokes zostało usunięte.

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

Zmienianie kontekstów rozpoznawania

Metoda OnNewStrokes aplikacji jest wywoływana, gdy użytkownik wybierze rozpoznawarkę w menu 'Utwórz nowe pociągnięcia'. Bieżący InkStrokes został zapisany. Jeśli wybrano inny rozpoznawacz języka, zostanie utworzony nowy kontekst rozpoznawania. Następnie nowy InkStrokes jest dołączany do nowego kontekstu rozpoznawania.

// 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;
}

Następnie wywołuje metodę StartNewStrokeCollection, która tworzy pusty InkStrokes i przypisuje go do kontekstu rozpoznawania.

Zapisywanie kolekcji pociągnięć dla kontekstu mechanizmu rozpoznawania

Metoda SaveStrokeCollection aplikacji sprawdza istniejący kontekst rozpoznawania gestów i finalizuje rozpoznawanie aktualnej kolekcji pociągnięć. Następnie kolekcja InkStrokes jest dodawana do CustomStrokes obiektu atramentu.

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