Hacker News new | comments | ask | show | jobs | submit login
Mousetrap: Keyboard shortcuts in Javascript (craig.is)
395 points by jasonmoo on July 5, 2012 | hide | past | web | favorite | 74 comments



I can't get "$" or "* a" to activate on my Swedish keyboard, where they're typed option-4 and shift-', respectively.

Dealing with keyboard-shortcuts and international keyboard is hard, I don't think I've ever gotten an app using ctrl-[ to work right.

edit: $ highlights when I type shift-4, while that's actually supposed to produce €


On chrome, 'ctrl-[' triggers a key event with .which, .keyCode, and .charCode all set to 27. 27 is DOM_VK_ESCAPE [1]. On firefox, 'esc' sets .keyCode to 27 [2]. Firefox's 'ctrl-[' sets .which and .charCode to 91 (codepoint for '['), but .keyCode to 0. On both firefox and chrome, plain '[' sets .charCode to 91, as does firefox's 'alt-['. But not 'ctrl-[' on chrome.

   (which,keyCode,charCode)
    
           chrome     firefox
   [       91 91 91   91 0 91
   alt-[   ?          91 0 91
   ctrl-[  27 27 27   91 0 91
   esc     ?          0 27 0
It's one example out of many, but how do you distinguish such cases, short of enumerating the behavior of every browser (and I guess keyboard layout too)?

[1] https://developer.mozilla.org/en/DOM/KeyboardEvent#Virtual_k...

[2] I don't know what chrome does, I couldn't convince it to capture an 'esc' or 'alt-['.


And on my Swedish keyboard you type "[" with alt-8, so when I press ctrl-alt-8, all bets are off.


Thanks for this, I noticed the same thing on chrome with other tools like codepen.io and wasn't able to figure out why it was happening.


This is why I love the JavaScript community. Tight little library, great API, brilliant project page. Excellent, shiny, hard. work.


They have a big advantage, you know! When you create a jQuery plugin, you can show everyone - instantly. I feel like desktop applications (and even websites, to a degree) don't have that luxury.


Just in case anyone is confused by this comment, though, this isn't a jQuery plugin.


"...brilliant project page..."

even the URL!

craig.is/killing/mice


It doesn't do modifier key event generation correctly. On a US keyboard, hold down shift and 4 (i.e. type "$"). The second item highlights. Now release shift. The first item highlights, incorrectly, because the library apparently generated a keydown event for "4" when the shift key was released. That's wrong by all standard conventions. Modifier key releases should never synthesize presses.


What browser are you using? It works correctly for me using Chrome on Mac. Could you make a ticket on Github?


Chrome 20 on linux. Bug submitted: https://github.com/ccampbell/mousetrap/issues/3


same issue on Win7 / FF13

Also affects the "* a" combo if you release shift before releasing 8 then release 8 and press "a" it doesn't recognize the combination (presumably because its reading a key press of 8 in between them)


Thank you.


I wonder if this is related to https://github.com/ccampbell/mousetrap/issues/6

In which case it should be a pretty painless fix.


I know it doesn't actually say that Opera is supported, but all highlights work, and that little bug he mentioned also occurs in Opera


I think there is no way to change this behavior: https://developer.mozilla.org/en/DOM/KeyboardEvent#Auto-repe...


It's a mess (the core problem is that the X server automatically generates release/press event pairs to implement key repeat which can't affirmatively be detected as "synthetic"). But it's handlable heuristically.

The way I've seen it done it via a timeout on "release after a long press". If the key has been down for more than ~1 second, then hold off on interpreting a release event to see if there's a matching press already queued in the pipe or not. The timeout can be very short (the X server sends them both synchronously down the socket with no delay).


One small suggestion is to return Mousetrap from the various methods, so method calls can be chained.

Also, +1 for a reset() command. I recently patched radio.js to do this, and I think it's something many Ajax-style apps need. However, I'm seeing there might be a need to whitelist some bindings as being durable (survive a reset).



I really hate pages that take control of the keyboard like this.

Your website isn't so special to completely change how I use my browser.

It might be okay for a game, but in every other case, if my regular bindings don't work, I leave.


But I think that's the right solution.

For most websites, I will leave. But for web "apps" like Google Docs, or GMail, or my company's internal apps, I want to use application-style keyboard shortcuts like Ctrl+S and Ctrl+T and Ctrl+N. I want Ctrl+N to create a new document inside my application, not a new browser window.

The best solution would be to ask users to give permission to a webpage to overwrite native keyboard shortcuts for their own uses.


Agree, probably the best example where it's okay to offer 'tip' type dialogs on opening the app "We've setup keyboard shortcuts for you, would you like to use them? (examples)". (Saving preferences for future visits).


Great point on using shortcuts on web apps. After a while I forget they on the web and start using shortcuts. This support is welcome.

Great app, project page and effort.


I second that. I mapped a specific trackpad gesture to 'Command-W' (using BetterTouchTools). Now when I perform my crazy gesture on pages like http://www.hnsearch.com/search#request/all&q=hello or http://try.github.com/levels/1/challenges/1 , it prints a 'w' in the text bar instead of closing the tab. It really bothers me.

It has legitimate uses though, I'm not saying it shouldn't be used. But please use it only where it makes sense.


The thing is, this isn't a problem space that's unique to web apps. I find nothing more frustrating than native OS X apps that bind over system-wide shortcuts (I'm looking at you, Adobe products). Web apps have a slightly trickier turf to navigate due to also having to watch out for web browser default shortcuts, but that doesn't suddenly make the problem unsolvable.

The problem isn't that keyboard shortcuts for web apps are inherently bad. The problem is application designers who choose their keyboard shortcuts poorly.


On the other hand, this is crucial for things like javascript terminal emulators (which are nice for avoiding the long load time of a java terminal emulator).


I agree. Overwriting the close tab and next/previous tab shortcuts causes me a lot of frustration. Thankfully few webpages do it.


Nice, but could do with a bit of preventDefault love, at least for the examples. Firefox on Linux has Ctrl+Shift+K as Web Console, Ctrl+K as (seemingly) Goto Google.


Ah good idea! I will add those on the demo page later.


It's been a while since I last used Firefox, but if I remember correctly, Ctrl/Command-K is a shortcut for your homepage.


On my Firefox, Ctrl-K puts the cursor in the search box. (And on Chromium it puts it in the omnibar with a ? prefilled.)


My home page is about:newtab. Odd.


Dear Asana, Evernote and all other text editing web apps: Can you please use this library to add ctrl + s = save support. I hit it so frequently during writing out of habit and every time I do so Chrome asks me to save the website out as a html file. Thanks! :)


This looks like it's doing basically the same thing that keymaster has already been doing, with an almost identical API:

https://github.com/madrobby/keymaster


This offers a few additional things such as supporting Gmail style key sequences, binding keyup events, supporting keys that require the shift modifier using their key name "?", triggering key commands programmatically, etc.


Awesome! I'm super excited about this. I've been using keymaster for my Chrome extension for custom key bindings [1] but it's suffering from two issues:

- Lack of "key-sequences" ala Gmail

- Bug where focusing on a page having already pushed down a modifier doesn't tell keymaster that the modifier is pushed. For example if you ctrl+tab to a page and keep the control key pushed, then hit an action key (say "f"), then what you really want is to trigger ctrl+f but keymaster doesn't recognize it because it doesn't see ctrl as having been pressed since it was already held down before the page had focus.

Looks like Mousetrap fixes both of these issues. Thanks a ton!

1: https://chrome.google.com/webstore/detail/logpjaacgmcbpdkdch...


Everything's already been done everywhere, all the time. Choices are a great thing.


Keymaster has stagnated a bit, that's correct, but it's still a pretty quality piece of work. I'm using it for my own keyboard shortcut (jquery) plugin here : http://joeloliveira.com/chaves.js/demo/defaults.html

The goal of my plugin isn't to just bind keys but to provide sensible defaults and an easy interface to either override the defaults or create your own, as well as have a built-in mechanism to display a "help" modal window. After all, what good are keyboard shortcuts if you don't know what they are.

Check it out. Would love any feedback

(sorry, Craig, for me-too'ing / "hey look at me too"'ing your post).


I've found Keymaster good in the past, but the project really isn't being maintained. (https://github.com/madrobby/keymaster/issues?direction=desc&...)

It would be nice to see an ongoing project for this, with keyboard shortcuts becoming more popular (in use at Twitter, GitHub, and Google Plus for example). I'm planning to add the functionality on my own app soon and will take a look at this.



I really like the doma.in/name/choice


I wouldn't have noticed it - thanks, made me smile. :)


I don't know if this is on purpose, but the "Cmd+Shift+K" binding is not activated by "Ctrl+Shift+K" or "Alt+Shift+K" on non-Macs. Seems to work great otherwise, though.


Thanks! Command is bound to e.metaKey so whatever that works out to on PC, but you can specify multiple keys like in the next example, by passing an array.


You might consider trying an "accel" alias modifier, so that you don't have to specify both Ctrl and Cmd. That's what Mozilla does: https://developer.mozilla.org/en/XUL_Tutorial/Keyboard_Short...

If you really do want fine-grained control, for example, so that Cmd works on OS X, but it maps to something else entirely on other platforms, you can still use Ctrl and Cmd.


did you try the 'Windows' key?


That doesn't seem to work, either. Besides, Command generally maps to Ctrl/Alt on most pieces of software.


This looks very similar to a library I created/am working on: http://keithcirkel.co.uk/jwerty/


This might make more sense as a object model rather than class model. There is a lot of state behind the scenes (bind, trigger, reset), which would be natural for an object. Instead it is dumped into global state.

The use case might be to support multiple sets of key bindings, e.g., default, user specific, app specific, view specific. When you don't need one set anymore you just "reset" that set instead of resetting everything.


You know a library (or whatever) is awesome when you're initial reaction is "I can't believe this didn't exist already". I'll definitely be using this!


John Resig's jquery.hotkeys do almost all of it (and it is stable enough, as it is 2 years old): https://github.com/jeresig/jquery.hotkeys


I checked out of curiosity: jquery.hotkeys is about 1.4kb minified, coincidentally the same size as this library. Of course you'd have to add jquery itself to get the total size, if you weren't already using it.


Very nice. I was about to hand roll my own implementation of this, but this just saved me some time :-)

I like how there's a working demo right there on the page - it's nothing groundbreaking but it definitely adds a bit more polish.

Something I'm wondering about - would it pay to have some sort of "variable" key binding whose value would differ depending on the user's OS (if this is even possible)? For example, instead of binding both command+k and ctrl+k, I would bind one combination that would work both on Mac and Windows systems. This isn't a deal breaker or major issue by any means, but I'd be interested to know if it can be done.


Very nice! Wrote something like this one too many times in the past, definitely delighted to replace it with a library in the future, thanks! :)


Hi craigc, I'd be interested in using this, but (and yeah, this is terrible) I need some sort of "scoping", i.e. hotkeys would dispatch differently based on what element is highlighted.

I realize I could achieve this by making my bound function aware of the scoping, but it would be much nicer to have first class library support (in a library with an already kickass-ly simple API). Any thoughts on this?


I'm not sure if I want to support this or not. Please make a ticket over at https://github.com/ccampbell/mousetrap


Perhaps some documentation on how to handle scoping with the callbacks is adequate.


This looks really useful, and the API looks simple.

Just a quick reminder for those using any library like this; screenreader users (typically blind people) rely heavily on the keyboard to use their web browser. Adding your own shortcuts can really screw them over. It's usually best to make your custom shortcuts a feature that the user opts in to, off by default.


If anyone is looking for a way to let users enter keycombos which you could then use with Mousetrap, I wrote this: http://suan.github.com/jquery-keycombinator/


Nice hack -- I've been going this as inside of backbone.js app. I have a asset management app that uses keyboard shortcuts to quickly tag, choose, and manage photos.

Had I know about this I might have used it rather than bundling it into my views.

Nice work!


I'd love to see this integrated into Backbone. Bindings could be specified in a keyboard_events hash similar to how the existing events hash is run.



+1 for the url to the project


Now there's no excuse to not have a Konami code easter egg on your sites.


Works. Simple and effective with an easy bar for entry. Good job.


The funny thing is that with my keymap (cs_CZ) the 4 and $ keybindings are reversed.


Ditto here on fr_bepo mapping, with chrome 20.0.1132.47.


Sweet! I can now non-metaphorically dare someone to build a better Mousetrap.


Shouldn't it be download it and throw away your mouse? ;)


This is awesome library. Thumbs up for the post.


I love you. I really do. This is amazing work.


it needs gmail like 'help' screen


awesome!


> For modifier keys you can use shift, ctrl, alt, option, meta, and command.

No. Just don't. Ever. Unless you are doing a standalone, web based app.




Applications are open for YC Summer 2019

Guidelines | FAQ | Support | API | Security | Lists | Bookmarklet | Legal | Apply to YC | Contact

Search: