From b83076468da57e2fcaf18f2f21c20bc34a0aa077 Mon Sep 17 00:00:00 2001 From: Andreas Svensson Date: Wed, 30 Jul 2014 00:34:01 +0200 Subject: [PATCH] Improve normalization of charCode, fix FF not reporting Enter --- src/browser/eventPlugins/SimpleEventPlugin.js | 7 ++- .../syntheticEvents/SyntheticKeyboardEvent.js | 19 ++++--- src/browser/ui/dom/getEventCharCode.js | 57 +++++++++++++++++++ src/browser/ui/dom/getEventKey.js | 13 ++--- 4 files changed, 78 insertions(+), 18 deletions(-) create mode 100644 src/browser/ui/dom/getEventCharCode.js diff --git a/src/browser/eventPlugins/SimpleEventPlugin.js b/src/browser/eventPlugins/SimpleEventPlugin.js index ae9f08351e..311abbf8ac 100644 --- a/src/browser/eventPlugins/SimpleEventPlugin.js +++ b/src/browser/eventPlugins/SimpleEventPlugin.js @@ -31,6 +31,8 @@ var SyntheticTouchEvent = require('SyntheticTouchEvent'); var SyntheticUIEvent = require('SyntheticUIEvent'); var SyntheticWheelEvent = require('SyntheticWheelEvent'); +var getEventCharCode = require('getEventCharCode'); + var invariant = require('invariant'); var keyOf = require('keyOf'); @@ -343,8 +345,9 @@ var SimpleEventPlugin = { break; case topLevelTypes.topKeyPress: // FireFox creates a keypress event for function keys too. This removes - // the unwanted keypress events. - if (nativeEvent.charCode === 0) { + // the unwanted keypress events. Enter is however both printable and + // non-printable. One would expect Tab to be as well (but it isn't). + if (getEventCharCode(nativeEvent) === 0) { return null; } /* falls through */ diff --git a/src/browser/syntheticEvents/SyntheticKeyboardEvent.js b/src/browser/syntheticEvents/SyntheticKeyboardEvent.js index e4a4000c44..8f6f4bbd7c 100644 --- a/src/browser/syntheticEvents/SyntheticKeyboardEvent.js +++ b/src/browser/syntheticEvents/SyntheticKeyboardEvent.js @@ -21,6 +21,7 @@ var SyntheticUIEvent = require('SyntheticUIEvent'); +var getEventCharCode = require('getEventCharCode'); var getEventKey = require('getEventKey'); var getEventModifierState = require('getEventModifierState'); @@ -43,11 +44,10 @@ var KeyboardEventInterface = { // `charCode` is the result of a KeyPress event and represents the value of // the actual printable character. - // KeyPress is deprecated but its replacement is not yet final and not - // implemented in any major browser. + // KeyPress is deprecated, but its replacement is not yet final and not + // implemented in any major browser. Only KeyPress has charCode. if (event.type === 'keypress') { - // IE8 does not implement "charCode", but "keyCode" has the correct value. - return 'charCode' in event ? event.charCode : event.keyCode; + return getEventCharCode(event); } return 0; }, @@ -66,9 +66,14 @@ var KeyboardEventInterface = { }, which: function(event) { // `which` is an alias for either `keyCode` or `charCode` depending on the - // type of the event. There is no need to determine the type of the event - // as `keyCode` and `charCode` are either aliased or default to zero. - return event.keyCode || event.charCode; + // type of the event. + if (event.type === 'keypress') { + return getEventCharCode(event); + } + if (event.type === 'keydown' || event.type === 'keyup') { + return event.keyCode; + } + return 0; } }; diff --git a/src/browser/ui/dom/getEventCharCode.js b/src/browser/ui/dom/getEventCharCode.js new file mode 100644 index 0000000000..8a7c71078b --- /dev/null +++ b/src/browser/ui/dom/getEventCharCode.js @@ -0,0 +1,57 @@ +/** + * Copyright 2013-2014 Facebook, Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * @providesModule getEventCharCode + * @typechecks static-only + */ + +"use strict"; + +/** + * `charCode` represents the actual "character code" and is safe to use with + * `String.fromCharCode`. As such, only keys that correspond to printable + * characters produce a valid `charCode`, the only exception to this is Enter. + * The Tab-key is considered non-printable and does not have a `charCode`, + * presumably because it does not produce a tab-character in browsers. + * + * @param {object} nativeEvent Native browser event. + * @return {string} Normalized `charCode` property. + */ +function getEventCharCode(nativeEvent) { + var charCode; + var keyCode = nativeEvent.keyCode; + + if ('charCode' in nativeEvent) { + charCode = nativeEvent.charCode; + + // FF does not set `charCode` for the Enter-key, check against `keyCode`. + if (charCode === 0 && keyCode === 13) { + charCode = 13; + } + } else { + // IE8 does not implement `charCode`, but `keyCode` has the correct value. + charCode = keyCode; + } + + // Some non-printable keys are reported in `charCode`/`keyCode`, discard them. + // Must not discard the (non-)printable Enter-key. + if (charCode >= 32 || charCode === 13) { + return charCode; + } + + return 0; +} + +module.exports = getEventCharCode; diff --git a/src/browser/ui/dom/getEventKey.js b/src/browser/ui/dom/getEventKey.js index ab96ea2f6d..fafa315601 100644 --- a/src/browser/ui/dom/getEventKey.js +++ b/src/browser/ui/dom/getEventKey.js @@ -19,7 +19,7 @@ "use strict"; -var invariant = require('invariant'); +var getEventCharCode = require('getEventCharCode'); /** * Normalization of deprecated HTML5 `key` values @@ -41,7 +41,7 @@ var normalizeKey = { }; /** - * Translation from legacy `which`/`keyCode` to HTML5 `key` + * Translation from legacy `keyCode` to HTML5 `key` * Only special keys supported, all others depend on keyboard layout or browser * @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names */ @@ -93,11 +93,7 @@ function getEventKey(nativeEvent) { // Browser does not implement `key`, polyfill as much of it as we can. if (nativeEvent.type === 'keypress') { - // Create the character from the `charCode` ourselves and use as an almost - // perfect replacement. - var charCode = 'charCode' in nativeEvent ? - nativeEvent.charCode : - nativeEvent.keyCode; + var charCode = getEventCharCode(nativeEvent); // The enter-key is technically both printable and non-printable and can // thus be captured by `keypress`, no other non-printable key should. @@ -108,8 +104,7 @@ function getEventKey(nativeEvent) { // `keyCode` value, almost all function keys have a universal value. return translateToKey[nativeEvent.keyCode] || 'Unidentified'; } - - invariant(false, "Unexpected keyboard event type: %s", nativeEvent.type); + return ''; } module.exports = getEventKey;