Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Even better normalization of KeyboardEvent + MouseEvent #776

Merged
merged 1 commit into from
May 5, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
7 changes: 5 additions & 2 deletions docs/docs/ref-05-events.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,9 @@ Properties:

```javascript
boolean altKey
boolean ctrlKey
Number charCode
boolean ctrlKey
function getModifierState(key)
String key
Number keyCode
String locale
Expand Down Expand Up @@ -120,6 +121,7 @@ Number buttons
Number clientX
Number clientY
boolean ctrlKey
function getModifierState(key)
boolean metaKey
Number pageX
Number pageY
Expand Down Expand Up @@ -147,6 +149,7 @@ Properties:
boolean altKey
DOMTouchList changedTouches
boolean ctrlKey
function getModifierState(key)
boolean metaKey
boolean shiftKey
DOMTouchList targetTouches
Expand Down Expand Up @@ -181,8 +184,8 @@ onWheel
Properties:

```javascript
Number deltaX
Number deltaMode
Number deltaX
Number deltaY
Number deltaZ
```
8 changes: 7 additions & 1 deletion src/browser/eventPlugins/SimpleEventPlugin.js
Original file line number Diff line number Diff line change
Expand Up @@ -341,8 +341,14 @@ var SimpleEventPlugin = {
// @see http://www.w3.org/TR/html5/index.html#events-0
EventConstructor = SyntheticEvent;
break;
case topLevelTypes.topKeyDown:
case topLevelTypes.topKeyPress:
// FireFox creates a keypress event for function keys too. This removes
// the unwanted keypress events.
if (nativeEvent.charCode === 0) {
return null;
}
/* falls through */
case topLevelTypes.topKeyDown:
case topLevelTypes.topKeyUp:
EventConstructor = SyntheticKeyboardEvent;
break;
Expand Down
37 changes: 33 additions & 4 deletions src/browser/syntheticEvents/SyntheticKeyboardEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
var SyntheticUIEvent = require('SyntheticUIEvent');

var getEventKey = require('getEventKey');
var getEventModifierState = require('getEventModifierState');

/**
* @interface KeyboardEvent
Expand All @@ -36,11 +37,39 @@ var KeyboardEventInterface = {
metaKey: null,
repeat: null,
locale: null,
getModifierState: getEventModifierState,
// Legacy Interface
'char': null,
charCode: null,
keyCode: null,
which: null
charCode: function(event) {
// `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.
if (event.type === 'keypress') {
// IE8 does not implement "charCode", but "keyCode" has the correct value.
return 'charCode' in event ? event.charCode : event.keyCode;
}
return 0;
},
keyCode: function(event) {
// `keyCode` is the result of a KeyDown/Up event and represents the value of
// physical keyboard key.

// The actual meaning of the value depends on the users' keyboard layout
// which cannot be detected. Assuming that it is a US keyboard layout
// provides a surprisingly accurate mapping for US and European users.
// Due to this, it is left to the user to implement at this time.
if (event.type === 'keydown' || event.type === 'keyup') {
return event.keyCode;
}
return 0;
},
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;
}
};

/**
Expand Down
3 changes: 3 additions & 0 deletions src/browser/syntheticEvents/SyntheticMouseEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
var SyntheticUIEvent = require('SyntheticUIEvent');
var ViewportMetrics = require('ViewportMetrics');

var getEventModifierState = require('getEventModifierState');

/**
* @interface MouseEvent
* @see http://www.w3.org/TR/DOM-Level-3-Events/
Expand All @@ -35,6 +37,7 @@ var MouseEventInterface = {
shiftKey: null,
altKey: null,
metaKey: null,
getEventModifierState: getEventModifierState,
button: function(event) {
// Webkit, Firefox, IE9+
// which: 1 2 3
Expand Down
5 changes: 4 additions & 1 deletion src/browser/syntheticEvents/SyntheticTouchEvent.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@

var SyntheticUIEvent = require('SyntheticUIEvent');

var getEventModifierState = require('getEventModifierState');

/**
* @interface TouchEvent
* @see http://www.w3.org/TR/touch-events/
Expand All @@ -32,7 +34,8 @@ var TouchEventInterface = {
altKey: null,
metaKey: null,
ctrlKey: null,
shiftKey: null
shiftKey: null,
getModifierState: getEventModifierState
};

/**
Expand Down
40 changes: 35 additions & 5 deletions src/browser/ui/dom/getEventKey.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,10 @@

"use strict";

var invariant = require('invariant');

/**
* Normalization of deprecated HTML5 "key" values
* Normalization of deprecated HTML5 `key` values
* @see https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent#Key_names
*/
var normalizeKey = {
Expand All @@ -39,7 +41,7 @@ var normalizeKey = {
};

/**
* Translation from legacy "which/keyCode" to HTML5 "key"
* Translation from legacy `which`/`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
*/
Expand Down Expand Up @@ -77,9 +79,37 @@ var translateToKey = {
* @return {string} Normalized `key` property.
*/
function getEventKey(nativeEvent) {
return 'key' in nativeEvent ?
normalizeKey[nativeEvent.key] || nativeEvent.key :
translateToKey[nativeEvent.which || nativeEvent.keyCode] || 'Unidentified';
if (nativeEvent.key) {
// Normalize inconsistent values reported by browsers due to
// implementations of a working draft specification.

// FireFox implements `key` but returns `MozPrintableKey` for all
// printable characters (normalized to `Unidentified`), ignore it.
var key = normalizeKey[nativeEvent.key] || nativeEvent.key;
if (key !== 'Unidentified') {
return key;
}
}

// 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;

// The enter-key is technically both printable and non-printable and can
// thus be captured by `keypress`, no other non-printable key should.
return charCode === 13 ? 'Enter' : String.fromCharCode(charCode);
}
if (nativeEvent.type === 'keydown' || nativeEvent.type === 'keyup') {
// While user keyboard layout determines the actual meaning of each
// `keyCode` value, almost all function keys have a universal value.
return translateToKey[nativeEvent.keyCode] || 'Unidentified';
}

invariant(false, "Unexpected keyboard event type: %s", nativeEvent.type);
}

module.exports = getEventKey;
44 changes: 44 additions & 0 deletions src/browser/ui/dom/getEventModifierState.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/**
* Copyright 2013 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 getEventModifierState
* @typechecks static-only
*/

"use strict";

/**
* Translation from modifier key to the associated property in the event.
* @see http://www.w3.org/TR/DOM-Level-3-Events/#keys-Modifiers
*/

var modifierKeyToProp = {
'alt': 'altKey',
'control': 'ctrlKey',
'meta': 'metaKey',
'shift': 'shiftKey'
};

function getEventModifierState(nativeEvent) {
// IE8 does not implement getModifierState so we simply map it to the only
// modifier keys exposed by the event itself, does not support Lock-keys.
// Currently, all major browsers except Chrome seems to support Lock-keys.
return nativeEvent.getModifierState || function(keyArg) {
var keyProp = modifierKeyToProp[keyArg.toLowerCase()];
return keyProp && nativeEvent[keyProp];
};
}

module.exports = getEventModifierState;