If you are creating a Flash game that used keyboard controls, you may want to be aware of a bug in the Firefox browser (Mac and PC) that causes Flash to ignore keyboard events. When you embed a movie in a page using a transparent or opaque wmode, the movie seems to be unable to acquire keyboard focus. The specific problem is that Key.isDown always returns false. The workaround for this problem is to use Key.getCode instead. However, this is a problem for Flash games, because Key.getCode only returns the value of the last pressed or released key, so you can’t easily use it for multiple simultaneous key-presses.

So, I put together an ActionScript 2 class that can track multiple keypresses and act as a replacement for Key.isDown in cases where it does not work. The nice thing about this class is that it will default to the standard Key.isDown if Flash is working normally. So, if future versions of Firefox fix this problem, then you won’t need to change your code. Usage is simple. Instead of checking Key.isDown, simply use MochiKey.isDown instead.

Installation is simple. In the first frame of your movie, call MochiKey.initialize. After that, the MochiKey class will listen for keyboard events. The way it tracks multiple key presses is that it keeps an array of current keys pressed. When you press a key down, the onKeyDown event callback will add the key to the array. Likewise, the onKeyUp event will remove the key from the array. MochiKey.isDown will return true if the key you are checking is in the array, and false if not.

There is only one drawback to the class. If a user happens to focus on something outside your Flash movie while pressing keys (by using the mouse,) then the keys they were holding down will remain down because the onKeyUp events could not be captured. Once they focus back on the Flash and press those keys again, normal functionality will return. This is a minor issue though for most situations.

Download MochiKey.as. Here is the source:

/**
* Class: MochiKey
* This class offers a replacement for the Key.isDown method, which is faulty in Firefox when
* Flash movies are used with wmode transparent or opaque.  This class reverts to the standard
* Key.isDown method if that method works normally.
*
* ------------------------------------------------------------------------------------------
* INSTALLATION:
* Copy MochiKey.as to the same location as your FLA.  Add this to the first frame of your
* movie (this MUST be done before anything else!)
* MochiKey.initialize();
*
* ------------------------------------------------------------------------------------------
* USAGE:
* Simply use in a conditional just like Key.
* if (MochiKey.isDown(65)) return true; // checks if the 'A' key is down.
*
* ------------------------------------------------------------------------------------------
* LIMITATIONS:  This isDown function keeps a list of keys that are down in order to support
* multiple key presses.  If the Flash movie loses focus and keys are released, the onKeyUp
* event will not dispatch.  The keys will remain stuck down until they are pressed and released
* again.
*
* @author Geoff Gaudreault
* @version 0.1
*/

class MochiKey extends Key {

	// _revert is a flag that is set if standard Key.isDown works.
	private static var _revert:Boolean;
	// _keyListener is a listener object that receives Key events
	private static var _keyListener:Object;
	// _downKeys is an array that contains the state of keys pressed
	private static var _downKeys:Array;

	//
	// INITIALIZE created the Key event listener and creates the key down array
	public static function initialize ():Void {

		_downKeys = new Array();

		_keyListener = new Object();
		_keyListener.onKeyDown = function ():Void { MochiKey.onKeyDown(); }
		_keyListener.onKeyUp = function ():Void { MochiKey.onKeyUp(); }

		Key.addListener(_keyListener);

	}

	/**
	 * Method: onKeyDown
	 * Event listener that adds the last pressed key to the list of down keys
	 */
	public static function onKeyDown ():Void {

		//trace("Key pressed: " + chr(Key.getCode()));
		_downKeys[Key.getCode()] = true;

	}

	/**
	 * Method: onKeyUp
	 * Event listener that removes the last released key from the list of down keys
	 */
	public static function onKeyUp ():Void {

		//trace("Key released: " + chr(Key.getCode()));
		_downKeys[Key.getCode()] = false;

	}

	/**
	 * Method: isDown
	 * Get the down state of a key
	 * @param	keyCode the ASCII key code of the key you want to check
	 * @return true if the key is down, false if not
	 */
	public static function isDown (keyCode:Number):Boolean {

		if (Key.isDown(keyCode)) {
			_revert = true; // if Key.isDown ever returns true, revert to standard Key.isDown method.
			return true;
		} else if (_revert) {
			return false;
		}

		if (!isNaN(keyCode)) {
			if (_downKeys[keyCode] != null) {
				return _downKeys[keyCode];
			}
		}

		return false;

	}

	/**
	 * Method: letterIsDown
	 * Get the down state of a key
	 * @param keyChar the letter of the key you want to check
	 * @return true if the key is down, false if not
	 */
	public static function letterIsDown (keyChar:String):Boolean {

		if (Key.isDown(Key.getAscii(keyChar))) {
			_revert = true; // if Key.isDown ever returns true, revert to standard Key.isDown method.
			return true;
		} else if (_revert) {
			return false;
		}

		if (keyChar.length == 1) {
			var keyCode:Number = Key.getAscii(keyChar);
			return isDown(keyCode);
		} else {
			return false;
		}

	}

}