-
Notifications
You must be signed in to change notification settings - Fork 1.2k
Add support for React Native BackHandler API on Windows #4623
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
Conversation
|
|
||
| void ReactRootControl::AttachBackHandlers(XamlView const &rootView) noexcept { | ||
| auto rootElement(rootView.as<winrt::UIElement>()); | ||
| if (rootElement == nullptr) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
as will already throw if we can't QI (i.e. we terminate since it hits the noexcept boundary).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Switched to try_as with a null check
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@vmoroz was there a preference towards null-checking, or was pointing towards try_as more educational?
It's splitting hairs but I actually slightly preferred the terminating version.
| }); | ||
|
|
||
| // Handle keyboard "back" button press | ||
| winrt::KeyboardAccelerator goBack{}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure this is the right way to listen for the back action. From what I can find, SystemNavigationManager has a BackRequested event to express this intent. Can we hook into that instead?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The BackRequested event does not fire in all of the scenarios where the user might be using input devices to go back. The linked UWP documentation in the PR description goes into some more detail on this, and outlines this in a table:

There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh wow, you're right. I completely missed that in the description and in code. Thanks for linking it again.
It's unfortunate official reccomendations stray from the system API, but this makes sense then. I wonder a bit whether we could let developers opt into non system back events, but could see arguments both ways.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a comment with a link to the docs
NickGerleman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Requesting changes (see comments)
* Copied in Android BackHandler code from upstream * Changed the base file for the BackHandler override * Fixed weak ptr check * Removed unnecessary validation after casting XamlView to UIElement * Call JS with legacyPointer
| } | ||
|
|
||
| winrt::Windows::UI::Core::SystemNavigationManager::GetForCurrentView().BackRequested( | ||
| [this](winrt::IInspectable const & /*sender*/, winrt::BackRequestedEventArgs const &args) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
this [](start = 7, length = 4)
It is not safe. Please acquire std::weak_ptr instead and resolve it inside of lambda.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The same is for other case in this function.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed: passed a weak ptr to this in both
| void ReactRootControl::AttachBackHandlers(XamlView const &rootView) noexcept { | ||
| auto rootElement(rootView.as<winrt::UIElement>()); | ||
| winrt::Windows::UI::Core::SystemNavigationManager::GetForCurrentView().BackRequested( | ||
| [this](winrt::IInspectable const & /*sender*/, winrt::BackRequestedEventArgs const &args) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you know if it's safe to capture a raw pointer here? We should otherwise capture a weak ptr.
| m_SIPEventHandler->AttachView(xamlRootView, /*fireKeyboradEvents:*/ true); | ||
|
|
||
| UpdateRootViewInternal(); | ||
| AttachBackHandlers(xamlRootView); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
AttachBackHandlers [](start = 2, length = 18)
We must also detach in the UninitRootView.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a function to remove the keyboard accelerators attached to the XAML root element and the BackRequested listener on uninitialization.
| [this](winrt::KeyboardAccelerator const & /*sender*/, winrt::KeyboardAcceleratorInvokedEventArgs const &args) { | ||
| args.Handled(OnBackRequested()); | ||
| }); | ||
| rootElement.KeyboardAccelerators().Append(goBack); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Append [](start = 37, length = 6)
It also must be reversible upon unload.
The ReactRootControl could be initialized/uninitialized multiple times.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a function to remove the keyboard accelerators attached to the XAML root element on uninitialization.
| return false; | ||
| } | ||
|
|
||
| auto &legacyReactInstance = query_cast<Mso::React::ILegacyReactInstance &>(*m_weakReactInstance.GetStrongPtr()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
auto & [](start = 2, length = 6)
Assigning a temporary to a reference is a recipe for disaster. VS must have a warning here.
See the ToggleInspector() for the correct usage.
You must keep the result of GetStrongPtr() in a variable when you call the query_cast. The query_cast does not increment the ref count.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Fixed to match ToggleInspector()
vmoroz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🕐
* Use weak pointers to this in event handlers * Fix safety issue in query_cast * Revoke handlers on Uninit * Remove added binary file
|
We should think about how this interacts with AppViewBackButton though? |
vmoroz
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
![]()
|
Taking a look at the validate-overrides issue. It's probably related to line ending handling in the tool. |
9ac65dc to
a4362cc
Compare
|
Hello @NickGerleman! Because this pull request has the p.s. you can customize the way I help with merging this pull request, such as holding this pull request until a specific person approves. Simply @mention me (
|
* Added initial implementation * Add backrequested listener * Add handlers for other back actions Also remove debug code * Change files * Remove TODO * Responding to PR comments * Copied in Android BackHandler code from upstream * Changed the base file for the BackHandler override * Fixed weak ptr check * Removed unnecessary validation after casting XamlView to UIElement * Call JS with legacyPointer * More PR feedback * Use weak pointers to this in event handlers * Fix safety issue in query_cast * Revoke handlers on Uninit * Remove added binary file * use weak ptr for BackRequested too * Fix override hash verification
Fixes #4606
Adds support for React Native's BackHandler API, which will fire an event to its listeners when one of the events that the UWP documentation suggests listening for occurs. These are:
The implementation of the BackHandler API for Windows is pretty much the same as that of Android in the react-native repo.
Microsoft Reviewers: Open in CodeFlow