I don't know when I learnt that Windows + E opened up Windows Explorer. It must have been a while ago. But it's imprinted in my muscle memory, the number of times I hit that combo every day is probably quite high. But how many other hotkeys do I use? Asides from a few other functional ones, like Win + D, I don't use hotkeys so much. And I got to thinking, I'd love to open Google Chrome with a hotkey just like I do with explorer.

So I wrote FireKeys - a lightweight application that lets you assign hotkeys to actions. These actions could be opening program, a folder or a URL, but the underlying model is designed to be extensible.

[Above: A screenshot of FireKeys - a tool to bind actions to Windows Hot Keys]

In this article, I'll introduce the tool, show you how it works and how to get it, and then look into some of the more interesting areas of the code that others may be able to benefit from. There'll also be a bit of a discussion on the benefits and drawbacks of ClickOnce deployments.

FireKeys

So let's get started and introduce the FireKeys application. The application can be installed by ClickOnce, just use the link below:

You can also download the code and build it yourself if you like. Once you install FireKeys, you can open it up by double-clicking the FireKeys tray icon. By default, there will be no bindings set, so the application will be saying that you can open up its suggestions:

Choose to add Suggestions - the suggestions window will be shown, which offers suggestions for commonly used programs on your machine.

Now that you have some bindings, you can add more with 'New Binding'. You can create a binding to open a program, folder or URL:

Finally, the system tray icon for FireKeys will always show what bindings you have set if you click on it. You can open it and manually fire off an action by clicking on its menu item.

Code Highlights

Essentially, this program is a very basic WPF application, however, there are some aspects of the program that are interesting to highlight, which may be useful to others creating similar applications.

System Tray Based Applications

This application is what I would call a 'true' system tray based application. Why is this? Well, from the users point of view, the application runs in the system tray. Opening the exe doesn't seem to do anything apart from put the icon in the system tray and enable the functionality. This is different to an application that you run up which has a main window and a taskbar icon, which also has a system tray icon. This program runs, but in normal usage it has no main window, and in a typical run, doesn't necessarily need to show one.

This has a fundamental affect on the design of the application. Let's take a look at the entry point:

If the argument is a specific value, we might immediately show the main window.

We create a Context Menu (this will be used by the tray icon).

We create the tray icon.

We create the menu items, and when the bindings change we re-create them.

We run the application.

It's important to note that we don't run a main window here, we use Application.Run to keep the application alive, but that's it. This has an important consequence:

If you have no main Window, integration into Win32 is hard.

What does this rather obscure sentence mean? Well, imagine we want to register a hotkey binding, no problems, we can interop into the Win32 SDK to do this (and this is detailed later). But what if we want to listen for hotkeys? We need to...... listen for a specific windows message.

Win32 does most communication via windows messages. So if you don't have a window, you can have a problem.

Now this is actually quite bad design, in a sense. Sometimes you might want a logical component that can listen for windows messages and run a message pump, but not have any UI. In fact, that's exactly what our application needs?

How do we get around this? Typically, we don't really get around it - we bite the bullet and create the window. Sometimes invisible, other times we hijack another window we need.

In this program, we have to create a context menu object for the system tray icon. The context menu will be created whether or not the user clicks on it, so we use this menu as the object that listens for hot key messages. It's not perfect, and is not ideal design because the context menu logically shouldn't need to do this. It's supposed to be a context menu, not a context menu that listens for hotkeys. However, in the real world we cannot adhere to design patterns perfectly, and should know when to bend the rules. In this case, having the context menu listen for the messages works well.

Now everything else is easy. When the user double clicks on the menu, or activates the 'Settings' item, we can do the following:

If anyone would really like to have a Visual Studio Template for a Context Menu based application, then I'll knock one up. It's been on my todo list for a while, but making Visual Studio templates is slow and fiddly - or give it a bash yourself with the help of my article on the topic on Item Templates. Project templates are similar.

If you want to make a WinForms system tray application, you can get the code for QuickAccent as a starting point - it does the same as the above, but is purely WinForms.

Using Apex for MVVM

Initially I wrote this application with WinForms, thinking it's going to be quick and simple, and that would do the trick. I soon moved to WPF because it's just getting faster and faster to write WPF apps if you have a framework. I use Apex for MVVM, it also has a load of useful things like controls, converters and helpers that you sometimes need. I'm not going to go into detail here about Apex, but it is nice to see how it helps with a few common tasks.

Most MVVM frameworks use a lightweight syntax for defining properties that use INotifyPropertyChanged. I use a slightly more weighty syntax, trying to keep consistent with DepdencyProperties. Here's an example:

It's really quick to write it out with the addition of the Snippets for Apex (installed for Visual Studio as part of the Apex SDK), just key in 'apexnp' for an apex notifiying property. I have written a whole load of snippets for MVVM:

apexnp - creates an Apex notifying property.

apexoc - creates an Observable Collection.

apexdp - creates a Dependency Property.

apexadp - creates an attached dependency property.

apexc - creates an ICommand back command.

apexac - creates an Apex asynchronous command.

File/Folder Text Boxes

It's quite a common task to have a text box with an ellipses to browse for a file. Also common is the same but to browse for a folder. Apex has the FileTextBox and FolderTextBox controls which offer just that. The folder text box pinvokes into the shell for its folder dialog, and doesn't use WinForms.

Multiborders

Again, it's a simple control, a border that lets you specific different brushes, widths etc for each edge, but without it, creating the Wizard style interface is much harder (there are subtle effects like a grey line below each section, with a lighter line to emphasise it). It's the MultiBorder control, there if you need it.

There are a load of other features in Apex I didn't need to use for this app, but for a MVVM application its worth considering. You can use the controls only, or the MVVM stuff, or pick and choose bits and pieces you like. You can get apex from the Apex Homepage or Nuget.

How Windows Hotkeys Work

Pretty fundamental to the project is knowing how Windows Hotkeys work. Well, they're straightforward. We ask the Win32 SDK to register a hotkey for us, then listen for the WM_HOTKEY message. Registering a hotkey requires an id, the id of the hotkey used is sent in the windows message. Here's the key MSDN documentation:

As mentioned in the first section, you need a message pump to listen for the message - I use the context menu of the application as it is always created. You can pinvoke these functions with the signatures below by the way:

KeyInterop is provided by the .NET framework for mapping Win32 keys to WPF keys.

Storing Data in XML

A first glance at the main program object shows something odd - I save the application settings (which at the moment is just a bool saying whether or not to startup automatically) with an XmlSerializer, and the key bindings with a DataContractSerializer? Why?

XmlSerializer

Brilliantly easy to use, lets you choose to store data as attributes or elements, change the name etc etc. Great for simple data that the end user might theoretically want to look at and change themselves.

DataContractSerializer

Harder to use, but much more powerful. Allows the serialization of graphs (i.e. interconnected objects) and more complicated entities such as references to interface types.

So why use a DataContractSerializer for my key bindings?

Consider the definition of a key binding below (comments removed for brevity):

How the hell can we expect the system to deal with serializing the IHotKeyAction typed member 'Action'? It's an interface, how will the framework serialize, and even more difficult, deserialize this to the right type (which might be a RunProgramAction, OpenFolderAction, OpenURLAction etc etc)?

We the datacontract serializer just handles it for you, by writing out the type used in the xml. We must provide the serializer object with the types it'll need to know about (our three interface implementations), but then it'll just work. This is very funky.

This is especially funky when you remember the DataContractSerializer is what is used by WCF (and fundamental to it), this sort of behaviour can be extended to work across services. So DataContractSerializer is very powerful, but for simple cases, XmlSerializer usually suffices.

Plugin Models

I have not had the time to make this application pluggable, but it is only a short way away from being there. Here's what you need to think about when considering it:

What's a plugin going to need to offer? Keep it simple if possible.

Will it need to present UI?

How will it deal with logging, exceptions etc?

Typically, consider MEF as a first thing to look at for plugins. I've used it extensively, and it's very powerful. An application like this could be made pluggable very quickly - we've already abstracted out the 'IHotKeyAction' interface, which represents some kind of action. It already supports custom UI for the action, as well as saving any type derived from IHotKeyAction in the key bindings xml file automatically, so we're pretty much there.

If it seems like anyone finds this project or code useful, I'll extend them model to make it pluggable and update the article.

ClickOnce Deployment

ClickOnce is a pretty nifty way of deploying applications. You publish an application to a share, a website or FTP path, then the user runs a file, such as 'FireKeys.Application'. The system installs the program and runs it. Super easy. You can configure ClickOnce to check for updates, not allow the application to run unless it is the latest version and more.

You can deploy an updated version to a central location and have end users updated automatically.

You can force the latest version to be used.

You can allow offline mode as well.

You can uninstall ClickOnce installed programs though the Add/Remove programs applet of Windows.

ClickOnce is fast, typically a user just hits OK its installed.

Cons

If you deploy to a webserver, and you distribute to a lot of people, you could end up having a lot of traffic to the site.

You cannot customise the installation experience.

The installed files are deployed to the Users profile, not to 'program files' as many end-users expect.

Most anti-virus programs are pretty smart, if they detect things being installed from the web like this, they'll often ask the user to confirm it (in fact, often Windows will too, with its SmartScreen technology).

As an indicator of how good ClickOnce can be - notice that Google Chrome use it to install their browser! Interestingly enough, I am yet to see many Microsoft based tools that use it, but then again they do tend to make very large heavyweight software that wouldn't be suitable for it.

Wrapping Up

Well that's it. Hopefully, some people will find the tool useful and some will find the code or discussion topics useful. I'm always looking to improve, so if you have any suggestions then let me know!

I need a way to see a list of the existing hot keys on my W7 x64 system.
A microsoft utility I've tried to install asks me to choose a hotkey, yet every choice I submit
comes back as not available. I have asked in other forums how to see which hot keys are active on the system, but no one seems to know the answer.

Strictly, this is not supported by the Win32 SDK. I've seen some posts from people saying that it can be done by registering low level keyboard hooks and inspecting code around that, but I'm not certain that is a good way of doing it. Short answer seems to be no!

If also already tried to register hotkeys and so on. However there was always one last thing which didn't want to work as desired (I can't recall what it was, I guess it was something along overwriting the default hotkeys...). I ended up just scripting everything I wanted in AutoHotkey (which is also very powerful in hooking up Hotkeys).

And since MS dropped the Setup Project in VS2012 I found my self struggling with ClickOnce too (I never fancied that deployment method as it is not neatly packaged into one file and there is a lot of fussing around with certificates and signing (ClickOnce caught me here that it wouldn't launch (while showing no error) when using sha256rsa signature algorithm... ))