Skip to content

Conversation

@DrewHiggins
Copy link
Contributor

@DrewHiggins DrewHiggins commented Apr 16, 2020

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 BackRequested event, which covers a lot of input buttons for back, such as an Xbox Controller's B button or Backspace
  • A GoBack virtual key press
  • The Alt + Left arrow keyboard shortcut
  • The mouse back button, which maps to the XButton1 virtual key

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


void ReactRootControl::AttachBackHandlers(XamlView const &rootView) noexcept {
auto rootElement(rootView.as<winrt::UIElement>());
if (rootElement == nullptr) {
Copy link
Contributor

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).

Copy link
Member

Choose a reason for hiding this comment

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

The non-throwing version is the try_as.


In reply to: 409825498 [](ancestors = 409825498)

Copy link
Contributor Author

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

Copy link
Contributor

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{};
Copy link
Contributor

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?

Copy link
Contributor Author

@DrewHiggins DrewHiggins Apr 16, 2020

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:
image

Copy link
Contributor

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.

Copy link
Member

Choose a reason for hiding this comment

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

Consider to add a comment with a link.


In reply to: 409855996 [](ancestors = 409855996)

Copy link
Contributor Author

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

Copy link
Contributor

@NickGerleman NickGerleman left a 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)

@ghost ghost added Needs: Author Feedback The issue/PR needs activity from its author (label drives bot activity) and removed Needs: Author Feedback The issue/PR needs activity from its author (label drives bot activity) labels Apr 16, 2020
* 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
@vmoroz
Copy link
Member

vmoroz commented Apr 16, 2020

CodeFlow for GitHub does not download executable files. If you trust this file and would like to run it, please download it yourself through GitHub.

Please remove this file.


Refers to: vnext/ReactUWP/RCa15532:1 in cf8a17c. [](commit_id = cf8a17c, deletion_comment = False)

}

winrt::Windows::UI::Core::SystemNavigationManager::GetForCurrentView().BackRequested(
[this](winrt::IInspectable const & /*sender*/, winrt::BackRequestedEventArgs const &args) {
Copy link
Member

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.

Copy link
Member

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.

Copy link
Contributor Author

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) {
Copy link
Contributor

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);
Copy link
Member

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.

Copy link
Contributor Author

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);
Copy link
Member

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.

Copy link
Contributor Author

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());
Copy link
Member

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.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed to match ToggleInspector()

Copy link
Member

@vmoroz vmoroz left a comment

Choose a reason for hiding this comment

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

🕐

@ghost ghost added the Needs: Author Feedback The issue/PR needs activity from its author (label drives bot activity) label Apr 16, 2020
* Use weak pointers to this in event handlers
* Fix safety issue in query_cast
* Revoke handlers on Uninit
* Remove added binary file
@ghost ghost removed the Needs: Author Feedback The issue/PR needs activity from its author (label drives bot activity) label Apr 16, 2020
@asklar
Copy link
Member

asklar commented Apr 17, 2020

We should think about how this interacts with AppViewBackButton though?

Copy link
Member

@vmoroz vmoroz left a comment

Choose a reason for hiding this comment

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

:shipit:

@NickGerleman
Copy link
Contributor

Taking a look at the validate-overrides issue. It's probably related to line ending handling in the tool.

@DrewHiggins DrewHiggins force-pushed the jahiggin/backHandler branch from 9ac65dc to a4362cc Compare April 17, 2020 20:33
@NickGerleman NickGerleman added the AutoMerge Causes a PR to be automatically merged once all requirements are passed (label drives bot activity) label Apr 17, 2020
@ghost
Copy link

ghost commented Apr 17, 2020

Hello @NickGerleman!

Because this pull request has the AutoMerge label, I will be glad to assist with helping to merge this pull request once all check-in policies pass.

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 (@msftbot) and give me an instruction to get started! Learn more here.

@ghost ghost merged commit 7834106 into microsoft:master Apr 17, 2020
asklar pushed a commit to asklar/react-native-windows that referenced this pull request Apr 19, 2020
* 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
This pull request was closed.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AutoMerge Causes a PR to be automatically merged once all requirements are passed (label drives bot activity)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Support the Backhandler React Native API

5 participants