The Quest for Custom Keymapping and International Keyboard Support
Normally, in regaining momentum for a project, I’ll pick it back up and work on small-ticket items just to get into the groove again, then work my way into the larger items. Though this time I have done the opposite, I finally have a handle on one of the larger features for version 0.4: custom keymapping.
One of the recurring pieces of feedback for Dance of Death was the inability to descend stairs when using non-English keyboards (Danish, Finnish, etc.). A quick glance over my code revealed no obvious mistakes: I was checking for character codes, as I should have been. This meant that, as long as Flash reported the correct character codes, the fact that a key was placed in another spot would be a non-issue.
Of course, Flash did not report the correct character codes.
Somehow, when using a Danish keyboard, Flash thought it was perfectly acceptable to report a [<] character code in a KeyboardEvent, when a TextField placed upon the stage displayed a [;], the correct character according to the Danish keyboard map.
Some further research revealed an ominous string in the Flash AS3 Language Reference for the KeyboardEvent Class:
Because mappings between keys and specific characters vary by device and operating system, use the TextEvent event type for processing character input.
WTF, Adobe? Not one of your brightest ideas.
After much trial-and-error, the solution emerged, and it looks something like this:
- Create a stage-wide TextField, add it to the stage, and give it focus.
- In addition to the already-in-place KeyboardEvents, add a listener to the TextField for TextEvents. This event’s text property contains a string of the last character entered into the TextField.
- Rewrite the key handler to decouple key presses from in-game actions.
- Store game actions and give them a default mapping that is either a string (for all keypresses that produce a string), or a keycode (for keypresses without character codes, those which do not produce strings). It is important that an action never match both the text and the keycode, or it may be called twice.
- In the KeyboardEvent handler, search through the actions that have keycodes set, find a matching one, and invoke a generalized input handling function with that action (in my case, I defined an Enum-style set of uint consts). Similarly, in the TextEvent handler, search through the actions that have text set, find the matching one, and invoke said generalized function with that action.
Sounds somewhat convoluted, but it feels like a reasonably elegant solution, given Flash’s inane keyboard input handling.
The remaining steps in wrapping up this three-part feature are: providing an interface to allow the user to customize keymapping, and saving/loading mappings across game sessions.