Windows: Ctrl-click can trigger duplicate new-window-open events during the new window's initial navigation
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
Run an Electrobun application on Windows using the WebView2 renderer.
Load a page containing an internal link, for example:
<a href="/target.html">Open target</a>Handle
new-window-openby creating a newBrowserWindowand loading the requested URL.Hold Ctrl and click the link.
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:
- Ctrl-click emits
new-window-openfor the link. - The application creates a new window.
- The new window starts its initial navigation while Ctrl is still physically held.
- The native
NavigationStartinghandler checksGetKeyState(VK_CONTROL)and emits anothernew-window-open. - 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:
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 = TRUEto prevent the default popup; - emit one
new-window-openevent to the host; - do not apply Ctrl-key detection to ordinary
NavigationStartingevents.
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
Source: blackboardsh/electrobun