Convert ui.browseableMessage to wx.html2.WebView#20251
Draft
LeonarddeR wants to merge 21 commits into
Draft
Conversation
Replace the old COM/MSHTML ShowHTMLDialogEx approach with a wx.html2.WebView
embedded in MessageDialog. Move the HTML template to message.html with
{{TITLE}} and {{MESSAGE}} placeholders. Handle keyboard shortcuts (Escape,
Alt+C) via JS navigation to nvda-action:// URLs intercepted in Python.
Fix focus routing for Shell DocObject View and WxWebView overlay classes.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
- Extract HtmlMessageDialog(MessageDialog) owning all WebView concerns (control creation, SetPage, nvda-action:// bridge, focus), replacing the isHtmlMessage flag and its branches in __init__, setMessage and _realizeLayout with the _createMessageControl/_wrapMessageControl hooks. - ui.browseableMessage no longer pokes _messageControl or imports wx.html2; it registers a "copy" action and calls focusMessage(). - Reuse api.copyToClip(notify=True) for the copy button instead of a hand-rolled clipboard write. - Make the WebView backend overridable via the _webViewBackend class attr. - Defer focusMessage() until EVT_WEBVIEW_LOADED so async backends (Edge) focus the inner document only once its content has loaded. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Use api.copyToClip(message) plus a flat ui.message("Copied to clipboard")
confirmation instead of copyToClip(notify=True), so the (potentially large)
message content is not echoed, and reuse the existing translatable string.
Use the stock wx.ID_COPY button id.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
|
@LeonarddeR Thanks for working on this! |
- Override _FAIL_ON_NO_BUTTONS to False so HtmlMessageDialog can be shown without any buttons (the HTML content handles its own actions). - Override _getFallbackAction to return a synthetic close command when no commands are registered, so Escape and Alt+F4 still close the dialog even without buttons. - Add wx accelerator table for Escape so IE backend (which consumes the key natively before JS keydown fires) still triggers Close(). - Replace focusMessage() with Show() override: defers showing the dialog until the WebView content has loaded, fixing a blank-dialog flash with the Edge backend. Rename _focusContentWhenLoaded to _deferShowUntilLoaded. Co-Authored-By: Leonard de Ruijter <leonard@nvaccess.org>
Contributor
There was a problem hiding this comment.
Pull request overview
Note
Copilot was unable to run its full agentic suite in this review.
This PR modernizes NVDA’s browseable message experience by replacing the legacy MSHTML dialog with a wx.html2.WebView-based dialog, and adds system tests to validate the new behavior.
Changes:
- Introduces
gui.message.HtmlMessageDialogand extensibility hooks onMessageDialogfor custom message controls. - Updates
ui.browseableMessageto render templated HTML with a WebView and route actions vianvda-action://…. - Adds a new Robot system test suite for browseable messages and wires it into CI.
Reviewed changes
Copilot reviewed 10 out of 10 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
| user_docs/en/changes.md | Documents the dialog modernization and new/updated APIs. |
| tests/system/robot/browseableMessageTests.robot | Adds Robot test suite entry points for browseable message scenarios. |
| tests/system/robot/browseableMessageTests.py | Implements system-test logic for open/navigation/close behaviors. |
| tests/system/nvdaSettingsFiles/browseableMessage-gestures.ini | Provides a deterministic gesture mapping used by the system tests. |
| source/ui.py | Migrates browseableMessage to the new HtmlMessageDialog and updated templating/copy behavior. |
| source/message.html | Replaces legacy IE dialog scripting with a simple HTML template and action URL routing. |
| source/gui/message.py | Adds hooks to MessageDialog and implements HtmlMessageDialog with WebView/action routing. |
| source/NVDAObjects/IAccessible/wx.py | Refines wxWebView overlay selection and suppresses redundant focus reporting. |
| source/NVDAObjects/IAccessible/init.py | Changes focus redirection behavior for ShellDocObjectView. |
| .github/workflows/testAndPublish.yml | Adds the new browseableMessage system tests to the CI matrix (with runner exclusions). |
Comment on lines
+144
to
+146
| gui.mainFrame.prePopup() | ||
| dialog.Show() | ||
| gui.mainFrame.postPopup() |
Collaborator
Author
There was a problem hiding this comment.
Not sure about this one. We can remove the Show override, but then a webview with Edge will show, then the content loads async and NVDA has issues to focus it.
seanbudd
reviewed
Jun 2, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Link to issue number:
Fixes #18878
Summary of the issue:
NVDA shows browseable messages (formatting info, etc.) in a legacy Internet Explorer control, driven by MSHTML's
ShowHTMLDialogEx(COM URL monikers +Scripting.Dictionary).Description of user facing changes:
Browseable messages now render in a
wx.html2.WebViewhosted inside NVDA's standard message dialog instead of a standalone IE/MSHTML window. The dialog now has native NVDA buttons (Close, and Copy where requested) rather than HTML buttons. Escape closes the dialog andAlt+Ccopies. Copying announces a simple "Copied to clipboard" confirmation (spoken and brailled), matching the About dialog; the message text itself is not echoed.Description of developer facing changes:
gui.message.HtmlMessageDialog(MessageDialog)that renders a full HTML document in a WebView. Public API:registerAction(action, handler)to handlenvda-action://<action>URLs triggered from JavaScript, andfocusMessage(). The backend is a class attribute_webViewBackend(defaults toWebViewBackendIE) that subclasses can override.MessageDialoggains two protected extension hooks,_createMessageControl()and_wrapMessageControl(), replacing the inlinewx.StaticTextcreation andWrapcall, so the message control can be swapped without branching.ui.browseableMessagerewritten: removed the comtypes /winBindings.mshtml/winBindings.urlmonmachinery (ShowHTMLDialogEx, URL monikers,Scripting.Dictionary) and_warnBrowsableMessageComponentFailure. It now fills themessage.htmltemplate ({{TITLE}}/{{MESSAGE}}) and builds anHtmlMessageDialog, reusingapi.copyToClipfor copy (matching the About dialog).message.htmlreduced from ~110 lines of MSHTML-specific JS to a minimal template plus a smallkeydownhandler that routes Escape /Alt+Ctonvda-action://URLs.ShellDocObjectViewmoves from an imperativeevent_gainFocusto a declarative_get_focusRedirect(which now also covers the wx WebView case);WxWebViewis only applied forOBJID_CLIENTand suppresses the redundant focus report on the outer control.Description of development approach:
The wx
WebViewis hosted in the existingMessageDialograther than reimplementing dialog chrome, buttons, and fallback handling in HTML. Because the WebView captures keyboard focus and the dialog is shown modeless, keyboard activation (Escape / Alt+C) is bridged from JS to Python vianvda-action://URLs intercepted in the navigating event; mouse activation uses the native buttons.Testing strategy:
Alt+Cboth copy to the clipboard and announce the result.Known issues with pull request:
Deliberately not switching to the default Edge WebView2 backend yet: Edge is very slow to initialise from a cold state, and keeping a permanent WebView2 singleton alive to hide that cost is debatable. So the IE backend (
WebViewBackendIE) is retained for now, but the backend is made overridable (_webViewBackend) andShowis deferred until theEVT_WEBVIEW_LOADEDevent, so an Edge-backed subclass can be adopted later without further rework. A switch to Edge requires WXPython 4.3 at least.Code Review Checklist:
🤖 Generated with Claude Code