Conversation
Start the dev cycle for the 2026.2 release. This won't be a compatibility breaking release. Complete: - [x] New section in the change log. - [x] Update NVDA version in `master` - [x] Update [`nvdaAPIVersions.json` to include the next version](https://github.com/nvaccess/addon-datastore-transform) nvaccess/addon-datastore-transform#36 - Re-run the last "Transform NVDA addons to views" on [addon-datastore](https://github.com/nvaccess/addon-datastore/actions/workflows/transformDataToViews.yml) to regenerate projections (views) for the add-on datastore API. On merge: - [x] [Update auto milestone ID](https://github.com/nvaccess/nvda/settings/variables/actions)
Close #625 First step to #18400 ### Summary of the issue: People want commands to repeat the last spoken information, to be able to display it and to copy it. Actually, they also want a deeper history of the speech, but NV Access has recommended in #18400 to begin with the last speech. ### Description of user facing changes: A new commands has been introduced: Repeat last spoken information (`NVDA+shift+F12`). Pressing it twice displays this information in a browseable message. The copy concern can be considered addressed since browseable message now have a copy button. When in on-demand speech mode, the last string to be spoken is memorized, no matter if it is actually spoken (on-demand command), or not. This provide a quite handy mode to retrive the last information that should have been spoken if speech mode had been on. ### Description of developer facing changes: N/A ### Description of development approach: Use `pre_speech` extension point to store the last spoken information ### Testing strategy: Manual test, with speech modes on and on-demand. ### Known issues with pull request: This minimalist PR may be frustrating for a lot of people expecting more, i.e. a more complete speech history feature as in the add-on, in Jaws or in Narrator.
Fixed: #17434 ### Summary of the issue: Previously, we called `InvalidateRect` every 100 milliseconds to refresh the entire window. This caused `dwm.exe` to perform extensive calculations, resulting in high GPU or CPU utilization—particularly noticeable on low-performance machines. ### Description of user facing changes: Enabling the highlighter does not cause `dwm.exe` to consume excessive resources continuously, especially when no objects are being updated. ### Description of developer facing changes: * **Type Hinting Improvements:** Updated type hints across `autoSettings.py`, `mouseHandler.py`, and `NVDAHighlighter.py` to use modern Python syntax (e.g., standard collection generics like `list[...]` instead of `typing.List`, and `type` aliases). Added `override` decorators where appropriate. * **Formatting import** Use ruff to format import statement. * **NVDAHighlighter Refactor:** * `HighlightStyle` is now a `NamedTuple` with explicit type annotations. * Refactored `HighlightWindow` to separate logic for coordinate mapping (`_mapRectToClient`) and determining draw targets (`_getDrawRects`). * Introduced state tracking (`_prevContextRects`) to the highlighter window to facilitate delta updates. ### Description of development approach: To address the performance issue with `dwm.exe`: 1. **Dirty Rectangle Invalidation:** Instead of blindly invalidating the entire screen overlay window every refresh cycle (`InvalidateRect(..., None, ...)`), the approach was changed to calculate specific "dirty" regions. 2. **State Tracking:** The `HighlightWindow` now caches the rectangles rendered in the previous frame. 3. **Delta Calculation:** During `refresh()`: * The current required rectangles are calculated. * They are compared with the cached previous state. * If a context's rectangle has changed or was removed, the **old** screen region is invalidated (to clear the artifact). * If a context's rectangle is new or changed, the **new** screen region is invalidated (to draw the new highlight). 4. **Region Calculation:** A helper method `_invalidateContextRect` maps the logical object rectangle to client coordinates and adds necessary padding (accounting for the pen width and anti-aliasing) to ensure the invalidation rect covers the entire visual drawing. This minimizes the surface area that the Windows DWM needs to recompose, drastically reducing GPU/CPU usage. ### Testing strategy: Manual Testing: 1. Build and install the self-signed launcher. 2. Enable the highlighter tool and move the focus to check for drawing errors. (especially drawn on the start menu)
Closes #19318 ### Summary of the issue: The log cannot be opened when log level is on Disabled. ### Description of user facing changes: The log can be opened when log level is on Disabled. ### Description of developer facing changes: N/A ### Description of development approach: When log is disabled, just open the log as if we had clicked the corresponding NVDA menu item. ### Testing strategy: Manual test with: * Changing the log level in the settings dialog * starting with `-l 100` flag ### Known issues with pull request: No test performed with `--no-logging` flag due to #19333.
Closes #19211 ### Summary of the issue: There was no command to toggle keyboard layout (desktop / laptop). It may be useful for testing, or for someone switching between built-in and external keyboard. ### Description of user facing changes: * Added an unassigned command to toggle keyboard layout. ### Description of developer facing changes: N/A ### Description of development approach: Added the command script in `globalCommands.py`. ### Testing strategy: Manual test ### Known issues with pull request: None
### Summary of the issue: Updated actions/cache@v4 to actions/cache@v5 ### Description of user facing changes: none ### Description of developer facing changes: Update /.github/workflows/testAndPublish.yml file actions/cache@version ### Description of development approach: Update /.github/workflows/testAndPublish.yml file ### Testing strategy: Because GitHub Actions' stability has been quite poor recently, the build didn't succeed on the first attempt, so we need to carefully test whether it can compile successfully.
[actions/upload-artifact Notes](https://github.com/actions/upload-artifact/releases/tag/v6.0.0) [download-artifact Notes](https://github.com/actions/download-artifact/releases/tag/v7.0.0)
Co-authored-by: Cyrille Bougot <cyrille.bougot2@laposte.net> Co-authored-by: Bill Dengler <codeofdusk@gmail.com> Co-authored-by: Sascha Cowley <16543535+SaschaCowley@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
…ments with a height less than 0. #19384 Fixes: #19383 Summary of the issue: The highlighter gets an error getting a rectangle of objects with heights less than 0. This is because we are not handling the ValueError exception thrown by locationHelper.RectLTRB. Description of user facing changes: The highlighter does not report an error when it encounters an object with a height less than 0. Description of developer facing changes: Description of development approach: Handle ValueError exception when NVDAHighlighter.updateContextRect gets the context rectangle
) Fix-up of #19354 Summary of the issue: In the PR to start 2026.2 dev cycle, the new 2026.2 section has been created, but the markdown disable instruction has remained below 2026.1 section. Description of user facing changes: None Description of developer facing changes: Moved the instruction to disable markdown linting below 2026.2 section.
Fixes #19395 Fix-up of #19173. Summary of the issue: Sometimes, e.g. in Notepad, skim reading process was not correctly interrupted when pressing control key: say all was restarting when another key was pressed. Description of user facing changes: Skim reading process is now correctly interrupted when control is pressed. Description of developer facing changes: N/A Description of development approach: When the speech sequence is stored, it is first filtered. CallbackCommands are filtered out of the sequence since callback functions such as say all ones should not be called again when repeating the last speech (this was the cause of say all restarting). Not all BaseCallbackCommands are filtered since other BaseCallbackCommand such as BeepCommand (for indentation reporting) or WaveFileCommands (for spelling error reporting) still need to be reported. I have not included IndexCommands in the filtering since in any case, they only seem to appear downstream, in the speech manager part. Regarding CancellableSpeechCommands, I have included them, since I've seen that they are also filtered out from remote speech. Though, I do not exactly know how cancellable speech works, so please double check. Thanks.
…) (#19394) Fixes #19386 Summary of the issue: When using UIA to access Microsoft Word documents, page change announcements do not occur when navigating between table rows that span different pages. Page changes are only announced after exiting the table. This does not occur in IAccessible mode ("only where necessary" setting), where page changes are announced correctly within tables. Description of user facing changes: When navigating table rows in Word documents using UIA, NVDA will now correctly announce page changes (e.g., "page 2") when moving between rows on different pages. Description of developer facing changes: Description of development approach: The WordDocumentTextInfo._getFormatFieldAtRange method now retrieves page numbers via Word's custom attribute API (UIACustomAttributeID.PAGE_NUMBER), similar to how line numbers and section numbers are already retrieved. The fallback mechanism in getTextWithFields has been updated to only propagate page numbers from control elements when UIARemote is not supported, preserving the more accurate custom attribute values.
Fixes #17005 Summary of the issue: Currently, slider controls (HTML range inputs and ARIA sliders) are not included in browse mode navigation. Users cannot navigate to sliders using quick navigation keys. Description of user facing changes: Slider controls are now included in browse mode navigation. Users can navigate to sliders using quick navigation. By default, no gesture is assigned. Description of developer facing changes: Added "slider" node type to browseMode.py base implementation; Implemented slider detection for: Gecko (Firefox) virtual buffers, MSHTML (Internet Explorer) virtual buffers, UIA (Edge, modern UI) browsers, Chromium (Chrome) IAccessible implementation. Updated changes.md documentation. Description of development approach: Extended the existing browse mode navigation framework to recognize slider controls; Used existing control type detection patterns (ARIA roles, HTML input types, UIA control types); Followed the same pattern as other form controls (checkbox, radio button, etc.).
…contains only hidden content (#19409) Summary of the issue: When a form control (such as a checkbox or radio button) has both: An aria-label attribute providing the accessible name A <label for="..."> element whose content is entirely aria-hidden NVDA's browse mode in Firefox fails to announce the accessible name. The name is correctly announced in focus mode. Example HTML that reproduces the issue: <input type="checkbox" id="testinput" aria-label="TestArea"> <label for="testinput"><span aria-hidden="true">Test</span></label> In Firefox browse mode, navigating to this checkbox announces only "check box not checked" with no name, even though the accessible name is "TestArea" from aria-label. The root cause is in getLabelInfo() which determines if a control's label is "visible" by checking IA2_RELATION_LABELLED_BY targets. It only checked if the label element had STATE_SYSTEM_INVISIBLE, but a label element can be visible while containing only aria-hidden content, meaning it contributes no accessible text to the virtual buffer. This caused NVDA to incorrectly assume the user would read the label content in browse mode, so it didn't force the aria-label name to be announced. It could be argued that exposing the labelled by association even if the name is set using aria-label is a bug in Firefox, since the label element is no longer contributing to the accessible name of the element and that it should be fixed there. I'm willing to open a Firefox bug for this if preferred. Description of user facing changes: Form controls with aria-label will now correctly have their accessible name announced in browse mode, even when an associated <label for> element exists but contains only hidden content.
Beta to master
# Conflicts: # source/globalCommands.py
… of page (#19424) Fixes #19423 ### Summary of the issue: When using UIA to access Microsoft Word documents, NVDA reports "page -1" when navigating to the final line of a page. This regression was introduced in PR #19394 which added support for retrieving page numbers via Word's Custom Attributes API. The issue occurs because Word's Custom Attributes API returns `-1` when the page number value is not yet available. The original code accepted any integer value without validation, causing NVDA to announce "page -1" to users. ### Description of user facing changes: NVDA will now correctly announce the page number (e.g., "page 2") instead of "page -1" when reaching the final line of a page. ### Description of developer facing changes: N/A ### Description of development approach: The fix implements a two-layer validation and fallback mechanism: 1. **Custom Attributes API Validation**: Page numbers from the Custom Attributes API are now validated to reject invalid values (< 1). When Word returns -1, the value is not used. 2. **Enhanced Fallback Mechanism**: The existing control field fallback (which uses automation IDs like `UIA_AutomationId_Word_Page_2`) now: - Runs regardless of UIARemote support status (previously it was disabled when UIARemote was supported) - Only propagates page numbers from control fields, not format fields - Only fills in missing page numbers, preserving valid Custom Attributes API values - Converts control field page numbers (strings) to integers to match Custom Attributes API type This ensures type consistency and prevents false page change detections due to type mismatches between string `"2"` and integer `2`. Since this is a fixup pr, I did not include a changelog entry. ### Testing strategy: Manual testing with: - Multi-page Word documents - Forward navigation (down arrow) - page changes announced correctly - Backward navigation (up arrow) - page changes announced correctly - Navigation within tables - continues to work as fixed in #19394 - Navigation outside tables - now works correctly in both directions ### Known issues with pull request: None known
Co-authored-by: Sascha Cowley <16543535+SaschaCowley@users.noreply.github.com> Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> Co-authored-by: Bill Dengler <codeofdusk@gmail.com>
### Summary of the issue: Currently, failing type checks in CI only output errors and warning to the [workflow summary](https://github.com/nvaccess/nvda/actions/runs/20938000634/attempts/1#summary-60166146854), rather than the [job run details](https://github.com/nvaccess/nvda/actions/runs/20938000634/job/60166146854?pr=19432#step:5:26). ### Description of user facing changes: None ### Description of developer facing changes: Type checking failures in CI output details to both locations, making them easier to find. ### Description of development approach: Tee the output of running pyright rather than saving it directly to a variable. ### Testing strategy: Ran `ci/scripts/test/typeCheck.ps1` locally on a branch with pyright violations. ### Known issues with pull request: None known.
…when available instead of the legacy model (#19367) <!-- Please read and fill in the following template, for an explanation of the sections see: https://github.com/nvaccess/nvda/blob/master/projectDocs/dev/githubPullRequestTemplateExplanationAndExamples.md Please also note that the NVDA project has a Citizen and Contributor Code of Conduct which can be found at https://github.com/nvaccess/nvda/blob/master/CODE_OF_CONDUCT.md. NV Access expects that all contributors and other community members read and abide by the rules set out in this document while participating or contributing to this project. This includes creating or commenting on issues and pull requests. Please initially open PRs as a draft. When you would like a review, mark the PR as "ready for review". See https://github.com/nvaccess/nvda/blob/master/.github/CONTRIBUTING.md. --> ### Link to issue number: Closes #13517. ### Summary of the issue: NVDA exclusively uses Word's legacy object model for sentence navigation, even when UIA is enabled. ### Description of how this pull request fixes the issue: Added support for the [UIA custom extension](https://docs.microsoft.com/en-gb/office/uia/word/wordcustompatterns) to move and expand by sentence in supported scenarios. The legacy implementation remains as a fallback on systems without remote ops support (Windows below 11/Cobalt platform) or older Office versions. ### Testing strategy: Moved by sentence in a large document and verified functionality.
Beta to master
Closes #12539 Summary of the issue: This pull request introduces a new NVDA magnifier feature, including docked and lens magnifier modes, color filter support, and a set of global commands for controlling magnification. The changes add new classes for handling magnifier windows, provide optimized color filtering, and implement keyboard shortcuts for toggling magnification, zooming, cycling modes, and color filters. Description of user facing changes: Implemented new script commands in globalCommands.py for starting/stopping the magnifier, zooming in/out, cycling color filters, toggling fullscreen mode, cycling magnifier types, and spotlighting the magnifier window, each with descriptive messages and gestures. Description of developer facing changes: No significant changes. A new displayChanged extension point under winAPI._displayTracking, which notifies handlers of display configuration changes. Description of development approach: Introduced the main magnifier module with initialization, activation, and shutdown logic in __init__.py, supporting only full-screen magnification for now. Added a FullScreenMagnifier class implementing full-screen magnification, handling zoom, color filters, mouse centering, and spotlight mode, interfacing with the Windows Magnification API. Implemented keyboard command handlers for toggling the magnifier, zooming, cycling color filters, changing full-screen modes, and starting spotlight mode in commands.py. Added a configuration module (config.py) to manage default zoom level, color filter, full-screen mode, and mouse centering settings, with utilities for retrieving and setting these values.
Fixes #19435 Summary of the issue: NVDA on X86 and X64 is not linked with the /CETCOMPAT flag. This flag should improve security. Description of user facing changes: None Description of developer facing changes: None Description of development approach: Add the flag, but only on X64 and X86.
Summary of the issue:
When trying to execute Magnifier commands while Magnifier is not active, there is no error message and an error is logged because pgettext context argument has been put at a wrong position.
Description of user facing changes:
Executing Magnifier commands when Magnifier is not active now report a message as expected.
The reported messages have been improved to be more similar to other NVDA messages when an action cannot be performed.
Description of developer facing changes:
N/A
Description of development approach:
Fix pgettext call
Reworded error messages
#19462 Summary of the issue: Mouse movement was not smooth enough while using magnifier Spotlight steps were sacading due to zoom validation Description of user facing changes: None Description of developer facing changes: None Description of development approach: Reduce the value of refreshment for mouse Adding a function to zoom with raw values ( for animation purpose)
Fixes #20015 Summary of the issue: After cancelling an add-on download by closing the Add-on Store and choosing "Yes", the store can get into a bad state. If the user opens it again and starts another download, NVDA can raise: AttributeError: 'NoneType' object has no attribute 'submit' Closing the store again after that can also raise: AttributeError: 'NoneType' object has no attribute 'shutdown' Description of user facing changes: After cancelling a download, the Add-on Store can be used again normally. Starting another download no longer throws those exceptions. Closing the store again after that also works as expected. Description of developer facing changes: AddonFileDownloader now tracks state per download attempt. This prevents an older cancelled worker from interfering with a later retry of the same add-on. Description of development approach: The fix updates the downloader so each download attempt has its own state and temporary file path. After cancelAll(), the downloader can recreate its executor and be reused safely. When a worker finishes, it now checks whether it still belongs to the active attempt before updating progress, cleaning up files, or completing the download.
fix #20012 Summary of the issue: When Windows Magnifier was already running, NVDA Magnifier could still start because MagInitialize() succeeds even when the API is held by another process. Only MagSetFullscreenTransform() would fail, triggering the recovery loop — which itself only tested MagInitialize() and MagSetFullscreenColorEffect(), both of which succeed, causing it to falsely declare victory and restart the timer indefinitely. Description of user facing changes: NVDA now shows a clear message ("Cannot start magnifier: the magnification API is unavailable. Windows Magnifier may already be running.") when the magnification API cannot be fully initialized at startup. If the conflict occurs after startup, the recovery mechanism is now capped at 3 attempts before stopping the magnifier and notifying the user, preventing log spam. Description of developer facing changes: _initializeNativeMagnification() no longer uses @trackNativeMagnifierErrors — it now raises OSError on failure (including a MagSetFullscreenTransform probe that detects the Windows Magnifier conflict). _startMagnifier() catches this error, calls _stopMagnifier() to properly unregister the display change handler, and returns early. _attemptRecovery() reuses _initializeNativeMagnification() to avoid duplicating the probe logic, and is now capped by _MAX_RECOVERY_ATTEMPTS = 3. Description of development approach: The fix centers on making _initializeNativeMagnification() a reliable gate: it probes MagSetFullscreenTransform (the actual failing call) as part of initialization and raises on failure rather than silently returning. This single change fixes both the startup path and the recovery path, since _attemptRecovery() can delegate to the same method. A _recoveryAttempts counter (capped at _MAX_RECOVERY_ATTEMPTS) prevents the infinite restart loop when the API remains permanently unavailable.
[upgrade mikepenz/action-junit-report to v6 to resolve Node.js deprecation](https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/) "Node.js deprecation warnings (e.g., mikepenz/action-junit-report@v5 requiring Node.js 20) no longer appear in specific Actions runs, such as this job, following the upgrade to v6." https://github.com/dpy013/nvda/actions/runs/25235122899/job/74002155719?spm=5176.28103460.0.0.96a02988qH35o5 Signed-off-by: dpy013 <26911141+dpy013@users.noreply.github.com>
This serves as a fix for the math reading bug in #19813, but doesn't entirely close that issue since the underlying issue with ISimpleDOM is still present. Summary of the issue: NVDA can fail to read MathML in Chromium if the page was already open before NVDA starts or restarts. This seems to be due to ISimpleDOM not being registered. Description of user facing changes: Math is more reliably read in Chromium, even when a page is already opened before NVDA starts or restarts. Description of developer facing changes: The method Math._get_mathMl now checks the IA2 math attribute before falling back to ISimpleDOM. Description of development approach: Update Math._get_mathMl to use the IA2 math attribute when available, strip embedded HTML comments, and return the result wrapped in <math>. If the IA2 math attribute is not available, fall back to the existing ISimpleDOM behavior. A quick note about the embedded HTML comments: I only realized stripping of HTML comments was necessary after testing an initial implementation. It seems like Chromium inserts HTML comments into the IA2 math attribute, which was causing parse errors in MathCAT. Testing strategy: Started Chrome and opened a page containing math. Ran NVDA from source in debug mode after having already started Chrome. Moved through the page with NVDA and verified that the math was being read correctly. Inspected the log and verified that the new debug logs ("Got MathML from IA2 math attribute") were present. Repeated steps 1-4 with Edge instead of Chrome.
…0027) Fixes #20013. Summary of the issue: In NVDA's speech dictionaries, the four word-boundary entry types (Whole word, Part of word, Start of word and End of word) generate patterns based on \b and \w. Python's stdlib re treats Unicode combining marks (general category Mn) as non-word characters. For scripts that rely on combining marks — Hebrew niqqud, Arabic harakat, Devanagari matras, etc. — this means \w treats a base letter and its mark as separate runs and \b reports spurious word boundaries between them. As a result, word-boundary entries fail to match (or match in unintended places) on Hebrew, Arabic, Indic and other texts. Description of user facing changes: Speech dictionary entries of type Whole word, Part of word, Start of word and End of word now handle Unicode combining marks correctly. Entries match the intended word in scripts such as Hebrew, Arabic and Devanagari. Whole word entries no longer match inside larger words when those words contain combining marks. New Advanced setting "Use modern regular expression engine for speech dictionary entries" lets users opt Regular expression entries into the same modern engine. Disabled by default. Description of developer facing changes: New runtime dependency: the third-party regex package (Apache-2.0). speechDictHandler.types.SpeechDictEntry selects between re and regex per entry type: Word-boundary entry types (WORD, PART_OF_WORD, START_OF_WORD, END_OF_WORD) always compile via regex with regex.VERSION1 | regex.UNICODE. REGEXP continues to use stdlib re unless the new [featureFlag] speechDictsUseModernRegex flag is enabled. ANYWHERE keeps using stdlib re. UNIX is unaffected: fnmatch.translate output is still compiled via stdlib re. New [featureFlag] config key speechDictsUseModernRegex (BoolFlag, default disabled). Description of development approach: Engine choice is localised to SpeechDictEntry.__post_init__. The rest of the codebase still works with re. The regex module's VERSION1 mode classifies combining marks as word characters and respects them around \b, which is exactly the missing semantics. Word-boundary entry types switch unconditionally because they are new in 2026.2 and have no existing user data to break. REGEXP entries are gated behind a feature flag to avoid silently changing the meaning of patterns that users have written against re semantics. The flag is intended to flip to enabled in a future release once feedback confirms there are no regressions.
fixes #19691 Summary of the issue: When using the fullscreen magnifier in Center mode, clicking on controls in certain apps (Discord, Microsoft Teams, HyperX NGENUITY Beta) had no effect. The magnifier transform could shift between the physical button press and Windows applying it to the click coordinates, causing the click to land at the wrong logical position. Description of user facing changes: Mouse clicks on controls in apps such as Discord, Microsoft Teams, and HyperX NGENUITY Beta should work correctly when the fullscreen magnifier is running in Center mode. Description of developer facing changes: Replaced winUser.getKeyState / mouseHandler.isLeftMouseButtonLocked with winUser.getAsyncKeyState in FocusManager.getCurrentFocusCoordinates and FullScreenMagnifier._keepMouseCentered. Updated tests accordingly. Description of development approach: tKeyState is queue-based and can return a stale button state in the wx main thread when the message queue hasn't yet processed the click event. Switching to GetAsyncKeyState ensures the magnifier detects a button press immediately, preventing the Center mode transform from shifting between the physical press and Windows applying it to the click coordinates.
pre - #19473 parts of #19810 Summary of the issue: needed to add logic for changing types before new types Description of user facing changes: Magnifier got a new cycle gesture to change to soon to be implemented new types: fixed/docked/lens Description of developer facing changes: added a placeholder for easier developement to be done. Description of development approach: as the new modes will inherite from the same logics, first making sure they can be added correctly to the actual code
Summary of the issue: Caches expire after 6 hours, it would be nice if we could increase that number higher, to maybe 8-12. Description of user facing changes: None Description of developer facing changes: We can tweak cache expiration via github variables Description of development approach: Add variable
fix #19878 Summary of the issue: The magnifier could receive focus coordinates outside the screen boundaries, which allowed the magnified view to drift beyond the visible area depending on the mode. Description of user facing changes: The magnifier now stays within screen boundaries at all times, in both normal mode and true center mode. This makes the visible behavior more stable and prevents off-screen overflow. Description of developer facing changes: Automatic boundary protection was added through a currentCoordinates property that clamps coordinates on every assignment. The main magnifier lifecycle paths and pan logic now use this property, which centralizes validation and removes unsafe direct coordinate handling. Description of development approach: I isolated the nearest control point for magnifier coordinates, then added reusable clamping logic based on the existing screen limit calculation.
Summary of the issue: #18207 introduced these two lines in nvwave.py: if not isinstance(data, bytes): data = string_at(data, size) string_at creates another copy of the data buffer stored as bytes, which is not needed, since it will only be passed to wasPlay_feed. As many built-in synths pass in c_void_p or a ctype array instead of bytes, this would create a lot of unnecessary memory copies. data should be passed to wasPlay_feed directly if possible. As it turned out, those two lines were added because of the argtypes set for wasPlay_feed: wasPlay_feed = dll.wasPlay_feed wasPlay_feed.restype = HRESULT wasPlay_feed.argtypes = ( HWasapiPlayer, # player c_char_p, # data c_uint, # size POINTER(c_uint), # id ) c_void_p cannot be implicitly converted to c_char_p, so string_at was added as a fix. Description of user facing changes: None. Description of developer facing changes: None. data still accepts anything convertible to c_void_p and bytes. Description of development approach: This PR chooses another way to fix that problem: cast data to c_char_p explicitly. Anything that can be converted to c_void_p can be converted to c_char_p this way, including c_void_p, bytes, and ctypes array.
Summary of the issue:
Clean up the magnifying glass-related code.
Description of user facing changes:
None
Description of developer facing changes:
Clean up the magnifying glass-related code.
Description of development approach:
Remove duplicate screen curtain checks.
Type hint: Added @OverRide annotation.
fix tyype hint
Remove redundant return
rename filter variable to currentFilter, Because it shadows a builtin functions.
Closes #20046 Summary of the issue: libmathcat_py.pyd is created both in the NVDA installation directory and in include\nvda-mathcat\assets. Description of user facing changes: Reduces the size of the launcher by ~4 MB. Description of developer facing changes: None; libmathcat_py can still be imported the same way. The duplicate being removed was not imported or used by any other code. Description of development approach: Excludes importable files in the same way that is already used for synthDrivers on line 389 of setup.py.
Fixes #20021 Summary of the issue: In File Explorer on Windows 10, pressing Ctrl+F should move focus directly to the search edit field. Since NVDA 2026.1 beta, NVDA first reports the search edit field, but then reports a pane, so users need to press Ctrl+F a second time before they can reliably type in the search box. This is a regression from #19117. That PR removed several old Windows 8.x Start screen workarounds from the Explorer app module, including SearchBoxClient. Although that class was described as a Windows 8 workaround, it was still filtering a redundant File Explorer search band focus event. On Windows 10, the redundant object has: role == controlTypes.Role.PANE windowClassName == "Search Box" Description of user facing changes: Same behavior as before 2026.1Beta. Description of developer facing changes: Restores a small Explorer app module overlay for File Explorer search band pane objects. The overlay suppresses redundant IAccessible focus events from Search Box and UniversalSearchBand pane objects. Search Box has been confirmed on Windows 10. UniversalSearchBand is retained from the pre-#19117 filter because it appears to be another Explorer search band class, and the match is still limited to IAccessible pane objects. Description of development approach: This keeps the #19117 cleanup intact, except for the part that affected File Explorer search focus. The Windows 8 Start screen tile, group, launcher, and suggestion overlays are not restored.
<!-- Please read and fill in the following template, for an explanation of the sections see: https://github.com/nvaccess/nvda/blob/master/projectDocs/dev/githubPullRequestTemplateExplanationAndExamples.md Please also note that the NVDA project has a Citizen and Contributor Code of Conduct which can be found at https://github.com/nvaccess/nvda/blob/master/CODE_OF_CONDUCT.md. NV Access expects that all contributors and other community members read and abide by the rules set out in this document while participating or contributing to this project. This includes creating or commenting on issues and pull requests. Please initially open PRs as a draft. When you would like a review, mark the PR as "ready for review". See https://github.com/nvaccess/nvda/blob/master/.github/CONTRIBUTING.md. --> ### Link to issue number: <!-- Use Closes/Fixes/Resolves #xxx to link this PR to the issue it is responding to. --> ### Summary of the issue: ### Description of user facing changes: ### Description of developer facing changes: ### Description of development approach: ### Testing strategy: ### Known issues with pull request: ### Code Review Checklist: <!-- This checklist is a reminder of things commonly forgotten in a new PR. Authors, please do a self-review of this pull-request. Check items to confirm you have thought about the relevance of the item. Where items are missing (eg unit / system tests), please explain in the PR. To check an item `- [ ]` becomes `- [x]`, note spacing. You can also check the checkboxes after the PR is created. A detailed explanation of this checklist is available here: https://github.com/nvaccess/nvda/blob/master/projectDocs/dev/githubPullRequestTemplateExplanationAndExamples.md#code-review-checklist --> - [ ] Documentation: - Change log entry - User Documentation - Developer / Technical Documentation - Context sensitive help for GUI changes - [ ] Testing: - Unit tests - System (end to end) tests - Manual testing - [ ] UX of all users considered: - Speech - Braille - Low Vision - Different web browsers - Localization in other languages / culture than English - [ ] API is compatible with existing add-ons. - [ ] Security precautions taken.
#19938 Summary of the issue: This PR adds pinch in and pinch out gestures as the first step toward expanding NVDA's touch gestures. See #19938 for more information. Description of user facing changes: Two new touch gestures are now available for assignment: Pinch in: place two fingers on the screen and move them toward each other. Pinch out: place two fingers on the screen and move them away from each other. The fingers must move at least 50 pixels closer together or further apart to be recognised as a pinch. Description of developer facing changes: Description of development approach: The pinch gesture is detected entirely within TrackerManager in touchTracker.py. When two fingers are on screen simultaneously, the initial distance between them is recorded. When both fingers lift, the final distance is computed from their last known positions. If the change in distance meets or exceeds the minimum threshold, a pinch in or pinch out MultiTouchTracker is queued and emitted like any other gesture.
…#20096) Fixes #15159. Summary of the issue: In focus mode in web browsers, when a control specifies a label using aria-label or aria-labelledby, it is impossible to review or spell that label; e.g. using read current line or the review cursor. This is particularly annoying and detrimental to efficiency when using web apps such as Gmail and Slack, among others, where you have to switch to browse mode to work around this even though it might be more efficient to use focus mode for navigation. Description of user facing changes: In focus mode in web browsers, it is now possible to review and spell the labels of controls when those labels are specifically provided for accessibility; e.g. via aria-label or aria-labelledby. Description of development approach: When in focus mode, for non-editable controls, both speech and braille report the name, description, value, etc. of the control; they don't use the TextInfo. However, previously, the review cursor and the read line command always used the TextInfo. Since IA2TextTextInfo is used for all objects supporting IAccessibleText, this meant that if the content wasn't a flat piece of text equal to the label, the review cursor and read line command would report something different, often nothing at all. To fix this, for IA2Web objects that aren't editors, use NVDAObjectTextInfo instead of the object's TextInfo for object review and the read line command. I first attempted to do this generically in #18271 using _hasNavigableText, but this caused problems elsewhere. Instead, the scope of this change is very specific, introducing a new _shouldUseTextInfoForReview NVDAObject attribute which is only set to False for Ia2Web objects.
Fixes #20080 Summary of the issue: When NVDA is configured to report if the language of the text been read is supported, an error is produced if the syntesizer exposes available languages as None. Description of user facing changes: Fixed an error with certain syntesizers when reporting if the language of the text been read is supported. Description of developer facing changes: Description of development approach: Check if available language is None.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR is the final master→beta merge for the NVDA 2026.2 release, bringing beta up to date with commit 567a5797cb from master.
Changes:
- Introduces/updates multiple user-facing features and infrastructure changes (e.g. magnifier work, input help speech changes, logging updates) as part of the 2026.2 release merge.
- Expands automated test coverage (unit + system tests) for newly added/changed behavior.
- Updates build/CI/tooling + project documentation to align with the merged release state.
Reviewed changes
Copilot reviewed 186 out of 191 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| tests/unit/test_speech.py | Adjust speech unit sequence. |
| tests/unit/test_remote/test_localMachine.py | Readability tweak in param generation. |
| tests/unit/test_magnifier/test_magnifierCommands.py | New magnifier command unit tests. |
| tests/unit/test_magnifier/init.py | Magnifier unit test package init. |
| tests/unit/test_logHandler.py | New tests for log redaction. |
| tests/unit/test_asyncioEventLoop.py | New asyncio event loop tests. |
| tests/system/robot/symbolPronunciationTests.py | Update expected speech spacing. |
| tests/system/robot/chromeTests.robot | Add chrome_link robot tests. |
| tests/system/robot/chromeTests.py | Add link destination system tests. |
| tests/sconscript | Remove old checkPot SCons alias. |
| tests/manual/nvdaUI/addonStore.md | Markdown table formatting tweak. |
| tests/checkPot.py | Update checkPot strings/CLI exit behavior. |
| source/winBindings/magnification.py | Add MagSetFullscreenTransform binding. |
| source/winAPI/_powerTracking.py | Use ngettext for percent string. |
| source/winAPI/_displayTracking.py | Add displayChanged extension point + typing. |
| source/virtualBuffers/MSHTML.py | Add slider searchable attrs. |
| source/virtualBuffers/gecko_ia2.py | Add slider searchable attrs. |
| source/virtualBuffers/init.py | Refactor screen layout toggle helper. |
| source/utils/raii.py | Add RAII helpers for cleanup. |
| source/utils/_deprecate.py | Add callValue option to RemovedSymbol. |
| source/UIAHandler/remote.py | Refactor Word extended pattern + new sentence op. |
| source/UIAHandler/browseMode.py | Add slider quicknav iterator. |
| source/touchTracker.py | Add pinch gesture tracking. |
| source/touchHandler.py | Add TouchMode enum + browse-mode touch integration. |
| source/textUtils/init.py | Supplementary Unicode normalization mapping. |
| source/textInfos/init.py | Improve link destination lookup traversal. |
| source/synthDrivers/oneCore.py | Add punctuation silence support. |
| source/synthDriverHandler.py | Add PunctuationSilenceSetting + language support fix. |
| source/speechDictHandler/dictFormatUpgrade.py | Logging/formatting cleanup in dict upgrade. |
| source/speechDictHandler/definitions.py | New speech dictionary definitions registry. |
| source/speech/init.py | Register pre_speech hook to track last speech string. |
| source/setup.py | Bundle detect-secrets modules + adjust MathCAT assets path. |
| source/screenCurtain/_screenCurtain.py | Notify magnifier on screen curtain enable/disable. |
| source/review.py | Add typing + use _shouldUseTextInfoForReading. |
| source/nvwave.py | Adjust feed path + lastActiveTime typing. |
| source/NVDAObjects/JAB/init.py | Optimize table-parent detection. |
| source/NVDAObjects/IAccessible/winword.py | Lambda formatting readability tweak. |
| source/NVDAObjects/IAccessible/ia2Web.py | MathML via IA2 attr + reading TextInfo flag. |
| source/NVDAObjects/behaviors.py | Use ngettext for percent string. |
| source/NVDAObjects/init.py | Add _shouldUseTextInfoForReading flag. |
| source/nvda.pyw | Add shebang. |
| source/nvda_slave.pyw | Add shebang. |
| source/mouseHandler.py | Add type hints for geometry helpers. |
| source/mathPres/MathCAT/MathCAT.py | Refactor MathCAT navigation scripting. |
| source/mathPres/init.py | Initialize MathCAT nav scripts. |
| source/logHandler.py | Add secrets log level + secret redaction support. |
| source/locale/fr/gestures.ini | Add FR zoomOut gesture mapping. |
| source/locale/fi/symbols.dic | Update Finnish caret symbol name. |
| source/languageHandler.py | Fix getLanguageDescription return type. |
| source/keyboardHandler.py | Add character derivation via ToUnicodeEx. |
| source/inputCore.py | Improve input help speech/braille output logic. |
| source/gui/installerGui.py | Add post-install dialog w/ restart/start options. |
| source/gui/configManagement.py | Add factory reset undo dialog flow. |
| source/gui/addonStoreGui/viewModels/store.py | Parenthesize validCheck lambda. |
| source/gui/addonStoreGui/controls/storeDialog.py | Sorting/filter UI logic updates. |
| source/gui/addonStoreGui/controls/messageDialogs.py | Parenthesize filterFunc lambda. |
| source/gui/addonStoreGui/controls/addonList.py | Typing fixes + sortableFields usage. |
| source/core.py | Initialize/terminate asyncio event loop. |
| source/config/configSpec.py | Add settings (magnifier, braille rate, etc). |
| source/config/configFlags.py | Add SECRETS log level + PlayErrorSound enum. |
| source/comInterfaces_sconscript | Add shebang + formatting. |
| source/buildVersion.py | Bump version_major to 2. |
| source/brailleTables/__tables.py | Add/update table display names. |
| source/brailleDisplayDrivers/freedomScientific.py | Simplify lambda formatting. |
| source/brailleDisplayDrivers/dotPad/defs.py | Add DP command helpers + key groups. |
| source/brailleDisplayDrivers/brailliantB.py | Reformat bluetooth detection predicate. |
| source/brailleDisplayDrivers/baum.py | Add Orbit Reader 40 IDs. |
| source/braille.py | Add auto-scroll support + disable on navigation. |
| source/autoSettingsUtils/autoSettings.py | Typing cleanups + modern type alias. |
| source/argsParsing.py | Add secrets log level CLI choice. |
| source/appModules/whatsapp_root.py | New app module for WhatsApp WebView2. |
| source/appModules/explorer.py | Explorer focus event workaround + product info. |
| source/addonHandler/init.py | Add speechDictionaries manifest support. |
| source/_magnifier/utils/filterHandler.py | New magnifier filter matrices. |
| source/_magnifier/utils/errorHandling.py | New magnifier native error decorator. |
| source/_magnifier/utils/init.py | Magnifier utils package init. |
| source/_magnifier/lensMagnifier.py | New lens magnifier skeleton. |
| source/_magnifier/fixedMagnifier.py | New fixed magnifier skeleton. |
| source/_magnifier/dockedMagnifier.py | New docked magnifier skeleton. |
| source/_magnifier/init.py | New magnifier module entry points. |
| source/_bridge/runtimes/synthDriverHost/synthDriverHost.py | Add brokerAudio option + nvwave proxy binding. |
| source/_bridge/runtimes/synthDriverHost/main.pyw | Add shebang. |
| source/_bridge/runtimes/synthDriverHost/config.py | Lambda formatting tweak. |
| source/_bridge/components/services/nvwave.py | New WavePlayer RPYC service. |
| source/_bridge/components/proxies/synthDriver.py | Remove audio ducking suspender behavior. |
| source/_bridge/components/proxies/nvwave.py | New WavePlayer proxy implementation. |
| source/_bridge/clients/synthDriverHost32/launcher.py | Expose WavePlayer service + installProxies args. |
| source/_bridge/base.py | Add pipe handle duplication helpers. |
| source/_asyncioEventLoop/utils.py | Add coroutine scheduling helpers. |
| source/_asyncioEventLoop/_state.py | New shared state module. |
| source/_asyncioEventLoop/init.py | New background asyncio loop lifecycle. |
| security.md | Update severity levels + SLAs. |
| runcheckpot.bat | New helper for translation checks. |
| pyproject.toml | Dependency bumps + new deps. |
| projectDocs/testing/automated.md | Update translation check instructions. |
| projectDocs/issues/triage.md | Document ADR-required flow. |
| projectDocs/issues/readme.md | Clarify where to report issues. |
| projectDocs/issues/githubIssueTemplateExplanationAndExamples.md | Document ADR template + translator scope. |
| projectDocs/dev/userGuideStandards.md | Update markdown examples + terminology. |
| projectDocs/dev/proposingMajorChanges.md | New ADR process doc. |
| projectDocs/dev/developerGuide/sconscript | Add shebang + formatting + Return placement. |
| projectDocs/dev/createDevEnvironment.md | Update liblouis version. |
| projectDocs/dev/contributing.md | Rewrite contribution guidance + checkPot update. |
| projectDocs/dev/codingStandards.md | Clarify gettext usage + fix typos. |
| projectDocs/dev/buildingNVDA.md | Adjust scons instructions. |
| projectDocs/dev/addons.md | Update addon links. |
| projectDocs/community/expertsList.md | Markdown table formatting. |
| nvdaHelper/vbufBase/sconscript | Add shebang + formatting. |
| nvdaHelper/vbufBackends/webKit/sconscript | Add shebang + formatting. |
| nvdaHelper/vbufBackends/mshtml/sconscript | Add shebang + formatting. |
| nvdaHelper/vbufBackends/lotusNotesRichText/sconscript | Add shebang + formatting. |
| nvdaHelper/vbufBackends/gecko_ia2/sconscript | Add shebang + formatting. |
| nvdaHelper/vbufBackends/gecko_ia2/gecko_ia2.cpp | Improve label visibility check logic. |
| nvdaHelper/vbufBackends/adobeAcrobat/sconscript | Add shebang + formatting. |
| nvdaHelper/uwp/sconscript | Add shebang + formatting. |
| nvdaHelper/UIARemote/sconscript | Add shebang + formatting. |
| nvdaHelper/sonic/sconscript | Add shebang + formatting. |
| nvdaHelper/remoteLoader/sconscript | Add shebang. |
| nvdaHelper/remote/sconscript | Add shebang + formatting. |
| nvdaHelper/localWin10/sconscript | Add shebang. |
| nvdaHelper/localWin10/oneCoreSpeech.h | Add punctuation silence API exports. |
| nvdaHelper/localWin10/oneCoreSpeech.cpp | Implement punctuation silence get/set. |
| nvdaHelper/local/sconscript | Add shebang + formatting. |
| nvdaHelper/local/nvdaHelperLocal.cpp | Hook SendMessageA/TimeoutA + refactor helper. |
| nvdaHelper/liblouis/sconscript | Add shebang + formatting. |
| nvdaHelper/javaAccessBridge/sconscript | Add shebang + formatting. |
| nvdaHelper/ISimpleDOM_sconscript | Add shebang + formatting. |
| nvdaHelper/ia2_sconscript | Add shebang. |
| nvdaHelper/espeak/sconscript | Add shebang + formatting/cleanup. |
| nvdaHelper/detours/sconscript | Add shebang. |
| nvdaHelper/client/sconscript | Add shebang + formatting. |
| nvdaHelper/archBuild_sconscript | Add shebang + formatting + CET compat flag. |
| nvdaHelper/acrobatAccess_sconscript | Add shebang + formatting. |
| ensureuv.ps1 | Bump uv version. |
| cldrDict_sconscript | Add shebang. |
| ci/scripts/tests/typeCheck.ps1 | Preserve pyright output for failure message. |
| ci/scripts/tests/translationCheck.ps1 | Switch to runcheckpot.bat. |
| ci/README.md | Expand fork setup guidance + wording tweaks. |
| appx/sconscript | Add shebang + formatting. |
| .pre-commit-config.yaml | Add actionlint + bump tool versions + runcheckpot hook. |
| .markdownlint.jsonc | Configure table column style. |
| .github/workflows/testAndPublish.yml | Update action versions + add chrome_link suite. |
| .github/workflows/clearCaches.yml | Improve inputs + default cache expiration logic. |
| .github/ISSUE_TEMPLATE/16-adr_major_project.md | Add ADR advanced template. |
| .github/ISSUE_TEMPLATE/11-bug_report.md | Update tool name wording. |
| .github/ISSUE_TEMPLATE/06-adr_major_project.yaml | Add ADR form template. |
| .github/ISSUE_TEMPLATE/01-bug_report.yaml | Update tool name wording. |
| .github/instructions/userGuide.instructions.md | Add user guide authoring instructions. |
| .github/instructions/review.instructions.md | Add PR review guidance for Copilot. |
| .github/instructions/cpp.instructions.md | Add C++ review guidance. |
| .gitattributes | Normalize eol/text attributes. |
| .git-blame-ignore-revs | Add formatting-only revision ignores. |
Comment on lines
+343
to
351
| # wasPlay_feed requires c_char_p, so cast data to c_char_p before calling. | ||
| # Casting bytes to c_char_p is also fine, as long as the original data is not released. | ||
| dataptr = cast(data, c_char_p) | ||
| try: | ||
| wasapi.wasPlay_feed( | ||
| self._player, | ||
| data, | ||
| dataptr, | ||
| size if size is not None else len(data), | ||
| byref(feedId) if onDone else None, |
Comment on lines
+51
to
+52
| case _: | ||
| raise ValueError(f"Unsupported magnifier view: {MagnifiedView}") |
Comment on lines
+16
to
+19
| eventLoop: asyncio.BaseEventLoop | ||
| """The asyncio event loop used by NVDA.""" | ||
| asyncioThread: Thread | ||
| """Thread running the asyncio event loop.""" |
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.
Final merge for 2026.2 release, using commit 567a579 from master.
Changes intended for 2026.2 must now set base/target to the beta branch
Merge not squash