01 November 2014

 

There is a problem with the world of the browser.  Browsers should present a unified environment to where it doesn’t matter a out the operating system you are using.  This is the ideal.  Whether using Windows, OS X, Ubuntu, or something else, markup, script, and style should behave the same way.  In general this is true, with a few gotchas here and there.  Sometimes Firefox for OS X does not behave the same as Firefox for Windows in some minor use cases you don’t hit very often.  In general, the story for cross-platform compatibility is pretty good.  Not perfect, but pretty good.  I have seen situations where a bug will surface on the OS X version of Firefox but not on Windows Firefox, but they are rare.  The story for cross-browser compatibility is not as good but still pretty good.

Though the story is generally good regarding cross-platform compatibility for a given browser, there is an exception.  That exception is keyboard events.  When trying to handle key presses, there are big differences that present problems when dealing with different browsers and the same browsers running on different operating systems.

keyboard-31230_640

The problems start with the competing keyboard schemes for different operating systems.  Windows has modifier keys Shift, Ctrl, Alt, and Windows.  Mac keyboards for OS X have modifier keys Shift, Control, Option, and Command.  You would think that with what these sets have in common, there would be a pretty good story for operating in a similar fashion.  You would think wrong.  Unfortunately, the situation is further confounded by the fact that the most common modifier key for meta-functions in Windows is Ctrl and in OS X, it’s Command.  This means that the Ctrl and Command keys are probably a more fitting mapping than Ctrl to Control.  This is unfortunate and has led to differences in how browsers interpret what should map to what.

When trying to handle key events in Javascript, one has to be aware that the browser application can execute in browsers on multiple operating systems.  Because most web applications consider very little about how to handle key events and force most of their users into inferior input options (mouse and touch), it often goes unnoticed that it is painful to try to deal with cross-platform keyboard concerns in browser applications.

Handlers registered for Javascript key events are passed an event object with properties exposing information about the key pressed as well as information about the state of the modifier keys available.  In theory, this is adequate to have a straightforward programming model for dealing with keyboard events.  It is trickier than that, though.

The properties regarding modifier keys on the keyboard event object are:

  • shiftKey
  • ctrlKey
  • altKey
  • metaKey

These are all Boolean properties reflecting whether the key in question was pressed at the time of the key event.

It would be beautiful if these would just operate the way you expect and map as such:

  Windows OS X
shiftKey Shift Shift

ctrlKey

Ctrl Command

altKey

Alt Alt

metaKey

Windows Control

 

Alas, this does not work as you would expect.  There are lots of gotchas and nuances of which you need to be aware.  It is alleged that the Windows key in Windows will trigger a true on the metaKey property, but this did not work in my testing.

 

Here is a fiddle I put together that demontrates what happens when you press keys in a browser with Javascript responding to keybaord events:

http://jsfiddle.net/raelyard/fjj8rfuv/

The results of what I have tested are as follows:

The shitKey property of the event works naturally and expected across browsers and there is nothing about which to worry here.  This property is true when the key is held during a key press and false otherwise.

The altKey property of the event is straightforward in that it is set to true when the alt key is held in Windows and the Option key in OS X.  This is as you would expect and is pretty natural.

The ctrlKey property of the event does indeed map to the ctrl key in Windows and the Control key in OS X as you would expect.  This is good and consistent, but is a bit of a problem in that OS X users expect to use the Command key in cases where Windows users would expect to use the ctrl key.  For instance, copying something in Windows is done with Ctrl+C and in OS X, with Command+C.  Going through a list of keyboard control in these two operating systems will show a thread of a majority of commands fitting this pattern.  This means that for this reason, web developers need to take into account different operating systems and respond to keyboard input differently.

The metaKey property does not seem to work at all on Windows, unless I am missing something.  Mozilla’s documentation indicates that this event should map to the Windows key on a Windows keyboard when using Windows, but that doesn’t seem to be the case for me.  In OS X, the story is pretty consistent in the browsers I have tested (Chrome, Firefox, and Safari) – the command key sets the meataKey property in the keypress and keydown events, but not in the keyup.  Be aware, developers, of the different behaviors of these properties in different events.

Also, it is not a problem of cross-platform compatibility, but one of cross-browser, but in different browsers, the actually codes for the key pressed (apart from the properties for modifier keys) can behave differently.  The good news is that for this, the browsers seem to be internally consistent across different operating systems.  The keyboard key event has properties called:

keyCode

charCode

which

These properties are treated in some ways the same and in some ways differently by the different browsers.  One thing that is the same in all the browsers is that what is done with these properties in the different key events is different.  In all my testing of browsers, charCode is always 0 (never set) in the keydown and keyup events.  charCode is intended to be a translation of the pressed key into the Unicode value representing the character of the key.  This does not always have meaning, as not all keys map to a character and across browsers, the attempt at this mapping is only made in the keypress event.  The value of the charCode when it is set is something that differes among browsers, so that will be addressed in a moment.  Also common among the browsers is that which and keyCode are set in the keydown and keyup events to the Unicode value corresponding to the key pressed without any regard to whether the shift key is pressed (case insensitive – the Unicode for the capital letter is used, given that the character is a letter – the Unicode for the number is used given that the character is one of the pairing of a number with a punctuation/special character on normal keybaords).

 

The differences in the setting of the properties really come from the fact that Firefox treats the properties in the keypress event differenly than other browsers.  On Windows, I tested Chrome, Firefox, Opera, Internet Explorer, and Safari.  On OS X, I tested Chrome, Firefox, and Safari.  In all of these, except for Firefox on both Operating Systems, in the keypress event which, keyCode, and charCode all have identical values on every keypress, and that value is the case-sensitive (translated according to whether the shift key is held) Unicode value of the character key pressed if the key corresponds to a character and the Unicode value of the key if it does not.  For Firefox on both Windows and OS X, the keycode is only set if the key is a non-character and the charCode is only set if the key is a character.  For example, the following table maps key presses to resulting Javascript events:

 

Key Event Firefox Others
a (just the A key) keypress which: 97; keyCode: 0; charCode: 97 which: 97; keyCode: 97; charCode: 97
  keydown which: 65; keyCode: 0; charCode: 65 which: 65; keyCode: 65; charCode: 65
  keyup which: 65; keyCode: 65; charCode: 0 which: 65; keyCode: 65; charCode: 0
A (Shift+A) keypress which: 65; keyCode: 0; charCode: 65 which: 65; keyCode: 65; charCode: 65
  keydown which: 65; keyCode: 65; charCode: 0 which: 65; keyCode: 65; charCode: 0
  keyup which: 65; keyCode: 65; charCode: 0 which: 65; keyCode: 65; charCode: 0
Enter keypress which: 13; keyCode: 13; charCode: 0 which: 13; keyCode: 13; charCode: 13
  keydown which: 13; keyCode: 13; charCode: 0 which: 13; keyCode: 13; charCode: 0
  keyup which: 13; keyCode: 13; charCode: 0 which: 13; keyCode: 13; charCode: 0


blog comments powered by Disqus