11
votes

For a rich web application, I need keyboard shortcuts. Because there are many different keyboard layouts, they have to be configurable. Unfortunately, I can't figure out a way to map keyboard events to human-readable shortcut names such as Ctrl + Alt + Y or Alt + \.

The keypress event is useless since it doesn't fire for all keys. Here are some properties of keydown events:

  • charCode: Works only for printable characters. Deprecated, according to MDN
  • code: Works, but ignores the keyboard layout. When I press Z, I get code: "KeyY" on my German keyboard.
  • key: Works, but gives different results depending on modifiers. E. g. Shift+3 yields key: "§" on my keyboard and key: "#" on most US keyboards.
  • keyCode: The value is not unique. Ä, Ö, Ü or ^ yields keyCode: 0. Deprecated, according to MDN
  • which: Just like keyCode, the value is not unique. Deprecated, according to MDN
  • altKey, ctrlKey, metaKey, shiftKey: Useful for detecting modifier keys

How should I do this? Is it even possible without knowing the user's keyboard layout?

3
Does this library help you? github.com/ccampbell/mousetrapTarun Lalwani
Haven't tried it yet, but looks promising!Aloso
@TarunLalwani The plugin works, thanks!Aloso
Great will post it as answer after few hoursTarun Lalwani

3 Answers

3
votes

The thing is, at this point in time you can never know the keyboard layout from within the browser, you can only guess and speculate. There are various ways to try some kind of detection, but they are always complex and not out-of-the-box solutions.

However, there are some things which you can do to determine somehow what key has been pressed.

So Keydown will give you (say the event object is e):

e.code: Holds a string that identifies the physical key being pressed. The value is not affected by the current keyboard layout or modifier state, so a particular key will always return the same value. (from mozilla.org)

e.key: The key value of the key represented by the event. If the value has a printed representation, this attribute's value is the same as the char attribute.

e.which and e.keyCode: Although deprecated, will give you the position code of the key on the keyboard and if the e.charCode is 0, then this is either a position code (if < 256) or unicode (that means the keyboard is switched in another language)

Now the tricky part here is that e.key actually represents the unicode character if it is printable and is not from the US keyboard and is not a special key. You can convert this character into decimal number and check the value. If it is a unicode character, it's decimal value will be equal to the which and keyCode values. If it is and ordinary ASCII, it's lowercase value will be equal to the which and keyCode values. Also, before doing this (the conversion), you can check if e.key is a string (like Control, Alt, CapsLock, etc.) or a char (like a, b, c, etc.) So if it is a char, then you convert it.

All this will give you the idea which key has been pressed and what is the native printable character for this key. I don't have a German, Italian or some other keyboard to test, but you get the point.

Oh, and if you worry if Shift+3 yields "§" or "#", you should always represent that combination as Shift+3 no matter the character it yields, not to speak that the same will be produced with the combination of Ctrl+Shift+3. You have to worry only about the alphabetical characters, but I believe I gave you the means to check that.

Also, I believe that you may not need even the e.which and e.keyCode, because the e.key should give you everything.

2
votes

I think that your problem is not a problem but only an incorrect analyze of the problem and that you have already the answer !

You say that you want to define human readable shortcuts and you refuse key property because when user press Shift+3, key value is § and I think that you are waiting that key value is 3.

The question is "What is human readable ?".

Pressing § and obtaining § or the developper that say it is not normal that when he press § in pressing Shift+3, he obtains § and not Shift+3.

But if user presses § or Shift+3 (on your german keyboard), it is normal that key value is equal to § and you can use keydown event to intercept when user press only 3 or §.

On my french keyboard, I have a key é that is on same key as digit 2. If I press key é (or 2) I obtain 'é' character. If I press key Shift+2 (or Shift+é) I obtain a 2 character.

I can use keydown event to intercept Ctrl+é and Ctrl+2 (=Ctrlt+Shift+2) without problem.

I think that you can use keydown event to intercept §. Intercepting Shift+3 is impossible because shift+3 is equivalent to §.

If your goal is to intercept SHIFT+DIGIT key independently of keyboard layout, you can add some Javascript code to create some exceptions (or filter) for digit keys (but only digit keys), I think that it is not necessary for other keys.

In this case, you can consider keyCode properties to intercept pressing digit keys.

I all situations, trying to know the keyboard's layout is not necessary.

Currently, I work with french/french, french/belgian, french/swiss and american/american keyboard (or Tastatur) and I have encountered same problem in writing a C++ ActiveControl using MFC 20 year ago.

If my answer is not enough good for you, can you post some examples so I can help you for this specific new cases.

2
votes

Instead of re-inventing the wheel, I would rather use a cross browser library which already does that

https://github.com/ccampbell/mousetrap

I can't paste the complete JavaScript here to avoid a link only answer as the JS is over the limit if allowed characters.