Windows: Ctrl-click can trigger duplicate new-window-open events during the new window's initial navigation

Author: NitroRCrCreated Sep 8, 2026Updated Sep 8, 2026

On Windows, Ctrl-clicking an internal link can result in more than one new-window-open event.

The first event is emitted for the user's Ctrl-click. The host creates a new BrowserWindow for the requested URL. While Ctrl is still held, the new window's initial programmatic navigation is then processed by the native NavigationStarting handler as if it were another Ctrl-click. This produces a second new-window-open event and may leave the first window at about:blank.

Reproduction

  1. Run an Electrobun application on Windows using the WebView2 renderer.

  2. Load a page containing an internal link, for example:

    xml
    <a href="/target.html">Open target</a>
  3. Handle new-window-open by creating a new BrowserWindow and loading the requested URL.

  4. Hold Ctrl and click the link.

  5. Observe the emitted events and created windows.

Expected behavior

A single user Ctrl-click should produce exactly one new-window-open event for the link's target URL.

The navigation used to initialize the newly created window should be treated as host-controlled/programmatic navigation and must not be interpreted as another Ctrl-click.

Actual behavior

The following sequence can occur:

  1. Ctrl-click emits new-window-open for the link.
  2. The application creates a new window.
  3. The new window starts its initial navigation while Ctrl is still physically held.
  4. The native NavigationStarting handler checks GetKeyState(VK_CONTROL) and emits another new-window-open.
  5. The first window may remain at about:blank, while a second window is created or navigated.

The current 500 ms debounce reduces the frequency but does not prevent the underlying issue.

Relevant implementation detail

The Windows native implementation currently infers Ctrl-click from the current keyboard state during NavigationStarting, approximately:

cpp
SHORT ctrlState = GetKeyState(VK_CONTROL);
bool isCtrlHeld = (ctrlState & 0x8000) != 0;

if (isCtrlHeld && capturedHandler) {
    // emit new-window-open
    args->put_Cancel(TRUE);
    return S_OK;
}

NavigationStarting is also invoked for navigations initiated by the host when setting up a new BrowserWindow. Therefore, checking the global/current Ctrl key state at that point is not sufficient to determine whether the navigation originated from a user click.

Suggested direction

The new-window decision should be based on the browser engine's actual new-window request mechanism rather than inferred from keyboard state during normal navigation.

For WebView2, this likely means handling CoreWebView2::NewWindowRequested:

  • accept only the actual new-window request;
  • set Handled = TRUE to prevent the default popup;
  • emit one new-window-open event to the host;
  • do not apply Ctrl-key detection to ordinary NavigationStarting events.

If NavigationStarting still needs to be used for compatibility or another renderer, it should distinguish host-created initial navigations from user-initiated navigations without relying only on GetKeyState(VK_CONTROL).

The same principle should apply to any native renderer implementation: a navigation triggered while opening the new window must not recursively generate another new-window event.

Environment

  • OS: Windows
  • Renderer: WebView2
  • Electrobun: 2.0.1