Some browsers do not distinguish some or all of the numpad keys.

You can bind your Keypress Listener to a particular DOM element if you only want to watch for combos when a particular element is active. Read more about that below in the advanced options.

You can enter special characters that can only be entered with the shift key (eg. !, @, #, $, etc.) as part of your combo and Keypress will seamlessly handle that for you.

The prevent_repeat option makes sure your callback is only called once instead of being called every time the keydown event is fired.

The prevent_default option in Keypress is special because it will preventDefault on all keys that are part of a combo, rather than only preventing when the full combo is pressed.

Below in the documentation you can find details of all the options you can specify when creating a Keypress combo, but here's a quick synopsis of some more things you can do:

The combos will not register if the user takes too long to enter the combo. By default the user is given 800ms between each keypress for the combo to activate, but you can change that number to any ms value by setting the sequence_delay property of your Keypress Listener.

You can probably find other fun uses for sequence combos such as entering combos in a fighting game. Try making Ryu do a hadoken ("down", "right" then "x").

Write the word ' keypress ' and the word ' JavaScript ' (including proper capitalization) to see these in action. We've created sequence combos for the sequences "key", "keypress" and "JavaScript".

Sequence combos are great if you want to hide an easter egg or some kind of cheat code. You can have multiple sequence combos without worrying about collisions (if one combo contained another for instance, they would both fire).

As long as we're holding down the tab key, on each press of the spacebar, we'll call the keyDown callback with an additional count argument which is an integer letting us know how many times space has been pressed. This count is reset each time the last key of the combo, "tab", has been released.

Counting combos are a unique feature that was created for fast and predictable navigation. For this demo, the tab key is used for menu navigation. Pressing it once will always take us back to the default menu position, but we can press the spacebar while holding down the tab key to jump through the options. The same number of keypresses will always take you to the same option no matter which one is currently activated.

If the user continues to press space while holding tab, we'll wrap around to the start (we do that in our callback using modulo on the count integer that keypress passes to the callback as the second argument).

Yes, manila file folder, very tacky and silly, but you get it. I'm only trying to make a very obvious point about how you could use this feature.

Nothing to see here folks. You don't even get lipsum.

You would probably want to arrange these by order of importance and how often you expect the user to get to them. This requires only pressing tab and space once.

The first tab is very easy to get to by simply pressing the tab key once on it's own. This is great for something users will need to get back to often and quickly.

You can navigate these tabs by holding the tab button down and pressing the spacebar repeatedly to cycle through them.

This allows for a very intuitive wasd tile-based movement system that allows for things like holding down one key of a component vector and tapping the other to repeatedly trigger the diagonal movement, rather than having to repeatedly press them both. We're using a combination of the is_exclusive property and the on_keyup events to achieve this.

With Keypress you can specify combos that include multiple non-modifer keys. In this demo we're using combinations of the wasd keys to create combos that allow us to move in diagonals without simply firing both components of the diagonal direction individually.

Any keys you press on your keyboard should reflect on the keyboard above. Be default we are not preventing the default action for the events, so standard browser key shortcuts will still fire normally.

The keyboard demo above demonstrates binding to both by depressing the key when keydown is triggered, and then releasing it when keyup is triggered. For some key combos or outlier keys (eg. pressing a non-modifier key while the command key is depressed) no keyup event is fired, in which case we manually trigger the keyup callback immediately after keydown.

While most of the time you'll want to bind to the keydown event to improve the perceived responsiveness, there are times when you'll need to bind to keyup in addition to keydown, or even exclusively.

Keypress is an input capture library with some very special features, it is easy to pick up and use, has a reasonable footprint (~9kb), and has no dependencies. Here's some of what Keypress offers:

Great! So how do I use it?

The first thing to do is include the JavaScript file in your page. Once you've got that loaded in, you'll want to start by instantiating a listener:

var listener = new window.keypress.Listener();

Once you've done that you can register combos with that listener you've created. The simplest way to do that is using the simple_combo API. It takes a space dilineated string or an array of strings of key names that describe your combo. The second parameter is the callback function that will get called every time the combo is entered by your users.

listener.simple_combo("shift s", function() { console.log("You pressed shift and s"); }); // There are also a few other shortcut methods: // If we want to register a counting combo listener.counting_combo("tab space", function(e, count) { console.log("You've pressed this " + count + " times."); }); // If you want to register a sequence combo listener.sequence_combo("up up down down left right left right b a enter", function() { lives = 30; }, true);

If you only want to use Keypress for some very simple keyboard shortcuts, that's all you need to know!

Advanced Options

If you want to use some of the more advanced features of Keypress, you can use the register_combo API and supply an object with any number of options described below. All of the options are listed below with their default settings.

listener.register_combo({ "keys" : null, "on_keydown" : null, "on_keyup" : null, "on_release" : null, "this" : undefined, "prevent_default" : false, "prevent_repeat" : false, "is_unordered" : false, "is_counting" : false, "is_exclusive" : false, "is_solitary" : false, "is_sequence" : false });

keys: This option can be either an array of strings, or a single space separated string of key names that describe the keys that make up the combo.

This option can be either an array of strings, or a single space separated string of key names that describe the keys that make up the combo. on_keydown: This is a function that gets called everytime the keydown event for our combo is fired. We pass all event handlers three arguments: the key event that triggered it, and an integer representing the number of times the combo has been pressed (this will be 0 unless it is a counting combo), and whether or not the event was autorepeated from holding the keydown.

This is a function that gets called everytime the keydown event for our combo is fired. We pass all event handlers three arguments: the key event that triggered it, and an integer representing the number of times the combo has been pressed (this will be 0 unless it is a counting combo), and whether or not the event was autorepeated from holding the keydown. on_keyup: Same as above but for keyup events.

Same as above but for keyup events. on_release: This is similar to keyup, but will fire once when ALL of the keys of a combo have been released. If you're unsure, you probably want to ignore this and use on_keyup.

This is similar to keyup, but will fire once when ALL of the keys of a combo have been released. If you're unsure, you probably want to ignore this and use on_keyup. this: By default our key event callbacks will be called with their scope set to window, but we can specify the scope with this option.

By default our key event callbacks will be called with their scope set to window, but we can specify the scope with this option. prevent_default: Any handlers for your combos will event.preventDefault() for the relevant event by default (you can return true in the handler to prevent this). But there is additionally a prevent_default property which will preventDefault() for events of keypresses of all constituent keys of the combo. What this means is that if you have a combo "shift s", both 'shift' and 's' keypresses will independently preventDefault() when pressed.

Any handlers for your combos will event.preventDefault() for the relevant event by default (you can return true in the handler to prevent this). But there is additionally a prevent_default property which will preventDefault() for events of keypresses of all constituent keys of the combo. What this means is that if you have a combo "shift s", both 'shift' and 's' keypresses will independently preventDefault() when pressed. prevent_repeat: Normally the on_keydown callback will be called as fast as your browser fires the keydown event, but by setting this option to true, the on_keydown callback will only be called the first time.

Normally the on_keydown callback will be called as fast as your browser fires the keydown event, but by setting this option to true, the on_keydown callback will only be called the first time. is_unordered: By default we require that the user pressed the keys down in the same order that they are listed. As an example, a combo of "shift s" will only fire if shift is pressed before s is pressed. This order can be arbitrary by specifying true for this setting.

By default we require that the user pressed the keys down in the same order that they are listed. As an example, a combo of "shift s" will only fire if shift is pressed before s is pressed. This order can be arbitrary by specifying true for this setting. is_counting: Setting this to true will make the combo a counting combo as described above.

Setting this to true will make the combo a counting combo as described above. is_exclusive: Normally when pressing a key, any and all combos that match will have their callbacks called. For instance, pressing 'shift' and then 's' would activate the following combos if they existed: "shift", "shift s" and "s". When we set is_exclusive to true, we will not call the callbacks for any combos that are also exclusive and less specific. This property is used to great effect in the arbitrary modifiers demo above to make sure that when you press diagonal combos, the component direction combos are not also fired. This can also be used with sequence combos. The default when using the sequence_combo() method is to make them exclusive. What this will do is reset what is evaluated for matching sequence combos. So for instance if you had two sequences, one for "key" and one for "keypress", if the "key" combo were exclusive, the "keypress" sequence would not be triggered because the "key" combo would trigger and reset the evaluated keys.

Normally when pressing a key, any and all combos that match will have their callbacks called. For instance, pressing 'shift' and then 's' would activate the following combos if they existed: "shift", "shift s" and "s". When we set is_exclusive to true, we will not call the callbacks for any combos that are also exclusive and less specific. This property is used to great effect in the arbitrary modifiers demo above to make sure that when you press diagonal combos, the component direction combos are not also fired. This can also be used with sequence combos. The default when using the sequence_combo() method is to make them exclusive. What this will do is reset what is evaluated for matching sequence combos. So for instance if you had two sequences, one for "key" and one for "keypress", if the "key" combo were exclusive, the "keypress" sequence would not be triggered because the "key" combo would trigger and reset the evaluated keys. is_sequence: Setting this to true will make the combo a sequence combo as described above.

Setting this to true will make the combo a sequence combo as described above. is_solitary: This option will check that ONLY the combo's keys are being pressed when set to true. When set to the default value of false, a combo can be activated even if extraneous keys are pressed.

If you are registering a lot of combos at once, you'll probably want to describe combo objects as described above, store them all in an array, and then register them all at once using the register_many API. That might look something like this:

var my_scope = this; var my_combos = listener.register_many([ { "keys" : "shift s", "is_exclusive" : true, "on_keydown" : function() { console.log("You pressed shift and s together."); }, "on_keyup" : function(e) { console.log("And now you've released one of the keys."); }, "this" : my_scope }, { "keys" : "s", "is_exclusive" : true, "on_keyup" : function(event) { // Normally because we have a keyup event handler, // event.preventDefault() would automatically be called. // But because we're returning true in this handler, // event.preventDefault() will not be called. return true }, "this" : my_scope } ]);

You can then also unregister your combos either specifying the keys (beware that this will clear ALL combos that match the keys), or you can unregister by passing in the object or array of objects that were returned when registered with the listener. Or you can simply remove all registered combos by calling 'reset' on your listener.

// Remove all "shift s" combos we've registered listener.unregister_combo("shift s"); // Or only these specific combos listener.unregister_many(my_registered_combos); // Or remove ALL combos that have been registered listener.reset();

If we simply want our listener to stop listening (for instance when focusing on a text input field or textarea). We could use listener.stop_listening() like so:

$('input[type=text]') .bind("focus", function() { listener.stop_listening(); }) .bind("blur", function() { listener.listen(); });

Alternatively we might ONLY want to be listening when a particular DOM element is active. In that case, you'll probably want to bind your listener to a particular element. You can simply pass any element in as the first argument when creating a Keypress Listener. The second argument it takes is a defaults dictionary in case you want to completely override the defaults. That might look something like this:

var game_ele = document.getElementById("my_game_element_id"); var my_defaults = { is_unordered : true, prevent_repeat : true }; var listener = window.keypress.Listener(game_ele, my_defaults);

And here's a complete look at the Listener class' complete public API:

simple_combo(keys, on_keydown_callback); // Registers a very basic combo; counting_combo(keys, on_count_callback); // Registers a counting combo sequence_combo(keys, callback); // Registers a sequence combo register_combo(combo_dictionary); // Registers a combo from a dictionary register_many(combo_dictionary_array); // Registers an array of dictionaries unregister_combo(keys_or_combo_dictionary); // Unregisters a single combo unregister_many(array_of_keys_or_combo_dictionaries); // Unregisters many combos get_registered_combos(); // Get a list of the combos registered with this listener reset(); // Unregister all combos listen(); // Begin listening. Listener is listening by default stop_listening(); // Stop listening for combos until listen() is called again destroy(); // This will cleanup after the listener

A few important bits of info

If you want to make a shortcut to override default behavior such as saving, you should use the "meta" key instead of specifically using "ctrl" or "cmd". This "meta" key will become "ctrl" or "cmd" appropriately depending on the user's system.

Non-modifier keys do not ever fire a keyup event when the command key is held down, so we manually force a keyup event immediately after keydown is received. This means that if your combo includes the meta or command key, it can contain any number of modifier keys, but only one non-modifier key. Modifier keys are: "meta", "alt", "option", "ctrl", "shift", and "cmd". That means, for example, "meta shift s" is okay but "meta s p" is not.

Some keys have unreliable support and should mostly be avoided. Print, Scroll Lock, Pause/Break, and Insert have unreliable keyup or keydown firing in Windows or OS X, so I suggest avoiding them, although Keypress does still allow them.

The numpad keys should also be used with caution since you can't always count on the user having a numpad, and browser support for the numpad keys is not standardized. The numpad keys have to be specified manually with "num_" preceeding the key name. If you used a "." in your combo, for instance, it would assume a period and not a decimal (which can be used with the name "num_decimal").

For a full list of the key names, you should refer to the source code.

Support & Contact

This library has been tested with all major browsers and operating systems, but has not been thoroughly tested on non-English keyboards. If you run into any issues, please open an issue on GitHub.

Thank you

Any feedback is appreciated, and if you are using this library, I'd love to hear about it. Contact me on twitter as @dmaurolizer.