Coder Social home page Coder Social logo

keydrown's Introduction

Keydrown

A JavaScript key state handler for web apps

When building games or any application that requires quick reactions from the user, a system to track key states is needed. You might say "Silly developer! There are events for that! They're called keydown and keyup!" This is correct, but the problem that Keydrown solves is more subtle: When you press and hold any key on the keyboard, there is a brief delay between the initial firing of the keydown event handler and the subsequent firings of that event for every tick. Here's an approximate ASCII visualization:

TIME (seconds)           KEYDOWN HANDLER FIRING STATE
-----------------------------------------------------

0                        Firing
0.25                     Not firing
0.50                     Not firing
0.75                     Not firing
1                        Firing
1.25                     Firing
1.50                     Firing
1.75                     Firing
2                        Firing

...And the handler will just keep firing until the button is released. The expectation from the user is that the key handler would be firing for the entire duration of time that the key is held down - the early ticks where the keydown state is not handled creates a feeling of sluggishness and noticeably worsens the User Experience. A way around this delay is to only listen for one keydown event for a button, and execute the key handler on every tick until the corresponding keyup event is detected for that button.

Keydrown makes this super easy.

API

All Keydrown functionality exists under the kd namespace.

Key Objects

Every letter key, as well as some other keys on the keyboard are represented in a map of kd.Key instances with uppercase key names:

kd.A instanceof kd.Key; // true
kd.SPACE instanceof kd.Key; // true
kd.UP instanceof kd.Key; // true

You can see the full list of supported keys in kd.map.js (more key codes can easily be added, please submit a Pull Request if you add more). kd.Key has the following API:

/**
 * @param {function=} opt_handler
 */
kd.Key.prototype.down = function (opt_handler)

opt_handler fires for every tick where the key is held down. There is no early delay, as described in the ASCII graph above. Calling this method for a key again will overwrite the previous opt_handler - only one handler function is allowed per key.

If opt_handler is omitted, this function invokes whatever handler function was previously bound with kd.Key#down.

/**
 * @param {function=} opt_handler
 */
kd.Key.prototype.up = function (opt_handler)

opt_handler fires when the key is released by the user. As with kd.Key#down, only one handler function is allowed. Unlike kd.Key#down, opt_handler does not fire continuously โ€” only once when the key is released.

If opt_handler is omitted, this function invokes whatever handler function was previously bound with kd.Key#up.

/**
 * @param {function=} opt_handler
 */
kd.Key.prototype.press = function (opt_handler)

opt_handler fires once when the key is pressed by the user. Only one handler function is allowed. This is not a repeating state โ€” it only fires once until the user releases the key and presses it again.

If opt_handler is omitted, this function invokes whatever handler function was previously bound with kd.Key#press.

kd.Key.prototype.isDown = function()

Returns true if the key is currently pressed, otherwise returns false.

Example

kd.B.down(function () {
  console.log('The "B" key is being held down!');
});

kd.B.up(function () {
  console.log('The "B" key was released!');
});

kd.SPACE.press(function () {
  console.log('The space bar was pressed!');
});

if (kd.LEFT.isDown()) {
  console.log('The left arrow key is being held down!')
}

down, up, and press functions also provide the raw Keyboard event Object created by the corresponding browser event. The schema of this Object may differ across browsers, particularly older ones.

kd.A.down(function (evt) {
  if (evt.shiftKey) {
    console.log('The shift key is being held down!');
  }

  if (evt.ctrlKey) {
    console.log('The ctrl key is being held down!');
  }
});

kd.Key.prototype.unbindDown = function ()

Unbinds the function handler that was bound with kd.Key#down.

kd.Key.prototype.unbindUp = function ()

Unbinds the function handler that was bound with kd.Key#up.

kd.Key.prototype.unbindPress = function ()

Unbinds the function handler that was bound with kd.Key#press.

Example

kd.B.down(function () {
  console.log('The "B" key is being held down!');
});

// Now pressing the "B" key won't do anything
kd.B.unbindDown();

Helper methods

The kd Object has helper methods attached to it, and they are represented by camelCase property names.

kd.tick = function ()

Check the states of all of the keys and invoke the necessary key handlers. You should call this once and only once somewhere in your run loop. If you don't call tick somewhere in your run loop, Keydrown won't do anything.

/**
 * @param {function} handler
 */
kd.run = function (handler)

A basic run loop. If your application already has a run loop, you don't need this. kd.run uses requestAnimationFrame if it is available, and falls back to a setTimeout loop if it is not.

kd.stop = function ()

Cancels the run loop started by kd.run.

Example

kd.run(function () {
  kd.tick();
});

kd.SPACE.down(function () {
  console.log('The space bar is being held down!');
});

kd.ESC.down(function () {
  console.log('Canceling the loop.');
  kd.stop();
});

Getting the code

If you want to keep things simple, all you need is either dist/keydrown.js or dist/keydrown.min.js from this Git repo. Alternatively, you can install Keydrown via NPM:

$: npm install keydrown

Module compatibility

If loaded directly (without a script loader), Keydrown creates the kd browser global. However, it can also be loaded as an AMD module or as a CommonJS module (through a tool like Webpack).

// Loaded as a CommonJS module with Webpack
var kd = require('keydrown');

kd.run(function () {
  kd.tick();
});
// Loaded with an AMD loader (such as Require.js)
require(['./path/to/keydrown'], function (kd) {
  kd.run(function () {
    kd.tick();
  });
});

Browser compatibility

Keydrown supports all modern browsers, as well as Internet Explorer 7 and up (please see the note below about IE compatibility).

Limitations

Keydrown has a feature where when the user blurs the browser window (for example, switching to another application or tab), the key state is reset and "down" handlers stop firing. On other words, keys aren't considered "down" if the user is not focused on the browser window. This functionality is not supported in IE 7 and 8, as there doesn't seem to be a way to bind to the window's blur event correctly in those browsers. You can assign a function to window.onblur, but that function will only fire once IE regains focus, which is not sufficient for Keydrown's reset-on-blur functionality.

Keydrown in the wild

Keydrown has been used in several interesting projects:

License

Keydrown is distibuted under the MIT license. You are encouraged to use and modify the code to suit your needs, as well as redistribute it.

keydrown's People

Contributors

andrezsanchez avatar gzopel avatar jeremyckahn avatar kevzettler avatar piicksarn avatar sm64js avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

keydrown's Issues

CommonJS compatibility

In kd.outro.js and kd.intro.js, you're assuming the root object this is window, but that's not the case when using keydrown with a server-side module tool like browserify.

For now, I've changed this to window and all is well, but explicit support for CommonJS modules would be even better. See, for example, how underscore does it. For an example of supporting both AMD and CommonJS, see jQuery.

Thanks for the great library.

request: kd.<key>.press

Often input apis include .state() (which is essentially kd.down/up) and .pressed(), which only returns true if the bound key was "just" pressed (ie, since the last tick), and false otherwise.

In games, .down and .up are useful for autofire, player movement, etc. But there are lots of use cases where you just want to know once if a key was pressed, eg interacting with an object or opening a menu. You could just use .keyup, but that feels less responsive to the player.

I'm not sure if you'd consider this bloat or not, but it would be very useful to me. And it seems like you're intended audience is games, not just web apps.

Numeric keys

For what I can tell from /src/kd.map.js there is no support for numeric keys. Is there any hope this gets implemented?
Thanks.

holding certain keys prevents others from being pressed

I come from the same project as the last person (sm64js), and I changed the controls in the game because sometimes some keys don't respond when others are held down, and this can limit your moveset. Do you know why this happens?

No Way To Determine Delta Time

For keydrown to be more useful to any javascript game developers, within the key event functions there must be some way to find out how much time has elapsed since the last time kd.tick() was called or a tick occurred.

state of a key without a callback

I think that it's convenient to use combinations of key states when handling input, but it's a bit annoying to do with the callback system of getting a key's state. It would be great if keydrown would let you get the boolean state of a key without callbacks.

eg

var left = kd.A.state() || kd.LEFT.state() || kd.J.state()
var right = kd.D.state() || kd.RIGHT.state() || kd.L.state()
xMovement = right - left

I've looked at the code, but not enough to understand all of it yet, so I thought I'd ask, would this be easy to implement?

npm

Could you publish this to npm? I'm using browserify so it would be convenient to use npm

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.