|
| 1 | +# keymaster.js |
| 2 | + |
| 3 | +Keymaster is a simple micro-library for defining and |
| 4 | +dispatching keyboard shortcuts in web applications. |
| 5 | + |
| 6 | +It has no dependencies. |
| 7 | + |
| 8 | +*It’s a work in progress (e.g. beta), so spare me your nerdrage and instead |
| 9 | +contribute! Patches are welcome, but they are not guaranteed to make |
| 10 | +it in.* |
| 11 | + |
| 12 | +## Usage |
| 13 | + |
| 14 | +Include `keymaster.min.js` in your web app, by loading it as usual: |
| 15 | + |
| 16 | +```html |
| 17 | +<script src="keymaster.min.js"></script> |
| 18 | +``` |
| 19 | + |
| 20 | +Keymaster has no dependencies and can be used completely standalone. |
| 21 | +It should not interfere with any JavaScript libraries or frameworks. |
| 22 | + |
| 23 | +## Defining shortcuts |
| 24 | + |
| 25 | +One global method is exposed, `key` which defines shortcuts when |
| 26 | +called directly. |
| 27 | + |
| 28 | +```javascript |
| 29 | +// define short of 'a' |
| 30 | +key('a', function(){ alert('you pressed a!') }); |
| 31 | + |
| 32 | +// returning false stops the event and prevents default browser events |
| 33 | +key('ctrl+r', function(){ alert('stopped reload!'); return false }); |
| 34 | + |
| 35 | +// multiple shortcuts that do the same thing |
| 36 | +key('⌘+r, ctrl+r', function(){ }); |
| 37 | +``` |
| 38 | + |
| 39 | +The handler method is called with two arguments set, the keydown `event` fired, and |
| 40 | +an object containing, among others, the following two properties: |
| 41 | + |
| 42 | +`shortcut`: a string that contains the shortcut used, e.g. `ctrl+r` |
| 43 | +`scope`: a string describing the scope (or `all`) |
| 44 | + |
| 45 | +```javascript |
| 46 | +key('⌘+r, ctrl+r', function(event, handler){ |
| 47 | + console.log(handler.shortcut, handler.scope); |
| 48 | +}); |
| 49 | + |
| 50 | +// "ctrl+r", "all" |
| 51 | +``` |
| 52 | + |
| 53 | +## Supported keys |
| 54 | + |
| 55 | +Keymaster understands the following modifiers: |
| 56 | +`⇧`, `shift`, `option`, `⌥`, `alt`, `ctrl`, `control`, `command`, and `⌘`. |
| 57 | + |
| 58 | +The following special keys can be used for shortcuts: |
| 59 | +`backspace`, `tab`, `clear`, `enter`, `return`, `esc`, `escape`, `space`, |
| 60 | +`up`, `down`, `left`, `right`, `home`, `end`, `pageup`, `pagedown`, `del`, `delete` |
| 61 | +and `f1` through `f19`. |
| 62 | + |
| 63 | +## Modifier key queries |
| 64 | + |
| 65 | +At any point in time (even in code other than key shortcut handlers), |
| 66 | +you can query the `key` object for the state of any keys. This |
| 67 | +allows easy implementation of things like shift+click handlers. For example, |
| 68 | +`key.shift` is `true` if the shift key is currently pressed. |
| 69 | + |
| 70 | +```javascript |
| 71 | +if(key.shift) alert('shift is pressed, OMGZ!'); |
| 72 | +``` |
| 73 | + |
| 74 | +## Other key queries |
| 75 | + |
| 76 | +At any point in time (even in code other than key shortcut handlers), |
| 77 | +you can query the `key` object for the state of any key. This |
| 78 | +is very helpful for game development using a game loop. For example, |
| 79 | +`key.isPressed(77)` is `true` if the M key is currently pressed. |
| 80 | + |
| 81 | +```javascript |
| 82 | +if(key.isPressed("M")) alert('M key is pressed, can ya believe it!?'); |
| 83 | +if(key.isPressed(77)) alert('M key is pressed, can ya believe it!?'); |
| 84 | +``` |
| 85 | + |
| 86 | +You can also get these as an array using... |
| 87 | +```javascript |
| 88 | +key.getPressedKeyCodes() // returns an array of key codes currently pressed |
| 89 | +``` |
| 90 | + |
| 91 | + |
| 92 | +## Scopes |
| 93 | + |
| 94 | +If you want to reuse the same shortcut for seperate areas in your single page app, |
| 95 | +Keymaster supports switching between scopes. Use the `key.setScope` method to set scope. |
| 96 | + |
| 97 | +```javascript |
| 98 | +// define shortcuts with a scope |
| 99 | +key('o, enter', 'issues', function(){ /* do something */ }); |
| 100 | +key('o, enter', 'files', function(){ /* do something else */ }); |
| 101 | + |
| 102 | +// set the scope (only 'all' and 'issues' shortcuts will be honored) |
| 103 | +key.setScope('issues'); // default scope is 'all' |
| 104 | +``` |
| 105 | + |
| 106 | +## Filter key presses |
| 107 | + |
| 108 | +By default, when an `INPUT`, `SELECT` or `TEXTAREA` element is focused, Keymaster doesn't process any shortcuts. |
| 109 | + |
| 110 | +You can change this by overwriting `key.filter` with a new function. This function is called before |
| 111 | +Keymaster processes shortcuts, with the keydown event as argument. |
| 112 | + |
| 113 | +If your function returns false, then the no shortcuts will be processed. |
| 114 | + |
| 115 | +Here's the default implementation for reference: |
| 116 | + |
| 117 | +```javascript |
| 118 | +function filter(event){ |
| 119 | + var tagName = (event.target || event.srcElement).tagName; |
| 120 | + return !(tagName == 'INPUT' || tagName == 'SELECT' || tagName == 'TEXTAREA'); |
| 121 | +} |
| 122 | +``` |
| 123 | + |
| 124 | +If you only want _some_ shortcuts to work while in an input element, you can change the scope in the |
| 125 | +`key.filter` function. Here's an example implementation, setting the scope to either `'input'` or `'other'`. |
| 126 | +Don't forget to return `true` so the any shortcuts get processed. |
| 127 | + |
| 128 | +```javascript |
| 129 | +key.filter = function(event){ |
| 130 | + var tagName = (event.target || event.srcElement).tagName; |
| 131 | + key.setScope(/^(INPUT|TEXTAREA|SELECT)$/.test(tagName) ? 'input' : 'other'); |
| 132 | + return true; |
| 133 | +} |
| 134 | +``` |
| 135 | + |
| 136 | +However a more robust way to handle this is to use proper |
| 137 | +focus and blur event handlers on your input element, and change scopes there as you see fit. |
| 138 | + |
| 139 | +## noConflict mode |
| 140 | + |
| 141 | +You can call ```key.noConflict``` to remove the ```key``` function from global scope and restore whatever ```key``` was defined to before Keymaster was loaded. Calling ```key.noConflict``` will return the Keymaster ```key``` function. |
| 142 | + |
| 143 | +```javascript |
| 144 | +var k = key.noConflict(); |
| 145 | +k('a', function() { /* ... */ }); |
| 146 | + |
| 147 | +key() |
| 148 | +// --> TypeError: 'undefined' is not a function |
| 149 | +``` |
| 150 | + |
| 151 | +## Unbinding shortcuts |
| 152 | + |
| 153 | +Similar to defining shortcuts, they can be unbound using `key.unbind`. |
| 154 | + |
| 155 | +```javascript |
| 156 | +// unbind 'a' handler |
| 157 | +key.unbind('a'); |
| 158 | + |
| 159 | +// unbind a key only for a single scope |
| 160 | +// when no scope is specified it defaults to the current scope (key.getScope()) |
| 161 | +key.unbind('o, enter', 'issues'); |
| 162 | +key.unbind('o, enter', 'files'); |
| 163 | +``` |
| 164 | + |
| 165 | +## Notes |
| 166 | + |
| 167 | +Keymaster should work with any browser that fires `keyup` and `keydown` events, |
| 168 | +and is tested with IE (6+), Safari, Firefox and Chrome. |
| 169 | + |
| 170 | +See [http://madrobby.github.com/keymaster/](http://madrobby.github.com/keymaster/) for a live demo. |
| 171 | + |
| 172 | +## CoffeeScript |
| 173 | + |
| 174 | +If you're using CoffeeScript, configuring key shortcuts couldn't be simpler: |
| 175 | + |
| 176 | +```coffeescript |
| 177 | +key 'a', -> alert('you pressed a!') |
| 178 | + |
| 179 | +key '⌘+r, ctrl+r', -> |
| 180 | + alert 'stopped reload!' |
| 181 | + off |
| 182 | + |
| 183 | +key 'o, enter', 'issues', -> |
| 184 | + whatevs() |
| 185 | + |
| 186 | +alert 'shift is pressed, OMGZ!' if key.shift |
| 187 | +``` |
| 188 | + |
| 189 | +## Ender support |
| 190 | + |
| 191 | +Add `keymaster` as a top level method to your [Ender](http://ender.no.de) compilation. |
| 192 | + |
| 193 | + $ ender add keymaster |
| 194 | + |
| 195 | +Use it: |
| 196 | + |
| 197 | +``` js |
| 198 | +$.key('⌘+r', function () { |
| 199 | + alert('reload!') |
| 200 | +}) |
| 201 | +``` |
| 202 | + |
| 203 | +## Contributing |
| 204 | + |
| 205 | +To contribute, please fork Keymaster, add your patch and tests for it (in the `test/` folder) and |
| 206 | +submit a pull request. |
| 207 | + |
| 208 | +## TODOs |
| 209 | + |
| 210 | +* Finish test suite |
| 211 | + |
| 212 | +Keymaster is (c) 2011-2013 Thomas Fuchs and may be freely distributed under the MIT license. |
| 213 | +See the `MIT-LICENSE` file. |
0 commit comments