16
votes

Quick background:

  • when a key is pressed in a browser, three events are generated: keyDown, keyPress and keyUp.
  • keyDown and keyUp have a keyCode property which is approximately the physical key pressed.
  • keyPress also has charCode property set which takes into account modifier keys and keyboard layout (A and a have same keyCode but a different charCode).
  • all three events have properties that indicate which modifier keys were pressed during those events.

I'm the main noVNC developer and I have a tough problem: noVNC needs the translated charCode value without using the keyPress event for the following reasons:

  • noVNC needs to send the keyDown and keyUp events separately to the VNC server (otherwise it's not a completely functional VNC client).
  • more importantly, noVNC needs to prevent the default keyboard actions while connected which means calling the preventDefault() method of the keyDown event. This has the side-effect of also preventing the keyPress event from firing.

Due to differences in keyboard layouts (i.e. different keyCode to charCode mappings) I've determine that noVNC will need a lookup table for different keyboard layouts.

But here is the real problem: on alternate layouts, some different physical keys have the SAME keyCode. For example, with an azerty (French) keyboard layout the '-' (dash) and '_' underscore keys both generate keyCode 189. Ack!!!

So ... how do I get proper keyCode to charCode mapping and prevent default browser actions at the same time?

BTW, I suspect the solution to this will be applicable to other interactive web applications and HTML5 games since you often want to be able to know full information about the key pressed without triggering any additional browser response to that keypress.

Useful links:

Solution: see my post below.

2

2 Answers

9
votes

I have solved my own question. It's not a 100% solution but it should cover most of what is needed. Hopefully there will be a cleaner solution when browser vendors start integrating DOM Level 3 Events.

Just to re-iterate the main constraints:

  1. The key down and key up events should be reported/sent at the time they actually happen. I.e. sending a key down and key up together during the keyPress event is insufficient.
  2. Many key combinations must be fully handled during the keyDown event either because they never trigger a keyPress event (i.e. Ctrl key) or because the default action must be stopped in keyDown (WebKit) and doing so prevents the keyPress event from happening.
  3. The key down and key events should report the translated character code and not keyCode value.

Without some out-of-the-box epiphany, the current browser implementations appear to prevent all three constraints from being fulfilled completely. So I have decided to relax constraint #3 just a bit.

  • On browser keyDown event add the event to a key down list and check to see if it is a safe (no undesirable browser default behavior) key combination:

    • Safe: do nothing until the keyPress.

    • Unsafe: report/send a key down event immediately. This is where constraint #3 is relaxed because these limited key combinations are not translated to a character code (many of them don't have them though anyways).

  • On browser keyPress event (which happens immediately after the keyDown event) check to see if it is a safe key combination:

    • Safe: report/send a key down event. Update the key down list using the translated character code (event.which).

    • Unsafe: do nothing since it was already reported/sent during keyDown.

  • On browser keyUp event, find and remove the matching event from the key down list and use the translated code to report/send the key up event.

Some additional links for those interesting:

3
votes

This is an absolute minefield and I would urge you not to attempt this if you can possibly avoid it. Not only is there a long and tangled history of browser manufacturers not agreeing on key event behaviour, there is also the fact that they still don't agree and are still regularly changing the key behaviour of their browsers.

The following is the best I can offer and the definitive resource on browser key events: http://unixpapa.com/js/key.html

If you have to do this, I think you're going to end up with loads of key code mapping tables that will go out of date very quickly. Good luck.