Gecko Keypress Event

Gecko 1.9 key handling changed significantly after Beta 5 (bug 359638, bug 429510 and the bugs on which they depend). The changes were risky so late in the release schedule, but they were necessary for fixing the many key handling bugs.

charCode of DOM keypress event

If a keypress event is fired without any modifier keys (Ctrl/Alt(Option)/Meta(Win/Command)), then the properties of the event are the same as they were in Gecko1.8.1. That is, when the currently selected keyboard layout produces a Unicode character (according to the current state of CapsLock and NumLock), the charCode property contains that character.

When the keypress event includes modifier keys, sometimes the charCode value is replaced with an ASCII character according to the following rules.

The accel key depends on the platform. Ctrl is the accel key on Windows and Linux, while Meta (i.e. Command) is the accel key on Mac.

When the accel key is down, the charCode of a keypress event may be replaced with a character from a Latin keyboard layout only when the original character is not an ASCII character.

This behavior helps the internationalization of web applications that have custom shortcut keys. If Gecko doesn't replace the charCode with an ASCII character, the web application developers would need to consider all non-Latin keyboard layouts (Arabic, Greek, Hebrew, Russian, etc.).

The charCode value depends on the state of CapsLock and NumLock (except they are currently ignored if Alt (Option) is down on Mac - see bug 432953). There are also some differences between the platforms, as described in the following sections.

Windows

The charCode is replaced only when Ctrl is down but Alt is not down.

If the OS-provided character cannot be entered without using the Ctrl key, then, Gecko does not replace the character. e.g., Ctrl+Shift+'2' on Persian keyboard layout inputs a ZWNJ, though Shift+'2' inputs '@', and so, if Gecko were to replace the charCode in this case, users would not be able to input ZWNJ (bug 414130).

Otherwise, Gecko can replace the charCode with an ASCII character. However, Gecko replaces the charCode only when the key pressed corresponds to a Latin letter (VK_A to VK_Z), numeral (VK_0 to VK_9), Plus sign (VK_OEM_PLUS), or Minus sign key (VK_OEM_MINUS).

Note that replacing the original (non-ASCII) characters on these keys means that there are some accessibility issues for non-Latin keyboard layout users as many non-ASCII characters will not be available for shortcuts. Therefore, web application developers should use only letters, ASCII numerals, plus sign, and minus sign for custom shortcut keys.

Linux

The charCode is replaced only when Ctrl is down but Alt and Meta are not down.

If the character provided by the keyboard layout cannot be entered without Ctrl key, then, Gecko does not replace the character (as on Windows).

Mac

The charCode is replaced when Meta (Command) or Ctrl is down.

If the current keyboard layout is Dvorak-QWERTY layout or a non-Latin layout, the Command key switches the keyboard layout to the US QWERTY keyboard layout temporary. Gecko uses the character from this keyboard layout for the Ctrl key also.

However, when Ctrl is down, Gecko 1.9 currenly only replaces the charCode only when the key corresponds to a basic Latin letter. This behavior is a bug, this behavior will be changed in a future major release (bug 432951).

Alternative charCodes for internal key handling

This section documents only Gecko internal keypress event handling, so Web application developers can ignore this section.

Gecko replaces the charCode of DOM keypress events for accelerator key handling, but that is not enough.

Problem 1

The Zoom-in shortcut handler in Firefox is defined as <key key="+" modifiers="accel"/>. However, the Shift key must be used to enter '+' on US keyboard layout, and so the state of the Shift key causes the modifiers not to match those specified in the handler.

For the US keyboard layout, a related handler is defined with <key key="=" modifiers="accel"/>, so that users do not need to use the Shift key to access the Zoom-in shortcut. Of course, this is not much help to users with other keyboard layouts. e.g., on a Japanese keyboard, '+' is entered with Shift+';' (bug 339723).

Problem 2

The access keys for the menu items are specified with the localized characters on some localized builds. These localized access keys work fine with the keyboard layout of the locale.

However, users with the same non-Latin keyboard layouts would also like to be able to use Latin access keys of en-US builds (including nightly builds) without needing to switch keyboard layout (bug 399939).

Problem 3

Users with non-Latin keyboard layouts would like to be able to use Latin access keys in web pages without switching to a Latin layout (bug 429510).

Problem 4

The Shift key must be down (with default preferences) to use accesskeys in web contents on Windows and Linux. This makes it impossible for users to distinguish between accesskeys using two different characters on the same key (when the Shift modifier is usually used to select one of the characters). The pairs of characters that might be on the same key depend on the keyboard layout.

(bug 359638 partially addressed this issue by trying both characters on the key, but bug 303192 would provide a complete solution.)

Solution

The following rules apply:

  • Key handlers should be provided with information about all the possible meanings of the event.
  • A handler on the innermost element should handle a key event even when the event does not match exactly and there is an outer element with a handler that does match exactly (bug 433192).
  • When handling web content accesskeys, the handlers should consider both characters that are available on the key (without and with Shift). The character that is normally entered without Shift is preferred. (Chrome accesskey, including menu accesskey, handling is currently similar, but this should not be relied on. There should be no chrome access keys with punctuation characters or other characters that would normally require depressing the Shift key.)
  • During accel key handling, if the event includes the Shift modifier, but an alternative charCode is not a bicameral letter (i.e., it does not have upper and lower case forms), then the Shift modifier state should be ignored if there is no exactly matching handler (requiring Shift to be down). (When Option (Alt) on Mac is down, the Alt modifier should be ignored in the same way, but this is not implemented in Gecko 1.9. See bug 306585).
  • During accel key handling, if the character is a bicameral letter, the Shift key should never be ignored. i.e., Ctrl+Shift+'C' should not execute Ctrl+'C' (bug 433192).
  • During accel key handling, when Shift is not down and the character without Shift is not a numeral but the character with Shift is a numeral, the key may be one of the numeral keys in the top row of a French AZERTY keyboard layout (or similar). Because numerals are common in short cuts, the numeral from the key should be considered as a low priority shortcut key candidate (bug 429219).

These conditions are complex, and the handling rules may be modified if new issues are discovered. XUL application developers should use key elements for handling accel keys, so as to make use of the handling logic already provided for these elements. XUL applications should not attempt to implement shortcuts by interpreting keypress events. Similarly, applications should use the accesskey attribute for access keys, rather than attempting to interpret keypress events.

In the unfortunately situation where XUL applications attempt to implement their own shortcut key handling, the decentralized implementation may need to be rewritten every time any of the above process is changed.

Implementation

The native keypress event records all the possible meanings of the key event in nsKeyEvent::alternativeCharCodes in nsGUIEvent.h. However, it should usually not be necessary to access these directly. It is better to use the logic already in nsContentUtils::GetAccelKeyCandidates() for accel key handling, and nsContentUtils::GetAccessKeyCandidates() for access key handling (See nsContentUtils.h and nsContentUtils.cpp).