private void OpenPopup_Click(object sender, RoutedEventArgs e) { var tab = tabs.SelectedItem as WebViewTab; if (tab == null) { return; } IChromiumWebView webView = tab.WebView; if (webView == null) { return; } tab.PopupHandlingDisabled = true; EventHandler <CreateWindowEventArgs> callback = null; callback = (a, b) => { tab.PopupHandlingDisabled = false; Dispatcher.UIThread.Post(() => webView.CreateWindow -= callback, DispatcherPriority.Normal); }; webView.CreateWindow += callback; webView.GetMainFrame().ExecuteJavaScript("window.open('http://example.com')", null, 1); }
/// <summary> /// Clears browser cookies. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task ClearBrowserCookiesAsync(this IChromiumWebView webview, CancellationToken cancellationToken) { if (webview is null) throw new ArgumentNullException(nameof(webview)); ThrowIfNotEmptyResponse(await ExecuteDevToolsMethodInternalAsync(webview, "Network.clearBrowserCookies", null, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Captures page screenshot. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="settings">The capture settings or null.</param> /// <param name="targetStream">A stream to save the captured image to.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>The task object representing the asynchronous operation.</returns> /// <exception cref="ArgumentNullException"> /// <paramref name="webview"/> or <paramref name="targetStream"/> is null. /// </exception> /// <exception cref="DevToolsProtocolException"> /// An error occurred while trying to execute a DevTools Protocol method. /// </exception> /// <exception cref="InvalidOperationException">Other error occurred.</exception> public static async Task CaptureScreenshotAsync(this IChromiumWebView webview, PageCaptureSettings settings, Stream targetStream, CancellationToken cancellationToken) { if (webview is null) throw new ArgumentNullException(nameof(webview)); if (targetStream is null) throw new ArgumentNullException(nameof(targetStream)); CefDictionaryValue args; if (settings is null) { args = null; } else { args = new CefDictionaryValue(); if (settings.Format == ImageCompressionFormat.Jpeg) { args.SetString("format", "jpeg"); if (settings.Quality.HasValue) args.SetInt("quality", settings.Quality.Value); } if (!settings.FromSurface) args.SetBool("fromSurface", false); if (settings.Viewport != null) { PageViewport viewport = settings.Viewport; var viewportDict = new CefDictionaryValue(); viewportDict.SetDouble("x", viewport.X); viewportDict.SetDouble("y", viewport.Y); viewportDict.SetDouble("width", viewport.Width); viewportDict.SetDouble("height", viewport.Height); viewportDict.SetDouble("scale", viewport.Scale); args.SetDictionary("clip", viewportDict); } if (settings.CaptureBeyondViewport) args.SetBool("captureBeyondViewport", true); } byte[] rv = (byte[])await ExecuteDevToolsMethodInternalAsync(webview, "Page.captureScreenshot", args, null, cancellationToken).ConfigureAwait(false); if (rv != null && rv.Length > 11 && rv[rv.Length - 1] == '}' && rv[rv.Length - 2] == '"' && "{\"data\":\"".Equals(Encoding.ASCII.GetString(rv, 0, 9), StringComparison.Ordinal)) { using (var input = new MemoryStream(rv, 9, rv.Length - 11)) using (var base64Transform = new FromBase64Transform(FromBase64TransformMode.IgnoreWhiteSpaces)) using (var cryptoStream = new CryptoStream(input, base64Transform, CryptoStreamMode.Read)) { await cryptoStream.CopyToAsync(targetStream, 4096, cancellationToken).ConfigureAwait(false); await targetStream.FlushAsync(cancellationToken).ConfigureAwait(false); } } else { throw new InvalidOperationException(); } }
private void TestV8ValueTypes_Click(object sender, RoutedEventArgs e) { IChromiumWebView webView = SelectedView; if (webView == null) { return; } webView.GetMainFrame().SendProcessMessage(CefProcessId.Renderer, new CefProcessMessage("TestV8ValueTypes")); }
/// <summary> /// Executes a method call over the DevTools protocol. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="method">The method name.</param> /// <param name="parameters"> /// The JSON string with method parameters. May be null. /// See the <see href="https://chromedevtools.github.io/devtools-protocol/"> /// DevTools Protocol documentation</see> for details of supported methods /// and the expected parameters. /// </param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns> /// The JSON string with the response. Structure of the response varies depending /// on the method name and is defined by the 'RETURN OBJECT' section of /// the Chrome DevTools Protocol command description. /// </returns> /// <remarks> /// Usage of the ExecuteDevToolsMethodAsync function does not require an active /// DevTools front-end or remote-debugging session. Other active DevTools sessions /// will continue to function independently. However, any modification of global /// browser state by one session may not be reflected in the UI of other sessions. /// <para/> /// Communication with the DevTools front-end (when displayed) can be logged /// for development purposes by passing the `--devtools-protocol-log- /// file=<path>` command-line flag. /// </remarks> public static Task<string> ExecuteDevToolsMethodAsync(this IChromiumWebView webview, string method, string parameters, CancellationToken cancellationToken) { CefValue args = null; if (parameters != null) { args = CefApi.CefParseJSON(parameters, CefJsonParserOptions.AllowTrailingCommas, out string errorMessage); if (args is null) throw new ArgumentOutOfRangeException(nameof(parameters), errorMessage is null ? "An error occurred during JSON parsing." : errorMessage); } return ExecuteDevToolsMethodAsync(webview, method, args is null ? default(CefDictionaryValue) : args.GetDictionary(), cancellationToken); }
private async void Alert_Click(object sender, RoutedEventArgs e) { IChromiumWebView webView = SelectedView; if (webView == null) { return; } dynamic scriptableObject = await webView.GetMainFrame().GetScriptableObjectAsync(CancellationToken.None).ConfigureAwait(false); scriptableObject.window.alert("hello"); }
/// <summary> /// Overrides user agent with the given string. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="userAgent">User agent to use.</param> /// <param name="acceptLanguage">Browser langugage to emulate.</param> /// <param name="platform">The platform navigator.platform should return.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task SetUserAgentOverrideAsync(this IChromiumWebView webview, string userAgent, string acceptLanguage, string platform, CancellationToken cancellationToken) { if (webview is null) throw new ArgumentNullException(nameof(webview)); var args = new CefDictionaryValue(); args.SetString("userAgent", userAgent); if (acceptLanguage is not null) args.SetString("acceptLanguage", acceptLanguage); if (platform is not null) args.SetString("platform", platform); ThrowIfNotEmptyResponse(await ExecuteDevToolsMethodInternalAsync(webview, "Emulation.setUserAgentOverride", args, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Executes a method call over the DevTools protocol. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="method">The method name.</param> /// <param name="parameters"> /// The dictionaly with method parameters. May be null. /// See the <see href="https://chromedevtools.github.io/devtools-protocol/"> /// DevTools Protocol documentation</see> for details of supported methods /// and the expected parameters. /// </param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns> /// The JSON string with the response. Structure of the response varies depending /// on the method name and is defined by the 'RETURN OBJECT' section of /// the Chrome DevTools Protocol command description. /// </returns> /// <remarks> /// Usage of the ExecuteDevToolsMethodAsync function does not require an active /// DevTools front-end or remote-debugging session. Other active DevTools sessions /// will continue to function independently. However, any modification of global /// browser state by one session may not be reflected in the UI of other sessions. /// <para/> /// Communication with the DevTools front-end (when displayed) can be logged /// for development purposes by passing the `--devtools-protocol-log- /// file=<path>` command-line flag. /// </remarks> public static Task<string> ExecuteDevToolsMethodAsync(this IChromiumWebView webview, string method, CefDictionaryValue parameters, CancellationToken cancellationToken) { if (webview is null) throw new ArgumentNullException(nameof(webview)); if (method is null) throw new ArgumentNullException(nameof(method)); method = method.Trim(); if (method.Length == 0) throw new ArgumentOutOfRangeException(nameof(method)); return ExecuteDevToolsMethodInternalAsync(webview, method, parameters, cancellationToken); }
/// <summary> /// Clears browser cookies. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task ClearBrowserCookiesAsync(this IChromiumWebView webview, CancellationToken cancellationToken) { if (webview is null) { throw new ArgumentNullException(nameof(webview)); } byte[] rv = await ExecuteDevToolsMethodInternalAsync(webview, "Network.clearBrowserCookies", null, cancellationToken); if (rv is null || rv.Length != 2 || rv[0] != '{' || rv[1] != '}') { throw new InvalidOperationException(); } }
/// <summary> /// Enables touch on platforms which do not support them. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="enabled">True whether the touch event emulation should be enabled.</param> /// <param name="maxTouchPoints">Maximum touch points supported. Defaults to one.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task SetTouchEmulationEnabledAsync(this IChromiumWebView webview, bool enabled, int? maxTouchPoints, CancellationToken cancellationToken) { if (webview is null) throw new ArgumentNullException(nameof(webview)); var args = new CefDictionaryValue(); args.SetBool("enabled", enabled); if (maxTouchPoints is not null) { if (maxTouchPoints.Value < 1 || maxTouchPoints.Value > 16) throw new ArgumentOutOfRangeException(nameof(maxTouchPoints), "Touch points must be between 1 and 16."); args.SetInt("maxTouchPoints", maxTouchPoints.Value); } ThrowIfNotEmptyResponse(await ExecuteDevToolsMethodInternalAsync(webview, "Emulation.setTouchEmulationEnabled", args, cancellationToken).ConfigureAwait(false)); }
private static async Task <byte[]> ExecuteDevToolsMethodInternalAsync(IChromiumWebView webview, string method, CefDictionaryValue parameters, CancellationToken cancellationToken) { CefBrowser browser = webview.BrowserObject; if (browser is null) { throw new InvalidOperationException(); } cancellationToken.ThrowIfCancellationRequested(); CefBrowserHost browserHost = browser.Host; DevToolsProtocolClient protocolClient = GetProtocolClient(browserHost); await CefNetSynchronizationContextAwaiter.GetForThread(CefThreadId.UI); cancellationToken.ThrowIfCancellationRequested(); int messageId = browserHost.ExecuteDevToolsMethod(protocolClient.IncrementMessageId(), method, parameters); protocolClient.UpdateLastMessageId(messageId); DevToolsMethodResult r; if (cancellationToken.CanBeCanceled) { Task <DevToolsMethodResult> waitTask = protocolClient.WaitForMessageAsync(messageId); await Task.WhenAny(waitTask, Task.Delay(Timeout.Infinite, cancellationToken)).ConfigureAwait(false); cancellationToken.ThrowIfCancellationRequested(); r = waitTask.Result; } else { r = await protocolClient.WaitForMessageAsync(messageId).ConfigureAwait(false); } if (r.Success) { return(r.Result); } CefValue errorValue = CefApi.CefParseJSONBuffer(r.Result, CefJsonParserOptions.AllowTrailingCommas); if (errorValue is null) { throw new DevToolsProtocolException($"An unknown error occurred while trying to execute the '{method}' method."); } throw new DevToolsProtocolException(errorValue.GetDictionary().GetString("message")); }
/// <summary> /// Executes a method call over the DevTools protocol. /// </summary> /// <typeparam name="T">The type of object to return.</typeparam> /// <param name="webview">The WebView control.</param> /// <param name="method">The method name.</param> /// <param name="parameters"> /// The dictionaly with method parameters. May be null. /// See the <see href="https://chromedevtools.github.io/devtools-protocol/"> /// DevTools Protocol documentation</see> for details of supported methods /// and the expected parameters. /// </param> /// <param name="convert"> /// A callback function that converts the result content into an object of type <see cref="T"/>. /// If null, a byte array containing a UTF-8-encoded copy of the content is returned. /// </param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns> /// The JSON string with the response. Structure of the response varies depending /// on the method name and is defined by the 'RETURN OBJECT' section of /// the Chrome DevTools Protocol command description. /// </returns> /// <remarks> /// Usage of the ExecuteDevToolsMethodAsync function does not require an active /// DevTools front-end or remote-debugging session. Other active DevTools sessions /// will continue to function independently. However, any modification of global /// browser state by one session may not be reflected in the UI of other sessions. /// <para/> /// Communication with the DevTools front-end (when displayed) can be logged /// for development purposes by passing the `--devtools-protocol-log- /// file=<path>` command-line flag. /// </remarks> public static async Task<T> ExecuteDevToolsMethodAsync<T>(this IChromiumWebView webview, string method, CefDictionaryValue parameters, ConvertUtf8BufferToTypeDelegate<T> convert, CancellationToken cancellationToken) where T : class { if (webview is null) throw new ArgumentNullException(nameof(webview)); if (method is null) throw new ArgumentNullException(nameof(method)); method = method.Trim(); if (method.Length == 0) throw new ArgumentOutOfRangeException(nameof(method)); object result = await ExecuteDevToolsMethodInternalAsync(webview, method, parameters, (buffer, size) => convert(buffer, size), cancellationToken).ConfigureAwait(false); return (T)result; }
/// <summary> /// Emulates the given media type or media feature for CSS media queries. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="media">Media type to emulate. Empty string disables the override.</param> /// <param name="features">Media features to emulate.</param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns>The task object representing the asynchronous operation.</returns> public static async Task SetEmulatedMediaAsync(this IChromiumWebView webview, string media, IDictionary<string, string> features, CancellationToken cancellationToken) { if (webview is null) throw new ArgumentNullException(nameof(webview)); var args = new CefDictionaryValue(); args.SetString("media", media); if (features is not null) { foreach (KeyValuePair<string, string> feature in features) { if (string.IsNullOrWhiteSpace(feature.Key)) throw new ArgumentOutOfRangeException(nameof(features), "Key may not be empty."); args.SetString(feature.Key, feature.Value); } } ThrowIfNotEmptyResponse(await ExecuteDevToolsMethodInternalAsync(webview, "Emulation.setEmulatedMedia", args, cancellationToken).ConfigureAwait(false)); }
/// <summary> /// Executes a method call over the DevTools protocol. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="method">The method name.</param> /// <param name="parameters"> /// The dictionaly with method parameters. May be null. /// See the <see href="https://chromedevtools.github.io/devtools-protocol/"> /// DevTools Protocol documentation</see> for details of supported methods /// and the expected parameters. /// </param> /// <param name="cancellationToken">The token to monitor for cancellation requests.</param> /// <returns> /// The JSON string with the response. Structure of the response varies depending /// on the method name and is defined by the 'RETURN OBJECT' section of /// the Chrome DevTools Protocol command description. /// </returns> /// <remarks> /// Usage of the ExecuteDevToolsMethodAsync function does not require an active /// DevTools front-end or remote-debugging session. Other active DevTools sessions /// will continue to function independently. However, any modification of global /// browser state by one session may not be reflected in the UI of other sessions. /// <para/> /// Communication with the DevTools front-end (when displayed) can be logged /// for development purposes by passing the `--devtools-protocol-log- /// file=<path>` command-line flag. /// </remarks> public static async Task <string> ExecuteDevToolsMethodAsync(this IChromiumWebView webview, string method, CefDictionaryValue parameters, CancellationToken cancellationToken) { if (webview is null) { throw new ArgumentNullException(nameof(webview)); } if (method is null) { throw new ArgumentNullException(nameof(method)); } method = method.Trim(); if (method.Length == 0) { throw new ArgumentOutOfRangeException(nameof(method)); } byte[] rv = await ExecuteDevToolsMethodInternalAsync(webview, method, parameters, cancellationToken).ConfigureAwait(false); return(rv is null ? null : Encoding.UTF8.GetString(rv)); }
/// <summary> /// Executes a method call over the DevTools protocol without any optional parameters. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="method">The method name.</param> /// <returns> /// The JSON string with the response. Structure of the response varies depending /// on the method name and is defined by the 'RETURN OBJECT' section of /// the Chrome DevTools Protocol command description. /// </returns> /// <remarks> /// Usage of the ExecuteDevToolsMethodAsync function does not require an active /// DevTools front-end or remote-debugging session. Other active DevTools sessions /// will continue to function independently. However, any modification of global /// browser state by one session may not be reflected in the UI of other sessions. /// <para/> /// Communication with the DevTools front-end (when displayed) can be logged /// for development purposes by passing the `--devtools-protocol-log- /// file=<path>` command-line flag. /// </remarks> public static Task <string> ExecuteDevToolsMethodAsync(this IChromiumWebView webview, string method, CancellationToken cancellationToken) { return(ExecuteDevToolsMethodAsync(webview, method, default(CefDictionaryValue), cancellationToken)); }
/// <summary> /// Executes a method call over the DevTools protocol. /// </summary> /// <param name="webview">The WebView control.</param> /// <param name="method">The method name.</param> /// <param name="parameters"> /// The JSON string with method parameters. May be null. /// See the <see href="https://chromedevtools.github.io/devtools-protocol/"> /// DevTools Protocol documentation</see> for details of supported methods /// and the expected parameters. /// </param> /// <returns> /// The JSON string with the response. Structure of the response varies depending /// on the method name and is defined by the 'RETURN OBJECT' section of /// the Chrome DevTools Protocol command description. /// </returns> /// <remarks> /// Usage of the ExecuteDevToolsMethodAsync function does not require an active /// DevTools front-end or remote-debugging session. Other active DevTools sessions /// will continue to function independently. However, any modification of global /// browser state by one session may not be reflected in the UI of other sessions. /// <para/> /// Communication with the DevTools front-end (when displayed) can be logged /// for development purposes by passing the `--devtools-protocol-log- /// file=<path>` command-line flag. /// </remarks> public static Task <string> ExecuteDevToolsMethodAsync(this IChromiumWebView webview, string method, string parameters) { return(ExecuteDevToolsMethodAsync(webview, method, parameters, CancellationToken.None)); }