Skip to content

Commit

Permalink
Put focus back in WebView2 when focus leaves but it's the only focusa…
Browse files Browse the repository at this point in the history
…ble element (#7083)

Co-authored-by: Kristen Schau <[email protected]>
  • Loading branch information
krschau and krschau authored May 11, 2022
1 parent 017cd84 commit 57224da
Show file tree
Hide file tree
Showing 2 changed files with 32 additions and 19 deletions.
50 changes: 31 additions & 19 deletions dev/WebView2/WebView2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -594,7 +594,14 @@ void WebView2::RegisterCoreEventHandlers()
return winrt::FocusManager::FindNextElement(xamlDirection);
}
}();
if (nextElement)
if (nextElement && nextElement.try_as<winrt::WebView2>() == *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.
Expand Down Expand Up @@ -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;
}
}
Expand Down Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions dev/WebView2/WebView2.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down

0 comments on commit 57224da

Please sign in to comment.