Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

macOS Keyboard Support #657

Merged
merged 39 commits into from
Dec 12, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8df39e1
Update RCTCxxBridge.mm
HeyImChris May 14, 2020
4a9bcbd
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Jun 1, 2020
e8d2d8b
Merge pull request #1 from microsoft/master
HeyImChris Aug 17, 2020
ab71c3b
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Sep 3, 2020
e40c784
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Sep 8, 2020
204ddb3
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Sep 16, 2020
b30a024
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Sep 17, 2020
4ac284e
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Oct 7, 2020
7f1863a
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Oct 15, 2020
eec7a79
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Nov 11, 2020
136032a
macOS keyboard support
HeyImChris Nov 26, 2020
119f027
update comment
HeyImChris Nov 26, 2020
a76bcc1
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Nov 27, 2020
7d85560
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Dec 4, 2020
90f0cff
add key value checks so we don't send all events
HeyImChris Dec 10, 2020
508ac92
macOS keyboard support
HeyImChris Nov 26, 2020
1d1ff14
update comment
HeyImChris Nov 26, 2020
78d8e19
add key value checks so we don't send all events
HeyImChris Dec 10, 2020
5dcd7ce
[ado] Workaround homebrew openssl issue (#669)
alloy Dec 8, 2020
c56dff7
Fix detox yarn error with Xcode 12 (#670)
HeyImChris Dec 9, 2020
6b3487d
only use valid keys, bubble events to super
HeyImChris Dec 11, 2020
8568622
Merge branch 'heyimchris/keyboarding' of https://github.com/HeyImChri…
HeyImChris Dec 11, 2020
7011dc4
Merge branch 'master' of https://github.com/microsoft/react-native-macos
HeyImChris Dec 11, 2020
5894111
macOS keyboard support
HeyImChris Nov 26, 2020
ecc351c
update comment
HeyImChris Nov 26, 2020
2fee2cc
add key value checks so we don't send all events
HeyImChris Dec 10, 2020
b40eace
only use valid keys, bubble events to super
HeyImChris Dec 11, 2020
8620c29
macOS keyboard support
HeyImChris Nov 26, 2020
dfb3d4a
add key value checks so we don't send all events
HeyImChris Dec 10, 2020
9a43360
Merge branch 'heyimchris/keyboarding' of https://github.com/HeyImChri…
HeyImChris Dec 11, 2020
0c46c4a
resolve bad merge
HeyImChris Dec 11, 2020
5ee1b50
update valid key bug, api typo
HeyImChris Dec 12, 2020
7ff3849
spacing fix
HeyImChris Dec 12, 2020
9eefe91
Merge branch 'master' into heyimchris/keyboarding
HeyImChris Dec 12, 2020
974da4b
fix flow errors
HeyImChris Dec 12, 2020
c29f431
Merge branch 'heyimchris/keyboarding' of https://github.com/HeyImChri…
HeyImChris Dec 12, 2020
6655bb9
fix snapshot tests for new APIs
HeyImChris Dec 12, 2020
c87d38b
yarn lint --fix
HeyImChris Dec 12, 2020
263182e
fix flipper
HeyImChris Dec 12, 2020
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 31 additions & 1 deletion Libraries/Components/Button.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';

Expand Down Expand Up @@ -113,6 +113,28 @@ 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",
*/
validKeysDown?: ?Array<string>,

/*
* Array of keys to receive key up events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysUp?: ?Array<string>,
// ]TODO(OSS Candidate ISS#2710739)
|}>;

Expand Down Expand Up @@ -163,6 +185,10 @@ class Button extends React.Component<ButtonProps> {
testID,
onFocus, // TODO(OSS Candidate ISS#2710739)
onBlur, // TODO(OSS Candidate ISS#2710739)
onKeyDown,
validKeysDown,
validKeysUp,
onKeyUp,
} = this.props;
const buttonStyles = [styles.button];
const textStyles = [styles.text];
Expand Down Expand Up @@ -207,6 +233,10 @@ class Button extends React.Component<ButtonProps> {
onPress={onPress}
onFocus={onFocus} // TODO(OSS Candidate ISS#2710739)
onBlur={onBlur} // TODO(OSS Candidate ISS#2710739)
onKeyDown={onKeyDown}
onKeyUp={onKeyUp}
validKeysDown={validKeysDown}
validKeysUp={validKeysUp}
touchSoundDisabled={touchSoundDisabled}>
<View style={buttonStyles}>
<Text style={textStyles} disabled={disabled}>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ exports[`<Pressable /> 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]}
Expand All @@ -29,6 +31,8 @@ exports[`<Pressable /> 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]}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]}
Expand Down Expand Up @@ -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]}
Expand Down
14 changes: 14 additions & 0 deletions Libraries/Components/Touchable/TouchableNativeFeedback.js
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,18 @@ type Props = $ReadOnly<{|
*/
nextFocusUp?: ?number,

/*
* Array of keys to receive key down events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysDown?: ?Array<string>,

/*
* Array of keys to receive key up events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysUp?: ?Array<string>,

/**
* Set to true to add the ripple effect to the foreground of the view, instead
* of the background. This is useful if one of your child views has a
Expand Down Expand Up @@ -297,6 +309,8 @@ class TouchableNativeFeedback extends React.Component<Props, State> {
nextFocusUp: this.props.nextFocusUp,
onLayout: this.props.onLayout,
testID: this.props.testID,
validKeysDown: this.props.validKeysDown,
validKeysUp: this.props.validKeysUp,
},
...children,
);
Expand Down
27 changes: 27 additions & 0 deletions Libraries/Components/Touchable/TouchableOpacity.js
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,17 @@ type Props = $ReadOnly<{|
style?: ?ViewStyleProp,

hostRef: React.Ref<typeof Animated.View>,
/*
* Array of keys to receive key down events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysDown?: ?Array<string>,

/*
* Array of keys to receive key up events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysUp?: ?Array<string>,
|}>;

type State = $ReadOnly<{|
Expand Down Expand Up @@ -165,6 +176,18 @@ class TouchableOpacity extends React.Component<Props, State> {
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);
}
},
validKeysDown: this.props.validKeysDown,
validKeysUp: this.props.validKeysUp,
onLongPress: this.props.onLongPress,
onPress: this.props.onPress,
onPressIn: event => {
Expand Down Expand Up @@ -279,6 +302,10 @@ class TouchableOpacity extends React.Component<Props, State> {
onDrop={this.props.onDrop}
onFocus={this.props.onFocus}
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}>
Expand Down
13 changes: 13 additions & 0 deletions Libraries/Components/Touchable/TouchableWithoutFeedback.js
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import type {EdgeInsetsProp} from '../../StyleSheet/EdgeInsetsPropType';
import type {
BlurEvent,
FocusEvent,
KeyEvent,
LayoutEvent,
PressEvent,
MouseEvent, // TODO(macOS ISS#2323203)
Expand Down Expand Up @@ -64,6 +65,10 @@ type Props = $ReadOnly<{|
onAccessibilityAction?: ?(event: AccessibilityActionEvent) => mixed,
onBlur?: ?(event: BlurEvent) => mixed,
onFocus?: ?(event: FocusEvent) => mixed,
onKeyDown?: ?(event: KeyEvent) => mixed,
onKeyUp?: ?(event: KeyEvent) => mixed,
validKeysDown?: ?Array<string>,
validKeysUp?: ?Array<string>,
onLayout?: ?(event: LayoutEvent) => mixed,
onLongPress?: ?(event: PressEvent) => mixed,
onPress?: ?(event: PressEvent) => mixed,
Expand Down Expand Up @@ -106,6 +111,10 @@ const PASSTHROUGH_PROPS = [
'onAccessibilityAction',
'onBlur',
'onFocus',
'onKeyDown',
'onKeyUp',
'validKeysDown',
'validKeysUp',
'onLayout',
'onMouseEnter', // [TODO(macOS ISS#2323203)
'onMouseLeave',
Expand Down Expand Up @@ -227,6 +236,10 @@ function createPressabilityConfig(props: Props): PressabilityConfig {
android_disableSound: props.touchSoundDisabled,
onBlur: props.onBlur,
onFocus: props.onFocus,
onKeyDown: props.onKeyDown,
onKeyUp: props.onKeyUp,
validKeysDown: props.validKeysDown,
validKeysUp: props.validKeysUp,
onLongPress: props.onLongPress,
onPress: props.onPress,
onPressIn: props.onPressIn,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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]}
Expand Down
4 changes: 4 additions & 0 deletions Libraries/Components/View/ReactNativeViewAttributes.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ const UIView = {
onDragEnter: true,
onDragLeave: true,
onDrop: true,
onKeyDown: true,
onKeyUp: true,
validKeysDown: true,
validKeysUp: true,
draggedTypes: true, // ]TODO(macOS ISS#2323203)
style: ReactNativeStyleAttributes,
};
Expand Down
14 changes: 14 additions & 0 deletions Libraries/Components/View/ReactNativeViewViewConfig.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,18 @@ const ReactNativeViewConfig = {
captured: 'onFocusCapture',
},
},
topKeyUp: {
phasedRegistrationNames: {
bubbled: 'onKeyUp',
captured: 'onKeyUpCapture',
},
},
topKeyDown: {
phasedRegistrationNames: {
bubbled: 'onKeyDown',
captured: 'onKeyDownCapture',
},
},
topKeyPress: {
phasedRegistrationNames: {
bubbled: 'onKeyPress',
Expand Down Expand Up @@ -343,6 +355,8 @@ const ReactNativeViewConfig = {
: {process: require('../../StyleSheet/processTransform')}): any),
translateX: true,
translateY: true,
validKeysDown: true,
validKeysUp: true,
width: true,
zIndex: true,
},
Expand Down
4 changes: 4 additions & 0 deletions Libraries/Components/View/ReactNativeViewViewConfigMacOS.js
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,10 @@ const ReactNativeViewViewConfigMacOS = {
onDragLeave: true,
onDrop: true,
onFocus: true,
onKeyDown: true,
onKeyUp: true,
validKeysDown: true,
validKeysUp: true,
onMouseEnter: true,
onMouseLeave: true,
tooltip: true,
Expand Down
17 changes: 17 additions & 0 deletions Libraries/Components/View/ViewPropTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -33,6 +34,8 @@ import type {

// [TODO(macOS ISS#2323203)
import type {DraggedTypesType} from '../View/DraggedType';
//$FlowFixMe
import {array} from 'yargs';
// ]TODO(macOS ISS#2323203)

export type ViewLayout = Layout;
Expand All @@ -41,6 +44,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<{|
Expand Down Expand Up @@ -599,6 +604,18 @@ export type ViewProps = $ReadOnly<{|
*/
enableFocusRing?: ?boolean, // TODO(macOS ISS#2323203)

/*
* Array of keys to receive key down events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysDown?: ?array<string>,

/*
* Array of keys to receive key up events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysUp?: ?array<string>,

/**
* Enables Dran'n'Drop Support for certain types of dragged types
*
Expand Down
41 changes: 41 additions & 0 deletions Libraries/Pressability/Pressability.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import {normalizeRect, type RectOrSize} from '../StyleSheet/Rect';
import type {
BlurEvent,
FocusEvent,
KeyEvent,
PressEvent,
MouseEvent,
} from '../Types/CoreEventTypes';
Expand Down Expand Up @@ -93,6 +94,28 @@ 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,

/*
* Array of keys to receive key down events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysDown?: ?Array<string>,

/*
* Array of keys to receive key up events for
* For arrow keys, add "leftArrow", "rightArrow", "upArrow", "downArrow",
*/
validKeysUp?: ?Array<string>,

/**
* Called when the hover is activated to provide visual feedback.
*/
Expand Down Expand Up @@ -156,6 +179,8 @@ export type EventHandlers = $ReadOnly<{|
onBlur: (event: BlurEvent) => void,
onClick: (event: PressEvent) => void,
onFocus: (event: FocusEvent) => void,
onKeyDown: (event: KeyEvent) => void,
onKeyUp: (event: KeyEvent) => void,
onMouseEnter?: (event: MouseEvent) => void,
onMouseLeave?: (event: MouseEvent) => void,
onResponderGrant: (event: PressEvent) => void,
Expand Down Expand Up @@ -446,6 +471,21 @@ export default class Pressability {
},
};

const keyEventHandlers = {
onKeyDown: (event: KeyEvent): void => {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For extra context, react-native-windows did this a slightly different way. There, we translate key events seen by Pressability into press events, instead of having Pressability emit key events. This matches some legacy behavior, but it also means press event shape is unexpected when press happens by keyboard activation.

If you want raw pass through, it might be simpler to just avoid passing the handlers from Pressable/Touchable to Pressability.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we get state change visuals on keyboard with this? IIRC hooking into the Pressability state machine gave us those for free.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This mimics the pattern we used for onFocus and onBlur for macOS. What do you mean by state change visuals on keyboard?

Copy link
Collaborator

@Saadnajmi Saadnajmi Dec 10, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I understand properly, windows treats onKeyUp as onPressIn, and onKeyDown as onPressOut. Then, any visuals that might be associated with the pressed state of a perusable also happen on key press. This sounds like a desirable behavior that I think we'd want to incorporate...
I just checked and it looks like react-native-windows is still doing the same thing, so I guess the flow problems were worth the trade off?

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 => {
const {disabled} = this._config;
Expand Down Expand Up @@ -602,6 +642,7 @@ export default class Pressability {
...focusEventHandlers,
...responderEventHandlers,
...mouseEventHandlers,
...keyEventHandlers,
};
}

Expand Down
Loading