Delen via


Voorbeeld van meerdere Herkenners

In dit voorbeeld ziet u geavanceerde functies van de MicrosoftTablet PC Automation Application Programming Interface (API) die wordt gebruikt voor handschrift herkenning.

Het bevat het volgende:

  • De geïnstalleerde recognizers opsommen
  • Een recognizer-context maken met een specifieke taalherkenning
  • Herkenningsresultaten serialiseren met een verzameling van handschriftstreken
  • Pennestreekverzamelingen ordenen in een aangepaste verzameling binnen het InkDisp--object
  • Het serialiseren van inktobjecten naar een ISF-bestand (Ink Serialized Format) en het ophalen daarvan uit een ISF-bestand
  • Instellen van invoerhandleidingen voor herkenner
  • Synchrone en asynchrone herkenning gebruiken

Inktkoppen

Neem eerst de headers op voor Tablet PC Automation-interfaces. Deze worden geïnstalleerd met de Microsoft Windows XP Tablet PC Edition Software Development Kit (SDK).

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

Het bestand EventSinks.h definieert de interfaces IInkEventsImpl en IInkRecognitionEmpl.

#include "EventSinks.h"

De geïnstalleerde Recognizers opsommen

De LoadMenu-methode van de toepassing vult het menu Nieuwe pennenstreken maken met de beschikbare herkenningsprogramma's. Er wordt een InkRecognizers aangemaakt. Als de eigenschap Languages van een InkRecognizers object niet leeg is, is de recognizer een tekstherkenningsobjecten wordt de waarde van de eigenschap Naam toegevoegd aan het 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)))
                ...
        }
    }

Een inktverzamelaar maken

De OnCreate-methode van de toepassing maakt een InkCollector--object, verbindt het met de gebeurtenisbron en schakelt inktverzameling in.

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

Een Recognizer-context maken

De methode CreateRecoContext van de toepassing maakt en initialiseert een nieuwe recognizer-context en stelt de handleidingen in die worden ondersteund door de bijbehorende taal. De methode IInkRecognizer object CreateRecognizerContext maakt een IInkRecognizerContext2 object voor de taal. Indien nodig wordt de oude recognizer-context vervangen. De context is verbonden met de gebeurtenisbron. Ten slotte wordt de eigenschap Capabilities van de recognizer-context gecontroleerd waarvoor de recognizer-context ondersteuning biedt.

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

Strokes verzamelen en herkenningsuitkomsten weergeven

De OnStroke-methode van de toepassing werkt de InkStrokes van de inktverzamelaar bij, annuleert bestaande asynchrone herkenningsaanvragen en maakt een herkenningsaanvraag voor de recognizer-context.

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

De OnRecognition methode van de toepassing verzendt de resultaten van de herkenningsaanvraag naar de UpdateString methode van het uitvoervenster.

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

Stroken en herkenningsresultaten verwijderen

De OnClear-methode van de toepassing verwijdert alle streken en herkenningsresultaten uit het InkDisp--object en wist de vensters. De koppeling van de recognizer-context met de InkStrokes verzameling wordt verwijderd.

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

Recognizer-contexten wijzigen

De methode OnNewStrokes van de toepassing wordt aangeroepen wanneer de gebruiker een herkenner selecteert in het menu 'Nieuwe pennenstreken maken'. De huidige InkStrokes wordt opgeslagen. Als er een andere taalherkenning is geselecteerd, wordt er een nieuwe recognizer-context gemaakt. Vervolgens wordt een nieuwe InkStrokes- gekoppeld aan de nieuwe recognizer-context.

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

Vervolgens wordt StartNewStrokeCollection aangeroepen, waardoor een lege InkStrokes wordt gemaakt en aan de context van de herkenner wordt gekoppeld.

De strokenverzameling opslaan voor een Recognizer-context

De SaveStrokeCollection-methode van de toepassing controleert op een bestaande recognizer-context en voltooit de herkenning van de huidige verzameling van pennenstreken. Vervolgens wordt de verzameling InkStrokes toegevoegd aan de CustomStrokes van het inktobject.

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