From 57224daa54659cb96fb2a1151daca64e276f1706 Mon Sep 17 00:00:00 2001 From: Kristen Schau <47155823+krschau@users.noreply.github.com> Date: Wed, 11 May 2022 12:46:47 -0700 Subject: [PATCH] Put focus back in WebView2 when focus leaves but it's the only focusable element (#7083) Co-authored-by: Kristen Schau --- dev/WebView2/WebView2.cpp | 50 ++++++++++++++++++++++++--------------- dev/WebView2/WebView2.h | 1 + 2 files changed, 32 insertions(+), 19 deletions(-) diff --git a/dev/WebView2/WebView2.cpp b/dev/WebView2/WebView2.cpp index 30d317dee5..ab65c1ac59 100644 --- a/dev/WebView2/WebView2.cpp +++ b/dev/WebView2/WebView2.cpp @@ -594,7 +594,14 @@ void WebView2::RegisterCoreEventHandlers() return winrt::FocusManager::FindNextElement(xamlDirection); } }(); - if (nextElement) + if (nextElement && nextElement.try_as() == *this) + { + // If the next element is this webview, then we are the only focusable element. Move focus back into the webview, + // or else we'll get stuck trying to tab out of the top or bottom of the page instead of looping around. + MoveFocusIntoCoreWebView(moveFocusRequestedReason); + args.Handled(TRUE); + } + else if (nextElement) { // If Anaheim is also losing focus via something other than TAB (web LostFocus event fired) // and the TAB handling is arriving later (eg due to longer MOJO delay), skip manually moving Xaml Focus to next element. @@ -1263,24 +1270,7 @@ void WebView2::HandleGotFocus(const winrt::Windows::Foundation::IInspectable&, c { if (m_coreWebView && m_xamlFocusChangeInfo.m_isPending) { - try - { - m_coreWebViewController.MoveFocus(m_xamlFocusChangeInfo.m_storedMoveFocusReason); - m_webHasFocus = true; - } - catch (winrt::hresult_error e) - { - // Occasionally, a request to restore the minimized window does not complete. This triggers - // FocusManager to set Xaml Focus to WV2 and consequently into CWV2 MoveFocus() call above, - // which in turn will attempt ::SetFocus() on InputHWND, and that will fail with E_INVALIDARG - // since that HWND remains minimized. Work around by ignoring this error here. Since the app - // is minimized, focus state is not relevant - the next (successful) attempt to restrore the app - // will set focus into WV2/CWV2 correctly. - if (e.code().value != E_INVALIDARG) - { - throw; - } - } + MoveFocusIntoCoreWebView(m_xamlFocusChangeInfo.m_storedMoveFocusReason); m_xamlFocusChangeInfo.m_isPending = false; } } @@ -1308,6 +1298,28 @@ void WebView2::HandleGettingFocus(const winrt::Windows::Foundation::IInspectable } } +void WebView2::MoveFocusIntoCoreWebView(winrt::CoreWebView2MoveFocusReason reason) +{ + try + { + m_coreWebViewController.MoveFocus(reason); + m_webHasFocus = true; + } + catch (winrt::hresult_error e) + { + // Occasionally, a request to restore the minimized window does not complete. This triggers + // FocusManager to set Xaml Focus to WV2 and consequently into CWV2 MoveFocus() call above, + // which in turn will attempt ::SetFocus() on InputHWND, and that will fail with E_INVALIDARG + // since that HWND remains minimized. Work around by ignoring this error here. Since the app + // is minimized, focus state is not relevant - the next (successful) attempt to restrore the app + // will set focus into WV2/CWV2 correctly. + if (e.code().value != E_INVALIDARG) + { + throw; + } + } +} + // Since WebView takes HWND focus (via OnGotFocus -> MoveFocus) Xaml assumes // focus was lost for an external reason. When the next unhandled TAB KeyDown diff --git a/dev/WebView2/WebView2.h b/dev/WebView2/WebView2.h index d485fb5404..adff726377 100644 --- a/dev/WebView2/WebView2.h +++ b/dev/WebView2/WebView2.h @@ -149,6 +149,7 @@ class WebView2 : void HandleKeyDown(const winrt::Windows::Foundation::IInspectable&, const winrt::KeyRoutedEventArgs& e); void HandleGettingFocus(const winrt::Windows::Foundation::IInspectable&, const winrt::GettingFocusEventArgs& args) noexcept; void HandleGotFocus(const winrt::Windows::Foundation::IInspectable&, const winrt::RoutedEventArgs&); + void MoveFocusIntoCoreWebView(winrt::CoreWebView2MoveFocusReason reason); void HandleAcceleratorKeyActivated(const winrt::Windows::UI::Core::CoreDispatcher&, const winrt::AcceleratorKeyEventArgs& args) noexcept; void HandleXamlRootChanged(); void HandleSizeChanged(const winrt::IInspectable& /*sender*/, const winrt::SizeChangedEventArgs& args);