-
Notifications
You must be signed in to change notification settings - Fork 135
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
[0.71] [Key handling] pass through all keys; allow specifying modifiers for validKeys[Down|Up] #1866
Conversation
Potential dupe of #1615 😅 |
Oops. I was totally unaware of this. It looks like there is a significant overlap, but there are differences around certain specifics. For example, my version allows specifying "don't care" for modifiers, so API users could achieve old behavior if desired with trivial (or no) changes. |
…validKeys[Down|Up] (#1867) * [Key handling] pass through all keys; allow specifying modifiers for validKeys[Down|Up] There are scenarios where it might be necessary to look at the incoming events without removing from the system queue. Currently that's impossible today on React Native macOS, since views are required to specify `validKeysDown` or `validKeysUp`, and such events are always removed from the queue. To mitigate, let's add a new `passthroughAllKeyEvents` prop to `RCTView`. We could keep it forever (towards an interest to reduce event spam from native to JS), or we could use it towards the path to making it the default behavior (stage 1: default false, i.e. opt in, stage 2: default true, i.e. opt out, stage 3: remove, is default behavior). - React/Views/RCTView.h - React/Views/RCTView.m - React/Views/RCTViewManager.m Note that this doesn't properly work with `RCTUITextField` (i.e. single line text fields). From what I can tell, that would need us to possibly provide a custom field editor for the window. I am scoping this out for this PR. Another peculiarity to note is regarding `RCTUITextView` (i.e. multi line text fields). Here, it looks like the text view itself isn't exposed to the JS (this view doesn't have a `nativeTag`), so there's a `RCTView` holding a child `RCTUITextView` where the former dispatches events to JS on behalf for the latter. The reason this matters (specifically for "pass through" events) is because the latter can dispatch certain events to the JS, and then depending on the super class implementation (`NSTextView`), it may or may not *also* pass the `NSEvent` to the next responder (i.e. parent view, i.e. `RCTView`). Passing the action to the next responder *can* cause us to send duplicate JS events for the same `NSEvent`. I couldn't find anything in macOS APIs to determine if the view the event was generated for is a specific view, so I am introducing a book-keeping mechanism to not send duplicate events. Introduce `RCTHandledKey` for specifying modifiers for `validKeysDown` and `validKeysUp`. Behavior noted in type definitions. - Libraries/Text/TextInput/RCTBaseTextInputView.m - React/Base/RCTConvert.h - React/Base/RCTConvert.m - React/Views/RCTHandledKey.h - React/Views/RCTHandledKey.m - React/Views/RCTView.h - React/Views/RCTView.m - React/Views/RCTViewKeyboardEvent.m - React/Views/RCTViewManager.m - React/Views/ScrollView/RCTScrollView.m macOS *usually* does things on key down (as opposed to, say, Win32, which seems to *usually* does things on key up). Like `RCTUITextField`, passs `performKeyEquivalent:` to `textInputDelegate` so we can handle the alternate `keyDown:` path (e.g. Cmd+A). This will be needed for properly handling keystrokes that go through said alternate path. There are probably several other selectors that also need implementing (`deleteBackward:`) to full pass through every possible key, but I am leaving that for some other time. - Libraries/Text/TextInput/Multiline/RCTUITextView.m Make a totally unrelated fix to `RCTSwitch`. In a test page where I added an on-by-default switch, I noticed the first toggle (ON->OFF) doesn't do anything. The second toggle (OFF->ON) then doesn't (expectedly) do anything. Found wrong behavior on the switch test page -- tempted to instead remove `wasOn`, but for now repeating the pattern in `setOn:animated:` - React/Views/RCTSwitch.m Flow stuff. `passthroughAllKeyEvents` is now a valid thing to pass to `View` types. - Libraries/Components/View/ReactNativeViewAttributes.js - Libraries/Components/View/ViewPropTypes.js - Libraries/NativeComponent/BaseViewConfig.macos.js Update signatures for `validKeysDown` and `validKeysUp` - Libraries/Components/View/ViewPropTypes.js Remove duplicated specifications on `Pressable`. Just use the one from `View`. As a benefit, future changes allow us to not have to touch `Pressable` anymore. - Libraries/Components/Pressable/Pressable.js - Libraries/Components/View/ViewPropTypes.js Update test pages with `passthoughAllKeyEvents` and the keyboard events page with an example modifier usage. - packages/rn-tester/js/examples/KeyboardEventsExample/KeyboardEventsExample.js - packages/rn-tester/js/examples/TextInput/TextInputSharedExamples.js Testing: * Using the keyboard events test page, validate "pass through" of all events for simple view, single line text input, multi line text input. Sanity test existing (non-"pass through") behavior. * Using the text input test page, ordering of `keyDown` and `keyUp` events w.r.t. other events (such as `keyPress` -- which isn't dispatched for every key) * Using the switch test page, sanity test switch behaviors * feedback * feedback #2 * PR feedback --------- Co-authored-by: Saad Najmi <saadnajmi2@gmail.com>
374f02f
to
553fe0c
Compare
Force pushed a cherry-pick of the main branch commit here to pick up all the latest changes |
There are scenarios where it might be necessary to look at the incoming events without removing from the system queue. Currently that's impossible today on React Native macOS, since views are required to specify
validKeysDown
orvalidKeysUp
, and such events are always removed from the queue.To mitigate, let's add a new
passthroughAllKeyEvents
prop toRCTView
. We could keep it forever (towards an interest to reduce event spam from native to JS), or we could use it towards the path to making it the default behavior (stage 1: default false, i.e. opt in, stage 2: default true, i.e. opt out, stage 3: remove, is default behavior).Note that this doesn't properly work with
RCTUITextField
(i.e. single line text fields). From what I can tell, that would need us to possibly provide a custom field editor for the window. I am scoping this out for this PR.Another peculiarity to note is regarding
RCTUITextView
(i.e. multi line text fields). Here, it looks like the text view itself isn't exposed to the JS (this view doesn't have anativeTag
), so there's aRCTView
holding a childRCTUITextView
where the former dispatches events to JS on behalf for the latter. The reason this matters (specifically for "pass through" events) is because the latter can dispatch certain events to the JS, and then depending on the super class implementation (NSTextView
), it may or may not also pass theNSEvent
to the next responder (i.e. parent view, i.e.RCTView
). Passing the action to the next responder can cause us to send duplicate JS events for the sameNSEvent
. I couldn't find anything in macOS APIs to determine if the view the event was generated for is a specific view, so I am introducing a book-keeping mechanism to not send duplicate events.Introduce
RCTHandledKey
for specifying modifiers forvalidKeysDown
andvalidKeysUp
. Behavior noted in type definitions.macOS usually does things on key down (as opposed to, say, Win32, which seems to usually does things on key up). Like
RCTUITextField
, passsperformKeyEquivalent:
totextInputDelegate
so we can handle the alternatekeyDown:
path (e.g. Cmd+A). This will be needed for properly handling keystrokes that go through said alternate path. There are probably several other selectors that also need implementing (deleteBackward:
) to full pass through every possible key, but I am leaving that for some other time.Make a totally unrelated fix to
RCTSwitch
. In a test page where I added an on-by-default switch, I noticed the first toggle (ON->OFF) doesn't do anything. The second toggle (OFF->ON) then doesn't (expectedly) do anything. Found wrong behavior on the switch test page -- tempted to instead removewasOn
, but for now repeating the pattern insetOn:animated:
This demonstrates the wrong\before behavior:
Flow stuff.
passthroughAllKeyEvents
is now a valid thing to pass toView
types.Update signatures for
validKeysDown
andvalidKeysUp
Remove duplicated specifications on
Pressable
. Just use the one fromView
. As a benefit, future changes allow us to not have to touchPressable
anymore.Update test pages with
passthoughAllKeyEvents
and the keyboard events page with an example modifier usage.Please select one of the following
Summary
Changelog
Test plan
keyDown
andkeyUp
events w.r.t. other events (such askeyPress
-- which isn't dispatched for every key)