The Residents’ Gingerbread Man and Keyboard Input Weirdness

In the README file packed in with The Residents' interactive Gingerbread Man CD-ROM software, good ol' Uncle Willie gives you some cryptic advice in operating the interactive movies:

Uncle Willie sez: If it hurts when you do that, then DON'T DO THAT!
(In other words, avoid the following...)
- If the Caps Lock key is down then the buttons don't work. This continually torments some of the slower testers around here.

Why don't the buttons work when Caps Lock is activated? I'm pretty sure DOOM II, released the same year, doesn't suddenly lock up if you accidentally hit caps lock... and since this is clearly written up in the README, it means that someone who worked on this game noticed this before it was shipped!

So why did this happen and why wasn't it fixed? In this post I'd like to look at the code to examine why exactly they could have missed such an obvious error.

So why doesn't it work with Caps Lock?

Adobe Director's Lingo programming language can handle keyboard input in multiple ways. Keyboard event functions basically have a few magical variables they can use.

One of these variables, called the keyCode (and yes, Lingo's verbose syntax means that articles can be randomly tossed around variable names like that) returns a number called... well, the "Key Code" which represents the actual physical button being pressed on a keyboard. Analyzing the key code is the most effective way of handling most keyboard input (and mouse button input for that matter!) since key code just abstractly represents that button's pressed state, with no other information getting in the way of that. What that means is that if you, say, flip on Caps Lock, it won't have any effect on the key codes being thrown at your input handlers.

However... there is another variable that input handlers can also used: the more simply-named the key returns a single character string representing the actual ASCII character being input. What this means is that things like the Caps Lock and Shift keys will affect what value this the key parameter holds! So, if you're using this parameter to check if, say, the a key is pressed, you'll have to check if the key = "a" or the key = "A". Yeesh, talk about verbose!

Okay, so they didn't use Key Codes? Is that it?

Not using keycodes is one reason why this seemingly glaring issue is present in the game. But as I demonstrated, you can still have "case insensitive" key detection in your code by using character strings. So were they really just too lazy to do this?

Well... kind of. Because of the way the code in Gingerbread Man is organized, implementing this case insensitivity is way harder than it should be. Let me show you an example of some uncompiled code found in the actual game's files!

InkEffect(1_2_3_4_5):
 49 : set the ink of sprite 37 = 36
 50 : set the ink of sprite 37 = 3
 51 : set the ink of sprite 37 = 1
 52 : set the ink of sprite 37 = 39
 53 : set the ink of sprite 37 = 2
(From SHARED.DIR in The Gingerbread Man)

I'm not entirely sure how this code works since I don't have access to the entire game's codebase, only random snippets that were left uncompiled. However, it appears to be using Lingo's case syntax to run specific bits of code based on the ASCII character code being pressed (probably gotten by passing the key into the charToNum()). In Lingo, multiple cases can't point to the same block of code and you can't put logical expressions in them either. So to make things case insensitive with this input handling framework in place, you'll need to double up every single line of code... and there are a LOT of lines of code like this, since this code is duplicated for each character's Director movie.

Here's some more code that responds to actual alphabetical characters:

AnimatedThought(a_s_d_f_g):
 97 : mPlaceAnimThought gDirectorObj, 1
 115 : mPlaceAnimThought gDirectorObj, 2
 100 : mPlaceAnimThought gDirectorObj, 3
 102 : mPlaceAnimThought gDirectorObj, 4
 103 : mPlaceAnimThought gDirectorObj, 5

And here's how that code has to be edited to make it be "case insensitive":

AnimatedThought(a_s_d_f_g):
 97 : mPlaceAnimThought gDirectorObj, 1
 65 : mPlaceAnimThought gDirectorObj, 1
 115 : mPlaceAnimThought gDirectorObj, 2
 83 : mPlaceAnimThought gDirectorObj, 2
 100 : mPlaceAnimThought gDirectorObj, 3
 68 : mPlaceAnimThought gDirectorObj, 3
 102 : mPlaceAnimThought gDirectorObj, 4
 70 : mPlaceAnimThought gDirectorObj, 4
 103 : mPlaceAnimThought gDirectorObj, 5
 71 : mPlaceAnimThought gDirectorObj, 5

Now in this example we only had to add 5 more lines of code, but also remember that because of the way this is organized, we're adding extra code that needs to be maintained! If we want to redefine the functionality of the "A" key for instance, we'd have to make sure that both the lowercase and uppercase blocks of code are updated. I assume having horribly rigid code like this would seriously inhibit creative tinkerers like The Residents (and would probably just be very time consuming to fix everywhere since Director didn't exactly have the most robust development tools!), so in the end they just slapped a "DON'T TURN ON CAPS LOCK OR YOU'LL BREAK EVERYTHING!" into the README file that came with the software.

Well I guess that solves that mystery!

Well, not quite. There is a bit of code that caught my eye in the first defined text node of SHARED.DIR:

Special(esc_\_|_):
 92 : put the freebytes/1024
 124 : put the pactiveobjlist of gdirectorobj

These seem to be key bindings for debugging functions! This code defines two key behaviors: it makes the \ (Backslash) key print out the amount of free kilobytes in memory to Director's message window, and it makes the | (Vertical Bar) key print out what I assume to be a list of active objects belonging to the global scene to Director's message window.

It's strange since on most keyboards, backslash and the vertical bar are on the same key and you have to actually press shift to type the vertical bar. This suggests that the programmer(s?) knew about this whole case insensitive input thing rather early on, and even took advantage of it to easily bind two debugging commands to the same key!

(By the way, if anyone does have a copy of GBM and a computer that can run it, I'd be interested in seeing if this functionality is still enabled in the game. Perhaps the debug information is spit out to standard output and can be read if you launch the game from the command prompt?)

I think this suggests that the whole Caps Lock issue was known pretty early on and they just straight up decided to ignore it. Maybe they designed the key handler like this early on and forgot later in development, until a tester couldn't get the game working with Caps Lock on? Or what if this software really was programmed by The Residents and as a result it is just kind of weird and clunky? Perhaps The Residents wanted to map separate behavior to the uppercase alphabet but stopped when they realized they couldn't really do much more, leaving uppercase letters to do mostly nothing at all.

And yes, I did say they mostly do nothing, since it seems that uppercase F, M, and S keys actually do something, specifically set the "random speed" parameter of the global director object... I assume it's the exact amount of time that has to pass between random events occurring on their own in the game. F, M, and S stand for "Fast", "Medium", and "Slow" respectively... I would assume.

randomSpeed(F_M_S_):
 70 : set the pRandomSpeed of gDirectorObj = 25
 77 : set the pRandomSpeed of gDirectorObj = 100
 83 : set the pRandomSpeed of gDirectorObj = 200

I don't think this functionality is documented anywhere, and again, I'm not even sure it works in the final game (given how it's plastered everywhere in the code I think it might still be functional though). But I think it seems to indicate that the game was designed around this weird case sensitive input system. Personally I think that's a really weird design decision, but hey, if the README is to believed this software was programmed by The Residents so I guess that makes sense...


So... that was a rather deep dive into how The Gingerbread Man probably handles keyboard input. This piece of software is such an anomaly to me as a Residents fan and computer programmer... and doing a deep dive like this leaves me only more puzzled as to why the developers designed the game in such way that you can't have caps lock on while playing it. Gingerbread Man was developed with the same technology as the other Residents CD-ROM projects, Freak Show CD-ROM and Bad Day on the Midway, but it was handled by a completely different development studio. I haven't looked at Freak Show yet, but I can tell just from how the available uncompiled code is laid out that Bad Day was... much better put together, to say the least.

I found all of this while researching these Residents CD-ROMs (with the ultimate goal to document Bad Day on the Midway in its entirety) and I hope I can learn more interesting things about these games as I continue trying to dig through the game files. Thanks for reading!


コメント

Join the discussion:
To leave a comment, you must sign in with Twitter.
Sign in with Twitter!


There are no comments. Why not leave one yourself?