Hacker News new | past | comments | ask | show | jobs | submit login
Keypress: A Javascript library for capturing input (dmauro.github.io)
192 points by nsmalch on Sept 29, 2013 | hide | past | favorite | 55 comments



Note that you should avoid using this (or anything else with JS) to emulate shortcuts.

The reason is because what this usually looks like "oh nice I can define shortcuts people can press". What it actually means is: "Ohcrap, that shortcut only works for US-US 104 keyboard layouts, and about 80% of people can't press that shortcut".

For example: suppose you want a shortcut for shift+/, which is for the US keyboard under the small right finger. But that shortcut can't be defined for SG (swiss-german) because there the / is on the numeric bar where 7 is. So if you assume (for whatever reason) that left+right small finger is a convenient shortcut, and left small finger + right index finger top isn't, then you're totally screwed. Instead, to reach the right small finger low on swiss german, you'd have to define shift + "-". Except that if you define that, it'll be one of the most uncomfortable keyboard shortcuts imaginable for US users, which find - on the numeric row top --> bottom left small finger + top right small finger = ugh.

The truth is that you cannot do reasonable shortcut definition the way that everybody would like to with JS... yet.

But wait, can't you like, define some reasonable presets and let people choose their own? The answer is no, because you don't have a reliable way to translate a keydown/keyup to a unicode char, and the unicode char is related to the modifier keys, not the key cap, so though you can do that shortcut definition, you can't show to the user what that shortcut definition actually is, because it'd be either undefined or completely wrong.

I've written at length about this here: http://codeflow.org/entries/2013/jan/30/keyboard-events-in-j...


> But wait, can't you like, define some reasonable presets and let people > choose their own? The answer is no, because you don't have a reliable way to > translate a keydown/keyup to a unicode char, and the unicode char is related > to the modifier keys, not the key cap, so though you can do that shortcut > definition, you can't show to the user what that shortcut definition actually > is, because it'd be either undefined or completely wrong.

But couldn't you let the user write the shortcut in a text field, capture the keycodes from the keydown/keyup events and the char from the text field?

Edit: This obviously doesn't work for shortcuts that do not produce any text, such as F-keys. But couldn't you at least get normal keys right most of the time?


That's kind of what I was thinking. Add to that a 20-questions thing to check which keyboard layout they're using, and you can probably uniquely detect almost every keyboard layout (minus custom, of course) in a couple keypresses.

But if you're going this far, you're probably significantly better off just letting people remap their shortcuts if it doesn't match what 95% of your users are using. The ones that care will love you for it, the ones that don't probably wouldn't have used it or been interested in 20-questions anyway.


"The truth is that you cannot do reasonable shortcut definition the way that everybody would like to with JS... yet."

couldn't agree more (learned the hard way), doing shortcuts with js is like translating your app into 50 different languages but only for half the keys - it creates a jumbled mess - best practice here is to never even do it.


How about single-letter shortcuts, like GitHub does? Press the ? key on GitHub to get the shortcut list. Some might not be as comfortable (e.g. / on a Swiss-German keyboard, as you say), but they'll still mostly work.


One small nitpick to your article: in Poland, QWERTY is the standard computer keyboard layout. QWERTZ used to be one in the old typewriters, but I haven't seen a single comp user with it.


pyalot's points are relevant for the consumer web, but for software as a service world I'd say not as much because you know more about your customers and can either guess their keyboard or simply ask them.


This is such nice work that I hesitate to bring up a minor point of coding style... But the use of names_with_underscores looks out of place in JavaScript.

JavaScript code traditionally uses PascalCaseNames for constructors and camelCaseNames for variables, properties, and methods. You do see UPPERCASE_NAMES_WITH_UNDERSCORES used sometimes for "constants", but that's about it.

Of course, names_with_underscores work just as well as any other names, and some people use them in their own JavaScript code, but I think libraries should follow the traditional native conventions of their language.

It would be like releasing a Ruby library that used camelCaseNames for its method names. It would work, but many Ruby developers would feel that those names were a bit out of place in a language where method names customarily use underscores.

Mentioning it here basically just as a reminder for other library developers: "When in Rome..."


I don't think the language gets to decide the coding style. Only the programmer gets to do that.

Especially if you program in multiple language it can be jarring to switch styles for each language.


I change keyboard layouts depending on (natural) language, though that's just personal preference.

I think that flexibility of style has been getting less and less favor recently : a lot of languages are starting to "force" some elements (such as indentation) , and go has done the most intelligent thing ever and ships with a formatter so that there's only 1 "right" way to write things.

Formatting issues is the source of so much bike-shedding, despite that it really shouldn't be much of a productivity sink in 99.9% of situations.


Sure, but a lot of languages are so closely related to their "standard library" that you adopt the style of the "standard library"

Take C# and the BCL. C# is a language but you'd be hard pressed to avoid using the BCL in any meaningful C# program.

    String.Format("Hello {0}", stringVariable);
All (nearly all?) the function names in the BCL are UpperCamelCase, and a lot of C# code follows that as a convention.

Repeat for class names, interfaces prefixed with I, public properties etc.


Python adopted a styleguide and I don't think I've seen any modern Python using camel case since. If anyone was to use camel case, they would be presumed to be a beginner.

http://www.python.org/dev/peps/pep-0008/


That's a good point, and I run into that problem myself. I prefer camelCaseNames over names_with_underscores in just about any language. When I write Ruby code for myself I sometimes use camelCaseNames just because I like them better.

But if I'm writing code for someone else I try to follow the language's conventions if possible. Especially if it's a library that will be combined with other libraries and application code that does follow native conventions.

After all, it's also jarring to write code in one language that has to use multiple styles because it integrates libraries that weren't consistent with the common language conventions.


I've seen both conventions; also in other languages, CSS class names ('-' vs '_' vs camelCase), e.g. anywhere a "name" is created to refer to something. Do try to not get hung up on it, it's mostly a matter of developer preference and you'll never get universal agreement unless the language itself enforces or excludes a particular convention.


XMLHttpRequest.


To be fair — introduced by microsoft.


Constructor, so is valid


Care to elaborate how you think a constructor validates it?


Tangentially, can someone on the W3C please fix the sorry state of key bindings across UAs?

Cross-browser idiosyncrasies are finally improving...except for webapp key bindings. Alt-F is taken in IE, Ctrl-whatever is taken in other UAs. Or an extension like (the awesome) vimium conflicts with some key bindings, so you have to disable it all together.

To the point where Asana uses tab as their short cut key. Tab! Wtf! "tab-p" for project. Bizarre!

But I guess I can't blame them, as I wouldn't be surprised if it's the only shortcut modifier that wasn't taken yet across all UAs.

I admittedly have no solutions to propose, so am just ranting about an understandably hard problem...but it would be nice if someone came along and fixed this. Please. :-)


I think that Asana's aren't actually tab and p, they're tab then p. Or at least that's true for all the ones I use. Given that, tab just takes focus out of whatever default / current text field the cursor is in, so 'p' is unambiguously a command and not a letter.


Isn't tab commonly bound to the meta key?

I don't personally do it, but its not unheard of ------


This looks like https://github.com/ccampbell/mousetrap I'm much more fond of the implicit syntax of mousetrap though.


I have referred people to Mousetrap in the past that don't have need of some of the more advanced features that Keypress offers. I wrote Keypress because there was nothing to support some of the more complex, game-specific things I wanted to do with keyboard combos.


Obligatory link to the fantastic http://unixpapa.com/js/key.html



additionally, good and concise http://www.javascripter.net/faq/keycodes.htm



Looks great. I was impressed that the keyboard visualization handled up to 7 simultaneous button pressed on my physical keyboard. Honestly, I wasn't aware my keyboard's wiring (MacBook Air) was capable of handling that.


It doesn't have to do with hardware, it's just client-side implementation. I had to write code for multiple key presses before. The browser will normally trigger a keydown and keyup event whenever something is pressed and released. The trick is to keep an array of keyCodes representing current keydowns; during keydowns add to array and during keyups, remove from array.


It is hardware related. USB has a maximum rollover limitation of 6 keys + 4 modifiers. Though keyboards can have n-key rollovers (i.e., greater than 10 keys simultaneously), you have to use PS/2.

See https://en.wikipedia.org/wiki/Rollover_(key)


I don't know the details, but it is possible for a USB keyboard to support N-key rollovers. As an example: http://www.corsair.com/en/support/faq/vengeance-gaming/


Do they require custom drivers? I see no reason you can't have all-key rollover with that, unless the OS refuses to do so.

Not that I'm saying you're wrong, I really don't know if normal driverless keyboard input is capable of this. I certainly hope so. I just see essentially all 10-key rollover (or more) keyboards using PS/2 and citing that it doesn't work through USB.


Looks neat, but how do you write a keyboard input library with sequence combos and then not have the Konami code as a secret demo?


Ha, fair point. I should get on that :)


Nice. This seems to solve a common problem for developers building rich UIs.

On a similar topic, does anybody have any pointers for implementing keystroke-by-keystroke character replacement in an INPUT box that doesn't suck? I'd like users to be able to enter "townhall" but have the input value be "TOWNHALL" and there doesn't seem to be a simple way to do this that doesn't fail when the user uses the arrow key or wants to insert more than one character in the middle of an input box.


It's a bit of a workaround, but one approach is to split the problem into two pieces: display and transmission. For display, you can avoid the cursor problems by using:

  text-transform: uppercase;
It's simple, the user experience remains natural, and there are no JavaScript dependencies. For the transmission phase, simply munge the actual entered content (which will not be all uppercase unless the user enters it as such) during the submit event. Of course you'll want to validate input on the server side as well.

Edit: clarity.


If you use this for hotkeys in your application make sure to return false or set e.handled to true or something like that. I don't remember the exact details right now.

Otherwise features from the browser like "incremental search" in firefox will get priority over the key captures in your app. In fact both your key capture and the incremental search will trigger which is very frustrating as the page starts scrolling to the first match of the letter you just typed.

But be very careful while doing this. Only do it for for your own hotkeys and make sure they are not used for other hotkeys in most common browsers! If you always swallow the keypress, normal hotkeys like ctrl+t for new tab will stop working for the user also.


I built a demo with some similarities 7 month ago (EDIT - that's not a plagiarism charge, the OPs submission predates mine and was created a year ago). https://gist.github.com/arnehormann/4163916 for the source and http://bl.ocks.org/arnehormann/raw/4163916/keycodes.html for the demo. The code is documented and includes a konami code and a mode switching example. It's set to a German Windows keyboard layout, but the code includes comments on how to change that.


I know the mess is in the OS-side but is there any chance we will have some day a DOM API independent of the keyboard layout?

For instance you want to make a game using WSAD keys, well in a french keyboard it's ZSQD... Also in a French keyboard, there some keys which trigger the same keycode so you cannot differenciate them! (I think it was the comma with something else)

If you want to make a software like Blender on the web which have a lot of key shortcuts you are a bit screwed!


My biggest issue is wanting to bind ctrl/meta-x/c/v to do what you think they would do in my UI (a graph editor), but not do anything in input fields. I can stopPropagation, but it is a pain to keep track of.


You can attach an event to the window or some other higher-level element and check if event.target is an input field... something along the lines of:

    document.body.addEventListener('keydown', function(e) {
      if (e.target.tagName !== 'INPUT') doKeyBindings();
    }, false);


This just looks like a development implementation of http://keycodes.atjayjo.com/


I see the potential for reading key presses when people are entering data into a form. I look forwarding to investigating this. Thank you!


iPad keyboard data entry firm that farms keypresses via HTTP to solve newly discovered cancer systems or other genetic puzzles.

At least give data enterers feedback, WPM, errors. Elderly can do data entry while on a walk to the park, and afford their peppermints.


Is it meant to work with all the keys? Chrome 29:

> Open page

> Don't touch anything

> Type

    this is a test
> Now you've moved down three times.


the spacebar makes the page scroll down


Yes, I have used a web browser before today.

It doesn't work unless you interact with elements on the page first, in which case the library catches space.

Hence my instruction not to touch anything on the page.


That doesn't seem to be the case for me. OS 10.8/Chrome 29.


pressing as many keys as possible makes me wonder how is wired my keyboard, I can get all 8 'asdf' and 'uiop' in down state, but not 'asdf' 'hjkl' nor 'qwer' 'hjkl' .. funny



Ooh, I could use this in a project I'm working on. Thanks!


Pause/break not working in Firefox 24.0 on Windows x64 8.


suggestion: add to console echo when pressed something in your demo


Looks great.


This will do to onscreen keyboards what Wordpress did to onscreen journals.




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

Search: