Sometimes bad code arises from incompetence, whether individual, or more usually institutional. Sometimes it's overly tight deadlines, misguided architecture. And sometimes… it's just the easiest way.
Naomi writes in to confess to some bad code.
I've recently joined the team for a mod for the obscure-outside-its-niche Freespace Open engine. Now, in some ways, the engine is pretty modern - but it is based on 20+-year-old code, so it has its share of weird quirks.
I want to make a few things clear: this is a passion project for its developers, which they offer up for free to the fans, and from which Naomi has chosen to confess one of her minor WTFs. I'm sharing Naomi's submission because, well, we all find ourselves in positions where we write bad code to accomplish our goals. Consider this more of a celebration of hacking around problems, than a traditional WTF.
Game engines, in general, have a difficult relationship with keyboard layouts. A game engine from 1999 is no exception to that. While any halfway decent engine will allow control rebindings, they're not always able to adapt to more unusual configurations. For example, as someone who types Dvorak, I'll usually switch to QWERTY before firing up a game. But some games only see QWERTY, regardless of what I've told the OS to use for its layout. Some games will latch onto whatever the keyboard layout was when I launched the game- so if I accidentally launch in Dvorak, changing to QWERTY won't take effect until I relaunch the game. Very few game engines seem to be able to handle dynamic changes to the keyboard layout.
Now, this is a problem for a small number of users. Few game engine developers care. Few players care. And most of the time, players can workaround the issues.
The Freespace engine didn't have much support for multiple keyboard layouts, but it wasn't a problem. If a player was using QWERTY, then the "Q" key could rebalance their shields, and the "A" key would accelerate their ship. The same keys would have the same behavior on an AZERTY keyboard- but their positions would be flipped. So most players would rebind- an AZERTY user would change "A" to be "shields" and "Q" to be accelerate.
And this was fine until someone added a hacking minigame to their mod. One player submitted a bug report: they couldn't pass the hacking minigame. Specifically, whatever they typed in came out wrong. And without the ability to type, they couldn't clear the mission.
Well, in this case, Naomi discovered that the user was using an AZERTY keyboard. Since the scripts controlling the hacking minigame are reading literal keypresses without applying a keyboard layout, it tries to interpret the AZERTY keystrokes as QWERTY keystrokes, zhich definitely ,qkes typing hqrd.
Naomi writes:
This might be a low priority for the engine maintainers, but it made the mod actually unplayable for some subset of users. A proper fix is coming in the next version of the engine... several months down the road, and we didn't want to wait that long. So, I authored this ridiculous hack.
--------------------------------
-- Freespace doesn't really handle different keyboard layouts very well. As a
-- workaround, we've chosen a key combination - Alt-Q - that is distinct on
-- QWERTY, AZERTY, and Dvorak keyboards. By listening for all three key
-- combinations, we can guess which mapping the user is actually using, and
-- adjust accordingly.
-- This is a horrible hack and should be removed as soon as FSO supports
-- these layouts properly.
local keyboards = {
['Alt-Q'] = {
['A'] = 'A', ['B'] = 'B', ['C'] = 'C', ['D'] = 'D', ['E'] = 'E', ['F'] = 'F',
['G'] = 'G', ['H'] = 'H', ['I'] = 'I', ['J'] = 'J', ['K'] = 'K', ['L'] = 'L',
['M'] = 'M', ['N'] = 'N', ['O'] = 'O', ['P'] = 'P', ['Q'] = 'Q', ['R'] = 'R',
['S'] = 'S', ['T'] = 'T', ['U'] = 'U', ['V'] = 'V', ['W'] = 'W', ['X'] = 'X',
['Y'] = 'Y', ['Z'] = 'Z', ['1'] = '1', ['2'] = '2', ['3'] = '3', ['4'] = '4',
['5'] = '5', ['6'] = '6', ['7'] = '7', ['8'] = '8', ['9'] = '9', ['0'] = '0',
['Spacebar'] = ' ',
['Backspace'] = 'Backspace',
['Enter'] = 'Enter'
},
['Alt-A'] = {
['Q'] = 'A', ['B'] = 'B', ['C'] = 'C', ['D'] = 'D', ['E'] = 'E', ['F'] = 'F',
['G'] = 'G', ['H'] = 'H', ['I'] = 'I', ['J'] = 'J', ['K'] = 'K', ['L'] = 'L',
[';'] = 'M', ['N'] = 'N', ['O'] = 'O', ['P'] = 'P', ['A'] = 'Q', ['R'] = 'R',
['S'] = 'S', ['T'] = 'T', ['U'] = 'U', ['V'] = 'V', ['Z'] = 'W', ['X'] = 'X',
['Y'] = 'Y', ['W'] = 'Z', ['1'] = '1', ['2'] = '2', ['3'] = '3', ['4'] = '4',
['5'] = '5', ['6'] = '6', ['7'] = '7', ['8'] = '8', ['9'] = '9', ['0'] = '0',
['Spacebar'] = ' ',
['Backspace'] = 'Backspace',
['Enter'] = 'Enter'
}
}
Now, I'll be honest, as annoying as this code is to write or maintain, I don't know that it's fair to call it a "horrible hack", but certainly, it should hopefully go away. The choice of keys to control which mode you're in is actually rather nice- those keys are in the same physical position, regardless of which layout you're in. On Dvorak, that could be ALT+'
.
This, if you ask me, is a rather nice little solution to an ugly problem. Sure, it's a hack, but it gets the feature working, there's a plan for a longer term fix, and the stakes are really, really low. I think it's more important to actually deliver working functionality than anything else, so long as you know what mess you have to clean up in the future.
That's part of why I decided to share this snippet, because it's the kind of thing a developer might feel bad about writing, but honestly: they shouldn't. Yes, it's a hack, yes it's ugly, yes you don't want to maintain something like this any longer than you have to. But it also works, it resolves an issue for one of your users, and it allows you to focus on finding other ways to deliver value instead of agonizing over whether this is the "right" way to solve the problem.
They key to success, at the end of the day, is to write code that does something useful, or at least enjoyable.
Naomi concludes:
For the curious, there's no entry for Dvorak yet simply because I haven't found a Dvorak user to test it. And the weird mapping table existing in the first place isn't my fault. It was like that in the original script, which I didn't want to change too much for fear of introducing other, more exciting bugs.
Now, I'm not looking to add "testing a game I otherwise don't play" to my list of activities, but I hope Naomi finds another Dvorak user out there. There are dozens of us! Dozens!