Skip to content
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

How to programmatically launch WebView2's Find function. #1737

Open
RajeshAKumar opened this issue Sep 13, 2021 · 81 comments
Open

How to programmatically launch WebView2's Find function. #1737

RajeshAKumar opened this issue Sep 13, 2021 · 81 comments
Assignees
Labels
feature request feature request tracked We are tracking this work internally.

Comments

@RajeshAKumar
Copy link

RajeshAKumar commented Sep 13, 2021

We have a HTML page in local WPF app using WebView2, but want to highlight occurrences of a search phrase in the page.
WebView2 does a very nice job of showing this when invoked by user.
We want to leverage this function programmatically.

Can you please guide?

AB#36194641

@champnic
Copy link
Member

Hey @RajeshAKumar - I don't think we currently have a way to do this. Would you like me to add this as a scenario on our backlog?

@champnic champnic self-assigned this Sep 16, 2021
@Symbai
Copy link

Symbai commented Sep 16, 2021

want to highlight occurrences of a search phrase in the page.

This can be done via executing a javascript calling window.find() already. For more info see https://developer.mozilla.org/en-US/docs/Web/API/Window/find

@RajeshAKumar
Copy link
Author

want to highlight occurrences of a search phrase in the page.

This can be done via executing a javascript calling window.find() already. For more info see https://developer.mozilla.org/en-US/docs/Web/API/Window/find

Want to highlight "all" the words like how Edge/ Edge control does when we use CTRL + F.

@RajeshAKumar
Copy link
Author

Hey @RajeshAKumar - I don't think we currently have a way to do this. Would you like me to add this as a scenario on our backlog?

Yes please log this.
Also is there any way to make this work by "Sending CTRL + F" to the control?
I could not make that work either?

@champnic champnic added feature request feature request tracked We are tracking this work internally. and removed question labels Sep 16, 2021
@champnic
Copy link
Member

@RajeshAKumar I've added this as a scenario on our backlog - thanks!

@RajeshAKumar
Copy link
Author

want to highlight occurrences of a search phrase in the page.

This can be done via executing a javascript calling window.find() already. For more info see https://developer.mozilla.org/en-US/docs/Web/API/Window/find

I tried that and it highlights one time, once we click the page, the highlight goes away.
We want to replicate the Edge control CTRL + F behavior or something close where all matches are shown and scrollbar is marked to indicate where they are in page.

@ajtruckle
Copy link

Proper support for this would be great please.

@ajtruckle
Copy link

ajtruckle commented Feb 5, 2022

@RajeshAKumar you said:

WebView2 does a very nice job of showing this when invoked by user.

How can I do this with WebView2? I know how to invoke Find / Find Next in CHtmlView using an ExecWB call. It displays its own window with Find / Find Next capabilities etc. But WebView2?

MNU_MWBEditor_Edit_Find

@RajeshAKumar
Copy link
Author

@RajeshAKumar you said:

WebView2 does a very nice job of showing this when invoked by user.
How can I do this with WebView2? I know how to invoke Find / Find Next in CHtmlView using an ExecWB call. It displays its own window with Find / Find Next capabilities etc. But WebView2?

MNU_MWBEditor_Edit_Find

Can you explain this via APIs to understand how to use this?
I would want the window to go away with options selected and window with matching text highlighted.

@ajtruckle
Copy link

@RajeshAKumar ? My screen shot is of CHtmlView which is unrelated to WebView2.

@RajeshAKumar
Copy link
Author

My issue is to solve this via API in WebView2 in WPF.

@ajtruckle
Copy link

I guess I miss-read your original text.

@frankdekker
Copy link

My issue is to solve this via API in WebView2 in WPF.

I'm also looking for an API to search on the page. The current Microsoft Edge native find dialog steals focus from the main window and when pressing escape doesn't give it back. Kinda breaking the user experience when do quick searches.

The API from CefSharp worked quite well:

// start a find
WebView2.Find(string int identifier, string searchText, bool forward, bool matchCase, bool findNext)
// callback for each time the find reports back
WebView2.FindResultCallback += (int identifier, int count, Rect selectionRect, int activeMatchOrdinal, bool finalUpdate) => {}
// stop the search
WebView2.StopFinding(bool clearSelection)

To be able to build a UI that fits more with the application WebView2 is integrated with:
image
image

@ajtruckle
Copy link

FYI, I did just try adding this to a custom context menu:

wil::com_ptr<ICoreWebView2ContextMenuItem> itemFind;
CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
	L"Find", nullptr,
	COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &itemFind));

CHECK_FAILURE(itemFind->add_CustomItemSelected(
	Callback<ICoreWebView2CustomItemSelectedEventHandler>(
		[appWindow = this, target](ICoreWebView2ContextMenuItem* sender, IUnknown* args)
		{
			appWindow->m_pImpl->m_webView->ExecuteScript(L"window.find()", nullptr);

			return S_OK;
		})
	.Get(), nullptr));
CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemFind.get()));
itemsCount++;

It doesn't work. Nothing shows on screen. When I used the CHtmlView control this was a simple task:

m_pHtmlPreview->ExecWB(OLECMDID_FIND, OLECMDEXECOPT_PROMPTUSER, nullptr, nullptr);

Is there any updates on this issue? Thank you.

@ajtruckle
Copy link

Hi @champnic !

I have now managed to use SendInput to invoke the Find window via my context menu:

// ===============================================================
wil::com_ptr<ICoreWebView2ContextMenuItem> itemFind;
CHECK_FAILURE(webviewEnvironment->CreateContextMenuItem(
	L"Find (CTRL + F)", nullptr,
	COREWEBVIEW2_CONTEXT_MENU_ITEM_KIND_COMMAND, &itemFind));

CHECK_FAILURE(itemFind->add_CustomItemSelected(
	Callback<ICoreWebView2CustomItemSelectedEventHandler>(
		[](ICoreWebView2ContextMenuItem* sender, IUnknown* args)
		{
			// Create an array of generic keyboard INPUT structures
			std::vector<INPUT> vIP(4);
			for (int n = 0; n < 4; ++n)
			{
				vIP.at(n).type = INPUT_KEYBOARD;
				vIP.at(n).ki.wScan = 0;
				vIP.at(n).ki.time = 0;
				vIP.at(n).ki.dwFlags = 0; // 0 for key press
				vIP.at(n).ki.dwExtraInfo = 0;
			}

			vIP.at(0).ki.wVk = VK_CONTROL;
			vIP.at(1).ki.wVk = 'F';

			vIP.at(2).ki.wVk = 'F';
			vIP.at(2).ki.dwFlags = KEYEVENTF_KEYUP;

			vIP.at(3).ki.wVk = VK_CONTROL;
			vIP.at(3).ki.dwFlags = KEYEVENTF_KEYUP;

			SendInput(4, vIP.data(), sizeof(INPUT));

			return S_OK;
		})
	.Get(), nullptr));

CHECK_FAILURE(items->InsertValueAtIndex(itemsCount, itemFind.get()));
itemsCount++;
// ===============================================================

This works fine:

ContextMenuFind

My only request is that the Search bar be improved. The CHtmlView counterpart is richer:

image

@wusyong
Copy link

wusyong commented May 24, 2022

FWIW, electron also has this kind of feature

@michaldivis
Copy link

I'd love to have this feature as well.

@CiccioIV
Copy link

CiccioIV commented Aug 6, 2022

As a workaround, I did it by using the Winform SendKeys class .
You can use it in wpf apps too, by adding true in the project properties

  <PropertyGroup>
    <OutputType>WinExe</OutputType>
    <TargetFramework>net6.0-windows</TargetFramework>
    <Nullable>enable</Nullable>
    <UseWPF>true</UseWPF>
    <UseWindowsForms>true</UseWindowsForms>
  </PropertyGroup>

then, in my click method, I've first passed the focus to the webview2 (browser) element.
Then, called the SendWait method with "{F3}" as parameter

        private void openSearch(object sender, RoutedEventArgs e)
        {
            this.browser.Focus();
            System.Windows.Forms.SendKeys.SendWait("{F3}");
        }

not the most elegant way, perhaps. But it works.

@jebihug
Copy link

jebihug commented Aug 16, 2022

Can't find a way to close the find UI programmatically.

@champnic
Copy link
Member

@jebihug You could probably send an Escape key to dismiss the UI.

@jebihug
Copy link

jebihug commented Aug 17, 2022

@champnic This is not working. Especially when the browser don't have the focus and when there is many browsers opened and I want to close the find UI of one of them.

@ajtruckle
Copy link

ajtruckle commented Feb 11, 2024 via email

@ajtruckle
Copy link

@nishitha-burman @champnic

I am interested as to how this API is progressing as the suggested ETA was 1-3months and we are at 2months now. 😀

BTW is @nishitha-burman OK as they seemed to go off the radar. 🤗

@victorhuangwq
Copy link
Collaborator

victorhuangwq commented Mar 27, 2024

Hi @ajtruckle, from what I can see this item is indeed being picked up and being worked on. Do note that 1 - 3 months was an estimate and not a strong guarantee, as there might be unexpected complications that arises.

And thanks for your concern, @nishitha-burman is fine.

@ajtruckle
Copy link

@victorhuangwq
I see that the Find dialog has been updated in Edge and WebVie22:

image

So, when will be able to invoke this properly via API?

@victorhuangwq
Copy link
Collaborator

@ajtruckle looking at the current API proposal here: https://github.com/MicrosoftEdge/WebView2Feedback/pull/4399/files?short_path=a4e657f#diff-a4e657fb3aef3cc7b9a09b13af805de25931fdb082b2a93aeea46e45de10bb90

It seems like both match case and match whole word should be available options in the API.

@ajtruckle
Copy link

@victorhuangwq

Cool. Do you know when the stable API will be released?

@victorhuangwq
Copy link
Collaborator

victorhuangwq commented May 7, 2024

As you can see, it's still in the works. I'm unable to promise you a timeline.
But either @maxwellmyers or I will keep you (and this thread) posted whenever we have any updates.

@ThHeidenreich
Copy link

@victorhuangwq Any new info about the api release? We are now on the end of august... Would be very nice to have...

@ajtruckle
Copy link

ajtruckle commented Aug 26, 2024 via email

@zooguest
Copy link

We have a HTML page in local WPF app using WebView2, but want to highlight occurrences of a search phrase in the page. WebView2 does a very nice job of showing this when invoked by user. We want to leverage this function programmatically.

Can you please guide?

AB#36194641

Ohhhh. Today is the anniversary of this question. 3 years. Almost done man ;)

@ajtruckle
Copy link

@zoobesucher Oh yes! 3 years. Wow!

@nirdil
Copy link

nirdil commented Oct 11, 2024

@champnic any updates on this?
It's a crucial functionality and there's no known workarounds for this.

@ajtruckle
Copy link

@nirdil @champnic
A long time ago there were lots of tweaks to the documentation. Then nothing. So I have no idea I am afraid.

@Optimierungswerfer
Copy link

Ever since the mass layoffs and subsequent AI hype, I feel like there have not been many resources left dedicated to projects like WebView2 by Microsoft. I just wish they would handle it as free and open source software, so that the people who need this functionality implemented could at least do something about it themselves. I faintly remember the WebView2 team stating intentions to open source it a few years ago.

@nirdil
Copy link

nirdil commented Oct 14, 2024

Would have been great if it was open source and maintained by the community.
@champnic any way to make that happen?

@ajtruckle
Copy link

ajtruckle commented Oct 14, 2024 via email

@champnic
Copy link
Member

champnic commented Oct 16, 2024

Hey all - This is still being worked on. It ran into some issues during implementation that we have mostly solved at this point. Right now the estimate is that this will be available as a stable API with the version 132 release SDK, which should ship around mid-January.

@micilini
Copy link

micilini commented Jan 2, 2025

I have a solution my friends!!!

I have an application made with C# and WPF, with WebView2 and like to open Find Dialog when user click on my button (Open Find Dialog programatically).

For this, I need to download this package:

Install-Package InputSimulator

And this is my method:

using WindowsInput;

private void OpenSearchBox()
{
    myWebView.Focus();//This will focus WebView

    //This will simulate CTRL + F:
    var sim = new InputSimulator();
    sim.Keyboard.ModifiedKeyStroke(WindowsInput.Native.VirtualKeyCode.CONTROL, WindowsInput.Native.VirtualKeyCode.VK_F);
}

If you are using WindowsForms, try using SendKeys:

using System.Windows.Forms;

private void SimulateCtrlF()
{
    myWebView.Focus();//This will focus WebView
    SendKeys.Send("^(f)"); //This will simulate CTRL + F:
}

Works like a charm!

@maxwellmyers
Copy link

Hi all!

The FindOnPage API is now available as an experimental API in 1.0.3079-prerelease.

Using this API, your app can programmatically control Find operations, enabling you to:

  • Customize Find options (Find Term, Case Sensitivity, Word Matching, Match Highlighting, Default UI Suppression).
  • Find text strings and navigate among them within a WebView2 control.
  • Programmatically initiate Find operations and navigate Find results.
  • Track the status of Find operations (completion of find operations, events for match count and match index changing).

Please give it a try and let us know if you have any feedback!

@ajtruckle
Copy link

@maxwellmyers
Thanks. So I change to prerelease nuget package. But I can use stable edge? Only want to change what I have to. Thanks for confirming.

@victorhuangwq
Copy link
Collaborator

It's currently only in prerelease SDK, so you would need to use Edge Canary to test the feature.

@victorhuangwq
Copy link
Collaborator

cc @pushkin-

@ajtruckle
Copy link

ajtruckle commented Jan 25, 2025

I have deleted most of my comments and consolidating them into a single comment so that nothing is overlooked.

Using Canary Runtime

In the end I had to modify the user environment variables for my application to pickup the canary runtime.

Image

Trying to do it programmatically appeared to have no effect:

CHECK_FAILURE(options->put_ReleaseChannels(COREWEBVIEW2_RELEASE_CHANNELS_CANARY));
CHECK_FAILURE(options->put_ChannelSearchKind(COREWEBVIEW2_CHANNEL_SEARCH_KIND_LEAST_STABLE));

WebView2Find API Documentation

The proposed code snippets caused me issues for two reasons:

  1. The interfaces it refers to are different from the ones I needed to use.
  2. There are issues with the code.

Interfaces

I had to use the following interfaces:

  • auto webView2Environment18 = m_pImpl->m_webViewEnvironment.try_query<ICoreWebView2ExperimentalEnvironment18>();
  • wil::com_ptr<ICoreWebView2ExperimentalFindOptions> find_options;
  • auto webView2Environment29 = m_pImpl->m_webView.try_query<ICoreWebView2Experimental29>();
  • wil::com_ptr<ICoreWebView2ExperimentalFind> webView2Find;
  • ICoreWebView2ExperimentalFindStartCompletedHandler

Macros

The CHECK_FEATURE_RETURN macro can't be used in the proposed InitializeFindOptions method. This is because it returns true upon success. So I adapted by adding a new macro:

#define CHECK_FEATURE_RETURN_NULL(feature) { if (!feature) { FeatureNotAvailable(); return nullptr; } }

The sample code should be revised.

Methods

The sample code is using a different method for starting the find operation. I have to use:

webView2Find->Start

The documentation sample should be changed.

Completed Handler

Finally, I am unable to use the completed handler, as provided in the sample:

		Callback<ICoreWebView2ExperimentalFindStartCompletedHandler>(
			[this](HRESULT result, BOOL status) -> HRESULT
			{
				if (SUCCEEDED(result))
				{
					// Optionally update UI elements here upon successful Find operation.
				}
				else
				{
					// Handle errors.
				}
				return S_OK;
			}).Get()) );

I had to replace it with nullptr. Otherwise I get these build errors:

6>  EdgeWebBrowser.cpp
6>  C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\event.h(354,60): error C2064: term does not evaluate to a function taking 1 arguments
6>  (compiling source file '/EdgeWebBrowser.cpp')
6>      C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\event.h(354,60):
6>      class does not define an 'operator()' or a user defined conversion operator to a pointer-to-function or reference-to-function that takes appropriate number of arguments
6>      C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\event.h(354,60):
6>      while trying to match the argument list '(T)'
6>          with
6>          [
6>              T=HRESULT
6>          ]
6>      C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\event.h(354,60):
6>      the template instantiation context (the oldest one first) is
6>          D:\My Programs\2022\MeetSchedAssist\Meeting Schedule Assistant\EdgeWebBrowser.cpp(2101,3):
6>          see reference to function template instantiation 'Microsoft::WRL::ComPtr<TDelegateInterface> Microsoft::WRL::Callback<ICoreWebView2ExperimentalFindStartCompletedHandler,CWebBrowser::ConfigureAndExecuteFind::<lambda_3>>(TLambda &&) noexcept' being compiled
6>          with
6>          [
6>              TDelegateInterface=ICoreWebView2ExperimentalFindStartCompletedHandler,
6>              TLambda=CWebBrowser::ConfigureAndExecuteFind::<lambda_3>
6>          ]
6>          C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\event.h(460,45):
6>          see reference to function template instantiation 'Microsoft::WRL::ComPtr<TDelegateInterface> Microsoft::WRL::Details::DelegateArgTraits<HRESULT (__cdecl ICoreWebView2ExperimentalFindStartCompletedHandler::* )(HRESULT)>::Callback<ICoreWebView2ExperimentalFindStartCompletedHandler,ICoreWebView2ExperimentalFindStartCompletedHandler,Microsoft::WRL::NoCheck,T>(TLambda &&) noexcept' being compiled
6>          with
6>          [
6>              TDelegateInterface=ICoreWebView2ExperimentalFindStartCompletedHandler,
6>              T=CWebBrowser::ConfigureAndExecuteFind::<lambda_3>,
6>              TLambda=CWebBrowser::ConfigureAndExecuteFind::<lambda_3>
6>          ]
6>          C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\event.h(367,9):
6>          while compiling class template member function 'Microsoft::WRL::ComPtr<TDelegateInterface>::ComPtr(Microsoft::WRL::ComPtr<U> &&,Details::EnableIf<Microsoft::WRL::Details::IsConvertible<U*,T*>::value,void*>::type *) noexcept'
6>          with
6>          [
6>              TDelegateInterface=ICoreWebView2ExperimentalFindStartCompletedHandler,
6>              T=ICoreWebView2ExperimentalFindStartCompletedHandler
6>          ]
6>          C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\event.h(367,9):
6>          see reference to class template instantiation 'Microsoft::WRL::Details::IsConvertible<Microsoft::WRL::Details::DelegateArgTraits<HRESULT (__cdecl ICoreWebView2ExperimentalFindStartCompletedHandler::* )(HRESULT)>::DelegateInvokeHelper<ICoreWebView2ExperimentalFindStartCompletedHandler,T,Microsoft::WRL::NoCheck,HRESULT> *,ICoreWebView2ExperimentalFindStartCompletedHandler *>' being compiled
6>          with
6>          [
6>              T=CWebBrowser::ConfigureAndExecuteFind::<lambda_3>
6>          ]
6>          C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\internal.h(67,35):
6>          see reference to class template instantiation 'Microsoft::WRL::Details::DelegateArgTraits<HRESULT (__cdecl ICoreWebView2ExperimentalFindStartCompletedHandler::* )(HRESULT)>::DelegateInvokeHelper<ICoreWebView2ExperimentalFindStartCompletedHandler,T,Microsoft::WRL::NoCheck,HRESULT>' being compiled
6>          with
6>          [
6>              T=CWebBrowser::ConfigureAndExecuteFind::<lambda_3>
6>          ]
6>          C:\Program Files (x86)\Windows Kits\10\Include\10.0.22621.0\winrt\wrl\event.h(352,35):
6>          while compiling class template member function 'HRESULT Microsoft::WRL::Details::DelegateArgTraits<HRESULT (__cdecl ICoreWebView2ExperimentalFindStartCompletedHandler::* )(HRESULT)>::DelegateInvokeHelper<ICoreWebView2ExperimentalFindStartCompletedHandler,T,Microsoft::WRL::NoCheck,HRESULT>::Invoke(HRESULT) noexcept'
6>          with
6>          [
6>              T=CWebBrowser::ConfigureAndExecuteFind::<lambda_3>
6>          ]

Observations

When I invoke the Find window (which works) I don't actually "see" the find options):

Image

I would like to activate the Find Options toggle so that it is initially visible.

@ajtruckle
Copy link

@champnic @maxwellmyers @pushkin-
Consolidated my findings (no pun intended 🤭) See ☝️

@ajtruckle
Copy link

ChatGPT helped me with the completion handler issue and it seems the help documentation needs updating. I had to remove the BOOL status parameter so now we have:

	// Start the Find operation with a callback for completion.
	CHECK_FAILURE(webView2Find->Start(
		find_options.get(), 
		Callback<ICoreWebView2ExperimentalFindStartCompletedHandler>(
			[this](HRESULT result) -> HRESULT
			{
				if (SUCCEEDED(result))
				{
					// Optionally update UI elements here upon successful Find operation.
				}
				else
				{
					// Handle errors.
				}
				return S_OK;
			}).Get()) );
			// End user interaction is handled via UI.

The application now compiles and displays the Find dialog seamlessly—thank you for that! 🙏 However, I still believe it would be a great enhancement to include a toggle feature for the Find Options, allowing users to show or hide them as needed.

@pushkin-
Copy link

nevermind, looks like I can't instantiate the FindOptions directly and need to use the CreateFindOptions API

@ajtruckle
Copy link

ajtruckle commented Jan 27, 2025

@pushkin-
Yes, that's how the docs described doing it for Win32:

wil::com_ptr<ICoreWebView2ExperimentalFindOptions> find_options;
CHECK_FAILURE(webView2Environment18->CreateFindOptions(&find_options));

Just a pity we can't also toggle the find options to be visible. Would be very useful.

@ajtruckle
Copy link

I have created new tickets for the above feedback.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature request feature request tracked We are tracking this work internally.
Projects
None yet
Development

No branches or pull requests