From 8df39e13e839f7fd51a150b1cd664fdb788554b1 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 14 May 2020 15:03:55 -0700 Subject: [PATCH 01/23] Update RCTCxxBridge.mm --- .../React/CxxBridge/RCTCxxBridge.mm | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/android-patches/patches-droid-office-grouped/OfficeRNHost/React/CxxBridge/RCTCxxBridge.mm b/android-patches/patches-droid-office-grouped/OfficeRNHost/React/CxxBridge/RCTCxxBridge.mm index 27800d7121bd0a..a38b4d84477734 100644 --- a/android-patches/patches-droid-office-grouped/OfficeRNHost/React/CxxBridge/RCTCxxBridge.mm +++ b/android-patches/patches-droid-office-grouped/OfficeRNHost/React/CxxBridge/RCTCxxBridge.mm @@ -1,10 +1,10 @@ ---- "e:\\github\\fb-react-native-forpatch-base\\React\\CxxBridge\\RCTCxxBridge.mm" 2020-01-30 13:55:48.476581100 -0800 -+++ "e:\\github\\ms-react-native-forpatch\\React\\CxxBridge\\RCTCxxBridge.mm" 2020-02-14 10:59:16.805390300 -0800 -@@ -596,6 +596,7 @@ - // This is async, but any calls into JS are blocked by the m_syncReady CV in Instance - _reactInstance->initializeBridge( - std::make_unique(self), -+ nullptr, // Use default executor delegate - executorFactory, - _jsMessageThread, - [self _buildModuleRegistryUnlocked]); +--- "e:\\github\\fb-react-native-forpatch-base\\React\\CxxBridge\\RCTCxxBridge.mm" 2020-01-30 13:55:48.476581100 -0800 ++++ "e:\\github\\ms-react-native-forpatch\\React\\CxxBridge\\RCTCxxBridge.mm" 2020-02-14 10:59:16.805390300 -0800 +@@ -596,6 +596,7 @@ + // This is async, but any calls into JS are blocked by the m_syncReady CV in Instance + _reactInstance->initializeBridge( + std::make_unique(self), ++ nullptr, // Use default executor delegate + executorFactory, + _jsMessageThread, + [self _buildModuleRegistryUnlocked]); From 136032af66296057ff9eeec3503e0df40563d613 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 26 Nov 2020 00:12:59 -0800 Subject: [PATCH 02/23] macOS keyboard support --- Libraries/Components/Button.js | 17 ++- .../Components/Touchable/TouchableOpacity.js | 12 +++ .../Touchable/TouchableWithoutFeedback.js | 7 ++ .../View/ReactNativeViewAttributes.js | 2 + .../View/ReactNativeViewViewConfig.js | 12 +++ .../View/ReactNativeViewViewConfigMacOS.js | 2 + Libraries/Components/View/ViewPropTypes.js | 3 + Libraries/Pressability/Pressability.js | 22 ++++ Libraries/Renderer/shims/ReactNativeTypes.js | 2 + Libraries/Types/CoreEventTypes.js | 7 ++ RNTester/Podfile.lock | 58 +++++----- .../KeyboardEventsExample.js | 100 ++++++++++++++++++ RNTester/js/utils/RNTesterList.ios.js | 5 + React/Base/RCTEventDispatcher.m | 2 +- React/Views/RCTView.h | 4 + React/Views/RCTView.m | 25 +++++ React/Views/RCTViewKeyboardEvent.h | 14 +++ React/Views/RCTViewKeyboardEvent.m | 29 +++++ React/Views/RCTViewManager.m | 4 + 19 files changed, 296 insertions(+), 31 deletions(-) create mode 100644 RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js create mode 100644 React/Views/RCTViewKeyboardEvent.h create mode 100644 React/Views/RCTViewKeyboardEvent.m diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index 73d32d1285fab0..ac676119288bf9 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -20,7 +20,7 @@ const View = require('./View/View'); const invariant = require('invariant'); -import type {PressEvent} from '../Types/CoreEventTypes'; +import type {PressEvent, KeyEvent} from '../Types/CoreEventTypes'; import type {FocusEvent, BlurEvent} from './TextInput/TextInput'; // TODO(OSS Candidate ISS#2710739) import type {ColorValue} from '../StyleSheet/StyleSheetTypes'; @@ -113,6 +113,17 @@ type ButtonProps = $ReadOnly<{| * Handler to be called when the button loses key focus */ onFocus?: ?(e: FocusEvent) => void, + + /** + * Handler to be called when a key down press is detected + */ + onKeyDown?: ?(e: KeyEvent) => void, + + /** + * Handler to be called when a key up press is detected + */ + onKeyUp?: ?(e: KeyEvent) => void, + // ]TODO(OSS Candidate ISS#2710739) |}>; @@ -163,6 +174,8 @@ class Button extends React.Component { testID, onFocus, // TODO(OSS Candidate ISS#2710739) onBlur, // TODO(OSS Candidate ISS#2710739) + onKeyDown, + onKeyUp, } = this.props; const buttonStyles = [styles.button]; const textStyles = [styles.text]; @@ -207,6 +220,8 @@ class Button extends React.Component { onPress={onPress} onFocus={onFocus} // TODO(OSS Candidate ISS#2710739) onBlur={onBlur} // TODO(OSS Candidate ISS#2710739) + onKeyDown={onKeyDown} + onKeyUp={onKeyUp} touchSoundDisabled={touchSoundDisabled}> diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index a49c69bcb7de21..56f1a72f14b88b 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -165,6 +165,16 @@ class TouchableOpacity extends React.Component { this.props.onFocus(event); } }, + onKeyDown: event => { + if (this.props.onKeyDown != null) { + this.props.onKeyDown(event); + } + }, + onKeyUp: event => { + if (this.props.onKeyUp != null) { + this.props.onKeyUp(event); + } + }, onLongPress: this.props.onLongPress, onPress: this.props.onPress, onPressIn: event => { @@ -268,6 +278,8 @@ class TouchableOpacity extends React.Component { onDrop={this.props.onDrop} onFocus={this.props.onFocus} onBlur={this.props.onBlur} + onKeyDown={this.props.onKeyDown} + onKeyUp={this.props.onKeyUp} draggedTypes={this.props.draggedTypes} // ]TODO(macOS ISS#2323203) ref={this.props.hostRef} {...eventHandlersWithoutBlurAndFocus}> diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index f907632447a2dc..2e415744eeca11 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -26,6 +26,7 @@ import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; import type { BlurEvent, FocusEvent, + KeyEvent, LayoutEvent, PressEvent, MouseEvent, // TODO(macOS ISS#2323203) @@ -64,6 +65,8 @@ type Props = $ReadOnly<{| onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed, onBlur?: ?(event: BlurEvent) => mixed, onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + onKeyUp?: ?(event: KeyEvent) => mixed, onLayout?: ?(event: LayoutEvent) => mixed, onLongPress?: ?(event: PressEvent) => mixed, onPress?: ?(event: PressEvent) => mixed, @@ -105,6 +108,8 @@ const PASSTHROUGH_PROPS = [ 'onAccessibilityAction', 'onBlur', 'onFocus', + 'onKeyDown', + 'onKeyUp', 'onLayout', 'onMouseEnter', // [TODO(macOS ISS#2323203) 'onMouseLeave', @@ -213,6 +218,8 @@ function createPressabilityConfig(props: Props): PressabilityConfig { android_disableSound: props.touchSoundDisabled, onBlur: props.onBlur, onFocus: props.onFocus, + onKeyDown: props.onKeyDown, + onKeyUp: props.onKeyUp, onLongPress: props.onLongPress, onPress: props.onPress, onPressIn: props.onPressIn, diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index bf264eabb4fb2a..f1ab35ade2a8e1 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -41,6 +41,8 @@ const UIView = { onDragEnter: true, onDragLeave: true, onDrop: true, + onKeyDown: true, + onKeyUp: true, draggedTypes: true, // ]TODO(macOS ISS#2323203) style: ReactNativeStyleAttributes, }; diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 8858f62d5b0be4..25175748e7568c 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -45,6 +45,18 @@ const ReactNativeViewConfig = { captured: 'onFocusCapture', }, }, + topKeyUp: { + phasedRegistrationNames: { + bubbled: 'onKeyUp', + captured: 'onKeyUpCapture', + }, + }, + topKeyDown: { + phasedRegistrationNames: { + bubbled: 'onKeyDown', + captured: 'onKeyDownCapture', + }, + }, topKeyPress: { phasedRegistrationNames: { bubbled: 'onKeyPress', diff --git a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js index 4aa28a0a45939e..35d174ba1ac41e 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js +++ b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js @@ -46,6 +46,8 @@ const ReactNativeViewViewConfigMacOS = { onDragLeave: true, onDrop: true, onFocus: true, + onKeyDown: true, + onKeyUp: true, onMouseEnter: true, onMouseLeave: true, tooltip: true, diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 395901478ae312..589ce39dc29560 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -18,6 +18,7 @@ import type { Layout, LayoutEvent, ScrollEvent, // TODO(macOS ISS#2323203) + KeyEvent, } from '../../Types/CoreEventTypes'; import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; import type {Node} from 'react'; @@ -41,6 +42,8 @@ export type ViewLayoutEvent = LayoutEvent; type BubblingEventProps = $ReadOnly<{| onBlur?: ?(event: BlurEvent) => mixed, onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + onKeyUp?: ?(event: KeyEvent) => mixed, |}>; type DirectEventProps = $ReadOnly<{| diff --git a/Libraries/Pressability/Pressability.js b/Libraries/Pressability/Pressability.js index f02c7339bbcca9..65d6607b221b0d 100644 --- a/Libraries/Pressability/Pressability.js +++ b/Libraries/Pressability/Pressability.js @@ -17,6 +17,7 @@ import {normalizeRect, type RectOrSize} from '../StyleSheet/Rect'; import type { BlurEvent, FocusEvent, + KeyEvent, PressEvent, MouseEvent, } from '../Types/CoreEventTypes'; @@ -93,6 +94,10 @@ export type PressabilityConfig = $ReadOnly<{| */ onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + + onKeyUp?: ?(event: KeyEvent) => mixed, + /** * Called when the hover is activated to provide visual feedback. */ @@ -156,6 +161,8 @@ export type EventHandlers = $ReadOnly<{| onBlur: (event: BlurEvent) => void, onClick: (event: PressEvent) => void, onFocus: (event: FocusEvent) => void, + onKeyDown: (event: KeyDown) => void, + onKeyUp: (event: KeyDown) => void, onMouseEnter?: (event: MouseEvent) => void, onMouseLeave?: (event: MouseEvent) => void, onResponderGrant: (event: PressEvent) => void, @@ -445,6 +452,21 @@ export default class Pressability { } }, }; + + const keyEventHandlers = { + onKeyDown: (event: KeyEvent): void => { + const {onKeyDown} = this._config; + if (onKeyDown != null) { + onKeyDown(event); + } + }, + onKeyUp: (event: KeyEvent): void => { + const {onKeyUp} = this._config; + if (onKeyUp != null) { + onKeyUp(event); + } + }, + }; const responderEventHandlers = { onStartShouldSetResponder: (): boolean => { diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index 10244570b65354..ec68139ab57208 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -80,6 +80,8 @@ export type ViewConfigGetter = () => ReactNativeBaseComponentViewConfig<>; export type NativeMethods = { blur(): void, focus(): void, + onKeyDown(): void, + onKeyUp(): void, measure(callback: MeasureOnSuccessCallback): void, measureInWindow(callback: MeasureInWindowOnSuccessCallback): void, measureLayout( diff --git a/Libraries/Types/CoreEventTypes.js b/Libraries/Types/CoreEventTypes.js index 065657395ef739..635548643bf574 100644 --- a/Libraries/Types/CoreEventTypes.js +++ b/Libraries/Types/CoreEventTypes.js @@ -152,6 +152,13 @@ export type FocusEvent = SyntheticEvent< |}>, >; +export type KeyEvent = SyntheticEvent< + $ReadOnly<{| + characters: string, + modifier: number, + |}>, +>; + export type MouseEvent = SyntheticEvent< $ReadOnly<{| clientX: number, diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index 9b0f823da65df7..a895cca6ab9299 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -431,7 +431,7 @@ DEPENDENCIES: - Yoga (from `../ReactCommon/yoga`) SPEC REPOS: - https://cdn.cocoapods.org/: + trunk: - CocoaAsyncSocket - CocoaLibEvent - Flipper @@ -519,8 +519,8 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: e99626a767684cd45377cfb2d270260b08612394 - FBReactNativeSpec: 4caa8b770647aad3624a57c46871bf01c1e1ef59 + FBLazyVector: 058eeb6417ef70b3b8949d2b4ea1588033186266 + FBReactNativeSpec: 9b1b4c1fa7ba24ffa7712799e2cbb602b97eda5d Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 @@ -533,34 +533,34 @@ SPEC CHECKSUMS: libevent: ee9265726a1fc599dea382964fa304378affaa5f OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: 7803a0a3a3d56e3cec84ae1ccbe0f4a2476f9f69 - RCTTypeSafety: ae513041fa8773699d99833a8691d2e8b8d6ee8a - React: d6306405782c4669fd3d4d0125a7b2cc2bb19233 - React-ART: 65684f957e38c119918b2ad8e2f2c386790b20d0 - React-callinvoker: edc229ccab488b3b57895e830d2b825e79f9f04c - React-Core: 50805a8b5eb817533763ae0132a0a61fc740fddf - React-CoreModules: 3147038a51e5a1a1819be556efb3c22855816aec - React-cxxreact: 88f9c5fbd0c391488fb884ab4bf8af85c548230c - React-jsi: e7b3496404f24299beb067b0e4fa38e836f1d6a4 - React-jsiexecutor: f214cb9bebf408f6deeea9f6fe6ca610ab88eb6e - React-jsinspector: 7fba9bc98d5047bf5c8dae0cd8acd36b86448d04 - React-RCTActionSheet: c4b92af34b6f64c786a972f5c196a375b7ce6cea - React-RCTAnimation: 5a0f7f7b3eaf0520e53d119f8352fdc622d0a90b - React-RCTBlob: 37befa1be701fe18ab0d63eb986b65829c843fc6 - React-RCTImage: a02ff4f1882f35574ae589556b5c94b9eee973da - React-RCTLinking: 70240d29450241879339d7384b0903232d30e2c6 - React-RCTNetwork: 17a1cd202a4566c25244444644a1fadd092466db - React-RCTPushNotification: eec1e289dfb203ee5360a9065c4009de0c16e097 - React-RCTSettings: 490435d0c7767d085ebc9218d6cc9f9e2018ff1c - React-RCTTest: 06e4d480573015d42b0acb110aeb343c16d0c595 - React-RCTText: a2a64b9c882d9b9a8e26c27773ca305ce910f4a6 - React-RCTVibration: d32b07b6c9e821cb784b04e1c65cee3b35099b54 + RCTRequired: ec85d1ef4d51803337cde71de052e3db103d6472 + RCTTypeSafety: a4430a19dff2b11c1c0521ddd9e90b0c033217b4 + React: 58c48d390d9c13c7e28ee4832d59a931e26d4a5c + React-ART: d6002339cd61232b4b6b64abc4c519f22c5a53b4 + React-callinvoker: ad1904b8c01625a218e541417c1f2269912eba6b + React-Core: d66de0613ce7984076226eaed78f75c6c46bf91c + React-CoreModules: 4be0efeb5b0434beae09740b7672d9c718856e78 + React-cxxreact: 8386895677c64406ab269a2390f1bd7a9416a698 + React-jsi: fcd89cccc1a8d1fea9a6a3b85645781a12daf712 + React-jsiexecutor: 1c8f0bf5110a999922389d8d71f99d6ee942dcd8 + React-jsinspector: 6dcbf0c485a9cefa3e3bf87dc3aa9f2ecea1a5dd + React-RCTActionSheet: 66b3b31c0566bab2e90b198c893432b4e8ac1883 + React-RCTAnimation: 42fee356deb87bf0f351836625dcc40e610000cd + React-RCTBlob: b3a07d1b087bc30d9a70e5f6aad3828531d03c67 + React-RCTImage: 50b248b2a61a4eba7a7c86de6f0ae1cb0b70c25d + React-RCTLinking: 2d5c14d4f96faa81c04e4754db0c7b05ea35de3e + React-RCTNetwork: 2707c0d37396d1f8876bc74eaa8e7374a8be788a + React-RCTPushNotification: 05efdc2e49aaa39c9a087d75d3d54fef2b8a9554 + React-RCTSettings: 230c589aabbcb4f04212ea17a7afdbf2b21d716d + React-RCTTest: 56492ab0dec8652ecf7bd33bcefc1494a759470b + React-RCTText: 07ea13069c32f7c8c13deb374c00ddfd641dd925 + React-RCTVibration: e71fbb228d655d109bc069bb3a50809761a078a8 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: cbe13444db8dc3af024947610c537a27cea1c1cb - ReactCommon: d849f99f384dafff03d56ac7e9fd173e117b1509 - Yoga: 5ba9af3554885e152355679790ed9be0b1d01695 + React-TurboModuleCxx-WinRTPort: 6c285289e9266a7e316cb87f44396469e23dba9b + ReactCommon: 378cffdae03f1a712467fa43af195df1f79080b3 + Yoga: c3920c26a6383607e1776e35919aca16bbbf1991 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 -COCOAPODS: 1.8.4 +COCOAPODS: 1.9.1 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js new file mode 100644 index 00000000000000..48d3250cc7ca43 --- /dev/null +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; // TODO(OSS Candidate ISS#2710739) + +const React = require('react'); +const ReactNative = require('react-native'); +import {Platform} from 'react-native'; +const {Button, PlatformColor, StyleSheet, Text, View } = ReactNative; + +import { KeyEvent } from 'react-native/Libraries/Types/CoreEventTypes'; + +class KeyEventExample extends React.Component<{}, State> { + state: State = { + eventStream: '', + characters: '', + }; + + onKeyDownEvent: (e: KeyEvent) => void = (e: KeyEvent) => { + console.log('received view key down event\n', e.nativeEvent['characters']); + this.setState({characters: e.nativeEvent.characters}) + this.setState(prevState => ({ + eventStream: prevState.eventStream + prevState.characters + '\nKey Down: ' + })); + }; + + onKeyUpEvent: (e: KeyEvent) => void = (e: KeyEvent) => { + console.log('received key up event\n', e.nativeEvent['characters']); + this.setState({characters: e.nativeEvent.characters}) + this.setState(prevState => ({ + eventStream: prevState.eventStream + prevState.characters + '\nKey Up: ' + })); + }; + + render() { + return ( + + + Key events are called when a component detects a key press. + + + {// Only test View on MacOS, since canBecomeFirstResponder is false on all iOS, therefore we can't focus + Platform.OS === 'macos' ? ( + + + + ) : null} + {'Events: ' + this.state.eventStream + JSON.stringify(this.state.characters) + '\n\n'} + + + ); + } +} + +var styles = StyleSheet.create({ + textInput: { + ...Platform.select({ + macos: { + color: PlatformColor('textColor'), + backgroundColor: PlatformColor('textBackgroundColor'), + borderColor: PlatformColor('gridColor'), + }, + default: { + borderColor: '#0f0f0f', + }, + }), + borderWidth: StyleSheet.hairlineWidth, + flex: 1, + fontSize: 13, + padding: 4, + }, +}); + +exports.title = 'Key Events'; +exports.description = 'Examples that show how Key events can be used.'; +exports.examples = [ + { + title: 'KeyEventExample', + render: function(): React.Element { + return ; + }, + }, +]; diff --git a/RNTester/js/utils/RNTesterList.ios.js b/RNTester/js/utils/RNTesterList.ios.js index 9ab6663e51b980..75f2389372a09a 100644 --- a/RNTester/js/utils/RNTesterList.ios.js +++ b/RNTester/js/utils/RNTesterList.ios.js @@ -51,6 +51,11 @@ const ComponentExamples: Array = [ module: require('../examples/FocusEventsExample/FocusEventsExample'), supportsTVOS: true, }, // ]TODO(OSS Candidate ISS#2710739) + { + key: 'KeyboardEvents', + module: require('../examples/KeyboardEventsExample/KeyboardEventsExample'), + supportsTVOS: false, + }, // ]TODO(OSS Candidate ISS#2710739) { key: 'ImageExample', module: require('../examples/Image/ImageExample'), diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m index 3da2e268ed72ba..5903834e824acf 100644 --- a/React/Base/RCTEventDispatcher.m +++ b/React/Base/RCTEventDispatcher.m @@ -84,7 +84,7 @@ - (void)sendTextEventWithType:(RCTTextEventType)type key:(NSString *)key eventCount:(NSInteger)eventCount { - static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress"}; + static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress", @"keyDown", @"keyUp"}; NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:@{ @"eventCount" : @(eventCount), diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index b0800d9e1e1169..78f83974d0179d 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -135,6 +135,10 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, copy) RCTDirectEventBlock onDragEnter; @property (nonatomic, copy) RCTDirectEventBlock onDragLeave; @property (nonatomic, copy) RCTDirectEventBlock onDrop; + +// Keyboarding events +@property (nonatomic, copy) RCTBubblingEventBlock onKeyDown; +@property (nonatomic, copy) RCTBubblingEventBlock onKeyUp; #endif // ]TODO(macOS ISS#2323203) /** diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 9ce2af8beff570..5f40720296bb96 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -16,6 +16,7 @@ #import "RCTRootContentView.h" // TODO(macOS ISS#2323203) #import "RCTUtils.h" #import "UIView+React.h" +#import "RCTViewKeyboardEvent.h" #if TARGET_OS_OSX // [TODO(macOS ISS#2323203) #import "RCTTextView.h" #endif // ]TODO(macOS ISS#2323203) @@ -1563,4 +1564,28 @@ - (BOOL)performDragOperation:(id )sender } #endif // ]TODO(macOS ISS#2323203) +#pragma mark - Keyboard Events + +#if TARGET_OS_OSX // TODO: add iOS keyboard event handling +- (void)keyDown:(NSEvent *)event { + if (!self.onKeyDown) { + [super keyDown:event]; + return; + } + + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; +} + +- (void)keyUp:(NSEvent *)event { + if (!self.onKeyUp) { + [super keyUp:event]; + return; + } + + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; +} +#endif // TARGET_OS_OSX + @end diff --git a/React/Views/RCTViewKeyboardEvent.h b/React/Views/RCTViewKeyboardEvent.h new file mode 100644 index 00000000000000..4bcbcfe10796ce --- /dev/null +++ b/React/Views/RCTViewKeyboardEvent.h @@ -0,0 +1,14 @@ +/* + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import + +@interface RCTViewKeyboardEvent : RCTComponentEvent + ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; + +@end diff --git a/React/Views/RCTViewKeyboardEvent.m b/React/Views/RCTViewKeyboardEvent.m new file mode 100644 index 00000000000000..17fc2e6e0b608e --- /dev/null +++ b/React/Views/RCTViewKeyboardEvent.m @@ -0,0 +1,29 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTViewKeyboardEvent.h" +#import + +@implementation RCTViewKeyboardEvent + ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { + RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyDown" + viewTag:reactTag + body:@{ @"characters" : characters, + @"modifier" : @(modifier) }]; + return event; +} + ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { + RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyUp" + viewTag:reactTag + body:@{ @"characters" : characters, + @"modifier" : @(modifier) }]; + return event; +} + +@end diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 79e4709a0d678c..d0d599fe5cf78e 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -112,6 +112,8 @@ - (RCTShadowView *)shadowView @"change", @"focus", @"blur", + @"keyDown", + @"keyUp", @"submitEditing", @"endEditing", @"keyPress", @@ -452,6 +454,8 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(onDragLeave, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDrop, RCTDirectEventBlock) #endif // ]TODO(macOS ISS#2323203) +RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events +RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events #pragma mark - ShadowView properties From 119f0276f56db4832cbf339796c35cae5c185ab0 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 26 Nov 2020 00:24:10 -0800 Subject: [PATCH 03/23] update comment --- .../js/examples/KeyboardEventsExample/KeyboardEventsExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index 48d3250cc7ca43..38b8c0c5a373e0 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -46,7 +46,7 @@ class KeyEventExample extends React.Component<{}, State> { Key events are called when a component detects a key press. - {// Only test View on MacOS, since canBecomeFirstResponder is false on all iOS, therefore we can't focus + { Platform.OS === 'macos' ? ( Date: Wed, 9 Dec 2020 16:03:51 -0800 Subject: [PATCH 04/23] add key value checks so we don't send all events --- RNTester/Podfile.lock | 68 +++++++++---------- .../KeyboardEventsExample.js | 10 ++- React/Views/RCTView.h | 2 + React/Views/RCTView.m | 21 +++--- React/Views/RCTViewKeyboardEvent.h | 4 +- React/Views/RCTViewKeyboardEvent.m | 4 +- React/Views/RCTViewManager.m | 4 +- 7 files changed, 65 insertions(+), 48 deletions(-) diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index a895cca6ab9299..1c5dbea32c6f02 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -15,12 +15,12 @@ PODS: - Flipper-Folly (~> 2.2) - Flipper-RSocket (~> 1.1) - Flipper-DoubleConversion (1.1.7) - - Flipper-Folly (2.2.0): + - Flipper-Folly (2.3.0): - boost-for-react-native - CocoaLibEvent (~> 1.0) - Flipper-DoubleConversion - Flipper-Glog - - OpenSSL-Universal (= 1.0.2.19) + - OpenSSL-Universal (= 1.0.2.20) - Flipper-Glog (0.3.6) - Flipper-PeerTalk (0.0.4) - Flipper-RSocket (1.1.0): @@ -64,9 +64,9 @@ PODS: - libevent/core (2.1.11): - libevent/event2-headers - libevent/event2-headers (2.1.11) - - OpenSSL-Universal (1.0.2.19): - - OpenSSL-Universal/Static (= 1.0.2.19) - - OpenSSL-Universal/Static (1.0.2.19) + - OpenSSL-Universal (1.0.2.20): + - OpenSSL-Universal/Static (= 1.0.2.20) + - OpenSSL-Universal/Static (1.0.2.20) - RCT-Folly (2020.01.13.00): - boost-for-react-native - DoubleConversion @@ -519,11 +519,11 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: 058eeb6417ef70b3b8949d2b4ea1588033186266 - FBReactNativeSpec: 9b1b4c1fa7ba24ffa7712799e2cbb602b97eda5d + FBLazyVector: a6ae1b79864b3b25e30e33ebf6efdede05eddbfa + FBReactNativeSpec: 0d87e289ca0559216298b1af12537cff0f54588c Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 - Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 + Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 @@ -531,34 +531,34 @@ SPEC CHECKSUMS: glog: 1cb7c408c781ae8f35bbababe459b45e3dee4ec1 hermes: 12d049af0d8e8379c5b3b54ffb1919d670045bdc libevent: ee9265726a1fc599dea382964fa304378affaa5f - OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 + OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: ec85d1ef4d51803337cde71de052e3db103d6472 - RCTTypeSafety: a4430a19dff2b11c1c0521ddd9e90b0c033217b4 - React: 58c48d390d9c13c7e28ee4832d59a931e26d4a5c - React-ART: d6002339cd61232b4b6b64abc4c519f22c5a53b4 - React-callinvoker: ad1904b8c01625a218e541417c1f2269912eba6b - React-Core: d66de0613ce7984076226eaed78f75c6c46bf91c - React-CoreModules: 4be0efeb5b0434beae09740b7672d9c718856e78 - React-cxxreact: 8386895677c64406ab269a2390f1bd7a9416a698 - React-jsi: fcd89cccc1a8d1fea9a6a3b85645781a12daf712 - React-jsiexecutor: 1c8f0bf5110a999922389d8d71f99d6ee942dcd8 - React-jsinspector: 6dcbf0c485a9cefa3e3bf87dc3aa9f2ecea1a5dd - React-RCTActionSheet: 66b3b31c0566bab2e90b198c893432b4e8ac1883 - React-RCTAnimation: 42fee356deb87bf0f351836625dcc40e610000cd - React-RCTBlob: b3a07d1b087bc30d9a70e5f6aad3828531d03c67 - React-RCTImage: 50b248b2a61a4eba7a7c86de6f0ae1cb0b70c25d - React-RCTLinking: 2d5c14d4f96faa81c04e4754db0c7b05ea35de3e - React-RCTNetwork: 2707c0d37396d1f8876bc74eaa8e7374a8be788a - React-RCTPushNotification: 05efdc2e49aaa39c9a087d75d3d54fef2b8a9554 - React-RCTSettings: 230c589aabbcb4f04212ea17a7afdbf2b21d716d - React-RCTTest: 56492ab0dec8652ecf7bd33bcefc1494a759470b - React-RCTText: 07ea13069c32f7c8c13deb374c00ddfd641dd925 - React-RCTVibration: e71fbb228d655d109bc069bb3a50809761a078a8 + RCTRequired: 29479b86ec65f4157241d78264f5ef561ade22fb + RCTTypeSafety: 43df0a984fb268c979ca4d48b9b7c2f36c2f8afa + React: 92b73328440bbd85d6aac595e0b72bbd908691fb + React-ART: d21f4390d74751534f13904901c26bfe6ec794b9 + React-callinvoker: f95c3045678d4c92bee335c1ec33eb3aab4b83cf + React-Core: 0abfcfd7ed793acd786214e31a42769e0e921250 + React-CoreModules: 7142aeffd74868437608d69dc1f596183df207c1 + React-cxxreact: 49eee018ad861486cbfb221cddd45ac439b730fa + React-jsi: 66ec265a85cc56188a6e433b72382ed115fcad06 + React-jsiexecutor: 8dcf37ad0edd05809b2854d233647955ce122aa0 + React-jsinspector: 1e18eda10420137d634f3b660764e248da09e431 + React-RCTActionSheet: 1e77963344b7554bd0d506fdddc248b3031a3acd + React-RCTAnimation: 24665293e82d8fe009c52544e44442e24af67226 + React-RCTBlob: b80b29efb1b2cc0a568a6e9ef439e9e41b05127b + React-RCTImage: 0699991f74770bc2be51f76fcde7f7aeac7d4082 + React-RCTLinking: 4f0b40c7550999b4cf748e7c061c59b69e0f6648 + React-RCTNetwork: cfbd60b6797b913175b8a6349e10bb6fd961fc26 + React-RCTPushNotification: 80d37852e87f85b9e88f989142401c0f9257b2f8 + React-RCTSettings: dc94e747d8edc1810256bd0b024dd61ae4ab5a22 + React-RCTTest: 04d14b0b8a8d7ff9d8868fdb66218ff9db0259c1 + React-RCTText: 18fece5415a20dbaccd7ccfe17779bbf64c17fc4 + React-RCTVibration: b5d1d694cc4c6ca520cc23e10440e5adc39263d1 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: 6c285289e9266a7e316cb87f44396469e23dba9b - ReactCommon: 378cffdae03f1a712467fa43af195df1f79080b3 - Yoga: c3920c26a6383607e1776e35919aca16bbbf1991 + React-TurboModuleCxx-WinRTPort: d280a253fdf89944869969d1bbd5c839052f0287 + ReactCommon: 63ef025432213eb0b612bdb3542e7bf57dbd561c + Yoga: 18c5eda53e05f95700b68b07a38c2487dea04fa8 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index 38b8c0c5a373e0..f597a59ee9e428 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -17,6 +17,10 @@ const {Button, PlatformColor, StyleSheet, Text, View } = ReactNative; import { KeyEvent } from 'react-native/Libraries/Types/CoreEventTypes'; +type State = { + eventStream: string, +}; + class KeyEventExample extends React.Component<{}, State> { state: State = { eventStream: '', @@ -51,12 +55,16 @@ class KeyEventExample extends React.Component<{}, State> { @@ -69,7 +77,7 @@ class KeyEventExample extends React.Component<{}, State> { } } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ textInput: { ...Platform.select({ macos: { diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index 78f83974d0179d..d31a936dd83c4b 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -139,6 +139,8 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; // Keyboarding events @property (nonatomic, copy) RCTBubblingEventBlock onKeyDown; @property (nonatomic, copy) RCTBubblingEventBlock onKeyUp; +@property (nonatomic, copy) NSArray *validKeysDown; +@property (nonatomic, copy) NSArray *validKeysUp; #endif // ]TODO(macOS ISS#2323203) /** diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 5f40720296bb96..17d98abfa421d2 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -1566,25 +1566,30 @@ - (BOOL)performDragOperation:(id )sender #pragma mark - Keyboard Events -#if TARGET_OS_OSX // TODO: add iOS keyboard event handling +#if TARGET_OS_OSX - (void)keyDown:(NSEvent *)event { - if (!self.onKeyDown) { + if (self.onKeyDown != nil) { [super keyDown:event]; return; } - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; - [_eventDispatcher sendEvent:keyboardEvent]; + // only post events for keys we care about + if ([[self validKeysDown] containsObject:event.characters]) { + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; + } } - (void)keyUp:(NSEvent *)event { - if (!self.onKeyUp) { + if (self.onKeyUp != nil) { [super keyUp:event]; return; } - - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; - [_eventDispatcher sendEvent:keyboardEvent]; + + if ([[self validKeysUp] containsObject:event.characters]) { + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; + } } #endif // TARGET_OS_OSX diff --git a/React/Views/RCTViewKeyboardEvent.h b/React/Views/RCTViewKeyboardEvent.h index 4bcbcfe10796ce..ef9cf93f3a9be5 100644 --- a/React/Views/RCTViewKeyboardEvent.h +++ b/React/Views/RCTViewKeyboardEvent.h @@ -8,7 +8,7 @@ @interface RCTViewKeyboardEvent : RCTComponentEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; @end diff --git a/React/Views/RCTViewKeyboardEvent.m b/React/Views/RCTViewKeyboardEvent.m index 17fc2e6e0b608e..29a19c3a9decd4 100644 --- a/React/Views/RCTViewKeyboardEvent.m +++ b/React/Views/RCTViewKeyboardEvent.m @@ -10,7 +10,7 @@ @implementation RCTViewKeyboardEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyDown" viewTag:reactTag body:@{ @"characters" : characters, @@ -18,7 +18,7 @@ + (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSStri return event; } -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyUp" viewTag:reactTag body:@{ @"characters" : characters, diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index d0d599fe5cf78e..5e85bcd3768ce0 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -453,9 +453,11 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(onDragEnter, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDragLeave, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDrop, RCTDirectEventBlock) -#endif // ]TODO(macOS ISS#2323203) RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events +RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray) +RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray) +#endif // ]TODO(macOS ISS#2323203) #pragma mark - ShadowView properties From 508ac920aa0ef66f475e0cb288b760d7ca6433ca Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 26 Nov 2020 00:12:59 -0800 Subject: [PATCH 05/23] macOS keyboard support --- Libraries/Components/Button.js | 17 ++- .../Components/Touchable/TouchableOpacity.js | 12 +++ .../Touchable/TouchableWithoutFeedback.js | 7 ++ .../View/ReactNativeViewAttributes.js | 2 + .../View/ReactNativeViewViewConfig.js | 12 +++ .../View/ReactNativeViewViewConfigMacOS.js | 2 + Libraries/Components/View/ViewPropTypes.js | 3 + Libraries/Pressability/Pressability.js | 22 ++++ Libraries/Renderer/shims/ReactNativeTypes.js | 2 + Libraries/Types/CoreEventTypes.js | 7 ++ RNTester/Podfile.lock | 58 +++++----- .../KeyboardEventsExample.js | 100 ++++++++++++++++++ RNTester/js/utils/RNTesterList.ios.js | 5 + React/Base/RCTEventDispatcher.m | 2 +- React/Views/RCTView.h | 4 + React/Views/RCTView.m | 25 +++++ React/Views/RCTViewKeyboardEvent.h | 14 +++ React/Views/RCTViewKeyboardEvent.m | 29 +++++ React/Views/RCTViewManager.m | 4 + 19 files changed, 296 insertions(+), 31 deletions(-) create mode 100644 RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js create mode 100644 React/Views/RCTViewKeyboardEvent.h create mode 100644 React/Views/RCTViewKeyboardEvent.m diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index 73d32d1285fab0..ac676119288bf9 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -20,7 +20,7 @@ const View = require('./View/View'); const invariant = require('invariant'); -import type {PressEvent} from '../Types/CoreEventTypes'; +import type {PressEvent, KeyEvent} from '../Types/CoreEventTypes'; import type {FocusEvent, BlurEvent} from './TextInput/TextInput'; // TODO(OSS Candidate ISS#2710739) import type {ColorValue} from '../StyleSheet/StyleSheetTypes'; @@ -113,6 +113,17 @@ type ButtonProps = $ReadOnly<{| * Handler to be called when the button loses key focus */ onFocus?: ?(e: FocusEvent) => void, + + /** + * Handler to be called when a key down press is detected + */ + onKeyDown?: ?(e: KeyEvent) => void, + + /** + * Handler to be called when a key up press is detected + */ + onKeyUp?: ?(e: KeyEvent) => void, + // ]TODO(OSS Candidate ISS#2710739) |}>; @@ -163,6 +174,8 @@ class Button extends React.Component { testID, onFocus, // TODO(OSS Candidate ISS#2710739) onBlur, // TODO(OSS Candidate ISS#2710739) + onKeyDown, + onKeyUp, } = this.props; const buttonStyles = [styles.button]; const textStyles = [styles.text]; @@ -207,6 +220,8 @@ class Button extends React.Component { onPress={onPress} onFocus={onFocus} // TODO(OSS Candidate ISS#2710739) onBlur={onBlur} // TODO(OSS Candidate ISS#2710739) + onKeyDown={onKeyDown} + onKeyUp={onKeyUp} touchSoundDisabled={touchSoundDisabled}> diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 4381977e2b4193..a9d0f2d5d76da7 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -165,6 +165,16 @@ class TouchableOpacity extends React.Component { this.props.onFocus(event); } }, + onKeyDown: event => { + if (this.props.onKeyDown != null) { + this.props.onKeyDown(event); + } + }, + onKeyUp: event => { + if (this.props.onKeyUp != null) { + this.props.onKeyUp(event); + } + }, onLongPress: this.props.onLongPress, onPress: this.props.onPress, onPressIn: event => { @@ -279,6 +289,8 @@ class TouchableOpacity extends React.Component { onDrop={this.props.onDrop} onFocus={this.props.onFocus} onBlur={this.props.onBlur} + onKeyDown={this.props.onKeyDown} + onKeyUp={this.props.onKeyUp} draggedTypes={this.props.draggedTypes} // ]TODO(macOS ISS#2323203) ref={this.props.hostRef} {...eventHandlersWithoutBlurAndFocus}> diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index de448985aac3f9..739ec333a87da1 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -26,6 +26,7 @@ import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; import type { BlurEvent, FocusEvent, + KeyEvent, LayoutEvent, PressEvent, MouseEvent, // TODO(macOS ISS#2323203) @@ -64,6 +65,8 @@ type Props = $ReadOnly<{| onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed, onBlur?: ?(event: BlurEvent) => mixed, onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + onKeyUp?: ?(event: KeyEvent) => mixed, onLayout?: ?(event: LayoutEvent) => mixed, onLongPress?: ?(event: PressEvent) => mixed, onPress?: ?(event: PressEvent) => mixed, @@ -106,6 +109,8 @@ const PASSTHROUGH_PROPS = [ 'onAccessibilityAction', 'onBlur', 'onFocus', + 'onKeyDown', + 'onKeyUp', 'onLayout', 'onMouseEnter', // [TODO(macOS ISS#2323203) 'onMouseLeave', @@ -227,6 +232,8 @@ function createPressabilityConfig(props: Props): PressabilityConfig { android_disableSound: props.touchSoundDisabled, onBlur: props.onBlur, onFocus: props.onFocus, + onKeyDown: props.onKeyDown, + onKeyUp: props.onKeyUp, onLongPress: props.onLongPress, onPress: props.onPress, onPressIn: props.onPressIn, diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index b1956afc3f7c71..8ab81879c3ea32 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -42,6 +42,8 @@ const UIView = { onDragEnter: true, onDragLeave: true, onDrop: true, + onKeyDown: true, + onKeyUp: true, draggedTypes: true, // ]TODO(macOS ISS#2323203) style: ReactNativeStyleAttributes, }; diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 8858f62d5b0be4..25175748e7568c 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -45,6 +45,18 @@ const ReactNativeViewConfig = { captured: 'onFocusCapture', }, }, + topKeyUp: { + phasedRegistrationNames: { + bubbled: 'onKeyUp', + captured: 'onKeyUpCapture', + }, + }, + topKeyDown: { + phasedRegistrationNames: { + bubbled: 'onKeyDown', + captured: 'onKeyDownCapture', + }, + }, topKeyPress: { phasedRegistrationNames: { bubbled: 'onKeyPress', diff --git a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js index c28419bd527042..23016ab7bcc9f4 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js +++ b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js @@ -47,6 +47,8 @@ const ReactNativeViewViewConfigMacOS = { onDragLeave: true, onDrop: true, onFocus: true, + onKeyDown: true, + onKeyUp: true, onMouseEnter: true, onMouseLeave: true, tooltip: true, diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 0265dd1267160f..6bdf9009e8c726 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -18,6 +18,7 @@ import type { Layout, LayoutEvent, ScrollEvent, // TODO(macOS ISS#2323203) + KeyEvent, } from '../../Types/CoreEventTypes'; import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; import type {Node} from 'react'; @@ -41,6 +42,8 @@ export type ViewLayoutEvent = LayoutEvent; type BubblingEventProps = $ReadOnly<{| onBlur?: ?(event: BlurEvent) => mixed, onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + onKeyUp?: ?(event: KeyEvent) => mixed, |}>; type DirectEventProps = $ReadOnly<{| diff --git a/Libraries/Pressability/Pressability.js b/Libraries/Pressability/Pressability.js index f02c7339bbcca9..65d6607b221b0d 100644 --- a/Libraries/Pressability/Pressability.js +++ b/Libraries/Pressability/Pressability.js @@ -17,6 +17,7 @@ import {normalizeRect, type RectOrSize} from '../StyleSheet/Rect'; import type { BlurEvent, FocusEvent, + KeyEvent, PressEvent, MouseEvent, } from '../Types/CoreEventTypes'; @@ -93,6 +94,10 @@ export type PressabilityConfig = $ReadOnly<{| */ onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + + onKeyUp?: ?(event: KeyEvent) => mixed, + /** * Called when the hover is activated to provide visual feedback. */ @@ -156,6 +161,8 @@ export type EventHandlers = $ReadOnly<{| onBlur: (event: BlurEvent) => void, onClick: (event: PressEvent) => void, onFocus: (event: FocusEvent) => void, + onKeyDown: (event: KeyDown) => void, + onKeyUp: (event: KeyDown) => void, onMouseEnter?: (event: MouseEvent) => void, onMouseLeave?: (event: MouseEvent) => void, onResponderGrant: (event: PressEvent) => void, @@ -445,6 +452,21 @@ export default class Pressability { } }, }; + + const keyEventHandlers = { + onKeyDown: (event: KeyEvent): void => { + const {onKeyDown} = this._config; + if (onKeyDown != null) { + onKeyDown(event); + } + }, + onKeyUp: (event: KeyEvent): void => { + const {onKeyUp} = this._config; + if (onKeyUp != null) { + onKeyUp(event); + } + }, + }; const responderEventHandlers = { onStartShouldSetResponder: (): boolean => { diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index 10244570b65354..ec68139ab57208 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -80,6 +80,8 @@ export type ViewConfigGetter = () => ReactNativeBaseComponentViewConfig<>; export type NativeMethods = { blur(): void, focus(): void, + onKeyDown(): void, + onKeyUp(): void, measure(callback: MeasureOnSuccessCallback): void, measureInWindow(callback: MeasureInWindowOnSuccessCallback): void, measureLayout( diff --git a/Libraries/Types/CoreEventTypes.js b/Libraries/Types/CoreEventTypes.js index 065657395ef739..635548643bf574 100644 --- a/Libraries/Types/CoreEventTypes.js +++ b/Libraries/Types/CoreEventTypes.js @@ -152,6 +152,13 @@ export type FocusEvent = SyntheticEvent< |}>, >; +export type KeyEvent = SyntheticEvent< + $ReadOnly<{| + characters: string, + modifier: number, + |}>, +>; + export type MouseEvent = SyntheticEvent< $ReadOnly<{| clientX: number, diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index 9b0f823da65df7..a895cca6ab9299 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -431,7 +431,7 @@ DEPENDENCIES: - Yoga (from `../ReactCommon/yoga`) SPEC REPOS: - https://cdn.cocoapods.org/: + trunk: - CocoaAsyncSocket - CocoaLibEvent - Flipper @@ -519,8 +519,8 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: e99626a767684cd45377cfb2d270260b08612394 - FBReactNativeSpec: 4caa8b770647aad3624a57c46871bf01c1e1ef59 + FBLazyVector: 058eeb6417ef70b3b8949d2b4ea1588033186266 + FBReactNativeSpec: 9b1b4c1fa7ba24ffa7712799e2cbb602b97eda5d Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 @@ -533,34 +533,34 @@ SPEC CHECKSUMS: libevent: ee9265726a1fc599dea382964fa304378affaa5f OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: 7803a0a3a3d56e3cec84ae1ccbe0f4a2476f9f69 - RCTTypeSafety: ae513041fa8773699d99833a8691d2e8b8d6ee8a - React: d6306405782c4669fd3d4d0125a7b2cc2bb19233 - React-ART: 65684f957e38c119918b2ad8e2f2c386790b20d0 - React-callinvoker: edc229ccab488b3b57895e830d2b825e79f9f04c - React-Core: 50805a8b5eb817533763ae0132a0a61fc740fddf - React-CoreModules: 3147038a51e5a1a1819be556efb3c22855816aec - React-cxxreact: 88f9c5fbd0c391488fb884ab4bf8af85c548230c - React-jsi: e7b3496404f24299beb067b0e4fa38e836f1d6a4 - React-jsiexecutor: f214cb9bebf408f6deeea9f6fe6ca610ab88eb6e - React-jsinspector: 7fba9bc98d5047bf5c8dae0cd8acd36b86448d04 - React-RCTActionSheet: c4b92af34b6f64c786a972f5c196a375b7ce6cea - React-RCTAnimation: 5a0f7f7b3eaf0520e53d119f8352fdc622d0a90b - React-RCTBlob: 37befa1be701fe18ab0d63eb986b65829c843fc6 - React-RCTImage: a02ff4f1882f35574ae589556b5c94b9eee973da - React-RCTLinking: 70240d29450241879339d7384b0903232d30e2c6 - React-RCTNetwork: 17a1cd202a4566c25244444644a1fadd092466db - React-RCTPushNotification: eec1e289dfb203ee5360a9065c4009de0c16e097 - React-RCTSettings: 490435d0c7767d085ebc9218d6cc9f9e2018ff1c - React-RCTTest: 06e4d480573015d42b0acb110aeb343c16d0c595 - React-RCTText: a2a64b9c882d9b9a8e26c27773ca305ce910f4a6 - React-RCTVibration: d32b07b6c9e821cb784b04e1c65cee3b35099b54 + RCTRequired: ec85d1ef4d51803337cde71de052e3db103d6472 + RCTTypeSafety: a4430a19dff2b11c1c0521ddd9e90b0c033217b4 + React: 58c48d390d9c13c7e28ee4832d59a931e26d4a5c + React-ART: d6002339cd61232b4b6b64abc4c519f22c5a53b4 + React-callinvoker: ad1904b8c01625a218e541417c1f2269912eba6b + React-Core: d66de0613ce7984076226eaed78f75c6c46bf91c + React-CoreModules: 4be0efeb5b0434beae09740b7672d9c718856e78 + React-cxxreact: 8386895677c64406ab269a2390f1bd7a9416a698 + React-jsi: fcd89cccc1a8d1fea9a6a3b85645781a12daf712 + React-jsiexecutor: 1c8f0bf5110a999922389d8d71f99d6ee942dcd8 + React-jsinspector: 6dcbf0c485a9cefa3e3bf87dc3aa9f2ecea1a5dd + React-RCTActionSheet: 66b3b31c0566bab2e90b198c893432b4e8ac1883 + React-RCTAnimation: 42fee356deb87bf0f351836625dcc40e610000cd + React-RCTBlob: b3a07d1b087bc30d9a70e5f6aad3828531d03c67 + React-RCTImage: 50b248b2a61a4eba7a7c86de6f0ae1cb0b70c25d + React-RCTLinking: 2d5c14d4f96faa81c04e4754db0c7b05ea35de3e + React-RCTNetwork: 2707c0d37396d1f8876bc74eaa8e7374a8be788a + React-RCTPushNotification: 05efdc2e49aaa39c9a087d75d3d54fef2b8a9554 + React-RCTSettings: 230c589aabbcb4f04212ea17a7afdbf2b21d716d + React-RCTTest: 56492ab0dec8652ecf7bd33bcefc1494a759470b + React-RCTText: 07ea13069c32f7c8c13deb374c00ddfd641dd925 + React-RCTVibration: e71fbb228d655d109bc069bb3a50809761a078a8 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: cbe13444db8dc3af024947610c537a27cea1c1cb - ReactCommon: d849f99f384dafff03d56ac7e9fd173e117b1509 - Yoga: 5ba9af3554885e152355679790ed9be0b1d01695 + React-TurboModuleCxx-WinRTPort: 6c285289e9266a7e316cb87f44396469e23dba9b + ReactCommon: 378cffdae03f1a712467fa43af195df1f79080b3 + Yoga: c3920c26a6383607e1776e35919aca16bbbf1991 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 -COCOAPODS: 1.8.4 +COCOAPODS: 1.9.1 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js new file mode 100644 index 00000000000000..48d3250cc7ca43 --- /dev/null +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; // TODO(OSS Candidate ISS#2710739) + +const React = require('react'); +const ReactNative = require('react-native'); +import {Platform} from 'react-native'; +const {Button, PlatformColor, StyleSheet, Text, View } = ReactNative; + +import { KeyEvent } from 'react-native/Libraries/Types/CoreEventTypes'; + +class KeyEventExample extends React.Component<{}, State> { + state: State = { + eventStream: '', + characters: '', + }; + + onKeyDownEvent: (e: KeyEvent) => void = (e: KeyEvent) => { + console.log('received view key down event\n', e.nativeEvent['characters']); + this.setState({characters: e.nativeEvent.characters}) + this.setState(prevState => ({ + eventStream: prevState.eventStream + prevState.characters + '\nKey Down: ' + })); + }; + + onKeyUpEvent: (e: KeyEvent) => void = (e: KeyEvent) => { + console.log('received key up event\n', e.nativeEvent['characters']); + this.setState({characters: e.nativeEvent.characters}) + this.setState(prevState => ({ + eventStream: prevState.eventStream + prevState.characters + '\nKey Up: ' + })); + }; + + render() { + return ( + + + Key events are called when a component detects a key press. + + + {// Only test View on MacOS, since canBecomeFirstResponder is false on all iOS, therefore we can't focus + Platform.OS === 'macos' ? ( + + + + ) : null} + {'Events: ' + this.state.eventStream + JSON.stringify(this.state.characters) + '\n\n'} + + + ); + } +} + +var styles = StyleSheet.create({ + textInput: { + ...Platform.select({ + macos: { + color: PlatformColor('textColor'), + backgroundColor: PlatformColor('textBackgroundColor'), + borderColor: PlatformColor('gridColor'), + }, + default: { + borderColor: '#0f0f0f', + }, + }), + borderWidth: StyleSheet.hairlineWidth, + flex: 1, + fontSize: 13, + padding: 4, + }, +}); + +exports.title = 'Key Events'; +exports.description = 'Examples that show how Key events can be used.'; +exports.examples = [ + { + title: 'KeyEventExample', + render: function(): React.Element { + return ; + }, + }, +]; diff --git a/RNTester/js/utils/RNTesterList.ios.js b/RNTester/js/utils/RNTesterList.ios.js index 9ab6663e51b980..75f2389372a09a 100644 --- a/RNTester/js/utils/RNTesterList.ios.js +++ b/RNTester/js/utils/RNTesterList.ios.js @@ -51,6 +51,11 @@ const ComponentExamples: Array = [ module: require('../examples/FocusEventsExample/FocusEventsExample'), supportsTVOS: true, }, // ]TODO(OSS Candidate ISS#2710739) + { + key: 'KeyboardEvents', + module: require('../examples/KeyboardEventsExample/KeyboardEventsExample'), + supportsTVOS: false, + }, // ]TODO(OSS Candidate ISS#2710739) { key: 'ImageExample', module: require('../examples/Image/ImageExample'), diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m index 3da2e268ed72ba..5903834e824acf 100644 --- a/React/Base/RCTEventDispatcher.m +++ b/React/Base/RCTEventDispatcher.m @@ -84,7 +84,7 @@ - (void)sendTextEventWithType:(RCTTextEventType)type key:(NSString *)key eventCount:(NSInteger)eventCount { - static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress"}; + static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress", @"keyDown", @"keyUp"}; NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:@{ @"eventCount" : @(eventCount), diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index b0800d9e1e1169..78f83974d0179d 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -135,6 +135,10 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, copy) RCTDirectEventBlock onDragEnter; @property (nonatomic, copy) RCTDirectEventBlock onDragLeave; @property (nonatomic, copy) RCTDirectEventBlock onDrop; + +// Keyboarding events +@property (nonatomic, copy) RCTBubblingEventBlock onKeyDown; +@property (nonatomic, copy) RCTBubblingEventBlock onKeyUp; #endif // ]TODO(macOS ISS#2323203) /** diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 4f902b6bf8ca29..5b4a42d44c86ef 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -16,6 +16,7 @@ #import "RCTRootContentView.h" // TODO(macOS ISS#2323203) #import "RCTUtils.h" #import "UIView+React.h" +#import "RCTViewKeyboardEvent.h" #if TARGET_OS_OSX // [TODO(macOS ISS#2323203) #import "RCTTextView.h" #endif // ]TODO(macOS ISS#2323203) @@ -1569,4 +1570,28 @@ - (BOOL)performDragOperation:(id )sender } #endif // ]TODO(macOS ISS#2323203) +#pragma mark - Keyboard Events + +#if TARGET_OS_OSX // TODO: add iOS keyboard event handling +- (void)keyDown:(NSEvent *)event { + if (!self.onKeyDown) { + [super keyDown:event]; + return; + } + + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; +} + +- (void)keyUp:(NSEvent *)event { + if (!self.onKeyUp) { + [super keyUp:event]; + return; + } + + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; +} +#endif // TARGET_OS_OSX + @end diff --git a/React/Views/RCTViewKeyboardEvent.h b/React/Views/RCTViewKeyboardEvent.h new file mode 100644 index 00000000000000..4bcbcfe10796ce --- /dev/null +++ b/React/Views/RCTViewKeyboardEvent.h @@ -0,0 +1,14 @@ +/* + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import + +@interface RCTViewKeyboardEvent : RCTComponentEvent + ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; + +@end diff --git a/React/Views/RCTViewKeyboardEvent.m b/React/Views/RCTViewKeyboardEvent.m new file mode 100644 index 00000000000000..17fc2e6e0b608e --- /dev/null +++ b/React/Views/RCTViewKeyboardEvent.m @@ -0,0 +1,29 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTViewKeyboardEvent.h" +#import + +@implementation RCTViewKeyboardEvent + ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { + RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyDown" + viewTag:reactTag + body:@{ @"characters" : characters, + @"modifier" : @(modifier) }]; + return event; +} + ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { + RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyUp" + viewTag:reactTag + body:@{ @"characters" : characters, + @"modifier" : @(modifier) }]; + return event; +} + +@end diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index e1dff7e8c44fc2..671c1745804066 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -112,6 +112,8 @@ - (RCTShadowView *)shadowView @"change", @"focus", @"blur", + @"keyDown", + @"keyUp", @"submitEditing", @"endEditing", @"keyPress", @@ -464,6 +466,8 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(onDragLeave, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDrop, RCTDirectEventBlock) #endif // ]TODO(macOS ISS#2323203) +RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events +RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events #pragma mark - ShadowView properties From 1d1ff140c43e52ed46fda51106d4e17fa90ccbd0 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 26 Nov 2020 00:24:10 -0800 Subject: [PATCH 06/23] update comment --- .../js/examples/KeyboardEventsExample/KeyboardEventsExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index 48d3250cc7ca43..38b8c0c5a373e0 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -46,7 +46,7 @@ class KeyEventExample extends React.Component<{}, State> { Key events are called when a component detects a key press. - {// Only test View on MacOS, since canBecomeFirstResponder is false on all iOS, therefore we can't focus + { Platform.OS === 'macos' ? ( Date: Wed, 9 Dec 2020 16:03:51 -0800 Subject: [PATCH 07/23] add key value checks so we don't send all events --- RNTester/Podfile.lock | 68 +++++++++---------- .../KeyboardEventsExample.js | 10 ++- React/Views/RCTView.h | 2 + React/Views/RCTView.m | 21 +++--- React/Views/RCTViewKeyboardEvent.h | 4 +- React/Views/RCTViewKeyboardEvent.m | 4 +- React/Views/RCTViewManager.m | 4 +- 7 files changed, 65 insertions(+), 48 deletions(-) diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index a895cca6ab9299..1c5dbea32c6f02 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -15,12 +15,12 @@ PODS: - Flipper-Folly (~> 2.2) - Flipper-RSocket (~> 1.1) - Flipper-DoubleConversion (1.1.7) - - Flipper-Folly (2.2.0): + - Flipper-Folly (2.3.0): - boost-for-react-native - CocoaLibEvent (~> 1.0) - Flipper-DoubleConversion - Flipper-Glog - - OpenSSL-Universal (= 1.0.2.19) + - OpenSSL-Universal (= 1.0.2.20) - Flipper-Glog (0.3.6) - Flipper-PeerTalk (0.0.4) - Flipper-RSocket (1.1.0): @@ -64,9 +64,9 @@ PODS: - libevent/core (2.1.11): - libevent/event2-headers - libevent/event2-headers (2.1.11) - - OpenSSL-Universal (1.0.2.19): - - OpenSSL-Universal/Static (= 1.0.2.19) - - OpenSSL-Universal/Static (1.0.2.19) + - OpenSSL-Universal (1.0.2.20): + - OpenSSL-Universal/Static (= 1.0.2.20) + - OpenSSL-Universal/Static (1.0.2.20) - RCT-Folly (2020.01.13.00): - boost-for-react-native - DoubleConversion @@ -519,11 +519,11 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: 058eeb6417ef70b3b8949d2b4ea1588033186266 - FBReactNativeSpec: 9b1b4c1fa7ba24ffa7712799e2cbb602b97eda5d + FBLazyVector: a6ae1b79864b3b25e30e33ebf6efdede05eddbfa + FBReactNativeSpec: 0d87e289ca0559216298b1af12537cff0f54588c Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 - Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 + Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 @@ -531,34 +531,34 @@ SPEC CHECKSUMS: glog: 1cb7c408c781ae8f35bbababe459b45e3dee4ec1 hermes: 12d049af0d8e8379c5b3b54ffb1919d670045bdc libevent: ee9265726a1fc599dea382964fa304378affaa5f - OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 + OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: ec85d1ef4d51803337cde71de052e3db103d6472 - RCTTypeSafety: a4430a19dff2b11c1c0521ddd9e90b0c033217b4 - React: 58c48d390d9c13c7e28ee4832d59a931e26d4a5c - React-ART: d6002339cd61232b4b6b64abc4c519f22c5a53b4 - React-callinvoker: ad1904b8c01625a218e541417c1f2269912eba6b - React-Core: d66de0613ce7984076226eaed78f75c6c46bf91c - React-CoreModules: 4be0efeb5b0434beae09740b7672d9c718856e78 - React-cxxreact: 8386895677c64406ab269a2390f1bd7a9416a698 - React-jsi: fcd89cccc1a8d1fea9a6a3b85645781a12daf712 - React-jsiexecutor: 1c8f0bf5110a999922389d8d71f99d6ee942dcd8 - React-jsinspector: 6dcbf0c485a9cefa3e3bf87dc3aa9f2ecea1a5dd - React-RCTActionSheet: 66b3b31c0566bab2e90b198c893432b4e8ac1883 - React-RCTAnimation: 42fee356deb87bf0f351836625dcc40e610000cd - React-RCTBlob: b3a07d1b087bc30d9a70e5f6aad3828531d03c67 - React-RCTImage: 50b248b2a61a4eba7a7c86de6f0ae1cb0b70c25d - React-RCTLinking: 2d5c14d4f96faa81c04e4754db0c7b05ea35de3e - React-RCTNetwork: 2707c0d37396d1f8876bc74eaa8e7374a8be788a - React-RCTPushNotification: 05efdc2e49aaa39c9a087d75d3d54fef2b8a9554 - React-RCTSettings: 230c589aabbcb4f04212ea17a7afdbf2b21d716d - React-RCTTest: 56492ab0dec8652ecf7bd33bcefc1494a759470b - React-RCTText: 07ea13069c32f7c8c13deb374c00ddfd641dd925 - React-RCTVibration: e71fbb228d655d109bc069bb3a50809761a078a8 + RCTRequired: 29479b86ec65f4157241d78264f5ef561ade22fb + RCTTypeSafety: 43df0a984fb268c979ca4d48b9b7c2f36c2f8afa + React: 92b73328440bbd85d6aac595e0b72bbd908691fb + React-ART: d21f4390d74751534f13904901c26bfe6ec794b9 + React-callinvoker: f95c3045678d4c92bee335c1ec33eb3aab4b83cf + React-Core: 0abfcfd7ed793acd786214e31a42769e0e921250 + React-CoreModules: 7142aeffd74868437608d69dc1f596183df207c1 + React-cxxreact: 49eee018ad861486cbfb221cddd45ac439b730fa + React-jsi: 66ec265a85cc56188a6e433b72382ed115fcad06 + React-jsiexecutor: 8dcf37ad0edd05809b2854d233647955ce122aa0 + React-jsinspector: 1e18eda10420137d634f3b660764e248da09e431 + React-RCTActionSheet: 1e77963344b7554bd0d506fdddc248b3031a3acd + React-RCTAnimation: 24665293e82d8fe009c52544e44442e24af67226 + React-RCTBlob: b80b29efb1b2cc0a568a6e9ef439e9e41b05127b + React-RCTImage: 0699991f74770bc2be51f76fcde7f7aeac7d4082 + React-RCTLinking: 4f0b40c7550999b4cf748e7c061c59b69e0f6648 + React-RCTNetwork: cfbd60b6797b913175b8a6349e10bb6fd961fc26 + React-RCTPushNotification: 80d37852e87f85b9e88f989142401c0f9257b2f8 + React-RCTSettings: dc94e747d8edc1810256bd0b024dd61ae4ab5a22 + React-RCTTest: 04d14b0b8a8d7ff9d8868fdb66218ff9db0259c1 + React-RCTText: 18fece5415a20dbaccd7ccfe17779bbf64c17fc4 + React-RCTVibration: b5d1d694cc4c6ca520cc23e10440e5adc39263d1 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: 6c285289e9266a7e316cb87f44396469e23dba9b - ReactCommon: 378cffdae03f1a712467fa43af195df1f79080b3 - Yoga: c3920c26a6383607e1776e35919aca16bbbf1991 + React-TurboModuleCxx-WinRTPort: d280a253fdf89944869969d1bbd5c839052f0287 + ReactCommon: 63ef025432213eb0b612bdb3542e7bf57dbd561c + Yoga: 18c5eda53e05f95700b68b07a38c2487dea04fa8 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index 38b8c0c5a373e0..f597a59ee9e428 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -17,6 +17,10 @@ const {Button, PlatformColor, StyleSheet, Text, View } = ReactNative; import { KeyEvent } from 'react-native/Libraries/Types/CoreEventTypes'; +type State = { + eventStream: string, +}; + class KeyEventExample extends React.Component<{}, State> { state: State = { eventStream: '', @@ -51,12 +55,16 @@ class KeyEventExample extends React.Component<{}, State> { @@ -69,7 +77,7 @@ class KeyEventExample extends React.Component<{}, State> { } } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ textInput: { ...Platform.select({ macos: { diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index 78f83974d0179d..d31a936dd83c4b 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -139,6 +139,8 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; // Keyboarding events @property (nonatomic, copy) RCTBubblingEventBlock onKeyDown; @property (nonatomic, copy) RCTBubblingEventBlock onKeyUp; +@property (nonatomic, copy) NSArray *validKeysDown; +@property (nonatomic, copy) NSArray *validKeysUp; #endif // ]TODO(macOS ISS#2323203) /** diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 5b4a42d44c86ef..226e2fdfe646c0 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -1572,25 +1572,30 @@ - (BOOL)performDragOperation:(id )sender #pragma mark - Keyboard Events -#if TARGET_OS_OSX // TODO: add iOS keyboard event handling +#if TARGET_OS_OSX - (void)keyDown:(NSEvent *)event { - if (!self.onKeyDown) { + if (self.onKeyDown != nil) { [super keyDown:event]; return; } - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; - [_eventDispatcher sendEvent:keyboardEvent]; + // only post events for keys we care about + if ([[self validKeysDown] containsObject:event.characters]) { + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; + } } - (void)keyUp:(NSEvent *)event { - if (!self.onKeyUp) { + if (self.onKeyUp != nil) { [super keyUp:event]; return; } - - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; - [_eventDispatcher sendEvent:keyboardEvent]; + + if ([[self validKeysUp] containsObject:event.characters]) { + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; + } } #endif // TARGET_OS_OSX diff --git a/React/Views/RCTViewKeyboardEvent.h b/React/Views/RCTViewKeyboardEvent.h index 4bcbcfe10796ce..ef9cf93f3a9be5 100644 --- a/React/Views/RCTViewKeyboardEvent.h +++ b/React/Views/RCTViewKeyboardEvent.h @@ -8,7 +8,7 @@ @interface RCTViewKeyboardEvent : RCTComponentEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; @end diff --git a/React/Views/RCTViewKeyboardEvent.m b/React/Views/RCTViewKeyboardEvent.m index 17fc2e6e0b608e..29a19c3a9decd4 100644 --- a/React/Views/RCTViewKeyboardEvent.m +++ b/React/Views/RCTViewKeyboardEvent.m @@ -10,7 +10,7 @@ @implementation RCTViewKeyboardEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyDown" viewTag:reactTag body:@{ @"characters" : characters, @@ -18,7 +18,7 @@ + (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSStri return event; } -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyUp" viewTag:reactTag body:@{ @"characters" : characters, diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 671c1745804066..fbf713353402fa 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -465,9 +465,11 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(onDragEnter, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDragLeave, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDrop, RCTDirectEventBlock) -#endif // ]TODO(macOS ISS#2323203) RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events +RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray) +RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray) +#endif // ]TODO(macOS ISS#2323203) #pragma mark - ShadowView properties From 5dcd7ce0853e775c50cf877ea6a28731e93e4c93 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eloy=20Dur=C3=A1n?= Date: Tue, 8 Dec 2020 11:50:13 +0100 Subject: [PATCH 08/23] [ado] Workaround homebrew openssl issue (#669) https://github.com/actions/virtual-environments/issues/1811#issuecomment-732239051 --- .ado/templates/apple-node-setup.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.ado/templates/apple-node-setup.yml b/.ado/templates/apple-node-setup.yml index 9d3f4ecb1c3e76..b892f2c586ed2a 100644 --- a/.ado/templates/apple-node-setup.yml +++ b/.ado/templates/apple-node-setup.yml @@ -2,6 +2,9 @@ # Task Group: Brew install node version # steps: + - script: 'brew uninstall openssl@1.0.2t && rm -rf /usr/local/etc/openssl && rm -rf /usr/local/etc/openssl@1.1' + displayName: Fix Homebrew + - script: 'brew bundle' displayName: 'brew bundle' From c56dff7327662544ae2c87015c136446fb9720bd Mon Sep 17 00:00:00 2001 From: HeyImChris <48299693+HeyImChris@users.noreply.github.com> Date: Wed, 9 Dec 2020 15:58:18 -0800 Subject: [PATCH 09/23] Fix detox yarn error with Xcode 12 (#670) * Update RCTCxxBridge.mm * fix detox errors with xcode 12 --- package.json | 2 +- yarn.lock | 29 +++++++++++++++-------------- 2 files changed, 16 insertions(+), 15 deletions(-) diff --git a/package.json b/package.json index 057934650f4750..8f2378829555fc 100644 --- a/package.json +++ b/package.json @@ -128,7 +128,7 @@ "clang-format": "^1.2.4", "connect": "^3.6.5", "coveralls": "^3.0.2", - "detox": "15.4.4", + "detox": "16.7.2", "eslint": "5.1.0", "eslint-config-fb-strict": "^24.9.0", "eslint-config-fbjs": "2.1.0", diff --git a/yarn.lock b/yarn.lock index 40d4fa989a0057..a9799b66a8dfe9 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2139,10 +2139,10 @@ big-integer@^1.6.7: resolved "https://registry.yarnpkg.com/big-integer/-/big-integer-1.6.36.tgz#78631076265d4ae3555c04f85e7d9d2f3a071a36" integrity sha512-t70bfa7HYEA1D9idDbmuv7YbsbVkQ+Hp+8KFSul4aE5e/i1bjCNIRYJZlA8Q8p0r9T8cF/RVvwUgRA//FydEyg== -bluebird@3.5.x: - version "3.5.2" - resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.5.2.tgz#1be0908e054a751754549c270489c1505d4ab15a" - integrity sha512-dhHTWMI7kMx5whMQntl7Vr9C6BvV10lFXDAasnqnrMYhXVCzzk6IO9Fo2L75jXHT07WrOngL1WDXOp+yYS91Yg== +bluebird@^3.5.4: + version "3.7.2" + resolved "https://registry.yarnpkg.com/bluebird/-/bluebird-3.7.2.tgz#9f229c15be272454ffa973ace0dbee79a1b0c36f" + integrity sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg== bplist-creator@0.0.7: version "0.0.7" @@ -2849,16 +2849,17 @@ detect-newline@^2.1.0: resolved "https://registry.yarnpkg.com/detect-newline/-/detect-newline-2.1.0.tgz#f41f1c10be4b00e87b5f13da680759f2c5bfd3e2" integrity sha1-9B8cEL5LAOh7XxPaaAdZ8sW/0+I= -detox@15.4.4: - version "15.4.4" - resolved "https://registry.yarnpkg.com/detox/-/detox-15.4.4.tgz#0f56b0eb9dd81b65e9bd6b3a8730f323dd6cd897" - integrity sha512-mbsw/REE3yDuq+0fbPZSktfV5OVO/80LMHsistgKUcBEEM3BrwLkZsji8a7syJj9tiDo+SsUjEzXGhQwDLlitA== +detox@16.7.2: + version "16.7.2" + resolved "https://registry.yarnpkg.com/detox/-/detox-16.7.2.tgz#531c98416adf52d4ba95601b669969acadafb970" + integrity sha512-+837eRgk4xOewXmeF5H6vOTn0RbKUFIyCi5UsTXEhvplsMk+KrrqfKik2j8fvubJkByry7HqIN/JF9jKe+meIQ== dependencies: "@babel/core" "^7.4.5" bunyan "^1.8.12" bunyan-debug-stream "^1.1.0" chalk "^2.4.2" child-process-promise "^2.2.0" + find-up "^4.1.0" fs-extra "^4.0.2" funpermaproxy "^1.0.1" get-port "^2.1.0" @@ -2869,7 +2870,7 @@ detox@15.4.4: sanitize-filename "^1.6.1" shell-utils "^1.0.9" tail "^2.0.0" - telnet-client "0.15.3" + telnet-client "1.2.8" tempfile "^2.0.0" which "^1.3.1" ws "^3.3.1" @@ -7326,12 +7327,12 @@ tar@^4: safe-buffer "^5.1.2" yallist "^3.0.2" -telnet-client@0.15.3: - version "0.15.3" - resolved "https://registry.yarnpkg.com/telnet-client/-/telnet-client-0.15.3.tgz#99ec754e4acf6fa51dc69898f574df3c2550712e" - integrity sha512-GSfdzQV0BKIYsmeXq7bJFJ2wHeJud6icaIxCUf6QCGQUD6R0BBGbT1+yLDhq67JRdgRpwyPwUbV7JxFeRrZomQ== +telnet-client@1.2.8: + version "1.2.8" + resolved "https://registry.yarnpkg.com/telnet-client/-/telnet-client-1.2.8.tgz#946c0dadc8daa3f19bb40a3e898cb870403a4ca4" + integrity sha512-W+w4k3QAmULVNhBVT2Fei369kGZCh/TH25M7caJAXW+hLxwoQRuw0di3cX4l0S9fgH3Mvq7u+IFMoBDpEw/eIg== dependencies: - bluebird "3.5.x" + bluebird "^3.5.4" temp-dir@^1.0.0: version "1.0.0" From 6b3487d849941e106b2085e2010c6659cd4848d8 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 10 Dec 2020 23:02:41 -0800 Subject: [PATCH 10/23] only use valid keys, bubble events to super --- Libraries/Pressability/Pressability.js | 6 + Libraries/Types/CoreEventTypes.js | 17 ++- RNTester/Podfile.lock | 54 ++++---- .../KeyboardEventsExample.js | 10 +- React/Views/RCTView.m | 119 +++++++++++++++++- React/Views/RCTViewKeyboardEvent.h | 30 ++++- React/Views/RCTViewKeyboardEvent.m | 60 ++++++++- 7 files changed, 248 insertions(+), 48 deletions(-) diff --git a/Libraries/Pressability/Pressability.js b/Libraries/Pressability/Pressability.js index 65d6607b221b0d..da199bee42858d 100644 --- a/Libraries/Pressability/Pressability.js +++ b/Libraries/Pressability/Pressability.js @@ -94,8 +94,14 @@ export type PressabilityConfig = $ReadOnly<{| */ onFocus?: ?(event: FocusEvent) => mixed, + /* + * Called after a key down event is detected. + */ onKeyDown?: ?(event: KeyEvent) => mixed, + /* + * Called after a key up event is detected. + */ onKeyUp?: ?(event: KeyEvent) => mixed, /** diff --git a/Libraries/Types/CoreEventTypes.js b/Libraries/Types/CoreEventTypes.js index 635548643bf574..11c1b7100a5d3c 100644 --- a/Libraries/Types/CoreEventTypes.js +++ b/Libraries/Types/CoreEventTypes.js @@ -154,8 +154,21 @@ export type FocusEvent = SyntheticEvent< export type KeyEvent = SyntheticEvent< $ReadOnly<{| - characters: string, - modifier: number, + // Modifier keys + capsLockKey: boolean, + shiftKey: boolean, + controlKey: boolean, + optionKey: boolean, + commandKey: boolean, + numericPadKey: boolean, + helpKey: boolean, + functionKey: boolean, + // Key options + leftArrowKey: boolean, + rightArrowKey: boolean, + upArrowKey: boolean, + downArrowKey: boolean, + key: string, |}>, >; diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index 1c5dbea32c6f02..a56e0fef5ea607 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -519,8 +519,8 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: a6ae1b79864b3b25e30e33ebf6efdede05eddbfa - FBReactNativeSpec: 0d87e289ca0559216298b1af12537cff0f54588c + FBLazyVector: 15d29e4a0b8ae8fc03616b36fb5b9b8d554bfede + FBReactNativeSpec: 24e41f4afb47a2d5af7687f85b8dec0eb4163347 Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a @@ -533,32 +533,32 @@ SPEC CHECKSUMS: libevent: ee9265726a1fc599dea382964fa304378affaa5f OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: 29479b86ec65f4157241d78264f5ef561ade22fb - RCTTypeSafety: 43df0a984fb268c979ca4d48b9b7c2f36c2f8afa - React: 92b73328440bbd85d6aac595e0b72bbd908691fb - React-ART: d21f4390d74751534f13904901c26bfe6ec794b9 - React-callinvoker: f95c3045678d4c92bee335c1ec33eb3aab4b83cf - React-Core: 0abfcfd7ed793acd786214e31a42769e0e921250 - React-CoreModules: 7142aeffd74868437608d69dc1f596183df207c1 - React-cxxreact: 49eee018ad861486cbfb221cddd45ac439b730fa - React-jsi: 66ec265a85cc56188a6e433b72382ed115fcad06 - React-jsiexecutor: 8dcf37ad0edd05809b2854d233647955ce122aa0 - React-jsinspector: 1e18eda10420137d634f3b660764e248da09e431 - React-RCTActionSheet: 1e77963344b7554bd0d506fdddc248b3031a3acd - React-RCTAnimation: 24665293e82d8fe009c52544e44442e24af67226 - React-RCTBlob: b80b29efb1b2cc0a568a6e9ef439e9e41b05127b - React-RCTImage: 0699991f74770bc2be51f76fcde7f7aeac7d4082 - React-RCTLinking: 4f0b40c7550999b4cf748e7c061c59b69e0f6648 - React-RCTNetwork: cfbd60b6797b913175b8a6349e10bb6fd961fc26 - React-RCTPushNotification: 80d37852e87f85b9e88f989142401c0f9257b2f8 - React-RCTSettings: dc94e747d8edc1810256bd0b024dd61ae4ab5a22 - React-RCTTest: 04d14b0b8a8d7ff9d8868fdb66218ff9db0259c1 - React-RCTText: 18fece5415a20dbaccd7ccfe17779bbf64c17fc4 - React-RCTVibration: b5d1d694cc4c6ca520cc23e10440e5adc39263d1 + RCTRequired: 37f40377c0ea795d4b906f3499655fbd0ff42e27 + RCTTypeSafety: 3f230f2e3335fbe45ed5c9d4bd2eba467392479f + React: 707958373426608d07889c030a5db60b826e159e + React-ART: d81c7e291454d9cbaa6088758f264e8ea21099fc + React-callinvoker: 6d9636c3513c6cd0acc46914d3de03ddbdc84007 + React-Core: c71c9b022c3151ab6f61f6184291e8ecd706d2a1 + React-CoreModules: 45fb897af5ba457cb6cb66a82b5faa4d117bfe15 + React-cxxreact: 0e079067a4a355eb15be1492aa96cfd68720ad3e + React-jsi: e150452a6ba4ef7f3eb55a6b0e4991605ddf1ddd + React-jsiexecutor: 160af6637a201038dbbfd232caa8f1abe73a4a79 + React-jsinspector: f0e7ba53d923a58da6aa4c2abacfa178db78cb31 + React-RCTActionSheet: bca975a416caea8f77677616cfa06c2d6245d5cf + React-RCTAnimation: ea3f8968ad420f0bf55ed9a85c7fc9c225f3dc9a + React-RCTBlob: 2d237a23740260aee9716e66ac4c388a29c23ee3 + React-RCTImage: 57e1ce8afe2b04ab4a44254f9ac9ae54b473cdc9 + React-RCTLinking: ccf93f64ecf303ef4fac7fe50424ea55d74bc072 + React-RCTNetwork: 4d075d146f0ed6a6e3c657a57ae17b011e17df71 + React-RCTPushNotification: e9b3686f7f9ca6b74617a5427e7ffcba3d70f41c + React-RCTSettings: fc9afc6981735f0cce2b37c2ed90b7a800a38308 + React-RCTTest: c2c26c856d466e948dee7ff939372637d1c80069 + React-RCTText: 7effa140484e70f24e340450d24e7e0ed3f1ae88 + React-RCTVibration: c1867f60d25efafbf8705b445e6dc11089312cc7 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: d280a253fdf89944869969d1bbd5c839052f0287 - ReactCommon: 63ef025432213eb0b612bdb3542e7bf57dbd561c - Yoga: 18c5eda53e05f95700b68b07a38c2487dea04fa8 + React-TurboModuleCxx-WinRTPort: d7bf672478f94748329c159893310100ad26c34e + ReactCommon: 047272186b16e3cab56317cbd4c119a80329a5ab + Yoga: 56a44c9ff7008e519e20fcf7cc257b5a86f46695 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index f597a59ee9e428..d0602ee96ae5ea 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -29,7 +29,7 @@ class KeyEventExample extends React.Component<{}, State> { onKeyDownEvent: (e: KeyEvent) => void = (e: KeyEvent) => { console.log('received view key down event\n', e.nativeEvent['characters']); - this.setState({characters: e.nativeEvent.characters}) + this.setState({characters: e.nativeEvent.key}) this.setState(prevState => ({ eventStream: prevState.eventStream + prevState.characters + '\nKey Down: ' })); @@ -37,7 +37,7 @@ class KeyEventExample extends React.Component<{}, State> { onKeyUpEvent: (e: KeyEvent) => void = (e: KeyEvent) => { console.log('received key up event\n', e.nativeEvent['characters']); - this.setState({characters: e.nativeEvent.characters}) + this.setState({characters: e.nativeEvent.key}) this.setState(prevState => ({ eventStream: prevState.eventStream + prevState.characters + '\nKey Up: ' })); @@ -55,16 +55,16 @@ class KeyEventExample extends React.Component<{}, State> { diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 226e2fdfe646c0..ff934958601dae 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -1573,16 +1573,121 @@ - (BOOL)performDragOperation:(id )sender #pragma mark - Keyboard Events #if TARGET_OS_OSX +const NSString *leftArrowPressKey = @"leftArrow"; +const NSString *rightArrowPressKey = @"rightArrow"; +const NSString *upArrowPressKey = @"upArrow"; +const NSString *downArrowPressKey = @"downArrow"; + +- (RCTViewKeyboardEvent*)keyboardEvent:(NSEvent*)event downPress:(BOOL)downPress { + // modifiers + BOOL capsLockKey = NO; + BOOL shiftKey = NO; + BOOL controlKey = NO; + BOOL optionKey = NO; + BOOL commandKey = NO; + BOOL numericPadKey = NO; + BOOL helpKey = NO; + BOOL functionKey = NO; + // commonly used key short-cuts + BOOL leftArrowKey = NO; + BOOL rightArrowKey = NO; + BOOL upArrowKey = NO; + BOOL downArrowKey = NO; + NSString *key = event.charactersIgnoringModifiers; + unichar const code = [key characterAtIndex:0]; + + // detect arrow key presses + if (code == NSLeftArrowFunctionKey) { + leftArrowKey = YES; + } else if (code == NSRightArrowFunctionKey) { + rightArrowKey = YES; + } else if (code == NSUpArrowFunctionKey) { + upArrowKey = YES; + } else if (code == NSDownArrowFunctionKey) { + downArrowKey = YES; + } + + // detect modifier flags + if (event.modifierFlags & NSEventModifierFlagCapsLock) { + capsLockKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagShift) { + shiftKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagControl) { + controlKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagOption) { + optionKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagCommand) { + commandKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagNumericPad) { + numericPadKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagHelp) { + helpKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagFunction) { + functionKey = YES; + } + + RCTViewKeyboardEvent *keyboardEvent = nil; + // only post events for keys we care about + if (downPress) { + if ([self keyIsValid:key validKeys:[self validKeysDown]]) { + keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag + capsLockKey:capsLockKey + shiftKey:shiftKey + controlKey:controlKey + optionKey:optionKey + commandKey:commandKey + numericPadKey:numericPadKey + helpKey:helpKey + functionKey:functionKey + leftArrowKey:leftArrowKey + rightArrowKey:rightArrowKey + upArrowKey:upArrowKey + downArrowKey:downArrowKey + key:key]; + } + } else { + if ([self keyIsValid:key validKeys:[self validKeysUp]]) { + keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag + capsLockKey:capsLockKey + shiftKey:shiftKey + controlKey:controlKey + optionKey:optionKey + commandKey:commandKey + numericPadKey:numericPadKey + helpKey:helpKey + functionKey:functionKey + leftArrowKey:leftArrowKey + rightArrowKey:rightArrowKey + upArrowKey:upArrowKey + downArrowKey:downArrowKey + key:key]; + } + } + return keyboardEvent; +} + +// check if the user typed key matches a key we need to send an event for +- (BOOL)keyIsValid:(NSString*)key validKeys:(NSArray*)validKeys { + BOOL keyIsValid = NO; + + if ([validKeys containsObject:key] || [validKeys containsObject:leftArrowPressKey] || [validKeys containsObject:rightArrowPressKey] || [validKeys containsObject:upArrowPressKey] || [validKeys containsObject:downArrowPressKey]) { + keyIsValid = YES; + } + + return keyIsValid; +} + - (void)keyDown:(NSEvent *)event { if (self.onKeyDown != nil) { [super keyDown:event]; return; } - // only post events for keys we care about - if ([[self validKeysDown] containsObject:event.characters]) { - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; - [_eventDispatcher sendEvent:keyboardEvent]; + RCTViewKeyboardEvent *keyboardEvent = [self keyboardEvent:event downPress:YES]; + if (keyboardEvent != nil) { + [_eventDispatcher sendEvent:[self keyboardEvent:event downPress:YES]]; + } else { + [super keyDown:event]; } } @@ -1592,9 +1697,11 @@ - (void)keyUp:(NSEvent *)event { return; } - if ([[self validKeysUp] containsObject:event.characters]) { - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + RCTViewKeyboardEvent *keyboardEvent = [self keyboardEvent:event downPress:NO]; + if (keyboardEvent != nil) { [_eventDispatcher sendEvent:keyboardEvent]; + } else { + [super keyDown:event]; } } #endif // TARGET_OS_OSX diff --git a/React/Views/RCTViewKeyboardEvent.h b/React/Views/RCTViewKeyboardEvent.h index ef9cf93f3a9be5..2c31b5c418a8c9 100644 --- a/React/Views/RCTViewKeyboardEvent.h +++ b/React/Views/RCTViewKeyboardEvent.h @@ -8,7 +8,33 @@ @interface RCTViewKeyboardEvent : RCTComponentEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag + capsLockKey:(BOOL)capsLockKey + shiftKey:(BOOL)shiftKey + controlKey:(BOOL)controlKey + optionKey:(BOOL)optionKey + commandKey:(BOOL)commandKey + numericPadKey:(BOOL)numericPadKey + helpKey:(BOOL)helpKey + functionKey:(BOOL)functionKey + leftArrowKey:(BOOL)leftArrowKey + rightArrowKey:(BOOL)rightArrowKey + upArrowKey:(BOOL)upArrowKey + downArrowKey:(BOOL)downArrowKey + key:(NSString*)key; ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag + capsLockKey:(BOOL)capsLockKey + shiftKey:(BOOL)shiftKey + controlKey:(BOOL)controlKey + optionKey:(BOOL)optionKey + commandKey:(BOOL)commandKey + numericPadKey:(BOOL)numericPadKey + helpKey:(BOOL)helpKey + functionKey:(BOOL)functionKey + leftArrowKey:(BOOL)leftArrowKey + rightArrowKey:(BOOL)rightArrowKey + upArrowKey:(BOOL)upArrowKey + downArrowKey:(BOOL)downArrowKey + key:(NSString*)key; @end diff --git a/React/Views/RCTViewKeyboardEvent.m b/React/Views/RCTViewKeyboardEvent.m index 29a19c3a9decd4..6e65cde58b2cd3 100644 --- a/React/Views/RCTViewKeyboardEvent.m +++ b/React/Views/RCTViewKeyboardEvent.m @@ -10,19 +10,67 @@ @implementation RCTViewKeyboardEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag + capsLockKey:(BOOL)capsLockKey + shiftKey:(BOOL)shiftKey + controlKey:(BOOL)controlKey + optionKey:(BOOL)optionKey + commandKey:(BOOL)commandKey + numericPadKey:(BOOL)numericPadKey + helpKey:(BOOL)helpKey + functionKey:(BOOL)functionKey + leftArrowKey:(BOOL)leftArrowKey + rightArrowKey:(BOOL)rightArrowKey + upArrowKey:(BOOL)upArrowKey + downrrowKey:(BOOL)downArrowKey + key:(NSString*)key { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyDown" viewTag:reactTag - body:@{ @"characters" : characters, - @"modifier" : @(modifier) }]; + body:@{ @"capsLockKey" : @(capsLockKey), + @"shiftKey" : @(shiftKey), + @"controlKey" : @(controlKey), + @"optionKey" : @(optionKey), + @"commandKey" : @(commandKey), + @"numericPadKey" : @(numericPadKey), + @"helpKey" : @(helpKey), + @"functionKey" : @(functionKey), + @"leftArrowKey" : @(leftArrowKey), + @"rightArrowKey" : @(rightArrowKey), + @"upArrowKey" : @(upArrowKey), + @"downArrowKey" : @(downArrowKey), + @"key" : key }]; return event; } -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag + capsLockKey:(BOOL)capsLockKey + shiftKey:(BOOL)shiftKey + controlKey:(BOOL)controlKey + optionKey:(BOOL)optionKey + commandKey:(BOOL)commandKey + numericPadKey:(BOOL)numericPadKey + helpKey:(BOOL)helpKey + functionKey:(BOOL)functionKey + leftArrowKey:(BOOL)leftArrowKey + rightArrowKey:(BOOL)rightArrowKey + upArrowKey:(BOOL)upArrowKey + downrrowKey:(BOOL)downArrowKey + key:(NSString*)key { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyUp" viewTag:reactTag - body:@{ @"characters" : characters, - @"modifier" : @(modifier) }]; + body:@{ @"capsLockKey" : @(capsLockKey), + @"shiftKey" : @(shiftKey), + @"controlKey" : @(controlKey), + @"optionKey" : @(optionKey), + @"commandKey" : @(commandKey), + @"numericPadKey" : @(numericPadKey), + @"helpKey" : @(helpKey), + @"functionKey" : @(functionKey), + @"leftArrowKey" : @(leftArrowKey), + @"rightArrowKey" : @(rightArrowKey), + @"upArrowKey" : @(upArrowKey), + @"downArrowKey" : @(downArrowKey), + @"key" : key }]; return event; } From 58941114af25bb0635d65ace94d7d0572908861c Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 26 Nov 2020 00:12:59 -0800 Subject: [PATCH 11/23] macOS keyboard support --- Libraries/Components/Button.js | 17 ++- .../Components/Touchable/TouchableOpacity.js | 12 +++ .../Touchable/TouchableWithoutFeedback.js | 7 ++ .../View/ReactNativeViewAttributes.js | 2 + .../View/ReactNativeViewViewConfig.js | 12 +++ .../View/ReactNativeViewViewConfigMacOS.js | 2 + Libraries/Components/View/ViewPropTypes.js | 3 + Libraries/Pressability/Pressability.js | 22 ++++ Libraries/Renderer/shims/ReactNativeTypes.js | 2 + Libraries/Types/CoreEventTypes.js | 7 ++ RNTester/Podfile.lock | 58 +++++----- .../KeyboardEventsExample.js | 100 ++++++++++++++++++ RNTester/js/utils/RNTesterList.ios.js | 5 + React/Base/RCTEventDispatcher.m | 2 +- React/Views/RCTView.h | 4 + React/Views/RCTView.m | 25 +++++ React/Views/RCTViewKeyboardEvent.h | 14 +++ React/Views/RCTViewKeyboardEvent.m | 29 +++++ React/Views/RCTViewManager.m | 4 + 19 files changed, 296 insertions(+), 31 deletions(-) create mode 100644 RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js create mode 100644 React/Views/RCTViewKeyboardEvent.h create mode 100644 React/Views/RCTViewKeyboardEvent.m diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index 73d32d1285fab0..ac676119288bf9 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -20,7 +20,7 @@ const View = require('./View/View'); const invariant = require('invariant'); -import type {PressEvent} from '../Types/CoreEventTypes'; +import type {PressEvent, KeyEvent} from '../Types/CoreEventTypes'; import type {FocusEvent, BlurEvent} from './TextInput/TextInput'; // TODO(OSS Candidate ISS#2710739) import type {ColorValue} from '../StyleSheet/StyleSheetTypes'; @@ -113,6 +113,17 @@ type ButtonProps = $ReadOnly<{| * Handler to be called when the button loses key focus */ onFocus?: ?(e: FocusEvent) => void, + + /** + * Handler to be called when a key down press is detected + */ + onKeyDown?: ?(e: KeyEvent) => void, + + /** + * Handler to be called when a key up press is detected + */ + onKeyUp?: ?(e: KeyEvent) => void, + // ]TODO(OSS Candidate ISS#2710739) |}>; @@ -163,6 +174,8 @@ class Button extends React.Component { testID, onFocus, // TODO(OSS Candidate ISS#2710739) onBlur, // TODO(OSS Candidate ISS#2710739) + onKeyDown, + onKeyUp, } = this.props; const buttonStyles = [styles.button]; const textStyles = [styles.text]; @@ -207,6 +220,8 @@ class Button extends React.Component { onPress={onPress} onFocus={onFocus} // TODO(OSS Candidate ISS#2710739) onBlur={onBlur} // TODO(OSS Candidate ISS#2710739) + onKeyDown={onKeyDown} + onKeyUp={onKeyUp} touchSoundDisabled={touchSoundDisabled}> diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 4381977e2b4193..a9d0f2d5d76da7 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -165,6 +165,16 @@ class TouchableOpacity extends React.Component { this.props.onFocus(event); } }, + onKeyDown: event => { + if (this.props.onKeyDown != null) { + this.props.onKeyDown(event); + } + }, + onKeyUp: event => { + if (this.props.onKeyUp != null) { + this.props.onKeyUp(event); + } + }, onLongPress: this.props.onLongPress, onPress: this.props.onPress, onPressIn: event => { @@ -279,6 +289,8 @@ class TouchableOpacity extends React.Component { onDrop={this.props.onDrop} onFocus={this.props.onFocus} onBlur={this.props.onBlur} + onKeyDown={this.props.onKeyDown} + onKeyUp={this.props.onKeyUp} draggedTypes={this.props.draggedTypes} // ]TODO(macOS ISS#2323203) ref={this.props.hostRef} {...eventHandlersWithoutBlurAndFocus}> diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index de448985aac3f9..739ec333a87da1 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -26,6 +26,7 @@ import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; import type { BlurEvent, FocusEvent, + KeyEvent, LayoutEvent, PressEvent, MouseEvent, // TODO(macOS ISS#2323203) @@ -64,6 +65,8 @@ type Props = $ReadOnly<{| onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed, onBlur?: ?(event: BlurEvent) => mixed, onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + onKeyUp?: ?(event: KeyEvent) => mixed, onLayout?: ?(event: LayoutEvent) => mixed, onLongPress?: ?(event: PressEvent) => mixed, onPress?: ?(event: PressEvent) => mixed, @@ -106,6 +109,8 @@ const PASSTHROUGH_PROPS = [ 'onAccessibilityAction', 'onBlur', 'onFocus', + 'onKeyDown', + 'onKeyUp', 'onLayout', 'onMouseEnter', // [TODO(macOS ISS#2323203) 'onMouseLeave', @@ -227,6 +232,8 @@ function createPressabilityConfig(props: Props): PressabilityConfig { android_disableSound: props.touchSoundDisabled, onBlur: props.onBlur, onFocus: props.onFocus, + onKeyDown: props.onKeyDown, + onKeyUp: props.onKeyUp, onLongPress: props.onLongPress, onPress: props.onPress, onPressIn: props.onPressIn, diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index b1956afc3f7c71..8ab81879c3ea32 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -42,6 +42,8 @@ const UIView = { onDragEnter: true, onDragLeave: true, onDrop: true, + onKeyDown: true, + onKeyUp: true, draggedTypes: true, // ]TODO(macOS ISS#2323203) style: ReactNativeStyleAttributes, }; diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 8858f62d5b0be4..25175748e7568c 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -45,6 +45,18 @@ const ReactNativeViewConfig = { captured: 'onFocusCapture', }, }, + topKeyUp: { + phasedRegistrationNames: { + bubbled: 'onKeyUp', + captured: 'onKeyUpCapture', + }, + }, + topKeyDown: { + phasedRegistrationNames: { + bubbled: 'onKeyDown', + captured: 'onKeyDownCapture', + }, + }, topKeyPress: { phasedRegistrationNames: { bubbled: 'onKeyPress', diff --git a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js index c28419bd527042..23016ab7bcc9f4 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js +++ b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js @@ -47,6 +47,8 @@ const ReactNativeViewViewConfigMacOS = { onDragLeave: true, onDrop: true, onFocus: true, + onKeyDown: true, + onKeyUp: true, onMouseEnter: true, onMouseLeave: true, tooltip: true, diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 0265dd1267160f..6bdf9009e8c726 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -18,6 +18,7 @@ import type { Layout, LayoutEvent, ScrollEvent, // TODO(macOS ISS#2323203) + KeyEvent, } from '../../Types/CoreEventTypes'; import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType'; import type {Node} from 'react'; @@ -41,6 +42,8 @@ export type ViewLayoutEvent = LayoutEvent; type BubblingEventProps = $ReadOnly<{| onBlur?: ?(event: BlurEvent) => mixed, onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + onKeyUp?: ?(event: KeyEvent) => mixed, |}>; type DirectEventProps = $ReadOnly<{| diff --git a/Libraries/Pressability/Pressability.js b/Libraries/Pressability/Pressability.js index f02c7339bbcca9..65d6607b221b0d 100644 --- a/Libraries/Pressability/Pressability.js +++ b/Libraries/Pressability/Pressability.js @@ -17,6 +17,7 @@ import {normalizeRect, type RectOrSize} from '../StyleSheet/Rect'; import type { BlurEvent, FocusEvent, + KeyEvent, PressEvent, MouseEvent, } from '../Types/CoreEventTypes'; @@ -93,6 +94,10 @@ export type PressabilityConfig = $ReadOnly<{| */ onFocus?: ?(event: FocusEvent) => mixed, + onKeyDown?: ?(event: KeyEvent) => mixed, + + onKeyUp?: ?(event: KeyEvent) => mixed, + /** * Called when the hover is activated to provide visual feedback. */ @@ -156,6 +161,8 @@ export type EventHandlers = $ReadOnly<{| onBlur: (event: BlurEvent) => void, onClick: (event: PressEvent) => void, onFocus: (event: FocusEvent) => void, + onKeyDown: (event: KeyDown) => void, + onKeyUp: (event: KeyDown) => void, onMouseEnter?: (event: MouseEvent) => void, onMouseLeave?: (event: MouseEvent) => void, onResponderGrant: (event: PressEvent) => void, @@ -445,6 +452,21 @@ export default class Pressability { } }, }; + + const keyEventHandlers = { + onKeyDown: (event: KeyEvent): void => { + const {onKeyDown} = this._config; + if (onKeyDown != null) { + onKeyDown(event); + } + }, + onKeyUp: (event: KeyEvent): void => { + const {onKeyUp} = this._config; + if (onKeyUp != null) { + onKeyUp(event); + } + }, + }; const responderEventHandlers = { onStartShouldSetResponder: (): boolean => { diff --git a/Libraries/Renderer/shims/ReactNativeTypes.js b/Libraries/Renderer/shims/ReactNativeTypes.js index 10244570b65354..ec68139ab57208 100644 --- a/Libraries/Renderer/shims/ReactNativeTypes.js +++ b/Libraries/Renderer/shims/ReactNativeTypes.js @@ -80,6 +80,8 @@ export type ViewConfigGetter = () => ReactNativeBaseComponentViewConfig<>; export type NativeMethods = { blur(): void, focus(): void, + onKeyDown(): void, + onKeyUp(): void, measure(callback: MeasureOnSuccessCallback): void, measureInWindow(callback: MeasureInWindowOnSuccessCallback): void, measureLayout( diff --git a/Libraries/Types/CoreEventTypes.js b/Libraries/Types/CoreEventTypes.js index 065657395ef739..635548643bf574 100644 --- a/Libraries/Types/CoreEventTypes.js +++ b/Libraries/Types/CoreEventTypes.js @@ -152,6 +152,13 @@ export type FocusEvent = SyntheticEvent< |}>, >; +export type KeyEvent = SyntheticEvent< + $ReadOnly<{| + characters: string, + modifier: number, + |}>, +>; + export type MouseEvent = SyntheticEvent< $ReadOnly<{| clientX: number, diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index 9b0f823da65df7..a895cca6ab9299 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -431,7 +431,7 @@ DEPENDENCIES: - Yoga (from `../ReactCommon/yoga`) SPEC REPOS: - https://cdn.cocoapods.org/: + trunk: - CocoaAsyncSocket - CocoaLibEvent - Flipper @@ -519,8 +519,8 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: e99626a767684cd45377cfb2d270260b08612394 - FBReactNativeSpec: 4caa8b770647aad3624a57c46871bf01c1e1ef59 + FBLazyVector: 058eeb6417ef70b3b8949d2b4ea1588033186266 + FBReactNativeSpec: 9b1b4c1fa7ba24ffa7712799e2cbb602b97eda5d Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 @@ -533,34 +533,34 @@ SPEC CHECKSUMS: libevent: ee9265726a1fc599dea382964fa304378affaa5f OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: 7803a0a3a3d56e3cec84ae1ccbe0f4a2476f9f69 - RCTTypeSafety: ae513041fa8773699d99833a8691d2e8b8d6ee8a - React: d6306405782c4669fd3d4d0125a7b2cc2bb19233 - React-ART: 65684f957e38c119918b2ad8e2f2c386790b20d0 - React-callinvoker: edc229ccab488b3b57895e830d2b825e79f9f04c - React-Core: 50805a8b5eb817533763ae0132a0a61fc740fddf - React-CoreModules: 3147038a51e5a1a1819be556efb3c22855816aec - React-cxxreact: 88f9c5fbd0c391488fb884ab4bf8af85c548230c - React-jsi: e7b3496404f24299beb067b0e4fa38e836f1d6a4 - React-jsiexecutor: f214cb9bebf408f6deeea9f6fe6ca610ab88eb6e - React-jsinspector: 7fba9bc98d5047bf5c8dae0cd8acd36b86448d04 - React-RCTActionSheet: c4b92af34b6f64c786a972f5c196a375b7ce6cea - React-RCTAnimation: 5a0f7f7b3eaf0520e53d119f8352fdc622d0a90b - React-RCTBlob: 37befa1be701fe18ab0d63eb986b65829c843fc6 - React-RCTImage: a02ff4f1882f35574ae589556b5c94b9eee973da - React-RCTLinking: 70240d29450241879339d7384b0903232d30e2c6 - React-RCTNetwork: 17a1cd202a4566c25244444644a1fadd092466db - React-RCTPushNotification: eec1e289dfb203ee5360a9065c4009de0c16e097 - React-RCTSettings: 490435d0c7767d085ebc9218d6cc9f9e2018ff1c - React-RCTTest: 06e4d480573015d42b0acb110aeb343c16d0c595 - React-RCTText: a2a64b9c882d9b9a8e26c27773ca305ce910f4a6 - React-RCTVibration: d32b07b6c9e821cb784b04e1c65cee3b35099b54 + RCTRequired: ec85d1ef4d51803337cde71de052e3db103d6472 + RCTTypeSafety: a4430a19dff2b11c1c0521ddd9e90b0c033217b4 + React: 58c48d390d9c13c7e28ee4832d59a931e26d4a5c + React-ART: d6002339cd61232b4b6b64abc4c519f22c5a53b4 + React-callinvoker: ad1904b8c01625a218e541417c1f2269912eba6b + React-Core: d66de0613ce7984076226eaed78f75c6c46bf91c + React-CoreModules: 4be0efeb5b0434beae09740b7672d9c718856e78 + React-cxxreact: 8386895677c64406ab269a2390f1bd7a9416a698 + React-jsi: fcd89cccc1a8d1fea9a6a3b85645781a12daf712 + React-jsiexecutor: 1c8f0bf5110a999922389d8d71f99d6ee942dcd8 + React-jsinspector: 6dcbf0c485a9cefa3e3bf87dc3aa9f2ecea1a5dd + React-RCTActionSheet: 66b3b31c0566bab2e90b198c893432b4e8ac1883 + React-RCTAnimation: 42fee356deb87bf0f351836625dcc40e610000cd + React-RCTBlob: b3a07d1b087bc30d9a70e5f6aad3828531d03c67 + React-RCTImage: 50b248b2a61a4eba7a7c86de6f0ae1cb0b70c25d + React-RCTLinking: 2d5c14d4f96faa81c04e4754db0c7b05ea35de3e + React-RCTNetwork: 2707c0d37396d1f8876bc74eaa8e7374a8be788a + React-RCTPushNotification: 05efdc2e49aaa39c9a087d75d3d54fef2b8a9554 + React-RCTSettings: 230c589aabbcb4f04212ea17a7afdbf2b21d716d + React-RCTTest: 56492ab0dec8652ecf7bd33bcefc1494a759470b + React-RCTText: 07ea13069c32f7c8c13deb374c00ddfd641dd925 + React-RCTVibration: e71fbb228d655d109bc069bb3a50809761a078a8 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: cbe13444db8dc3af024947610c537a27cea1c1cb - ReactCommon: d849f99f384dafff03d56ac7e9fd173e117b1509 - Yoga: 5ba9af3554885e152355679790ed9be0b1d01695 + React-TurboModuleCxx-WinRTPort: 6c285289e9266a7e316cb87f44396469e23dba9b + ReactCommon: 378cffdae03f1a712467fa43af195df1f79080b3 + Yoga: c3920c26a6383607e1776e35919aca16bbbf1991 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 -COCOAPODS: 1.8.4 +COCOAPODS: 1.9.1 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js new file mode 100644 index 00000000000000..48d3250cc7ca43 --- /dev/null +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -0,0 +1,100 @@ +/** + * Copyright (c) 2015-present, Facebook, Inc. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + * + * @format + * @flow + */ + +'use strict'; // TODO(OSS Candidate ISS#2710739) + +const React = require('react'); +const ReactNative = require('react-native'); +import {Platform} from 'react-native'; +const {Button, PlatformColor, StyleSheet, Text, View } = ReactNative; + +import { KeyEvent } from 'react-native/Libraries/Types/CoreEventTypes'; + +class KeyEventExample extends React.Component<{}, State> { + state: State = { + eventStream: '', + characters: '', + }; + + onKeyDownEvent: (e: KeyEvent) => void = (e: KeyEvent) => { + console.log('received view key down event\n', e.nativeEvent['characters']); + this.setState({characters: e.nativeEvent.characters}) + this.setState(prevState => ({ + eventStream: prevState.eventStream + prevState.characters + '\nKey Down: ' + })); + }; + + onKeyUpEvent: (e: KeyEvent) => void = (e: KeyEvent) => { + console.log('received key up event\n', e.nativeEvent['characters']); + this.setState({characters: e.nativeEvent.characters}) + this.setState(prevState => ({ + eventStream: prevState.eventStream + prevState.characters + '\nKey Up: ' + })); + }; + + render() { + return ( + + + Key events are called when a component detects a key press. + + + {// Only test View on MacOS, since canBecomeFirstResponder is false on all iOS, therefore we can't focus + Platform.OS === 'macos' ? ( + + + + ) : null} + {'Events: ' + this.state.eventStream + JSON.stringify(this.state.characters) + '\n\n'} + + + ); + } +} + +var styles = StyleSheet.create({ + textInput: { + ...Platform.select({ + macos: { + color: PlatformColor('textColor'), + backgroundColor: PlatformColor('textBackgroundColor'), + borderColor: PlatformColor('gridColor'), + }, + default: { + borderColor: '#0f0f0f', + }, + }), + borderWidth: StyleSheet.hairlineWidth, + flex: 1, + fontSize: 13, + padding: 4, + }, +}); + +exports.title = 'Key Events'; +exports.description = 'Examples that show how Key events can be used.'; +exports.examples = [ + { + title: 'KeyEventExample', + render: function(): React.Element { + return ; + }, + }, +]; diff --git a/RNTester/js/utils/RNTesterList.ios.js b/RNTester/js/utils/RNTesterList.ios.js index 9ab6663e51b980..75f2389372a09a 100644 --- a/RNTester/js/utils/RNTesterList.ios.js +++ b/RNTester/js/utils/RNTesterList.ios.js @@ -51,6 +51,11 @@ const ComponentExamples: Array = [ module: require('../examples/FocusEventsExample/FocusEventsExample'), supportsTVOS: true, }, // ]TODO(OSS Candidate ISS#2710739) + { + key: 'KeyboardEvents', + module: require('../examples/KeyboardEventsExample/KeyboardEventsExample'), + supportsTVOS: false, + }, // ]TODO(OSS Candidate ISS#2710739) { key: 'ImageExample', module: require('../examples/Image/ImageExample'), diff --git a/React/Base/RCTEventDispatcher.m b/React/Base/RCTEventDispatcher.m index 3da2e268ed72ba..5903834e824acf 100644 --- a/React/Base/RCTEventDispatcher.m +++ b/React/Base/RCTEventDispatcher.m @@ -84,7 +84,7 @@ - (void)sendTextEventWithType:(RCTTextEventType)type key:(NSString *)key eventCount:(NSInteger)eventCount { - static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress"}; + static NSString *events[] = {@"focus", @"blur", @"change", @"submitEditing", @"endEditing", @"keyPress", @"keyDown", @"keyUp"}; NSMutableDictionary *body = [[NSMutableDictionary alloc] initWithDictionary:@{ @"eventCount" : @(eventCount), diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index b0800d9e1e1169..78f83974d0179d 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -135,6 +135,10 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; @property (nonatomic, copy) RCTDirectEventBlock onDragEnter; @property (nonatomic, copy) RCTDirectEventBlock onDragLeave; @property (nonatomic, copy) RCTDirectEventBlock onDrop; + +// Keyboarding events +@property (nonatomic, copy) RCTBubblingEventBlock onKeyDown; +@property (nonatomic, copy) RCTBubblingEventBlock onKeyUp; #endif // ]TODO(macOS ISS#2323203) /** diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 4f902b6bf8ca29..5b4a42d44c86ef 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -16,6 +16,7 @@ #import "RCTRootContentView.h" // TODO(macOS ISS#2323203) #import "RCTUtils.h" #import "UIView+React.h" +#import "RCTViewKeyboardEvent.h" #if TARGET_OS_OSX // [TODO(macOS ISS#2323203) #import "RCTTextView.h" #endif // ]TODO(macOS ISS#2323203) @@ -1569,4 +1570,28 @@ - (BOOL)performDragOperation:(id )sender } #endif // ]TODO(macOS ISS#2323203) +#pragma mark - Keyboard Events + +#if TARGET_OS_OSX // TODO: add iOS keyboard event handling +- (void)keyDown:(NSEvent *)event { + if (!self.onKeyDown) { + [super keyDown:event]; + return; + } + + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; +} + +- (void)keyUp:(NSEvent *)event { + if (!self.onKeyUp) { + [super keyUp:event]; + return; + } + + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; +} +#endif // TARGET_OS_OSX + @end diff --git a/React/Views/RCTViewKeyboardEvent.h b/React/Views/RCTViewKeyboardEvent.h new file mode 100644 index 00000000000000..4bcbcfe10796ce --- /dev/null +++ b/React/Views/RCTViewKeyboardEvent.h @@ -0,0 +1,14 @@ +/* + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import +#import + +@interface RCTViewKeyboardEvent : RCTComponentEvent + ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; + +@end diff --git a/React/Views/RCTViewKeyboardEvent.m b/React/Views/RCTViewKeyboardEvent.m new file mode 100644 index 00000000000000..17fc2e6e0b608e --- /dev/null +++ b/React/Views/RCTViewKeyboardEvent.m @@ -0,0 +1,29 @@ +/* + * Copyright (c) Facebook, Inc. and its affiliates. + * + * This source code is licensed under the MIT license found in the + * LICENSE file in the root directory of this source tree. + */ + +#import "RCTViewKeyboardEvent.h" +#import + +@implementation RCTViewKeyboardEvent + ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { + RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyDown" + viewTag:reactTag + body:@{ @"characters" : characters, + @"modifier" : @(modifier) }]; + return event; +} + ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { + RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyUp" + viewTag:reactTag + body:@{ @"characters" : characters, + @"modifier" : @(modifier) }]; + return event; +} + +@end diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index e1dff7e8c44fc2..671c1745804066 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -112,6 +112,8 @@ - (RCTShadowView *)shadowView @"change", @"focus", @"blur", + @"keyDown", + @"keyUp", @"submitEditing", @"endEditing", @"keyPress", @@ -464,6 +466,8 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(onDragLeave, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDrop, RCTDirectEventBlock) #endif // ]TODO(macOS ISS#2323203) +RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events +RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events #pragma mark - ShadowView properties From ecc351cfeca775fb8effee527a17251f460721a0 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 26 Nov 2020 00:24:10 -0800 Subject: [PATCH 12/23] update comment --- .../js/examples/KeyboardEventsExample/KeyboardEventsExample.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index 48d3250cc7ca43..38b8c0c5a373e0 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -46,7 +46,7 @@ class KeyEventExample extends React.Component<{}, State> { Key events are called when a component detects a key press. - {// Only test View on MacOS, since canBecomeFirstResponder is false on all iOS, therefore we can't focus + { Platform.OS === 'macos' ? ( Date: Wed, 9 Dec 2020 16:03:51 -0800 Subject: [PATCH 13/23] add key value checks so we don't send all events --- RNTester/Podfile.lock | 68 +++++++++---------- .../KeyboardEventsExample.js | 10 ++- React/Views/RCTView.h | 2 + React/Views/RCTView.m | 21 +++--- React/Views/RCTViewKeyboardEvent.h | 4 +- React/Views/RCTViewKeyboardEvent.m | 4 +- React/Views/RCTViewManager.m | 4 +- 7 files changed, 65 insertions(+), 48 deletions(-) diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index a895cca6ab9299..1c5dbea32c6f02 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -15,12 +15,12 @@ PODS: - Flipper-Folly (~> 2.2) - Flipper-RSocket (~> 1.1) - Flipper-DoubleConversion (1.1.7) - - Flipper-Folly (2.2.0): + - Flipper-Folly (2.3.0): - boost-for-react-native - CocoaLibEvent (~> 1.0) - Flipper-DoubleConversion - Flipper-Glog - - OpenSSL-Universal (= 1.0.2.19) + - OpenSSL-Universal (= 1.0.2.20) - Flipper-Glog (0.3.6) - Flipper-PeerTalk (0.0.4) - Flipper-RSocket (1.1.0): @@ -64,9 +64,9 @@ PODS: - libevent/core (2.1.11): - libevent/event2-headers - libevent/event2-headers (2.1.11) - - OpenSSL-Universal (1.0.2.19): - - OpenSSL-Universal/Static (= 1.0.2.19) - - OpenSSL-Universal/Static (1.0.2.19) + - OpenSSL-Universal (1.0.2.20): + - OpenSSL-Universal/Static (= 1.0.2.20) + - OpenSSL-Universal/Static (1.0.2.20) - RCT-Folly (2020.01.13.00): - boost-for-react-native - DoubleConversion @@ -519,11 +519,11 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: 058eeb6417ef70b3b8949d2b4ea1588033186266 - FBReactNativeSpec: 9b1b4c1fa7ba24ffa7712799e2cbb602b97eda5d + FBLazyVector: a6ae1b79864b3b25e30e33ebf6efdede05eddbfa + FBReactNativeSpec: 0d87e289ca0559216298b1af12537cff0f54588c Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 - Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 + Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 @@ -531,34 +531,34 @@ SPEC CHECKSUMS: glog: 1cb7c408c781ae8f35bbababe459b45e3dee4ec1 hermes: 12d049af0d8e8379c5b3b54ffb1919d670045bdc libevent: ee9265726a1fc599dea382964fa304378affaa5f - OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 + OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: ec85d1ef4d51803337cde71de052e3db103d6472 - RCTTypeSafety: a4430a19dff2b11c1c0521ddd9e90b0c033217b4 - React: 58c48d390d9c13c7e28ee4832d59a931e26d4a5c - React-ART: d6002339cd61232b4b6b64abc4c519f22c5a53b4 - React-callinvoker: ad1904b8c01625a218e541417c1f2269912eba6b - React-Core: d66de0613ce7984076226eaed78f75c6c46bf91c - React-CoreModules: 4be0efeb5b0434beae09740b7672d9c718856e78 - React-cxxreact: 8386895677c64406ab269a2390f1bd7a9416a698 - React-jsi: fcd89cccc1a8d1fea9a6a3b85645781a12daf712 - React-jsiexecutor: 1c8f0bf5110a999922389d8d71f99d6ee942dcd8 - React-jsinspector: 6dcbf0c485a9cefa3e3bf87dc3aa9f2ecea1a5dd - React-RCTActionSheet: 66b3b31c0566bab2e90b198c893432b4e8ac1883 - React-RCTAnimation: 42fee356deb87bf0f351836625dcc40e610000cd - React-RCTBlob: b3a07d1b087bc30d9a70e5f6aad3828531d03c67 - React-RCTImage: 50b248b2a61a4eba7a7c86de6f0ae1cb0b70c25d - React-RCTLinking: 2d5c14d4f96faa81c04e4754db0c7b05ea35de3e - React-RCTNetwork: 2707c0d37396d1f8876bc74eaa8e7374a8be788a - React-RCTPushNotification: 05efdc2e49aaa39c9a087d75d3d54fef2b8a9554 - React-RCTSettings: 230c589aabbcb4f04212ea17a7afdbf2b21d716d - React-RCTTest: 56492ab0dec8652ecf7bd33bcefc1494a759470b - React-RCTText: 07ea13069c32f7c8c13deb374c00ddfd641dd925 - React-RCTVibration: e71fbb228d655d109bc069bb3a50809761a078a8 + RCTRequired: 29479b86ec65f4157241d78264f5ef561ade22fb + RCTTypeSafety: 43df0a984fb268c979ca4d48b9b7c2f36c2f8afa + React: 92b73328440bbd85d6aac595e0b72bbd908691fb + React-ART: d21f4390d74751534f13904901c26bfe6ec794b9 + React-callinvoker: f95c3045678d4c92bee335c1ec33eb3aab4b83cf + React-Core: 0abfcfd7ed793acd786214e31a42769e0e921250 + React-CoreModules: 7142aeffd74868437608d69dc1f596183df207c1 + React-cxxreact: 49eee018ad861486cbfb221cddd45ac439b730fa + React-jsi: 66ec265a85cc56188a6e433b72382ed115fcad06 + React-jsiexecutor: 8dcf37ad0edd05809b2854d233647955ce122aa0 + React-jsinspector: 1e18eda10420137d634f3b660764e248da09e431 + React-RCTActionSheet: 1e77963344b7554bd0d506fdddc248b3031a3acd + React-RCTAnimation: 24665293e82d8fe009c52544e44442e24af67226 + React-RCTBlob: b80b29efb1b2cc0a568a6e9ef439e9e41b05127b + React-RCTImage: 0699991f74770bc2be51f76fcde7f7aeac7d4082 + React-RCTLinking: 4f0b40c7550999b4cf748e7c061c59b69e0f6648 + React-RCTNetwork: cfbd60b6797b913175b8a6349e10bb6fd961fc26 + React-RCTPushNotification: 80d37852e87f85b9e88f989142401c0f9257b2f8 + React-RCTSettings: dc94e747d8edc1810256bd0b024dd61ae4ab5a22 + React-RCTTest: 04d14b0b8a8d7ff9d8868fdb66218ff9db0259c1 + React-RCTText: 18fece5415a20dbaccd7ccfe17779bbf64c17fc4 + React-RCTVibration: b5d1d694cc4c6ca520cc23e10440e5adc39263d1 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: 6c285289e9266a7e316cb87f44396469e23dba9b - ReactCommon: 378cffdae03f1a712467fa43af195df1f79080b3 - Yoga: c3920c26a6383607e1776e35919aca16bbbf1991 + React-TurboModuleCxx-WinRTPort: d280a253fdf89944869969d1bbd5c839052f0287 + ReactCommon: 63ef025432213eb0b612bdb3542e7bf57dbd561c + Yoga: 18c5eda53e05f95700b68b07a38c2487dea04fa8 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index 38b8c0c5a373e0..f597a59ee9e428 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -17,6 +17,10 @@ const {Button, PlatformColor, StyleSheet, Text, View } = ReactNative; import { KeyEvent } from 'react-native/Libraries/Types/CoreEventTypes'; +type State = { + eventStream: string, +}; + class KeyEventExample extends React.Component<{}, State> { state: State = { eventStream: '', @@ -51,12 +55,16 @@ class KeyEventExample extends React.Component<{}, State> { @@ -69,7 +77,7 @@ class KeyEventExample extends React.Component<{}, State> { } } -var styles = StyleSheet.create({ +const styles = StyleSheet.create({ textInput: { ...Platform.select({ macos: { diff --git a/React/Views/RCTView.h b/React/Views/RCTView.h index 78f83974d0179d..d31a936dd83c4b 100644 --- a/React/Views/RCTView.h +++ b/React/Views/RCTView.h @@ -139,6 +139,8 @@ extern const UIAccessibilityTraits SwitchAccessibilityTrait; // Keyboarding events @property (nonatomic, copy) RCTBubblingEventBlock onKeyDown; @property (nonatomic, copy) RCTBubblingEventBlock onKeyUp; +@property (nonatomic, copy) NSArray *validKeysDown; +@property (nonatomic, copy) NSArray *validKeysUp; #endif // ]TODO(macOS ISS#2323203) /** diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 5b4a42d44c86ef..226e2fdfe646c0 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -1572,25 +1572,30 @@ - (BOOL)performDragOperation:(id )sender #pragma mark - Keyboard Events -#if TARGET_OS_OSX // TODO: add iOS keyboard event handling +#if TARGET_OS_OSX - (void)keyDown:(NSEvent *)event { - if (!self.onKeyDown) { + if (self.onKeyDown != nil) { [super keyDown:event]; return; } - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; - [_eventDispatcher sendEvent:keyboardEvent]; + // only post events for keys we care about + if ([[self validKeysDown] containsObject:event.characters]) { + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; + } } - (void)keyUp:(NSEvent *)event { - if (!self.onKeyUp) { + if (self.onKeyUp != nil) { [super keyUp:event]; return; } - - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; - [_eventDispatcher sendEvent:keyboardEvent]; + + if ([[self validKeysUp] containsObject:event.characters]) { + RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + [_eventDispatcher sendEvent:keyboardEvent]; + } } #endif // TARGET_OS_OSX diff --git a/React/Views/RCTViewKeyboardEvent.h b/React/Views/RCTViewKeyboardEvent.h index 4bcbcfe10796ce..ef9cf93f3a9be5 100644 --- a/React/Views/RCTViewKeyboardEvent.h +++ b/React/Views/RCTViewKeyboardEvent.h @@ -8,7 +8,7 @@ @interface RCTViewKeyboardEvent : RCTComponentEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; @end diff --git a/React/Views/RCTViewKeyboardEvent.m b/React/Views/RCTViewKeyboardEvent.m index 17fc2e6e0b608e..29a19c3a9decd4 100644 --- a/React/Views/RCTViewKeyboardEvent.m +++ b/React/Views/RCTViewKeyboardEvent.m @@ -10,7 +10,7 @@ @implementation RCTViewKeyboardEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyDown" viewTag:reactTag body:@{ @"characters" : characters, @@ -18,7 +18,7 @@ + (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSStri return event; } -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString*)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyUp" viewTag:reactTag body:@{ @"characters" : characters, diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 671c1745804066..fbf713353402fa 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -465,9 +465,11 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(onDragEnter, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDragLeave, RCTDirectEventBlock) RCT_EXPORT_VIEW_PROPERTY(onDrop, RCTDirectEventBlock) -#endif // ]TODO(macOS ISS#2323203) RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events +RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray) +RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray) +#endif // ]TODO(macOS ISS#2323203) #pragma mark - ShadowView properties From b40eace0002216ade3e12e3d556c22beee791171 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 10 Dec 2020 23:02:41 -0800 Subject: [PATCH 14/23] only use valid keys, bubble events to super --- Libraries/Pressability/Pressability.js | 6 + Libraries/Types/CoreEventTypes.js | 17 ++- RNTester/Podfile.lock | 54 ++++---- .../KeyboardEventsExample.js | 10 +- React/Views/RCTView.m | 119 +++++++++++++++++- React/Views/RCTViewKeyboardEvent.h | 30 ++++- React/Views/RCTViewKeyboardEvent.m | 60 ++++++++- 7 files changed, 248 insertions(+), 48 deletions(-) diff --git a/Libraries/Pressability/Pressability.js b/Libraries/Pressability/Pressability.js index 65d6607b221b0d..da199bee42858d 100644 --- a/Libraries/Pressability/Pressability.js +++ b/Libraries/Pressability/Pressability.js @@ -94,8 +94,14 @@ export type PressabilityConfig = $ReadOnly<{| */ onFocus?: ?(event: FocusEvent) => mixed, + /* + * Called after a key down event is detected. + */ onKeyDown?: ?(event: KeyEvent) => mixed, + /* + * Called after a key up event is detected. + */ onKeyUp?: ?(event: KeyEvent) => mixed, /** diff --git a/Libraries/Types/CoreEventTypes.js b/Libraries/Types/CoreEventTypes.js index 635548643bf574..11c1b7100a5d3c 100644 --- a/Libraries/Types/CoreEventTypes.js +++ b/Libraries/Types/CoreEventTypes.js @@ -154,8 +154,21 @@ export type FocusEvent = SyntheticEvent< export type KeyEvent = SyntheticEvent< $ReadOnly<{| - characters: string, - modifier: number, + // Modifier keys + capsLockKey: boolean, + shiftKey: boolean, + controlKey: boolean, + optionKey: boolean, + commandKey: boolean, + numericPadKey: boolean, + helpKey: boolean, + functionKey: boolean, + // Key options + leftArrowKey: boolean, + rightArrowKey: boolean, + upArrowKey: boolean, + downArrowKey: boolean, + key: string, |}>, >; diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index 1c5dbea32c6f02..a56e0fef5ea607 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -519,8 +519,8 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: a6ae1b79864b3b25e30e33ebf6efdede05eddbfa - FBReactNativeSpec: 0d87e289ca0559216298b1af12537cff0f54588c + FBLazyVector: 15d29e4a0b8ae8fc03616b36fb5b9b8d554bfede + FBReactNativeSpec: 24e41f4afb47a2d5af7687f85b8dec0eb4163347 Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a @@ -533,32 +533,32 @@ SPEC CHECKSUMS: libevent: ee9265726a1fc599dea382964fa304378affaa5f OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: 29479b86ec65f4157241d78264f5ef561ade22fb - RCTTypeSafety: 43df0a984fb268c979ca4d48b9b7c2f36c2f8afa - React: 92b73328440bbd85d6aac595e0b72bbd908691fb - React-ART: d21f4390d74751534f13904901c26bfe6ec794b9 - React-callinvoker: f95c3045678d4c92bee335c1ec33eb3aab4b83cf - React-Core: 0abfcfd7ed793acd786214e31a42769e0e921250 - React-CoreModules: 7142aeffd74868437608d69dc1f596183df207c1 - React-cxxreact: 49eee018ad861486cbfb221cddd45ac439b730fa - React-jsi: 66ec265a85cc56188a6e433b72382ed115fcad06 - React-jsiexecutor: 8dcf37ad0edd05809b2854d233647955ce122aa0 - React-jsinspector: 1e18eda10420137d634f3b660764e248da09e431 - React-RCTActionSheet: 1e77963344b7554bd0d506fdddc248b3031a3acd - React-RCTAnimation: 24665293e82d8fe009c52544e44442e24af67226 - React-RCTBlob: b80b29efb1b2cc0a568a6e9ef439e9e41b05127b - React-RCTImage: 0699991f74770bc2be51f76fcde7f7aeac7d4082 - React-RCTLinking: 4f0b40c7550999b4cf748e7c061c59b69e0f6648 - React-RCTNetwork: cfbd60b6797b913175b8a6349e10bb6fd961fc26 - React-RCTPushNotification: 80d37852e87f85b9e88f989142401c0f9257b2f8 - React-RCTSettings: dc94e747d8edc1810256bd0b024dd61ae4ab5a22 - React-RCTTest: 04d14b0b8a8d7ff9d8868fdb66218ff9db0259c1 - React-RCTText: 18fece5415a20dbaccd7ccfe17779bbf64c17fc4 - React-RCTVibration: b5d1d694cc4c6ca520cc23e10440e5adc39263d1 + RCTRequired: 37f40377c0ea795d4b906f3499655fbd0ff42e27 + RCTTypeSafety: 3f230f2e3335fbe45ed5c9d4bd2eba467392479f + React: 707958373426608d07889c030a5db60b826e159e + React-ART: d81c7e291454d9cbaa6088758f264e8ea21099fc + React-callinvoker: 6d9636c3513c6cd0acc46914d3de03ddbdc84007 + React-Core: c71c9b022c3151ab6f61f6184291e8ecd706d2a1 + React-CoreModules: 45fb897af5ba457cb6cb66a82b5faa4d117bfe15 + React-cxxreact: 0e079067a4a355eb15be1492aa96cfd68720ad3e + React-jsi: e150452a6ba4ef7f3eb55a6b0e4991605ddf1ddd + React-jsiexecutor: 160af6637a201038dbbfd232caa8f1abe73a4a79 + React-jsinspector: f0e7ba53d923a58da6aa4c2abacfa178db78cb31 + React-RCTActionSheet: bca975a416caea8f77677616cfa06c2d6245d5cf + React-RCTAnimation: ea3f8968ad420f0bf55ed9a85c7fc9c225f3dc9a + React-RCTBlob: 2d237a23740260aee9716e66ac4c388a29c23ee3 + React-RCTImage: 57e1ce8afe2b04ab4a44254f9ac9ae54b473cdc9 + React-RCTLinking: ccf93f64ecf303ef4fac7fe50424ea55d74bc072 + React-RCTNetwork: 4d075d146f0ed6a6e3c657a57ae17b011e17df71 + React-RCTPushNotification: e9b3686f7f9ca6b74617a5427e7ffcba3d70f41c + React-RCTSettings: fc9afc6981735f0cce2b37c2ed90b7a800a38308 + React-RCTTest: c2c26c856d466e948dee7ff939372637d1c80069 + React-RCTText: 7effa140484e70f24e340450d24e7e0ed3f1ae88 + React-RCTVibration: c1867f60d25efafbf8705b445e6dc11089312cc7 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: d280a253fdf89944869969d1bbd5c839052f0287 - ReactCommon: 63ef025432213eb0b612bdb3542e7bf57dbd561c - Yoga: 18c5eda53e05f95700b68b07a38c2487dea04fa8 + React-TurboModuleCxx-WinRTPort: d7bf672478f94748329c159893310100ad26c34e + ReactCommon: 047272186b16e3cab56317cbd4c119a80329a5ab + Yoga: 56a44c9ff7008e519e20fcf7cc257b5a86f46695 YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index f597a59ee9e428..d0602ee96ae5ea 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -29,7 +29,7 @@ class KeyEventExample extends React.Component<{}, State> { onKeyDownEvent: (e: KeyEvent) => void = (e: KeyEvent) => { console.log('received view key down event\n', e.nativeEvent['characters']); - this.setState({characters: e.nativeEvent.characters}) + this.setState({characters: e.nativeEvent.key}) this.setState(prevState => ({ eventStream: prevState.eventStream + prevState.characters + '\nKey Down: ' })); @@ -37,7 +37,7 @@ class KeyEventExample extends React.Component<{}, State> { onKeyUpEvent: (e: KeyEvent) => void = (e: KeyEvent) => { console.log('received key up event\n', e.nativeEvent['characters']); - this.setState({characters: e.nativeEvent.characters}) + this.setState({characters: e.nativeEvent.key}) this.setState(prevState => ({ eventStream: prevState.eventStream + prevState.characters + '\nKey Up: ' })); @@ -55,16 +55,16 @@ class KeyEventExample extends React.Component<{}, State> { diff --git a/React/Views/RCTView.m b/React/Views/RCTView.m index 226e2fdfe646c0..ff934958601dae 100644 --- a/React/Views/RCTView.m +++ b/React/Views/RCTView.m @@ -1573,16 +1573,121 @@ - (BOOL)performDragOperation:(id )sender #pragma mark - Keyboard Events #if TARGET_OS_OSX +const NSString *leftArrowPressKey = @"leftArrow"; +const NSString *rightArrowPressKey = @"rightArrow"; +const NSString *upArrowPressKey = @"upArrow"; +const NSString *downArrowPressKey = @"downArrow"; + +- (RCTViewKeyboardEvent*)keyboardEvent:(NSEvent*)event downPress:(BOOL)downPress { + // modifiers + BOOL capsLockKey = NO; + BOOL shiftKey = NO; + BOOL controlKey = NO; + BOOL optionKey = NO; + BOOL commandKey = NO; + BOOL numericPadKey = NO; + BOOL helpKey = NO; + BOOL functionKey = NO; + // commonly used key short-cuts + BOOL leftArrowKey = NO; + BOOL rightArrowKey = NO; + BOOL upArrowKey = NO; + BOOL downArrowKey = NO; + NSString *key = event.charactersIgnoringModifiers; + unichar const code = [key characterAtIndex:0]; + + // detect arrow key presses + if (code == NSLeftArrowFunctionKey) { + leftArrowKey = YES; + } else if (code == NSRightArrowFunctionKey) { + rightArrowKey = YES; + } else if (code == NSUpArrowFunctionKey) { + upArrowKey = YES; + } else if (code == NSDownArrowFunctionKey) { + downArrowKey = YES; + } + + // detect modifier flags + if (event.modifierFlags & NSEventModifierFlagCapsLock) { + capsLockKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagShift) { + shiftKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagControl) { + controlKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagOption) { + optionKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagCommand) { + commandKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagNumericPad) { + numericPadKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagHelp) { + helpKey = YES; + } else if (event.modifierFlags & NSEventModifierFlagFunction) { + functionKey = YES; + } + + RCTViewKeyboardEvent *keyboardEvent = nil; + // only post events for keys we care about + if (downPress) { + if ([self keyIsValid:key validKeys:[self validKeysDown]]) { + keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag + capsLockKey:capsLockKey + shiftKey:shiftKey + controlKey:controlKey + optionKey:optionKey + commandKey:commandKey + numericPadKey:numericPadKey + helpKey:helpKey + functionKey:functionKey + leftArrowKey:leftArrowKey + rightArrowKey:rightArrowKey + upArrowKey:upArrowKey + downArrowKey:downArrowKey + key:key]; + } + } else { + if ([self keyIsValid:key validKeys:[self validKeysUp]]) { + keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag + capsLockKey:capsLockKey + shiftKey:shiftKey + controlKey:controlKey + optionKey:optionKey + commandKey:commandKey + numericPadKey:numericPadKey + helpKey:helpKey + functionKey:functionKey + leftArrowKey:leftArrowKey + rightArrowKey:rightArrowKey + upArrowKey:upArrowKey + downArrowKey:downArrowKey + key:key]; + } + } + return keyboardEvent; +} + +// check if the user typed key matches a key we need to send an event for +- (BOOL)keyIsValid:(NSString*)key validKeys:(NSArray*)validKeys { + BOOL keyIsValid = NO; + + if ([validKeys containsObject:key] || [validKeys containsObject:leftArrowPressKey] || [validKeys containsObject:rightArrowPressKey] || [validKeys containsObject:upArrowPressKey] || [validKeys containsObject:downArrowPressKey]) { + keyIsValid = YES; + } + + return keyIsValid; +} + - (void)keyDown:(NSEvent *)event { if (self.onKeyDown != nil) { [super keyDown:event]; return; } - // only post events for keys we care about - if ([[self validKeysDown] containsObject:event.characters]) { - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyDownEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; - [_eventDispatcher sendEvent:keyboardEvent]; + RCTViewKeyboardEvent *keyboardEvent = [self keyboardEvent:event downPress:YES]; + if (keyboardEvent != nil) { + [_eventDispatcher sendEvent:[self keyboardEvent:event downPress:YES]]; + } else { + [super keyDown:event]; } } @@ -1592,9 +1697,11 @@ - (void)keyUp:(NSEvent *)event { return; } - if ([[self validKeysUp] containsObject:event.characters]) { - RCTViewKeyboardEvent *keyboardEvent = [RCTViewKeyboardEvent keyUpEventWithReactTag:self.reactTag characters:event.characters modifier:event.modifierFlags]; + RCTViewKeyboardEvent *keyboardEvent = [self keyboardEvent:event downPress:NO]; + if (keyboardEvent != nil) { [_eventDispatcher sendEvent:keyboardEvent]; + } else { + [super keyDown:event]; } } #endif // TARGET_OS_OSX diff --git a/React/Views/RCTViewKeyboardEvent.h b/React/Views/RCTViewKeyboardEvent.h index ef9cf93f3a9be5..2c31b5c418a8c9 100644 --- a/React/Views/RCTViewKeyboardEvent.h +++ b/React/Views/RCTViewKeyboardEvent.h @@ -8,7 +8,33 @@ @interface RCTViewKeyboardEvent : RCTComponentEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier; ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag + capsLockKey:(BOOL)capsLockKey + shiftKey:(BOOL)shiftKey + controlKey:(BOOL)controlKey + optionKey:(BOOL)optionKey + commandKey:(BOOL)commandKey + numericPadKey:(BOOL)numericPadKey + helpKey:(BOOL)helpKey + functionKey:(BOOL)functionKey + leftArrowKey:(BOOL)leftArrowKey + rightArrowKey:(BOOL)rightArrowKey + upArrowKey:(BOOL)upArrowKey + downArrowKey:(BOOL)downArrowKey + key:(NSString*)key; ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag + capsLockKey:(BOOL)capsLockKey + shiftKey:(BOOL)shiftKey + controlKey:(BOOL)controlKey + optionKey:(BOOL)optionKey + commandKey:(BOOL)commandKey + numericPadKey:(BOOL)numericPadKey + helpKey:(BOOL)helpKey + functionKey:(BOOL)functionKey + leftArrowKey:(BOOL)leftArrowKey + rightArrowKey:(BOOL)rightArrowKey + upArrowKey:(BOOL)upArrowKey + downArrowKey:(BOOL)downArrowKey + key:(NSString*)key; @end diff --git a/React/Views/RCTViewKeyboardEvent.m b/React/Views/RCTViewKeyboardEvent.m index 29a19c3a9decd4..6e65cde58b2cd3 100644 --- a/React/Views/RCTViewKeyboardEvent.m +++ b/React/Views/RCTViewKeyboardEvent.m @@ -10,19 +10,67 @@ @implementation RCTViewKeyboardEvent -+ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyDownEventWithReactTag:(NSNumber *)reactTag + capsLockKey:(BOOL)capsLockKey + shiftKey:(BOOL)shiftKey + controlKey:(BOOL)controlKey + optionKey:(BOOL)optionKey + commandKey:(BOOL)commandKey + numericPadKey:(BOOL)numericPadKey + helpKey:(BOOL)helpKey + functionKey:(BOOL)functionKey + leftArrowKey:(BOOL)leftArrowKey + rightArrowKey:(BOOL)rightArrowKey + upArrowKey:(BOOL)upArrowKey + downrrowKey:(BOOL)downArrowKey + key:(NSString*)key { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyDown" viewTag:reactTag - body:@{ @"characters" : characters, - @"modifier" : @(modifier) }]; + body:@{ @"capsLockKey" : @(capsLockKey), + @"shiftKey" : @(shiftKey), + @"controlKey" : @(controlKey), + @"optionKey" : @(optionKey), + @"commandKey" : @(commandKey), + @"numericPadKey" : @(numericPadKey), + @"helpKey" : @(helpKey), + @"functionKey" : @(functionKey), + @"leftArrowKey" : @(leftArrowKey), + @"rightArrowKey" : @(rightArrowKey), + @"upArrowKey" : @(upArrowKey), + @"downArrowKey" : @(downArrowKey), + @"key" : key }]; return event; } -+ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag characters:(NSString *)characters modifier:(NSUInteger)modifier { ++ (instancetype)keyUpEventWithReactTag:(NSNumber *)reactTag + capsLockKey:(BOOL)capsLockKey + shiftKey:(BOOL)shiftKey + controlKey:(BOOL)controlKey + optionKey:(BOOL)optionKey + commandKey:(BOOL)commandKey + numericPadKey:(BOOL)numericPadKey + helpKey:(BOOL)helpKey + functionKey:(BOOL)functionKey + leftArrowKey:(BOOL)leftArrowKey + rightArrowKey:(BOOL)rightArrowKey + upArrowKey:(BOOL)upArrowKey + downrrowKey:(BOOL)downArrowKey + key:(NSString*)key { RCTViewKeyboardEvent *event = [[self alloc] initWithName:@"keyUp" viewTag:reactTag - body:@{ @"characters" : characters, - @"modifier" : @(modifier) }]; + body:@{ @"capsLockKey" : @(capsLockKey), + @"shiftKey" : @(shiftKey), + @"controlKey" : @(controlKey), + @"optionKey" : @(optionKey), + @"commandKey" : @(commandKey), + @"numericPadKey" : @(numericPadKey), + @"helpKey" : @(helpKey), + @"functionKey" : @(functionKey), + @"leftArrowKey" : @(leftArrowKey), + @"rightArrowKey" : @(rightArrowKey), + @"upArrowKey" : @(upArrowKey), + @"downArrowKey" : @(downArrowKey), + @"key" : key }]; return event; } From 8620c29e8599b31e6e8bccebc5d40a1add1bd51e Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Thu, 26 Nov 2020 00:12:59 -0800 Subject: [PATCH 15/23] macOS keyboard support --- React/Views/RCTViewManager.m | 2 ++ 1 file changed, 2 insertions(+) diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index fbf713353402fa..ae248a84a8ee3e 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -470,6 +470,8 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray) RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray) #endif // ]TODO(macOS ISS#2323203) +RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events +RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events #pragma mark - ShadowView properties From dfb3d4a69ea9f213ea35c37fd60b18d03782ac1f Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Wed, 9 Dec 2020 16:03:51 -0800 Subject: [PATCH 16/23] add key value checks so we don't send all events --- React/Views/RCTViewManager.m | 3 +++ 1 file changed, 3 insertions(+) diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index ae248a84a8ee3e..5bf810e343a8f4 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -472,6 +472,9 @@ - (RCTShadowView *)shadowView #endif // ]TODO(macOS ISS#2323203) RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events +RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray) +RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray) +#endif // ]TODO(macOS ISS#2323203) #pragma mark - ShadowView properties From 0c46c4ad6dd447b70282ef6b6f83cfab0e14818b Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Fri, 11 Dec 2020 10:41:32 -0800 Subject: [PATCH 17/23] resolve bad merge --- React/Views/RCTViewManager.m | 5 ----- 1 file changed, 5 deletions(-) diff --git a/React/Views/RCTViewManager.m b/React/Views/RCTViewManager.m index 5bf810e343a8f4..fbf713353402fa 100644 --- a/React/Views/RCTViewManager.m +++ b/React/Views/RCTViewManager.m @@ -470,11 +470,6 @@ - (RCTShadowView *)shadowView RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray) RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray) #endif // ]TODO(macOS ISS#2323203) -RCT_EXPORT_VIEW_PROPERTY(onKeyDown, RCTBubblingEventBlock) // macOS keyboard events -RCT_EXPORT_VIEW_PROPERTY(onKeyUp, RCTBubblingEventBlock) // macOS keyboard events -RCT_EXPORT_VIEW_PROPERTY(validKeysDown, NSArray) -RCT_EXPORT_VIEW_PROPERTY(validKeysUp, NSArray) -#endif // ]TODO(macOS ISS#2323203) #pragma mark - ShadowView properties From 5ee1b50ef893003d1772b07b08cf3eacd5c57d25 Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Fri, 11 Dec 2020 23:47:47 -0800 Subject: [PATCH 18/23] update valid key bug, api typo --- Libraries/Components/Button.js | 15 ++++++ .../Components/Touchable/TouchableOpacity.js | 4 ++ .../Touchable/TouchableWithoutFeedback.js | 6 +++ .../View/ReactNativeViewAttributes.js | 2 + .../View/ReactNativeViewViewConfig.js | 2 + .../View/ReactNativeViewViewConfigMacOS.js | 2 + Libraries/Pressability/Pressability.js | 14 ++++- RNTester/Podfile.lock | 54 +++++++++---------- .../KeyboardEventsExample.js | 6 +-- React/Views/RCTView.m | 12 ++--- React/Views/RCTViewKeyboardEvent.h | 3 +- React/Views/RCTViewKeyboardEvent.m | 32 +++++------ React/Views/RCTViewManager.m | 14 ++++- 13 files changed, 109 insertions(+), 57 deletions(-) diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index ac676119288bf9..7032b631b8415d 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -124,6 +124,17 @@ type ButtonProps = $ReadOnly<{| */ onKeyUp?: ?(e: KeyEvent) => void, + /* + * Array of keys to receive key down events for + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + */ + validKeysDown?: ?Array, + + /* + * Array of keys to receive key up events for + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + */ + validKeysUp?: ?Array, // ]TODO(OSS Candidate ISS#2710739) |}>; @@ -175,6 +186,8 @@ class Button extends React.Component { onFocus, // TODO(OSS Candidate ISS#2710739) onBlur, // TODO(OSS Candidate ISS#2710739) onKeyDown, + validKeysDown, + validKeysUp, onKeyUp, } = this.props; const buttonStyles = [styles.button]; @@ -222,6 +235,8 @@ class Button extends React.Component { onBlur={onBlur} // TODO(OSS Candidate ISS#2710739) onKeyDown={onKeyDown} onKeyUp={onKeyUp} + validKeysDown={validKeysDown} + validKeysUp={validKeysUp} touchSoundDisabled={touchSoundDisabled}> diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index a9d0f2d5d76da7..74d4898e912704 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -175,6 +175,8 @@ class TouchableOpacity extends React.Component { this.props.onKeyUp(event); } }, + validKeysDown: this.props.validKeysDown, + validKeysUp: this.props.validKeysUp, onLongPress: this.props.onLongPress, onPress: this.props.onPress, onPressIn: event => { @@ -291,6 +293,8 @@ class TouchableOpacity extends React.Component { onBlur={this.props.onBlur} onKeyDown={this.props.onKeyDown} onKeyUp={this.props.onKeyUp} + validKeysDown={this.props.validKeysDown} + validKeysUp={this.props.validKeysUp} draggedTypes={this.props.draggedTypes} // ]TODO(macOS ISS#2323203) ref={this.props.hostRef} {...eventHandlersWithoutBlurAndFocus}> diff --git a/Libraries/Components/Touchable/TouchableWithoutFeedback.js b/Libraries/Components/Touchable/TouchableWithoutFeedback.js index 739ec333a87da1..77c2f7f1cf055a 100755 --- a/Libraries/Components/Touchable/TouchableWithoutFeedback.js +++ b/Libraries/Components/Touchable/TouchableWithoutFeedback.js @@ -67,6 +67,8 @@ type Props = $ReadOnly<{| onFocus?: ?(event: FocusEvent) => mixed, onKeyDown?: ?(event: KeyEvent) => mixed, onKeyUp?: ?(event: KeyEvent) => mixed, + validKeysDown?: ?Array, + validKeysDown?: ?Array, onLayout?: ?(event: LayoutEvent) => mixed, onLongPress?: ?(event: PressEvent) => mixed, onPress?: ?(event: PressEvent) => mixed, @@ -111,6 +113,8 @@ const PASSTHROUGH_PROPS = [ 'onFocus', 'onKeyDown', 'onKeyUp', + 'validKeysDown', + 'validKeysUp', 'onLayout', 'onMouseEnter', // [TODO(macOS ISS#2323203) 'onMouseLeave', @@ -234,6 +238,8 @@ function createPressabilityConfig(props: Props): PressabilityConfig { onFocus: props.onFocus, onKeyDown: props.onKeyDown, onKeyUp: props.onKeyUp, + validKeysDown: props.validKeysDown, + validKeysUp: props.validKeysUp, onLongPress: props.onLongPress, onPress: props.onPress, onPressIn: props.onPressIn, diff --git a/Libraries/Components/View/ReactNativeViewAttributes.js b/Libraries/Components/View/ReactNativeViewAttributes.js index 8ab81879c3ea32..cddfffa15d18ee 100644 --- a/Libraries/Components/View/ReactNativeViewAttributes.js +++ b/Libraries/Components/View/ReactNativeViewAttributes.js @@ -44,6 +44,8 @@ const UIView = { onDrop: true, onKeyDown: true, onKeyUp: true, + validKeysDown: true, + validKeysUp: true, draggedTypes: true, // ]TODO(macOS ISS#2323203) style: ReactNativeStyleAttributes, }; diff --git a/Libraries/Components/View/ReactNativeViewViewConfig.js b/Libraries/Components/View/ReactNativeViewViewConfig.js index 25175748e7568c..df8b840a3e17b9 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfig.js +++ b/Libraries/Components/View/ReactNativeViewViewConfig.js @@ -355,6 +355,8 @@ const ReactNativeViewConfig = { : {process: require('../../StyleSheet/processTransform')}): any), translateX: true, translateY: true, + validKeysDown: true, + validKeysUp: true, width: true, zIndex: true, }, diff --git a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js index 23016ab7bcc9f4..291bd7b7f9ae63 100644 --- a/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js +++ b/Libraries/Components/View/ReactNativeViewViewConfigMacOS.js @@ -49,6 +49,8 @@ const ReactNativeViewViewConfigMacOS = { onFocus: true, onKeyDown: true, onKeyUp: true, + validKeysDown: true, + validKeysUp: true, onMouseEnter: true, onMouseLeave: true, tooltip: true, diff --git a/Libraries/Pressability/Pressability.js b/Libraries/Pressability/Pressability.js index da199bee42858d..9dcb96132cc16b 100644 --- a/Libraries/Pressability/Pressability.js +++ b/Libraries/Pressability/Pressability.js @@ -103,7 +103,19 @@ export type PressabilityConfig = $ReadOnly<{| * Called after a key up event is detected. */ onKeyUp?: ?(event: KeyEvent) => mixed, - + + /* + * Array of keys to receive key down events for + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + */ + validKeysDown?: ?array, + + /* + * Array of keys to receive key up events for + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + */ + validKeysUp?: ?array, + /** * Called when the hover is activated to provide visual feedback. */ diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index a56e0fef5ea607..e54900ec49e973 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -519,8 +519,8 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: 15d29e4a0b8ae8fc03616b36fb5b9b8d554bfede - FBReactNativeSpec: 24e41f4afb47a2d5af7687f85b8dec0eb4163347 + FBLazyVector: 6c1eb116745a172c33072b3d99cb9518d3addce0 + FBReactNativeSpec: 8b91bac25292c24bbc28ee754c5482a838280210 Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a @@ -533,32 +533,32 @@ SPEC CHECKSUMS: libevent: ee9265726a1fc599dea382964fa304378affaa5f OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: 37f40377c0ea795d4b906f3499655fbd0ff42e27 - RCTTypeSafety: 3f230f2e3335fbe45ed5c9d4bd2eba467392479f - React: 707958373426608d07889c030a5db60b826e159e - React-ART: d81c7e291454d9cbaa6088758f264e8ea21099fc - React-callinvoker: 6d9636c3513c6cd0acc46914d3de03ddbdc84007 - React-Core: c71c9b022c3151ab6f61f6184291e8ecd706d2a1 - React-CoreModules: 45fb897af5ba457cb6cb66a82b5faa4d117bfe15 - React-cxxreact: 0e079067a4a355eb15be1492aa96cfd68720ad3e - React-jsi: e150452a6ba4ef7f3eb55a6b0e4991605ddf1ddd - React-jsiexecutor: 160af6637a201038dbbfd232caa8f1abe73a4a79 - React-jsinspector: f0e7ba53d923a58da6aa4c2abacfa178db78cb31 - React-RCTActionSheet: bca975a416caea8f77677616cfa06c2d6245d5cf - React-RCTAnimation: ea3f8968ad420f0bf55ed9a85c7fc9c225f3dc9a - React-RCTBlob: 2d237a23740260aee9716e66ac4c388a29c23ee3 - React-RCTImage: 57e1ce8afe2b04ab4a44254f9ac9ae54b473cdc9 - React-RCTLinking: ccf93f64ecf303ef4fac7fe50424ea55d74bc072 - React-RCTNetwork: 4d075d146f0ed6a6e3c657a57ae17b011e17df71 - React-RCTPushNotification: e9b3686f7f9ca6b74617a5427e7ffcba3d70f41c - React-RCTSettings: fc9afc6981735f0cce2b37c2ed90b7a800a38308 - React-RCTTest: c2c26c856d466e948dee7ff939372637d1c80069 - React-RCTText: 7effa140484e70f24e340450d24e7e0ed3f1ae88 - React-RCTVibration: c1867f60d25efafbf8705b445e6dc11089312cc7 + RCTRequired: b34a90dff6f3c18e0641b1e4a3620031f5d315b9 + RCTTypeSafety: 71c2ec451077ca55474685acf466c276b559d75e + React: 9c5ec954ca211713c2bcd2c9c572a9c6e48fa79b + React-ART: 9df7751bafac79781c00a219bad2e756910fd13a + React-callinvoker: 578d74024ed71187336615364da323f5e0e61c29 + React-Core: 76c7650388af283f9bb3aa54d48029188d1f3a8e + React-CoreModules: 4316d724429331c9205aef6f71e35f1876ca2ca1 + React-cxxreact: 54b090f769cba0c74f71bc018d2653ce631dc0f0 + React-jsi: 58c142c2bfa448915ba10ebeed2caed5ec2eee6f + React-jsiexecutor: e40d4bd213e8d05f87299f451f0ec07b7d93ca68 + React-jsinspector: a61940cf2c88407a169ad29d5c547ba732d29812 + React-RCTActionSheet: 0b4788e65fb860afee5407daea168c7e5b796cd1 + React-RCTAnimation: 18ef9f158160e4e4d77c2cdd5e9f4a057d7b9c2f + React-RCTBlob: 013b9c2e4f4d883c0b4866329e7f36b536086d14 + React-RCTImage: adb4904503c4152d922b8a5baadd0476686de229 + React-RCTLinking: b223ae5b946546498ec509065c92453f0f4c4a9a + React-RCTNetwork: 69ee4f9f67e979f5973876bc6b12b3a2c77fbeab + React-RCTPushNotification: 483616d9ea5e968742316a3b6d5be47de75e00a1 + React-RCTSettings: a8cb50695be2826b4e0a7efc57981d6701fd8626 + React-RCTTest: 8d800f84fb32a2e71a5e8c90d2e66e9b1590a39f + React-RCTText: 2c11805589b28a30a092d7d33b734066fcfe8b69 + React-RCTVibration: 902e0fddba6f8a7c983833c656d4d8ff21d96052 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: d7bf672478f94748329c159893310100ad26c34e - ReactCommon: 047272186b16e3cab56317cbd4c119a80329a5ab - Yoga: 56a44c9ff7008e519e20fcf7cc257b5a86f46695 + React-TurboModuleCxx-WinRTPort: 74cb192337ef30efda8e62ad84f248193d3f791a + ReactCommon: ba0a587c5df062da8b0ba51ddefa2531889414a9 + Yoga: dcb56e91da53f36596ed6fe8896b359064156fdc YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index d0602ee96ae5ea..2cfe1dbbb0b49c 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -28,7 +28,7 @@ class KeyEventExample extends React.Component<{}, State> { }; onKeyDownEvent: (e: KeyEvent) => void = (e: KeyEvent) => { - console.log('received view key down event\n', e.nativeEvent['characters']); + console.log('received view key down event\n', e.nativeEvent['key']); this.setState({characters: e.nativeEvent.key}) this.setState(prevState => ({ eventStream: prevState.eventStream + prevState.characters + '\nKey Down: ' @@ -36,7 +36,7 @@ class KeyEventExample extends React.Component<{}, State> { }; onKeyUpEvent: (e: KeyEvent) => void = (e: KeyEvent) => { - console.log('received key up event\n', e.nativeEvent['characters']); + console.log('received key up event\n', e.nativeEvent['key']); this.setState({characters: e.nativeEvent.key}) this.setState(prevState => ({ eventStream: prevState.eventStream + prevState.characters + '\nKey Up: ' @@ -57,7 +57,7 @@ class KeyEventExample extends React.Component<{}, State> { enableFocusRing={true} validKeysDown={["a", "b", "rightArrow"]} onKeyDown={this.onKeyDownEvent} - validKeysUp={["d", "e", "leftArrow"]} + validKeysUp={["c", "d", "leftArrow"]} onKeyUp={this.onKeyUpEvent} > ) : null} - {'Events: ' + this.state.eventStream + JSON.stringify(this.state.characters) + '\n\n'} + {'Events: ' + this.state.eventStream + '\n\n'} ); From 6655bb9ac3d7474291256e40cebbacdfa4b600ad Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Sat, 12 Dec 2020 11:29:28 -0800 Subject: [PATCH 21/23] fix snapshot tests for new APIs --- .../Pressable/__tests__/__snapshots__/Pressable-test.js.snap | 4 ++++ .../TextInput/__tests__/__snapshots__/TextInput-test.js.snap | 4 ++++ .../__tests__/__snapshots__/TouchableHighlight-test.js.snap | 2 ++ 3 files changed, 10 insertions(+) diff --git a/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap b/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap index aada55fc3c066a..00b9b67f112640 100644 --- a/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap +++ b/Libraries/Components/Pressable/__tests__/__snapshots__/Pressable-test.js.snap @@ -9,6 +9,8 @@ exports[` should render as expected: should deep render when mocked onBlur={[Function]} onClick={[Function]} onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} @@ -29,6 +31,8 @@ exports[` should render as expected: should deep render when not mo onBlur={[Function]} onClick={[Function]} onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} diff --git a/Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap b/Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap index 2469722ff60bc1..91acebe0e5774b 100644 --- a/Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap +++ b/Libraries/Components/TextInput/__tests__/__snapshots__/TextInput-test.js.snap @@ -13,6 +13,8 @@ exports[`TextInput tests should render as expected: should deep render when mock onChange={[Function]} onClick={[Function]} onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} @@ -42,6 +44,8 @@ exports[`TextInput tests should render as expected: should deep render when not onChange={[Function]} onClick={[Function]} onFocus={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} diff --git a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap index 7b68b8593fd50a..c9397c0641ceff 100644 --- a/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap +++ b/Libraries/Components/Touchable/__tests__/__snapshots__/TouchableHighlight-test.js.snap @@ -7,6 +7,8 @@ exports[`TouchableHighlight renders correctly 1`] = ` enableFocusRing={true} focusable={false} onClick={[Function]} + onKeyDown={[Function]} + onKeyUp={[Function]} onResponderGrant={[Function]} onResponderMove={[Function]} onResponderRelease={[Function]} From c87d38b8efb96ec62e773945cfcc9a5a88e22fba Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Sat, 12 Dec 2020 11:46:00 -0800 Subject: [PATCH 22/23] yarn lint --fix --- Libraries/Components/Button.js | 8 ++-- .../Touchable/TouchableNativeFeedback.js | 8 ++-- .../Components/Touchable/TouchableOpacity.js | 6 +-- Libraries/Components/View/ViewPropTypes.js | 8 ++-- Libraries/Pressability/Pressability.js | 8 ++-- .../KeyboardEventsExample.js | 42 +++++++++---------- 6 files changed, 38 insertions(+), 42 deletions(-) diff --git a/Libraries/Components/Button.js b/Libraries/Components/Button.js index 7032b631b8415d..480d7461761815 100644 --- a/Libraries/Components/Button.js +++ b/Libraries/Components/Button.js @@ -113,26 +113,26 @@ type ButtonProps = $ReadOnly<{| * Handler to be called when the button loses key focus */ onFocus?: ?(e: FocusEvent) => void, - + /** * Handler to be called when a key down press is detected */ onKeyDown?: ?(e: KeyEvent) => void, - /** + /** * Handler to be called when a key up press is detected */ onKeyUp?: ?(e: KeyEvent) => void, /* * Array of keys to receive key down events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysDown?: ?Array, /* * Array of keys to receive key up events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysUp?: ?Array, // ]TODO(OSS Candidate ISS#2710739) diff --git a/Libraries/Components/Touchable/TouchableNativeFeedback.js b/Libraries/Components/Touchable/TouchableNativeFeedback.js index 23e481e7c3323d..fe7c878f6835b6 100644 --- a/Libraries/Components/Touchable/TouchableNativeFeedback.js +++ b/Libraries/Components/Touchable/TouchableNativeFeedback.js @@ -81,16 +81,16 @@ type Props = $ReadOnly<{| * TV next focus up (see documentation for the View component). */ nextFocusUp?: ?number, - + /* * Array of keys to receive key down events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysDown?: ?Array, - + /* * Array of keys to receive key up events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysUp?: ?Array, diff --git a/Libraries/Components/Touchable/TouchableOpacity.js b/Libraries/Components/Touchable/TouchableOpacity.js index 92cd1dc879529a..c85586dca856d9 100644 --- a/Libraries/Components/Touchable/TouchableOpacity.js +++ b/Libraries/Components/Touchable/TouchableOpacity.js @@ -42,13 +42,13 @@ type Props = $ReadOnly<{| hostRef: React.Ref, /* * Array of keys to receive key down events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysDown?: ?Array, - + /* * Array of keys to receive key up events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysUp?: ?Array, |}>; diff --git a/Libraries/Components/View/ViewPropTypes.js b/Libraries/Components/View/ViewPropTypes.js index 18c73827f649c3..8b23249c3d1827 100644 --- a/Libraries/Components/View/ViewPropTypes.js +++ b/Libraries/Components/View/ViewPropTypes.js @@ -35,7 +35,7 @@ import type { // [TODO(macOS ISS#2323203) import type {DraggedTypesType} from '../View/DraggedType'; //$FlowFixMe -import { array } from 'yargs'; +import {array} from 'yargs'; // ]TODO(macOS ISS#2323203) export type ViewLayout = Layout; @@ -606,13 +606,13 @@ export type ViewProps = $ReadOnly<{| /* * Array of keys to receive key down events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysDown?: ?array, - + /* * Array of keys to receive key up events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysUp?: ?array, diff --git a/Libraries/Pressability/Pressability.js b/Libraries/Pressability/Pressability.js index 260d7c19d81971..a5640fd20dbee8 100644 --- a/Libraries/Pressability/Pressability.js +++ b/Libraries/Pressability/Pressability.js @@ -103,16 +103,16 @@ export type PressabilityConfig = $ReadOnly<{| * Called after a key up event is detected. */ onKeyUp?: ?(event: KeyEvent) => mixed, - + /* * Array of keys to receive key down events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysDown?: ?Array, /* * Array of keys to receive key up events for - * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", + * For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow", */ validKeysUp?: ?Array, @@ -470,7 +470,7 @@ export default class Pressability { } }, }; - + const keyEventHandlers = { onKeyDown: (event: KeyEvent): void => { const {onKeyDown} = this._config; diff --git a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js index c6e3774c51a5f2..9544c8919719b8 100644 --- a/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js +++ b/RNTester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js @@ -13,9 +13,9 @@ const React = require('react'); const ReactNative = require('react-native'); import {Platform} from 'react-native'; -const {Button, PlatformColor, StyleSheet, Text, View } = ReactNative; +const {Button, PlatformColor, StyleSheet, Text, View} = ReactNative; -import type { KeyEvent } from 'react-native/Libraries/Types/CoreEventTypes'; +import type {KeyEvent} from 'react-native/Libraries/Types/CoreEventTypes'; type State = { eventStream: string, @@ -29,47 +29,43 @@ class KeyEventExample extends React.Component<{}, State> { }; onKeyDownEvent: (e: KeyEvent) => void = (e: KeyEvent) => { - console.log('received view key down event\n', e.nativeEvent['key']); - this.setState({characters: e.nativeEvent.key}) + console.log('received view key down event\n', e.nativeEvent.key); + this.setState({characters: e.nativeEvent.key}); this.setState(prevState => ({ - eventStream: prevState.eventStream + prevState.characters + '\nKey Down: ' + eventStream: + prevState.eventStream + prevState.characters + '\nKey Down: ', })); }; - + onKeyUpEvent: (e: KeyEvent) => void = (e: KeyEvent) => { - console.log('received key up event\n', e.nativeEvent['key']); - this.setState({characters: e.nativeEvent.key}) + console.log('received key up event\n', e.nativeEvent.key); + this.setState({characters: e.nativeEvent.key}); this.setState(prevState => ({ - eventStream: prevState.eventStream + prevState.characters + '\nKey Up: ' + eventStream: prevState.eventStream + prevState.characters + '\nKey Up: ', })); }; render() { return ( - - Key events are called when a component detects a key press. - + Key events are called when a component detects a key press. - { - Platform.OS === 'macos' ? ( + {Platform.OS === 'macos' ? ( - + /> ) : null} {'Events: ' + this.state.eventStream + '\n\n'} From 263182e6f1802d82aa71653e0e26ebff3ea8ca4d Mon Sep 17 00:00:00 2001 From: Chris Hogan Date: Sat, 12 Dec 2020 12:37:02 -0800 Subject: [PATCH 23/23] fix flipper --- RNTester/Podfile.lock | 70 +++++++++++++++++++++---------------------- 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/RNTester/Podfile.lock b/RNTester/Podfile.lock index e54900ec49e973..5cea5f4e0e0cc5 100644 --- a/RNTester/Podfile.lock +++ b/RNTester/Podfile.lock @@ -15,12 +15,12 @@ PODS: - Flipper-Folly (~> 2.2) - Flipper-RSocket (~> 1.1) - Flipper-DoubleConversion (1.1.7) - - Flipper-Folly (2.3.0): + - Flipper-Folly (2.2.0): - boost-for-react-native - CocoaLibEvent (~> 1.0) - Flipper-DoubleConversion - Flipper-Glog - - OpenSSL-Universal (= 1.0.2.20) + - OpenSSL-Universal (= 1.0.2.19) - Flipper-Glog (0.3.6) - Flipper-PeerTalk (0.0.4) - Flipper-RSocket (1.1.0): @@ -64,9 +64,9 @@ PODS: - libevent/core (2.1.11): - libevent/event2-headers - libevent/event2-headers (2.1.11) - - OpenSSL-Universal (1.0.2.20): - - OpenSSL-Universal/Static (= 1.0.2.20) - - OpenSSL-Universal/Static (1.0.2.20) + - OpenSSL-Universal (1.0.2.19): + - OpenSSL-Universal/Static (= 1.0.2.19) + - OpenSSL-Universal/Static (1.0.2.19) - RCT-Folly (2020.01.13.00): - boost-for-react-native - DoubleConversion @@ -519,11 +519,11 @@ SPEC CHECKSUMS: CocoaAsyncSocket: 694058e7c0ed05a9e217d1b3c7ded962f4180845 CocoaLibEvent: 2fab71b8bd46dd33ddb959f7928ec5909f838e3f DoubleConversion: 56a44bcfd14ab2ff66f5a146b2e875eb4b69b19b - FBLazyVector: 6c1eb116745a172c33072b3d99cb9518d3addce0 - FBReactNativeSpec: 8b91bac25292c24bbc28ee754c5482a838280210 + FBLazyVector: b3ff0841fe404f6d35d321bdd7e2971a101ba057 + FBReactNativeSpec: 4e08b13d0b49f20e96adf7e77ca546142ec2aafd Flipper: be611d4b742d8c87fbae2ca5f44603a02539e365 Flipper-DoubleConversion: 38631e41ef4f9b12861c67d17cb5518d06badc41 - Flipper-Folly: e4493b013c02d9347d5e0cb4d128680239f6c78a + Flipper-Folly: c12092ea368353b58e992843a990a3225d4533c3 Flipper-Glog: 1dfd6abf1e922806c52ceb8701a3599a79a200a6 Flipper-PeerTalk: 116d8f857dc6ef55c7a5a75ea3ceaafe878aadc9 Flipper-RSocket: 64e7431a55835eb953b0bf984ef3b90ae9fdddd7 @@ -531,36 +531,36 @@ SPEC CHECKSUMS: glog: 1cb7c408c781ae8f35bbababe459b45e3dee4ec1 hermes: 12d049af0d8e8379c5b3b54ffb1919d670045bdc libevent: ee9265726a1fc599dea382964fa304378affaa5f - OpenSSL-Universal: ff34003318d5e1163e9529b08470708e389ffcdd + OpenSSL-Universal: 8b48cc0d10c1b2923617dfe5c178aa9ed2689355 RCT-Folly: 1347093ffe75e152d846f7e45a3ef901b60021aa - RCTRequired: b34a90dff6f3c18e0641b1e4a3620031f5d315b9 - RCTTypeSafety: 71c2ec451077ca55474685acf466c276b559d75e - React: 9c5ec954ca211713c2bcd2c9c572a9c6e48fa79b - React-ART: 9df7751bafac79781c00a219bad2e756910fd13a - React-callinvoker: 578d74024ed71187336615364da323f5e0e61c29 - React-Core: 76c7650388af283f9bb3aa54d48029188d1f3a8e - React-CoreModules: 4316d724429331c9205aef6f71e35f1876ca2ca1 - React-cxxreact: 54b090f769cba0c74f71bc018d2653ce631dc0f0 - React-jsi: 58c142c2bfa448915ba10ebeed2caed5ec2eee6f - React-jsiexecutor: e40d4bd213e8d05f87299f451f0ec07b7d93ca68 - React-jsinspector: a61940cf2c88407a169ad29d5c547ba732d29812 - React-RCTActionSheet: 0b4788e65fb860afee5407daea168c7e5b796cd1 - React-RCTAnimation: 18ef9f158160e4e4d77c2cdd5e9f4a057d7b9c2f - React-RCTBlob: 013b9c2e4f4d883c0b4866329e7f36b536086d14 - React-RCTImage: adb4904503c4152d922b8a5baadd0476686de229 - React-RCTLinking: b223ae5b946546498ec509065c92453f0f4c4a9a - React-RCTNetwork: 69ee4f9f67e979f5973876bc6b12b3a2c77fbeab - React-RCTPushNotification: 483616d9ea5e968742316a3b6d5be47de75e00a1 - React-RCTSettings: a8cb50695be2826b4e0a7efc57981d6701fd8626 - React-RCTTest: 8d800f84fb32a2e71a5e8c90d2e66e9b1590a39f - React-RCTText: 2c11805589b28a30a092d7d33b734066fcfe8b69 - React-RCTVibration: 902e0fddba6f8a7c983833c656d4d8ff21d96052 + RCTRequired: 5b6e3555bf3e4de31f5f9eec6765cb1e1c3f8588 + RCTTypeSafety: 433a5f0c42cffe0dce22d296be466b85134df89a + React: 76089aa2c64e9b8e68d800212aa8aeb29cfe6261 + React-ART: 222b1fab73ae6557fc5d574674edcc3188efb18d + React-callinvoker: ff08dfe52b3a0dc610a79a03e0f6c3e3f10e125c + React-Core: 81b5173e8855498a15a78e42aba1b699221f9b3e + React-CoreModules: 8ab2d55539bde7272ff41a15648c240577756647 + React-cxxreact: 698bc21b02495b901d09fb6925fb7e6520de0238 + React-jsi: a709fa4ff7117075b50ae4616a0866ae9bf6d0d5 + React-jsiexecutor: 3ff187bf23493fec692716a6641dc4a6fc5841ca + React-jsinspector: 551b5d3465e34674a0f77f9928bd400618ac0e61 + React-RCTActionSheet: 9ca162527c21bcff421a35e0e2673e0f5b9816dc + React-RCTAnimation: 649bca7ad18ce605f8c83cad39e24460133c2c7e + React-RCTBlob: ef322dcc9ff4e0432779c7c0bd0b1e538e454ef0 + React-RCTImage: aecac3315930fd44fe728eca2fd2239e7248f27d + React-RCTLinking: 4e894cb3edcac66b38b62728de5848023e044dc7 + React-RCTNetwork: 5aff7081f53f84c066e2fab498c663a3c874862b + React-RCTPushNotification: 9f7935165abe702411d378e3a4ce4576421328ce + React-RCTSettings: f12d385d733dc01db6b61b416dfb0a1876f15527 + React-RCTTest: 26f1ccd3a6de79722aadeb3abacbdcf245cf9ed6 + React-RCTText: 711cd763e14ff8718466a3b492c169b94ddc37ae + React-RCTVibration: 3b52dde3beeab10ca475e61a8016d38290019901 React-TurboModuleCxx-RNW: 4da8eb44b10ab3c5bbab9fcb0a8ae415c20ea3c9 - React-TurboModuleCxx-WinRTPort: 74cb192337ef30efda8e62ad84f248193d3f791a - ReactCommon: ba0a587c5df062da8b0ba51ddefa2531889414a9 - Yoga: dcb56e91da53f36596ed6fe8896b359064156fdc + React-TurboModuleCxx-WinRTPort: c7886867a28587fa55b5cc97f08a7e2acd30d842 + ReactCommon: 9ff853e68f82140864b99aa9094369d36c8d7b21 + Yoga: 620d1137a9da2515a80f96371b5485a9388d575f YogaKit: f782866e155069a2cca2517aafea43200b01fd5a PODFILE CHECKSUM: 18ca7d3b0e7db79041574a8bb6200b9e1c2d5359 -COCOAPODS: 1.9.1 +COCOAPODS: 1.9.1 \ No newline at end of file