Scott Hanselman

Screencast: Writing Managed .NET Plugins for the Optimus Mini Three Keyboard

March 8, '07 Comments [9] Posted in Coding4Fun | Learning .NET | Programming | Screencasts | Tools
Sponsored By

Here's a screencast demoing writing Managed .NET Plugins for the Optimus Mini Three Keyboard.

I'm a fan of the Optimus Mini-Three Keyboard for its potential. It's a harbinger of things to come, like someday a complete keyboard with screens for keys. Their hardware is wonderful. But, as a design shop with a specialization in hardware, not software, their software plugin model leaves much to be desired.

When I did my video on an Optimus Mini Three post in managed code, I ended up P/Invoking into their library, bypassing their plugin model and opting instead for a command line experience. Bummer, right?

The Optimus Configurator is pretty, to be sure, but it's programming model is obtuse and trapped in the C++ world. And not the nice OOP C++ world, the nasty part of that world.

The "implement these dozen virtual methods that tunnel strings via magic indexes" world:

virtual BOOL Paint(int button, HDC hdc) = 0;

// to collect INFO_* values from plugin 
virtual LPARAM GetInfo(int index) = 0;

 Meh. When your unmanaged C++ plugin gets called, the configuration app will call your GetInfo at least 20 times, passing in different magic numbers to get information about your plugin like name, webpage, version, etc. Not only are there these internal semantics to grok, there's a whole get/setProperties state bag thing to manage as well.

It's a common pattern for plugins though, especially when you as the host want to provide persistence to your plugins. The Windows Live Writer plugin model is similar...I had to maintain state for my Insert Amazon Links WLW Plugin via the same pattern.

On the other hand, the Paint stuff is very clever, actually. You get an HDC (handle to a device context) passed in, you paint to it, and they handle getting the resulting image over to the Optimus via their USB to Serial Bridge.

Screencast of managed Optimus Mini Three Keyboard PluginsBut, their plugins aren't managed code, and I believe that this more difficult model explains the fact that while the device is selling well, there are only (as of the writing of this post) three 3rd party plugins.

Harald Röxeisen went off (he says after reading my post...Cool!) and has released an alpha of a .NET library for Optimus Support. However, rather than supporting managed plugins in the Optimus Configurator, he's written his own configurator from scratch in .NET, and built a plugin model on top of that. It's basic, but a fantastic start. He proves my point about writing plugins, as even his alpha include THREE all new plugins written against his managed API. Excellent.

For me, I've done the inverse of Harald, and got managed plugins to work inside the existing configurator. After my last post, I got great ideas from Matt Davis of DocumentCommand and Jason Copenhaver. Jason's was managed/unmanaged C++ that would provide a bridge, and Matt's used COM and the .NET COM Interop stuff as a middleman. For me, Matt's was faster as I know that stuff pretty well.

Here's the general idea...Matt's shim implements the C++ virtuals that the configurator expects and calls CoCreateInstance on a known ProgId, in my example it's "Optimus.Nothing." Could be whatever. You'll need one shim and one ProgId per managed plugin as far as I can see. That call to CoCreateInstance is actually activating a .NET assembly that is implementing Matt's COM interface (that we might want to make even more COMish) created via TlbImp. Since we're .NET, the runtime and we get loaded, and wackiness ensues. 

We're in a no-man's land between managed and unmanaged code (and I'm sure we're leaking like a sieve) but we do things like Marshal.StringToHGlobalAnsi(managedString).ToInt32(); and

static int i = 0;
public int Paint(int button, IntPtr HDC)
{
    i++;
    DebugWrite(button);
    using (Graphics g = Graphics.FromHdc(HDC))
    {
        Brush b = ((i % 2 == 0) ? Brushes.Blue : Brushes.Red);
        g.FillRectangle(b, new Rectangle(0, 0, 96, 96));
    }
    if (i > 100) i = 0;
    return 1;
}

...for example. But, happily, we seem to not be noteworthy because the Mini Configurator loads us just fine.

I've approached Harald and perhaps we'll figure out a better bridge for .NET plugins where I could write a plugin that supports his managed API and use it in either his configurator, or the original configurator from Optimus. If I'm going to be promoting writing these plugins, we'll want the interface to hide a lot of the dispatchy stuff, more like the plugin model Bryan Batchelder and I did for the USB Security Key Fobs.

In Harald's .NET configurator, the abstract class you derive from to create a "Harald plugin" is very clean and includes new features like OnKeyHold and OnKeyDoublePress that the Optimus software doesn't make easy. He also, of course, uses BCL types like Bitmap over HDCs.

public abstract class OptimusMiniPlugin
{
    protected OptimusMiniPlugin();
    public abstract void Initialize();
    public virtual void OnKeyDoublePress();
    public virtual void OnKeyDown();
    public virtual void OnKeyHold();
    public virtual void OnKeyPress();
    public virtual void OnKeyRelease();
    public virtual void OnKeyUp();
    public abstract void Repaint();
    public void RequestNextUpdate(TimeSpan interval);
    public abstract void Terminate();
    public abstract void Update();
    public void UpdateImage(Bitmap image);
}

I'm excited to see the possibilities for this little device. Perhaps between my stuff and Haralds (and someone elses?) we can get a Windows Vista Side Show driver working for this thing...probably time for YAGCP (Yet Another Google Code Project). For now, here's what I've got. I'll do a Coding4Fun article on this in much more detail this weekend perhaps, for now, it's just scribbles and it works on my system. ;)

I wonder if the Optimus Keyboard folks care...I hope so. I'm convinced that writing managed plugins is easier than unmanaged (on Windows or in Mono). Is this even worth debating?

About Scott

Scott Hanselman is a former professor, former Chief Architect in finance, now speaker, consultant, father, diabetic, and Microsoft employee. I am a failed stand-up comic, a cornrower, and a book author.

facebook twitter subscribe
About   Newsletter
Sponsored By
Hosting By
Dedicated Windows Server Hosting by ORCS Web
Thursday, March 08, 2007 4:33:36 PM UTC
blinking red and blue eh? can't wait til you get the keyboard and put that on every key. insanity will follow later. Great post though, hopefully i'll have the budget to get a mini sometime in the near future.
Darren Kopp
Thursday, March 08, 2007 7:35:48 PM UTC
It was facinating watching you work on that last night.

Is this what you're going to be covering at PADNUG, writing device drivers?

If so, I'm going to have to figure out a way of getting to that, simply because writing drivers for hardware has always existed in my mind as, the black art of black arts.

Thursday, March 08, 2007 9:20:16 PM UTC
Malcolm - this isn't device drivers, per se, but sure, I can show this in detail at the next meeting.
Friday, March 09, 2007 9:59:08 AM UTC
Dear Scott,

you make cool things with our Optimus M3. If it is interesting to you, you could contact us directly.
Friday, March 09, 2007 3:41:24 PM UTC
Great article. It would be nice to see a little less "managed snobism". Personally, I don't need to use up 100MB of my memory with a framework just to let me generate 32x32 bitmaps. So I'm grateful that the managed route is not the default. Remember, 90% of functions in .NET are just wrappers around the underlying API functions, so in effect, all they do is slow you down, while giving you convenience.
Managed
Friday, March 09, 2007 5:03:29 PM UTC
Managed - Too bad you didn't leave your name...;) This is a great discussion to have.

Take a look at my MSDN Article "The Myth of .NET Purity" and tell me what you think.
Sunday, March 11, 2007 11:27:53 PM UTC
Hi... What tool do you use (or anyone else) to create screencasts?

Thanks.
Steve
Tuesday, March 13, 2007 9:25:23 AM UTC
Just encouragments !
I got a OM3 2 months ago, and fell desperate because of lack of plugins... Seems your work will help the community to develop plugins ! keep going, I can't wait long ! I can help for design, but unfortunatly forget about my programming skills !
Olivier
Saturday, March 17, 2007 3:16:10 PM UTC
50 percent
Comments are closed.

Disclaimer: The opinions expressed herein are my own personal opinions and do not represent my employer's view in any way.