rentzsch.com: tales from the red shed

Virtual Key Codes

Mac OS X

Virtual key codes — the unique number assigned to each and every key on your keyboard — unfortunately seem to reside somewhat on the voodoo side of Mac programming.

To start with, there’s two types of key codes: raw and virtual.

Raw key codes are the device-specific numbers used to identify individual keys. They can vary from device to device: the Z key on my MacBook Pro keyboard may be 42, while the “same” Z key could be 55 on a Matias Tactile Pro.

(I don’t know if this is really the case — this is just an illustrative example.)

This is a level of detail most parts of the system could care less about, so there’s also virtual key codes. When the OS accepts a keystroke, it will take the raw key code and apply a potentially device-specific mapping onto a common, consistent number space.

Now, it doesn’t matter if I’m typing on my MacBook Pro keyboard, my iMate-adapted Saratoga or an abacus hacked with a USB interface, Z will have a consistent virtual key code: 6.

(Hmm, I guess I’m not sure how you’d type Z with an abacus. Flick in 90 and pop a toggle switch?)

These virtual key codes are handy (for example, for plugging into RegisterEventHotKey() or CGPostKeyboardEvent()), but are somewhat buried in Apple’s older developer documentation.

The last time I saw them documented was in the ADB era with Inside Macintosh:Macintosh Toolbox Essentials (whoa boy! Pascal! A/UX considerations!). This HTML page has a figure illustrating which key cap maps onto which virtual key code. Unfortunately, that graphic is very rough and hard to read — the PDF version of the book (PDF, 6.2MB) has a legible vector version of the figures on pages 86-87.

Fortunately ADB-era virtual key codes have successfully weathered the USB storm and hold even today — Z is 6 today on my MacBook Pro keyboard as it was on my IIci’s Saratoga.

But there are keys on today’s USB keyboards that aren’t documented in the ancient scriptures. For example, my MacBook Pro has this fn modifier key I need to press and hold in order to activate the dual-use function keys along the top of the keyboard. What’s its virtual key code? Inside Macintosh doesn’t know.

I enhanced my little GetKeystrokes app for exploring Terminal.app’s “Secure Keyboard Entry” to also spit out the virtual key codes it’s seeing. As before, source is included (it also compiles on Intel now). Turns out fn’s virtual key code is 63.

Update: Peter Hosey reminds me of Peter Maurer’s Key Codes, which is prettier than mine.

Bruno Fernandes of Twisted Melon writes:

I just read your post about virtual key codes via link from DaringFireball. Voodoo indeed.

You did a good job of explaining the purpose of virtual keys for the lay person, but there’s another wrench that must be thrown into the mix unfortunately. Virtual keys are not the same across keyboard layout mappings. If you switch your keyboard to German or French for instance you will see that the virtual codes do not produce the same keys they do with an English keyboard. Take a look at “q” for instance. Or things like “[“

Mac OS unfortunately lacks any API for virtual key translation across keyboard layouts. So if I were to produce a list of virtual keys based on an English keyboard and wanted to give them to someone running a French layout to produce the same keystrokes, I’d be out of luck.

You can see that every program that records and plays back key sequences fails in this regard. Unfortunately, that includes our own software mira. We’re currently investigating some creative ways around this problem which will hopefully be seen in an upcoming release.

I hope Bruno both comes up with something clever and shares his findings with the class.

Update: Blake Seely chimes in.

Monday, September 25, 2006
12:00 AM