Wednesday, February 11, 2009 10:37 AM bart

MathML Visualizer in C# on Windows 7

Lately I’ve been playing quite a bit with mathematical representation formats like OMML (Office’s markup language for math) and MathML (the nice thing about standards is …, well you know). Both have their pros and cons, but let’s not dive into that for now. In today’s post, I’m showing you the new Windows 7 “Math Input Panel” and how you can retrieve its MathML data from the clipboard in a UI application. I’m actually using this technique to read MathML and feed it in to my interpreter that tries to turn it into execution. I’ll show how to do a similar thing with Office 2007’s OMML in a next post, using VSTO that time.

Okay, so what are we talking about. This:

image

When you open up this guy, you’ll see the following:

image

Now try to write something math-stylish. You’ll be surprised how good the recognition actually is. Forgive me for my bad handwriting (never thought I would actually ever show my handwriting through this medium):

image

Sweet! Now notice the Insert button in the bottom right corner. If you’d be in an application that knows about MathML, it would just paste fine as-is. One such application is Word 2007; give it a shot. However, we’re interested in reading the XML directly into our own application. Given that the data is put on the clipboard, we can use the Windows Forms Clipboard class to retrieve it easily. However, we want to go one step further and update our UI as soon as a MathML fragment is put on the clipboard. To be honest: in fact, I don’t care about UI at all. I just want to get the XML and feed it in to my library that tries to do stuff with it. It just turns out that, because of the clipboard-driven nature of the beast, a UI application is the fasted way to gain access to it.

So here it is: a simple form with a few events, using two user32 functions and a window message that were added in Vista:

using System;
using System.IO;
using System.Runtime.InteropServices;
using System.Windows.Forms;
using System.Xml.Linq;

namespace MathMLImport
{
    public partial class Form1 : Form
    {
        [DllImport("user32.dll")]
        public static extern bool AddClipboardFormatListener(IntPtr hwnd);

        [DllImport("user32.dll")]
        public static extern bool RemoveClipboardFormatListener(IntPtr hwnd);

        private static int WM_CLIPBOARDUPDATE = 0x031D;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (!AddClipboardFormatListener(this.Handle))
            {
                MessageBox.Show("Failed to add clipboard format listener.");
            }
        }

        protected override void DefWndProc(ref Message m)
        {
            if (m.Msg == WM_CLIPBOARDUPDATE)
            {
                UpdateClipboard();
            }
            else
            {
                base.DefWndProc(ref m);
            }
        }

        private void UpdateClipboard()
        {
            var data = (MemoryStream)Clipboard.GetData("MathML");
            if (data != null)
            {
                string tmp;
                using (data)
                {
                    tmp = Path.Combine(Path.GetTempPath(), Path.GetRandomFileName()) + ".xml";
                    using (var fs = File.OpenWrite(tmp))
                        data.WriteTo(fs);
                }

                webBrowser1.Navigate(tmp);
            }
        }

        private void Form1_FormClosed(object sender, FormClosedEventArgs e)
        {
            RemoveClipboardFormatListener(this.Handle);
        }
    }
}

The code is a bit quick-n-dirty but suffices for my purposes (I’m sure there will be other ways to code up similar functionality). As you can see, I have one single control on the form – the WebControl – used to display the XML. I wish I could simply use its DocumentStream property but turns out that doesn’t recognize the fact I’m trying to display XML and tries to show the markup as HTML. Oh well, a temporary file does the trick (yes, I know I really should delete it after being done with it…) and as expected it works just fine:

image

Besides the visualizer, I have the following to bridge the gap between the clipboard and the target format I use further on: System.Xml.Linq:

private static XDocument GetMathMLFromStream(Stream data)
{
    string mathMl;
    using (data)
    {
        using (var sr = new StreamReader(data))
        {
            mathMl = sr.ReadToEnd();
        }
    }

    return XDocument.Parse(mathMl);
}

Enjoy!

Del.icio.us | Digg It | Technorati | Blinklist | Furl | reddit | DotNetKicks

Filed under:

Comments

# re: MathML Visualizer in C# on Windows 7

Friday, February 13, 2009 3:17 AM by Garry Pilkington

Great article. I used to do a bit of MathML when I used to work for a local university and your example has given me the urge to have a look at it again. Thanks.