Sam's infrequently-updated cabinet of curiosities
Tuesday, 05 February 2008

IntelliType XML

Microsoft hardware is fabulous, but -- like everyone else ever to buy one -- I was disgruntled to find that the Natural Ergonomic Keyboard 4000's centre-keyboard lever is set to control zoom, and only zoom, rather than something like vertical scroll. Worse, IntelliType won't let you change it, unlike almost every other special key on the board.

Luckily, it turns out that it's a limitation of the interface, not the software; you can get a lot more done with a little registry tweaking and two XML configuration files in the installation directory:

  • C:\Program Files\Microsoft IntelliType Pro\commands.xml
  • C:\Program Files\Microsoft IntelliType Pro\mscmdkey.xml

There are two different kinds of customisation possible:

  1. Use the registry to map keys to commands specified in mscmdkey.xml
  2. Change the behaviour of those commands in specific contexts with commands.xml

First, we want to look at mscmdkey.xml.

mscmdkey.xml

mscmdkey.xml lists commands sent out by the keyboard to IntelliType. It should probably be treated as read-only, but it's informative; commands.xml can't easily be edited without it. The commands look like this:

<Command name= 'VOLUME_UP_COMMAND' id='700' isUI='false' default='true' >
    <ResourceIDs displayName='3809' description='4009' descriptionPlusAccel='0' osdText='4270'/>
</Command>

The magic numbers are inscrutable (a displayName of 3809, an osdText of 4270?), but the name and id are simple enough.

The name is a human-readable label. VOLUME_UP_COMMAND is the default action of the volume-up button. SAVE_COMMAND corresponds to the "Save" button above F11. Some of the commands don't have buttons on all keyboards: the Natural 4000 has no "next track" button (MEDIA_NEXT_TRACK_COMMAND), but the Natural MultiMedia does. Some of the commands never have buttons: BATTERY_LOW_COMMAND is an automatic feature of the battery-powered wireless models.

We'll need the id when we get to commands.xml. To change the Zoom lever we want:

  • <Command name= 'ZOOM_IN_COMMAND' id='319' default='true' >
  • <Command name= 'ZOOM_OUT_COMMAND' id='320' default='true' >

319 and 320, respectively.

Some commands have an MSReserved sub-element. The appCommand attribute corresponds to a WM_APPCOMMAND parameter (e.g., for NEW_COMMAND it's 29, the defined value of APPCOMMAND_NEW).

I've had no success trying to add my own commands under high, unused ids.

Remapping keys

The IntelliType software allows you to remap some, but not all, of the keyboard's keys. When you do, the changes are saved to the registry at HKEY_CURRENT_USER\Software\Microsoft\IntelliType Pro\EventMapping.

The easiest way to find the key-code of a key you want to remap is to use IntelliType to assign it, then modify the values. The entry for my second favourites button looks like this:

[HKEY_CURRENT_USER\Software\Microsoft\Intellitype Pro\EventMapping\79]
"ShellExecute"="cmd.exe"
"Friendly"="Python"
"Arguments"="/K python"
"Command"=dword:00000320

The important one is Command. dword:00000320 is 0x320 hex, or 800 in decimal. Search mscmdkey.xml for a command with an id of 800 and you'll find SHELL_EXECUTE_COMMAND -- that sounds a lot like what we're doing. You can use any of the commands from mscmdkey.xml here, though not all of them work.

Friendly is just a human-readable name (this entry displays in the favourites menu as "start Python"). ShellExecute and Arguments are specific to SHELL_EXECUTE_COMMAND.

IntelliType can only set the favorites buttons to applications and URLs, but I miss the next and previous track buttons from my Natural MultiMedia. I've put them as faves 4 and 5:

[HKEY_CURRENT_USER\Software\Microsoft\Intellitype Pro\EventMapping\81]
"Command"=dword:000002c0

[HKEY_CURRENT_USER\Software\Microsoft\Intellitype Pro\EventMapping\82]
"Command"=dword:000002bf

0x2c0 is 704, MEDIA_PREVIOUS_TRACK_COMMAND; 0x2bf is 703, MEDIA_NEXT_TRACK_COMMAND.

Some keys can't be remapped. The "My Favorites" key, for example, can be disabled with DISABLE_COMMAND (400) but operates as normal with any other value.

Editing commands.xml

commands.xml lets us redefine what those commands actually do in any given context. It makes sense: not all software is alike, so triggering (e.g.) a spell check will require something different in OpenOffice.Org Writer than in Microsoft Word. Many of the mappings are simpler than you might think: SAVE_COMMAND (311), for example, is just a macro that performs the "Ctrl + s" keyboard shortcut!

commands.xml looks something like this, trimmed for brevity:

<DPGCmd>
    <ENG>
        <Application UniqueName="StandardSupport">
            <C311 Type="5" KeySeq="ctrl s" />
            <C401 Type="5" KeySeq="F7" />
        </Application>
    </ENG>
    <ALL>
        <Application UniqueName="Notepad" AppName="Notepad">
            <C311 Type="1" wParam="0x10001" />
            <C401 Type="0" />
            <C309 Type="5" KeySeq="alt F4" />
        </Application>
    </ALL>
</DPGCmd>

We're not interested in a lot of this. Each installed language has an element under the root DPGCmd node defining the function of a command in that locale. ENG means English. The special element ALL applies to all languages; unless you're a hardcore polyglot then it's all you'll need.

Commands are mapped on a per-application basis, but AppName doesn't seem to actually do anything: change "Notepad" to "Potato" and the keys will work the same.

UniqueName is the important one, and refers to the window class name passed to the relevant Windows API functions. If you want to do application-specific customisation, there's third-party software around (e.g. The Customiser) that can get a class name from any active window. If not, the special UniqueName value "StandardSupport" applies to all window classes.

Be careful not to have conflicting rules. Commands defined under specific UniqueNames will override commands defined under StandardSupport, but they can't be defined under specific languages if they're also in ALL.

Commands

Every Application contains elements with names like C319, where 319 is the id of a command in mscmdkey.xml. All of these command-elements have a type attribute:

  • Types 1-4 take different kinds of undocumented magic numbers. Type 2 commands seem to be handled by Windows, rather than the active application, as they execute shell functions (open default browser, search window etc.), but that's all I can figure out.
  • Type 7 commands take another type as a subtype. By default it's only used for OFFICE_TASK_PANE_COMMAND, so I'm assuming it's a hack just for that.

The others are easier:

  • Type 0 disables the key.
  • Type 6 takes an Activator which is passed to the window. Some of them are evidently application-specific -- IllustratorZoomin, IE7Save -- but others seem more general. An incomplete listing:

    • ZoomIn
    • ZoomOut
    • ScrollUp
    • ScrollDown

Type 5 is the fun one, which takes a simple keyboard macro in its KeySeq attribute. As mentioned above, "Save" is implemented like this:

<C311 Type="5" KeySeq="ctrl s" />

i.e., it's exactly the same as pressing "Ctrl" and "s". Multiple chords can be separated with a | pipe character, so if you want a "Hello world!" button:

<C203 Type="5" KeySeq="shift h | e | l | l | o | 
    space | w | o | r | l | d | shift 1" />

Macros seem to be deliberately limited, possibly as a security feature. You can't alt tab out, for example, or navigate menus with alt | f | downarrow | downarrow | enter. You can implement macros that reach into "Save As" or "Open" file-pickers, though, and presumably other kinds of dialog.

See Also

I wouldn't even have considered looking for baroque XML configuration files if the internet hadn't said it was possible. Joel Bennett's guide has the most detail by far, plus a handy bit of XSL to remove the F-lock annoyance.