{"id":2885,"date":"2013-03-20T16:41:27","date_gmt":"2013-03-20T22:41:27","guid":{"rendered":"http:\/\/bililite.com\/blog\/?p=2885"},"modified":"2015-01-12T16:35:03","modified_gmt":"2015-01-12T22:35:03","slug":"hotkeys-with-keymap","status":"publish","type":"post","link":"https:\/\/bililite.com\/blog\/2013\/03\/20\/hotkeys-with-keymap\/","title":{"rendered":"<code>hotkeys<\/code> with <code>keymap<\/code>"},"content":{"rendered":"<p><strong>This post is obsolete; the <code>$.keymap<\/code> has changed significantly. Documentation is now at <a href=\"\/blog\/2015\/01\/12\/rethinking-keymap\/\">http:\/\/bililite.com\/blog\/2015\/01\/12\/rethinking-keymap\/<\/a><\/strong>.<\/p>\r\n<p>Inspired by John Resig's <a href=\"https:\/\/github.com\/jeresig\/jquery.hotkeys\">hotkeys<\/a>, I created a version that uses the modern <a href=\"http:\/\/api.jquery.com\/on\/\"><code>on<\/code><\/a>, and uses an object rather than a string for the keys (which would be confused with a selector). It also uses my <a href=\"http:\/\/bililite.com\/blog\/2013\/02\/22\/parsing-keydown-events\/\" title=\"Parsing keydown events\"><code>$.keymap<\/code><\/a> codes.<\/p>\r\n<p>It's written as a plugin to <a href=\"http:\/\/bililite.com\/blog\/2013\/02\/22\/parsing-keydown-events\/\" title=\"Parsing keydown events\"><code>$.keymap<\/code><\/a>.<\/p>\r\n<p><a href=\"https:\/\/github.com\/dwachss\/bililiteRange\/blob\/master\/jquery.keymap.js\">Download the code<\/a>.<\/p>\r\n<p><a href=\"\/blog\/blogfiles\/vi\/keymap.hotkeys.html\">See the demo<\/a>, or <a href=\"\/blog\/blogfiles\/vi\/hotkeys.html\">the demo with regular expressions<\/a>.<\/p>\r\n<p>It's part of my <a href=\"https:\/\/github.com\/dwachss\/bililiteRange\">bililiteRange repo<\/a> on github.<\/p>\r\n<h3>Usage<\/h3>\r\n<p>This modifies the event handling code so that you can listen for specific keys or sequences of keys (note that you can use <code class=\"language-javascript\" >keyup<\/code> as well as <code class=\"language-javascript\" >keydown<\/code>, but that is less useful):<\/p>\r\n<pre><code class=\"language-javascript\" >$('input').on('keydown', {keys: '^A'}, function() {alert('Control A was pressed')} );<\/code><\/pre>\r\n<p>The original <code class=\"language-javascript\" >$('input').on('keydown', function() {alert('A key was pressed')} );<\/code> is unchanged.<\/p>\r\n<p>Remove the handler with <code class=\"language-javascript\" >$('input').off('keydown', {keys: '^A'} );<\/code>. Use exactly the same <code class=\"language-javascript\" >keys<\/code> expression as when the handler was attached.<\/p>\r\n<p>It handles selectors correctly (I think):<\/p>\r\n<pre><code class=\"language-javascript\" >$('body').on('keydown', {keys: '^A'}, function() {alert('Control A')} );\r\n$('body').on('keydown', 'input', {keys: '^A'}, function() {alert('Control A was pressed in an input')} );<\/code><\/pre>\r\n<p>Attaches the handler for <code class=\"language-html\" >&lt;body&gt;<\/code> and keys <code>^A<\/code>, then adds a handler that is only triggered when the target element is an <code class=\"language-html\" >&lt;input&gt;<\/code> and the event bubbled up to the <code class=\"language-html\" >&lt;body&gt;<\/code>.<\/p>\r\n<p>Remove selector-specific handlers with <code class=\"language-javascript\" >$('body').off('keydown', 'input', {keys: '^A'} );<\/code>.<\/p>\r\n<p>Note that the handler function is replaced internally, so removing handlers with <code class=\"language-javascript\" >$('body').off('keydown', handler);<\/code> will fail. It's not a good idea anyway (see the <a href=\"http:\/\/api.jquery.com\/off\/#off-events-selector-handlereventObject\">documentation<\/a>); use namespaces instead (<code class=\"language-javascript\" >$('body').off('keydown.myinstance');<\/code>).<\/p>\r\n<p>Sequences of keystrokes are indicated by a space-delimited list:<\/p>\r\n<pre><code class=\"language-javascript\" >$('body').on('keydown', {\r\n    keys: '{up} {up} {down} {down} {left} {right} {left} {right} b a'\r\n  }, \r\n  function() {alert('Konami!')}\r\n);<\/code><\/pre>\r\n<p>Listens for the <a href=\"http:\/\/en.wikipedia.org\/wiki\/Konami_Code\">Konami code<\/a>.<\/p>\r\n<p>Normally, when listening for a sequence, the keydown events that match are discarded. If you want them to be passed to other handlers, use\r\n<code>allowDefault<\/code>:<\/p>\r\n<pre><code class=\"language-javascript\" >$('body').on('keydown', {\r\n    keys: '{up} {up} {down} {down} {left} {right} {left} {right} b a',\r\n    allowDefault: true \/\/ the arrow keys will still work\r\n  }, \r\n  function() {alert('Konami!')}\r\n);<\/code><\/pre>\r\n<p>To prevent other handling on the final event of a sequence, use the usual <code class=\"language-javascript\" >preventDefault<\/code> or <code class=\"language-javascript\" >return false<\/code> in the handler.<\/p>\r\n<h3>Regular Expressions<\/h3>\r\n<p>In addition to specifying the keys with a string, you can use a regular expression:<\/p>\r\n<pre><code class=\"language-javascript\" >$('body').on('keydown', { keys: \/\\d\/ }, \r\n  function(event) {alert('A digit key was pressed:' + event.hotkeys)}\r\n);<\/code><\/pre>\r\n<p>The actual key or sequence of keys is returned in <code class=\"language-javascript\" >event.hotkeys<\/code>. Note that passing the keys as a string will \"normalize\" the keys with <code class=\"language-javascript\" >$.keymap.normalize<\/code> to match that returned by <code class=\"language-javascript\" >$.keymap<\/code> (i.e. <code class=\"language-javascript\" >{keys: 'ctrl-a'}<\/code> will work). Passing a regular expression needs to be normalized (i.e. <code class=\"language-javascript\" >{keys: \/ctrl-\\w\/}<\/code> will <em>not<\/em> work; use <code class=\"language-javascript\" >{keys: \/\\^\\w\/}<\/code>). Multiple keys need to be separated by a single space (<code class=\"language-javascript\" >{keys: \/\\d \\d\/}<\/code> to catch two digits in a row). This will succeed on the first sequence of characters matched, with no look-ahead, so you can't do <code class=\"language-javascript\" >{keys: \/(\\d )+\/}<\/code> to match multiple digits; it will succeed on the first digit pressed.<\/p>\r\n<h3>Events<\/h3>\r\n<p>The plugin also triggers two other events: <code class=\"language-javascript\" >'keymapprefix'<\/code> when the event is the prefix of a valid sequence, and <code class=\"language-javascript\" >'keymapcomplete'<\/code> when a sequence is matched. Both are sent with an additional parameter indicating what keys were pressed so far (in <code class=\"language-javascript\" >$.keymap<\/code> notation). So:<\/p>\r\n<pre><code class=\"language-javascript\" >$('body').on('keymapprefix keymapcomplete', function(event, keys){\r\n\talert ('sequence pressed: '+keys);\r\n})<\/code><\/pre>\r\n\r\n<h3>More Information<\/h3>\r\n<p>Understanding special event handling in jQuery is very complicated; there is an <a href=\"http:\/\/learn.jquery.com\/events\/event-extensions\/\">article on learn.jquery.com<\/a> that is invaluable. But this is one area where you will have to go through the <a href=\"https:\/\/github.com\/jquery\/jquery\/blob\/master\/src\/event.js\">source code<\/a>. No way around that, but it's a very good way to get your brain about the way jQuery works, in a deep way.<\/p>","protected":false},"excerpt":{"rendered":"This post is obsolete; the $.keymap has changed significantly. Documentation is now at http:\/\/bililite.com\/blog\/2015\/01\/12\/rethinking-keymap\/. Inspired by John Resig's hotkeys, I created a version that uses the modern on, and uses an object rather than a string for the keys (which would be confused with a selector). It also uses my $.keymap codes. It's written as [&hellip;]","protected":false},"author":2,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[10,5],"tags":[],"_links":{"self":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2885"}],"collection":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/comments?post=2885"}],"version-history":[{"count":18,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2885\/revisions"}],"predecessor-version":[{"id":3428,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/posts\/2885\/revisions\/3428"}],"wp:attachment":[{"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/media?parent=2885"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/categories?post=2885"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/bililite.com\/blog\/wp-json\/wp\/v2\/tags?post=2885"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}