The Keyboard Input Manager

G.KB - Description

G.KB the keyboard input manager object. It captures and processes keyboard input, making it accessible to game code.

You can use its variables to schedule keyboard triggered logic within the normal flow of your game code, or have it execute event code immediately and on a key by key basis.

Unlike the mouse input manager object, G.KB only watches keys that have been registered inside game code. Registration is simple, and keys can be added or removed at any time.

See the tutorial for more details about using the keyboard input manager.

Variables

G.KB.on (type: boolean)

G.KB.on is a boolean flag denoting that the keyboard input manager is on.

It's not very useful at the moment, since the keyboard input manager is always on, but this may change in the future.

G.KB.lastKey (type: object)

G.KB.lastKey is an object that stores information about the last key that was pressed. It is set when the key up event fires on any key watched by G.KB. All values are overwritten by the next key up event on a watched key.

This object contains:

  • ctrlKey, a boolean flag denoting whether the CTRL key was pressed at the time of the key up event.
  • altKey, a boolean flag denoting whether the ALT key was pressed at the time of the key up event.
  • shiftKey, a boolean flag denoting whether the SHIFT key was pressed at the time of the key up event.
  • keyStr, the uppercase string representation of the key that was pressed. E.g, 'A', 'B', 'SPACE'. See G.KB.keys and G.KB.getCharCode() for more details.
  • code, the Unicode value of the key that was pressed. E.g. if keyStr is 'A', then code is 65.

G.KB.keys (type: object)

G.KB.keys is the set of all keys being watched by G.KB, indexed by the human-readable string representation of the key. This same set is also available with machine-friendly indexes: G.KB.codes.

Use this set to access the properties of each key directly, eg.,

G.KB.keys.A.isPressed

Use G.KB.addKeys() to add, and G.KB.removeKeys() to remove keys from this set.

Keys are referenced in their uppercase form, if it exists, or by a special keyword. For example, G.KB.keys.A, G.KB.keys.SPACE, G.KB.keys.Z, etc. See G.KB.getCharCode(keystr) for a complete list of keyword-encoded keys.

Note that the SHIFT, ALT and CTRL keys are treated as modifiers of all other keys, and not as independent keys that can be monitored.

Each key in this set has a complete set of properties. Some are managed by G.KB, and others you can manage directly. These are the properties of each key:

  • on

    This is a boolean flag denoting that this key is currently active or 'on'. It is true by default. If this variable is set to false, the key is ignored by G.KB starting on the next game loop iteration.

    You can toggle this value directly or with enable() and disable(), eg.:

    G.KB.keys.UP.enable(); G.KB.keys.DOWN.disable();

    This flag is useful if you want to disable keys temporarily, instead of removing them altogether. For instance, it might be convenient to disable player controls inside of options menus.

  • isPressed

    A boolean flag denoting that this key is currently pressed. This flag is set automatically when the key down event fires on this key, and remains true as long as the key is down.

    Use this variable in your code for continuous key down events such as automatic firing or Gob dragging.

  • setWasPressed

    A boolean flag used internally by the hook function G.KB.syncWasPressed().

    It is set to true as soon as the key up event fires on this key, and tells G.KB to set wasPressed to true at the end of the current game loop iteration.

    You don't need to touch this variable.

  • wasPressed

    A boolean flag denoting that a key up event has fired on this key; i.e., that the key has just been released.

    This flag is set to true at the very end of the game loop iteration in which the key up event fires, and remains true until the end of the following game loop iteration.

    Use this variable in your code for instantaneous key events such as one-click-per-shot firing, or releasing a Gob from a dragging action.

  • ctrlKey

    A boolean flag denoting that the CTRL key was pressed at the time of the key up event on this key.

  • altKey

    A boolean flag denoting that the ALT key was pressed at the time of the key up event on this key.

  • shiftKey

    A boolean flag denoting that the SHIFT key was pressed at the time of the key up event on this key.

  • keyStr

    The uppercase string representation of the key that was pressed. E.g, 'A', 'B', 'SPACE'.

    This value is set automatically, and is used by G.KB.codes to retrieve the keyStr from the code: eg, G.KB.codes[code].keyStr

    You don't need to touch this variable.

  • code

    The Unicode value of the key that was pressed. E.g. if keyStr is 'A', then code is 65.

    This value is set automatically, and is used by G.KB to manage the key.

    See G.KB.addKeys() and G.KB.codes for more about key codes.

    You don't need to touch this variable.

  • keyDownEvent

    This is a function that will execute immediately upon firing the key down event on this key, and if they key is 'on'. Notice that it is just one function, and not an entire set of hooks.

    Set this function directly or with setKeyDownEvent(fn). Reset this value by setting it to NULL or false.

  • keyUpEvent

    This is a convenience function that will execute immediately upon firing the key up event on this key, and if they key is 'on'. Notice that it is just one function, and not an entire set of hooks.

    Set this function directly or with setKeyUpEvent(fn). Reset this value by setting it to NULL or false.

  • enable() (returns G.KB)

    This is a convenience function to enable the key. It sets G.KB.keys.<keystr>.on to true, and is used primarily with chaining.

  • disable() (returns G.KB)

    This is a convenience function to disable the key. It sets G.KB.keys.<keystr>.on to false, and is used primarily with chaining.

  • setKeyDownEvent(fn) (returns G.KB)

    This is a convenience function to add a key down event function to the key.

    It sets G.KB.keys.<keystr>.keyDownEvent to the supplied function. It is used primarily with chaining.

  • setKeyUpEvent(fn) (returns G.KB)

    This is a convenience function to add a key up event function to the key.

    It sets G.KB.keys.<keystr>.keyUpEvent to the supplied function. It is used primarily with chaining.

G.KB.codes (type: array)

G.KB.codes is the set of all keys being watched by G.KB, indexed by the machine-friendly Unicode value of the key. This same set is also available with human-readable indexes: G.KB.keys.

This set is used internally by G.KB to manage the monitored keys, but can also be used anywhere in game code that G.KB.keys is used.

Methods

G.KB.start() (returns G.KB)

G.KB.start() starts the keyboard input manager.

This function is called automatically by GMP at start up, and you never need to call it explicitly. See the 'G.KB - Supporting In-line Code' section, below, for more details.

G.KB.stop() (returns G.KB)

G.KB.stop() stops the keyboard input manager.

This function is called automatically by GMP inside of a stop hook, and you never need to call it explicitly. Note that there is no performance gain for turning off the keyboard input manager, and you can always just it ignore it if you aren't using it. In other words, you really never need to call this function.

See the 'G.KB - Supporting In-line Code' section, below, for more details about the stop hook.

G.KB.getCharCode(keystr) (returns int)

G.KB.getCharCode(keystr) returns the Unicode character value of the keystr parameter.

The value of keystr is a string, and can be a keyword or any individual character. See G.KB.addKeys() for the list of allowable keywords.

G.KB.addKeys() (returns G.KB)

G.KB.addKeys() tells G.KB to monitor the keys specified as arguments. Arguments to this function are comma-separated strings, eg:

G.KB.addKeys('A'); or G.KB.addKeys('A','B','SPACE');

Notice that this method doesn't name it's parameter(s) in the method definition. This is because it uses the JavaScript built-in arguments parameter to retrieve whatever you pass in.

All ASCII letter keys are referenced by their uppercase value, eg, 'A' and 'a' are the same key. You can determine the case of a pressed key by looking at its shiftKey modifier. See G.KB.keys for more details about modifiers.

Some special keys are referenced by an uppercase keyword like 'SPACE' or 'LEFT', because the actual keystroke is difficult to read in most text editors. You reference these keys everywhere in G.KB using their keywords.

The keys in this list are:

  • SPACE, the space bar
  • LEFT, the left arrow key
  • RIGHT, the right arrow key
  • UP, the up arrow key
  • DOWN, the up arrow key
  • ESC, the escape key
  • ENTER, the enter or return key

Note that the SHIFT, CTRL and ALT keys are treated as modifiers, and are not detected as stand-alone keys. This is because most browsers don't capture these keys except when accompanied by other keys. See G.KB.keys for details on accessing these keys as modifiers.

Choosing good keys for your game controls

Any key with a Unicode value less than 65K and with a single 'letter' representation can be monitored by G.KB, but this isn't recommended for games released on the internet.

There are very few keyboard keys that are going to be reliably available to game players. This is because keyboard configurations are quite varied among the world's computer users. Differences in language or operating system, assistive technologies, and even 'secured' and alternate keyboards can make the keys on the game programmers keyboard unavailable to another user.

There is no way to guarantee that everyone will have the keys you select as controllers for your games, but you can reach 99% of game players by using common ASCII values like numbers, letters and punctuation, SPACE and the arrow keys.

You can also 'double up' and provide multiple keys for each key-controlled behaviour, eg, using both SPACE and F to 'fire'.

Another thing to watch for when choosing keys is browser shortcut key behaviour. For example, SPACE is a shortcut for 'page down' in almost all browsers. You can work around this by choosing keys that don't have shortcut behaviour (most ASCII letters and numbers).

You can easily work around the paging behaviour of UP, DOWN, SPACE, LEFT and RIGHT by making sure the web page that contains your game doesn't have scrollbars. In other words, put it on a page by itself or with very little other content.

As a side note, you can also work around browser shortcuts by stopping propagation of the keyboard events. I recommend avoiding this entirely if you are releasing your game on the internet, because users REALLY don't like their keyboard behaviour to be hijacked by web sites.

A special case: the Opera web browser

The Opera web browser assigns menu shortcuts to most keyboard keys, eg, 'Z' is a shortcut to go back one page in the browser's history. This behaviour is usually only active when the user's mouse is not 'focused' inside a form input or text-area (where Opera would assume you are typing text).

This behaviour can be a problem for GMP based games, because it leaves you almost no keys to use for game controls.

You can always just tell users that your game controls may not work well unless they turn off their keyboard shortcuts.

But, if you or your game players are using Opera, there is a workaround.

  • Create a Gob with a form INPUT tag, and hide it using z-index or giving a negative x-coordinate.
  • Add a system hook that forces the document to focus on the new INPUT tag on every game loop iteration. This convinces Opera that you are typing actual text, and disables many keyboard shortcuts.
  • The above hook function should look to see that G.M.y is not a low number, say less than 50. This allows your user to place focus on their navigation bar (for typing new URLs, etc).
  • The above hook also needs some logic to truncate the INPUT's value every 200 game loop iterations, eg. G.O.myInput.setVal(''); We need to do this because every key press will be added to the value of the INPUT. Adding text gets more expensive the longer the string is, so we want to truncate it periodically. But it is also expensive to truncate, so we only reset it periodically.
  • Make sure you aren't using G.M.deselectGob, which is doing the opposite action: stopping focus on the page.

This Opera hack is FAR from perfect. For instance, users will not be able to focus their mouse anywhere on the page, (except the hidden INPUT) and will not be able to select text.

G.KB.removeKeys() (returns G.KB)

G.KB.removeKeys() stops G.KB from monitoring of the keys specified as arguments. Arguments to this function are comma-separated strings, eg: G.KB.removeKeys('A'); or G.KB.removeKeys('A','B','SPACE');

Notice that this method doesn't name it's parameter(s) in the method definition. This is because it uses the JavaScript built-in arguments parameter to retrieve whatever you pass in.

G.KB.removeAllKeys() (returns G.KB)

G.KB.removeAllKeys() is a convenience function that stops G.KB from monitoring any keys at all.

G.KB.keyDownEventHandler() (returns G.KB)

G.KB.keyDownEventHandler() captures and processes key down event data on all monitored keys in G.KB.keys.

Key-specific event data is stored in the appropriate G.KB.keys[KEYSTRING] object, and all scheduled key down events are fired.

G.KB.keyUpEventHandler() (returns G.KB)

G.KB.keyUpEventHandler() captures and processes key up event data on all monitored keys in G.KB.keys.

Key-specific event data is stored in the appropriate G.KB.keys[KEYSTRING] object, and all scheduled key up events are fired.

This function also updates the G.KB.lastKey object values. See. G.KB.lastKey for more details.

G.KB.syncWasPressed() (returns undefined)

G.KBsyncWasPressed() is a system hook that sets G.KB.keys[KEYSTRING].wasPressed at the correct time and on the correct keys.

This function is called automatically, and shouldn't be called in game code.

See G.KB.keys and 'G.KB - Supporting In-line Code' for more details.

Supporting In-line Code

There are 3 in-line chunks of code in the G.KB section of gmp-engine.js.

The first is after the function definition for G.KB.syncWasPressed():

G.addHook('syncKeyWasPressed', G.KB.syncWasPressed, 'system');

This code adds G.KB.syncWasPressed as a system hook. This hook sets G.M.keys[KEYNAME].wasPressed = 1 for one full loop iteration after a keyup event on the key KEYNAME. This ensures that all game code will have the opportunity to detect a key up event for exactly one game loop iteration.

The second in-line code block simply starts the Keyboard Input manager object:

G.KB.start();

The last in-line code block as at the end of the G.KB code definitions:

if (typeof window.onfocus == 'function') G.oldonfocus = window.onfocus; else G.oldonfocus = function () {}; window.onfocus = function () { G.oldonfocus(); for (var key in G.KB.keys) { G.KB.keys[key].wasPressed = 0; G.KB.keys[key].isPressed = 0; G.KB.keys[key].wasPressed = 0; G.KB.keys[key].setWasPressed = 0; G.KB.keys[key].altKey = 0; G.KB.keys[key].ctrlKey = 0; G.KB.keys[key].shiftKey = 0; } };

This code is added to the window onfocus event to make sure that internal key event variables are reset if the user changes focus to another window while pressing a key.

Previous: G.Mouse