Tablet PC: Overview of InkAnaysis events

The InkAnalysis API exposes functionality for both layout analysis (parsing) of ink, and the handwriting recognition for that ink as well. The InkAnalyzer class has several events that can be hooked up to in order to perform different tasks. For a complete list of events and brief descriptions of those events, see the example code below.

 

Consider the simple example where you write a word, then circle that word, add the strokes that make up that ink to an InkAnalyzer, then call BackgroundAnalyze(). What events would get fired? Here is actual output from the sample application (example code below) when run for this scenario: (Blue indicates parsing stage, red indicates recognition stage)

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

Activity event fired

InkAnalyzerStateChanging event fired

ContextNodeCreated event fired

ContextNodeMovingToPosition event fired

StrokesReparented event fired

ContextNodeCreated event fired

ContextNodeMovingToPosition event fired

ContextNodeCreated event fired

ContextNodeCreated event fired

ContextNodeCreated event fired

StrokesReparented event fired

ContextNodeDeleting event fired

ContextNodeLinkAdding event fired

ContextNodePropertiesUpdated event fired

ContextNodePropertiesUpdated event fired

ContextNodePropertiesUpdated event fired

ContextNodePropertiesUpdated event fired

ContextNodePropertiesUpdated event fired

IntermediateResultsUpdated event fired

Activity event fired

Activity event fired

InkAnalyzerStateChanging event fired

ContextNodePropertiesUpdated event fired

ResultsUpdated event fired

 

 

Screenshot of application running:

screenshot

 

Example code:

 //

// Basic Ink enabled Windows Forms application with

// handwriting recognition using InkAnalyzer

// Gavin Gear - http://blogs.msdn.com/gavingear

// 09/2006

//

using System;

using System.Collections.Generic;

using System.ComponentModel;

using System.Data;

using System.Drawing;

using System.Text;

using System.Windows.Forms;

using Microsoft.Ink; // The managed Tablet PC API

namespace BasicInkApplication

{

    public partial class BasicInkApplication : Form

    {

        // The InkOverlay that we'll attach to our Form

        private InkOverlay inkOverlay;

        private InkAnalyzer inkAnalyzer;

        private string eventsString = "";

        public BasicInkApplication()

        {

            InitializeComponent();

            // Create an InkOverlay object that's attached to the Form

            this.inkOverlay = new InkOverlay(this);

            // Enable the InkOverlay (default is Enabled == false)

            this.inkOverlay.Enabled = true;

            this.inkOverlay.Stroke += new InkCollectorStrokeEventHandler(inkOverlay_Stroke);

            // Create a new InkAnalyzer

           // - Associate with the InkOverlay's Ink object

            // - Send the Form "this" as the synchronizing object

            this.inkAnalyzer = new InkAnalyzer(this.inkOverlay.Ink, this);

            // Indicates analysis activity - can use to indicate progress

            this.inkAnalyzer.Activity += new ActivityEventHandler(inkAnalyzer_Activity);

           

            // A ContextNode was created- Example: An InkWordNode was created as the result of Analysis

            this.inkAnalyzer.ContextNodeCreated += new ContextNodeCreatedEventHandler(inkAnalyzer_ContextNodeCreated);

            // A ContextNode was deleted- Exmaple: An InkWordNode is deleted because the user deleted the

            // corresponding strokes from the ink collection surface

            this.inkAnalyzer.ContextNodeDeleting += new ContextNodeDeletingEventHandler(inkAnalyzer_ContextNodeDeleting);

            // A ContextLink is added - example: A circle was drawn around a word - a ContextLink is created indicating

            // that the drawing (circle) encloses the InkWordNode

            this.inkAnalyzer.ContextNodeLinkAdding += new ContextNodeLinkAddingEventHandler(inkAnalyzer_ContextNodeLinkAdding);

            // A ContextLink is removed - example: A circle enclosing a word is deleted by the user

            this.inkAnalyzer.ContextNodeLinkDeleting += new ContextNodeLinkDeletingEventHandler(inkAnalyzer_ContextNodeLinkDeleting);

            // A ContextNode is moved to a different position under the same parent - example: the strokes comprising

            // a word are moved by the user horizontally changing the word ordering within a line

            this.inkAnalyzer.ContextNodeMovingToPosition += new ContextNodeMovingToPositionEventHandler(inkAnalyzer_ContextNodeMovingToPosition);

           

            // A ContextNode's property was updated - see ContextNode documentation for more detail

            this.inkAnalyzer.ContextNodePropertiesUpdated += new ContextNodePropertiesUpdatedEventHandler(inkAnalyzer_ContextNodePropertiesUpdated);

           

            // A ContextNode is moved to another parent - example: The strokes comprising a line were moved from one

            // paragraph to another paragraph my the user

            this.inkAnalyzer.ContextNodeReparenting += new ContextNodeReparentingEventHandler(inkAnalyzer_ContextNodeReparenting);

           

            // The InkAnalyzer is about to integrate results from analysis with it's internal data structure

            // the application can synchronise to the data structure at this time

            this.inkAnalyzer.InkAnalyzerStateChanging += new InkAnalyzerStateChangingEventHandler(inkAnalyzer_InkAnalyzerStateChanging);

           

       // Layout analysis is complete (parsing) the ContextNodes, ContextLinks, etc are in place

            // this event is fired before the recognition stage is started

            this.inkAnalyzer.IntermediateResultsUpdated += new ResultsUpdatedEventHandler(inkAnalyzer_IntermediateResultsUpdated);

           

            // New strokes were loaded into the InkAnalyzer via InkAnalyzer.Load()

            this.inkAnalyzer.NewStrokesLoaded += new NewStrokesLoadedEventHandler(inkAnalyzer_NewStrokesLoaded);

  // A partially populated ContextNode needs to be populated with data before analysis can continue

            // this is part of an advanced topic called DataProxy whereby an application's data can be

            // synchronized with the InkAnalyzer on an as-needed basis

            this.inkAnalyzer.PopulateContextNode += new PopulateContextNodeEventHandler(inkAnalyzer_PopulateContextNode);

           

            // If automatic reconciliation is disabled, Reconcile() should be called from this event handler

            this.inkAnalyzer.ReadyToReconcile += new ReadyToReconcileEventHandler(inkAnalyzer_ReadyToReconcile);

            // Fired when background analysis is complete

            this.inkAnalyzer.ResultsUpdated += new ResultsUpdatedEventHandler(inkAnalyzer_ResultsUpdated);

            // Strokes were moved from one ContextNode to another

            this.inkAnalyzer.StrokesReparented += new StrokesReparentedEventHandler(inkAnalyzer_StrokesReparented);

            // The InkOverlay needs to be disposed due to unmanaged resources

            // used by the InkOverlay

            this.FormClosing += new FormClosingEventHandler(BasicInkApplication_FormClosing);

        }

        private void LogEvent(string EventName)

        {

            this.eventsString += EventName + " event fired" + Environment.NewLine;

        }

        void inkAnalyzer_StrokesReparented(object sender, StrokesReparentedEventArgs e)

        {

            LogEvent("StrokesReparented");

        }

        void inkAnalyzer_ResultsUpdated(object sender, ResultsUpdatedEventArgs e)

        {

            LogEvent("ResultsUpdated");

            // Since analysis is done, display the results...

            string result = this.inkAnalyzer.GetRecognizedString();

            MessageBox.Show(

                "Analysis complete, recognized string:" + Environment.NewLine +

                result + Environment.NewLine + Environment.NewLine +

                "Events that fired:" + Environment.NewLine +

                eventsString, "Analysis Summary");

        }

        void inkAnalyzer_ReadyToReconcile(object sender, EventArgs e)

        {

            LogEvent("ReadyToReconcile");

        }

        void inkAnalyzer_PopulateContextNode(object sender, PopulateContextNodeEventArgs e)

        {

            LogEvent("PopulateContextNode");

        }

        void inkAnalyzer_NewStrokesLoaded(object sender, NewStrokesLoadedEventArgs e)

        {

            LogEvent("NewStrokesLoaded");

        }

        void inkAnalyzer_IntermediateResultsUpdated(object sender, ResultsUpdatedEventArgs e)

        {

            LogEvent("IntermediateResultsUpdated");

      }

        void inkAnalyzer_InkAnalyzerStateChanging(object sender, EventArgs e)

        {

            LogEvent("InkAnalyzerStateChanging");

        }

        void inkAnalyzer_ContextNodeReparenting(object sender, ContextNodeReparentingEventArgs e)

        {

            LogEvent("ContextNodeReparenting");

        }

        void inkAnalyzer_ContextNodePropertiesUpdated(object sender, ContextNodePropertiesUpdatedEventArgs e)

        {

            LogEvent("ContextNodePropertiesUpdated");

        }

        void inkAnalyzer_ContextNodeMovingToPosition(object sender, ContextNodeMovingToPositionEventArgs e)

        {

            LogEvent("ContextNodeMovingToPosition");

        }

        void inkAnalyzer_ContextNodeLinkDeleting(object sender, ContextNodeLinkDeletingEventArgs e)

        {

            LogEvent("ContextNodeLinkDeleting");

        }

        void inkAnalyzer_ContextNodeLinkAdding(object sender, ContextNodeLinkAddingEventArgs e)

        {

            LogEvent("ContextNodeLinkAdding");

        }

        void inkAnalyzer_ContextNodeDeleting(object sender, ContextNodeDeletingEventArgs e)

        {

            LogEvent("ContextNodeDeleting");

        }

        void inkAnalyzer_ContextNodeCreated(object sender, ContextNodeCreatedEventArgs e)

        {

            LogEvent("ContextNodeCreated");

        }

        void inkAnalyzer_Activity(object sender, EventArgs e)

        {

            LogEvent("Activity");

        }

        void inkOverlay_Stroke(object sender, InkCollectorStrokeEventArgs e)

        {

            // We have a new stroke, add it to the InkAnalyzer

            this.inkAnalyzer.AddStroke(e.Stroke);

        }

        void BasicInkApplication_FormClosing(object sender, FormClosingEventArgs e)

        {

            this.inkOverlay.Dispose();

            this.inkAnalyzer.Dispose(); // Free the unmanaged resources

        }

        private void buttonRecognize_Click(object sender, EventArgs e)

        {

            this.eventsString = "";

            // Kick off asynchronous analysis

            this.inkAnalyzer.BackgroundAnalyze();

        }

    }

}

 

There’s a lot more that could be said regarding InkAnalysis events, but this gives you a basic idea of what events do in the InkAnalysis API.

 

See ya,

Gavin