Friday, 21 December 2007

OS X Progress Bar Illusion

Over the past year, I've often had usability on my mind. Once you start thinking about things like that you also start to pay more attention to software you come across. Last week I was waiting for a large file to copy in OS X. I noticed that the vertical stripes in the bar are animated and move from right to left. This happens even when the bar itself is not progressing. This is interesting because it gives the optical illusion that the progress bar is moving faster than it really is. Its all down to optical flow if I remember rightly. From a psychological point of view, this probably relieves a little frustration when you have to wait and are watching the bar. My knee jerk response was to think "That's cheeky, it's a trick!". No one really likes being deceived (unless its a magic show) and its annoying to think yourself fooled. However, assuming that whatever it is you are waiting for is going to take that much time anyways and I'm subconsciously comforted a little, is that such a bad thing?

C# Browser Helper Object Event Handling

I have recently needed to write an internet explorer plugin. I do have some experience writing Firefox plugins, and if you've even done that you'll know that its quite easy. You can just hack together some Javascript and you're away. If you need some sort of interface, you get to use XUL, which isn't bad at all.

Internet Explorer is a completely different animal. Whereas Mozilla, the makers of Firefox, are very keen for people to extend it, Microsoft do not seem to be. It is however possible, you must create a COM object which Internet Explorer will instantiate, this what they call a Browser Helper Object (BHO). OK, that's a bit of a pain, but it will have to do. The real difficulty is in the documentation or lack thereof. There are a few tutorials which use C++ and ATL. Being used to modern languages such as C#, Javascript, Python etc, going back to C++ is horrible! You end up spending huge amounts of time getting minor issues sorted out. I had almost resigned myself to my fate when I came across an explanation of how to build a BHO using C#, that was one of the happiest days of my life!

Steven Cohn's post walks you through the setting up of a C# BHO. It's a great post, however it does not cover one important issue: how to attach event handlers to DOM element events. This turned out to be quite tricky, needing some fiddly code. It took a lot of experimentation and digging through newsgroups to find a solution which I will now explain.

The DOM is a COM object and the event handlers must also be COM objects implementing the IDispatch interface. So you must build a COM visible class to proxy your event and use a delegate to attach the real event handler to it. First our event handler class:


[ComVisible(true)]
public class DHTMLFormEventHandler
{
public DHTMLFormEvent Handler;
private HTMLFormElement Form;
public DHTMLFormEventHandler(HTMLFormElement f)
{
this.Form = f;
}
[DispId(0)]
public void Call()
{
Handler(this.Form);
}
}


This class is, of course, exposed to COM. Its constructor keeps a reference to the element we will be interested in later when the event is raised. When the DOM raises the event it will call Call(). The DispId(0) is a sneaky way of implementing IDispatch (I think, I'm not too strong on COM yet). Call() will call the event handler which we attach using a delegate as normal:


public delegate void DHTMLFormEvent(HTMLFormElement form);
private void AttachHandler(HTMLFormElementClass form)
{
DHTMLFormEventHandler FormHandler = new DHTMLFormEventHandler(form);
FormHandler.Handler += new DHTMLFormEvent(SubmitHandler);
form.onclick = FormHandler;
}


The final step is to set the event to our event handler object. You might want to experiment with the attachEvent method instead of doing this assignment to make sure you don't override other event handlers.