Skip to content

Merge master into chinese word segmentation#20041

Merged
seanbudd merged 166 commits intonvaccess:try-chineseWordSegmentation-stagingfrom
CrazySteve0605:merge-master-into-chineseWordSegmentation
May 3, 2026
Merged

Merge master into chinese word segmentation#20041
seanbudd merged 166 commits intonvaccess:try-chineseWordSegmentation-stagingfrom
CrazySteve0605:merge-master-into-chineseWordSegmentation

Conversation

@CrazySteve0605
Copy link
Copy Markdown
Contributor

Link to issue number:

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:

  • 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.

github-actions Bot and others added 30 commits March 2, 2026 11:43
This pull request updates translations to languages being tracked from
Crowdin.

Co-authored-by: GitHub Actions <github-actions@github.com>
Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
Inspired by nvaccess#19686
Summary of the issue:

We regularly run into problems where the GUI being updated frequently causing issues.
We fix this using a ratelimiter/debouncer.
We do not have a generic debouncer in NVDA.
Description of user facing changes:

none
Description of developer facing changes:

Adds a generic debouncer to NVDA
Description of development approach:

This pull request introduces a new debouncing utility for limiting the frequency of function calls, primarily to improve GUI responsiveness and reduce unnecessary processing in NVDA. The main changes include the addition of the debounceLimiter decorator, its integration into the browseMode.py file for filtering elements, and comprehensive unit tests to verify its behavior. The pull request also modernizes type annotations throughout browseMode.py for improved readability and consistency.

Debounce utility and integration:

    Added a new debounceLimiter decorator in utils/debounce.py to control the execution rate of functions, supporting both GUI and daemon threads.
    Integrated debounceLimiter into the filtering logic of the elements list dialog in browseMode.py, replacing manual timer handling for improved efficiency and code clarity
This pull request updates translations to languages being tracked from
Crowdin.

Co-authored-by: GitHub Actions <github-actions@github.com>
…es, excluding lib exp and pdb files which are not needed. (nvaccess#19748)

Fixes nvaccess#19653

### Summary of the issue:
The 32 bit synthDriverhost runtime introduced in PR nvaccess#19432 includes some
extra lib exp and pdb files which are not necessary and just take up
space.

### Description of user facing changes:
Slightly reduces the size of NVDA.

### Description of developer facing changes:

### Description of development approach:
When building the main NvDA distribution with py2exe, only copy py and
dll files in the _synthDrivers32 directory, which now ignores lib exp
and pdb files.

### Testing strategy:
* [x] Build locally, ensuring that the unneeded lib exp and pdb files
are not included in the _synthDrivers32 directory. Ensure NvDA runs and
that the sapi4 and 32 bit sapi5 synthDrivers can be selected and used.
* [x] Create a try build, also ensuring all of the above.

### Known issues with pull request:
None known.

### Code Review Checklist:
- [x] Documentation:
  - Change log entry
  - User Documentation
  - Developer / Technical Documentation
  - Context sensitive help for GUI changes
- [x] Testing:
  - Unit tests
  - System (end to end) tests
  - Manual testing
- [x] UX of all users considered:
  - Speech
  - Braille
  - Low Vision
  - Different web browsers
  - Localization in other languages / culture than English
- [x] API is compatible with existing add-ons.
- [x] Security precautions taken.
…xists. (nvaccess#19749)

### Summary of the issue:
The 32 bit synthDriverhost runtime executable introduced in PR nvaccess#19432 is
not signed.
 
### Description of user facing changes:

### Description of developer facing changes:

### Description of development approach:
When building the main dist target with scons, also sign
nvda_synthDriverHost.exe if it exists.
This is an improvement over the previous try in pr nvaccess#19683, where now the
path is passed into the lambda by value so that it does not change in
the for loop after being captured.

### Testing strategy:
* [x] Compiled with scons synthDriverHost32Runtime and scons dist,
providing a signing certificate
  *Confirmed that nvda_synthDriverHost.exe was signed.
* [x] Run the above tests on a try build from this pr.

### Known issues with pull request:
None known.
Closes nvaccess#19559

### Summary of the issue:
Addons state is saved in a pickle file.

### Description of user facing changes:
None

### Description of developer facing changes:
The add-ons state file is now in JSON.
The `fromPickledDict` method on `AddonsState` has been renamed to
`fromDict`, but a shim has been introduced.

### Description of development approach:
Switch to using lists instead of sets when populating AddonsState from
dict and serializing to dict, as json.dump doesn't support serializing
sets.

Added methods to read in a pickled add-ons state file and emit a good
JSON representation of that add-ons state. My approach here was to
discard invalid values rather than raising an error, so we have the
greatest chance of success. This does mean that the conversion may be
lossy.

When updating NVDA, convert from pickle to JSON for the system config's
add-ons state file. This is done because this is essentially the only
context in which we should write to the system config directory and
which we know will be executed. User copies perform the migration on
first run by migrating if and only if no addonsState.json exists, but
addonsState.pickle does. User config migration is done by the installed
copy as (a) this is the only time we can guarantee that the user's NVDA
config wil be present; and (b) to minimise the amount of pickles we load
while elevated. In both cases, a backup of the old state file is kept
(as `addonsState.pickle.bak`).

When running on secure desktops, the pickled state will not be read,
even if it is the only addonsState file in the system config. This
should never happen, as the installer is responsible for migrating the
system config's add-ons state file. In other cases, the fallback of
reading the pickled state will attempt to save the JSON state and back
up the pickled state, but this is not required in order for the load to
succede. This is so when running in secure mode or with access to the
user config restricted, add-ons continue to function properly. This does
remove the security benefit of migrating away from pickle, but there's
no other option other than ripping pickle support out entirely and
breaking everyone's add-ons state entirely and having them manually
migrate.

### Testing strategy:
Unit and system tests.

Manual testing as follows:

1. Installed 2025.3.3
2. Installed add-ons (combination of 2026.1 compatible and incompatible,
enabled and disabled) and restarted NVDA
3. Copied user config to system config
4. Upgraded using self-signed launcher
5. Ensured that the installer migrated the system addons state, and the
installed copy migrated the user addons state on first run

Also "upgraded" my 2026.2 alpha copy with this launcher to ensure that
the migration works as expected if updating within the 2026.x series.

### Known issues with pull request:

None known (see notes above for some caviats about the approach though)
…nvaccess#19762)

Fixes nvaccess#19654

### Summary of the issue:
The 32 bit synthDriverhost runtime introduced in PR nvaccess#19432 Does not
contain correct version information in its executable.

### Description of user facing changes:

### Description of developer facing changes:

### Description of development approach:
* synthDriverHost's setup-runtime.py py2exe script now takes version and
publisher as commandline arguments, so that these can be set on the
executable dynamically.
* The github workflow and sconstruct pass the correct version and
publisher to the setup-runtime.py py2exe script.

### Testing strategy:
* [x] Locally compiled with scons synthDriverHost32Runtime, providing
custom version and publisher. Confirmed that the synthDriverHost
executable contains correct version and publisher information.
* [x] Create try bild. Confirming the same as above.

### Known issues with pull request:
None known.
Link to issue number:

None
Summary of the issue:

Liblouis 3.37.0 was released.
Description of how this pull request fixes the issue:

Update LibLouis.
Summary of the issue:

In Magnifier documentation: bold is used at some places.
Such formatting has not been used until now in the User Guide, so we'd better be consistent here. It probably does not bring so much information for blind users who usually have not font attribute reporting enabled (speech / braille). Also worth noting that such formatting had been removed from NVDA remote documentatation when it has been integrated in NVDA's user guide. At last such formatting makes the translators work a bit harder, so if it's not necessary, let's not use it.

Also, a list is unwantedly split in two parts.
Closes nvaccess#19643
Summary of the issue:

When selecting Bangla language for NVDA, the whole interface is in English. This is because there had been an attempt to have NVDA translated in Bangla around 2022. Unfortunately, almost no translation at all has reached an NVDA release. As a result:

    In the Bangla interface file, no string at all is translated
    In the symbols.dic file, the vast majority of symbols are just English. Only 6 complex symbols have been modified. And among these 6 symbols:
        one of them is written ". sentence ending" (with an extra space), thus it does not actually control anything
        the decimal point just has no replacement, making the rule apparently malformed or at least un-useful and harder to understand

Description of user facing changes:

    Bangla won't be proposed as an NVDA language in the languages list.
    When using Bengali voice, the 4 valid Bangla/Bengali complex symbols will be reported in English. But users using Bengali voice will benefit of any change done in English symbol file since 2022 and in the future.
Fixes nvaccess#19635
Summary of the issue:

When using Ctrl+Alt+Arrow to navigate vertical list, both the system focus (row) and the navigator object (cell) change simultaneously.

In getCurrentFocusCoordinates(), system focus had priority 3 and navigator had priority 4.
As a result, the magnifier always followed the row instead of the active cell.
Description of user facing changes:

    Magnifier should follow properly on (Ctrl+Alt+Arrow).
    No behavior change for:
        Tab / normal focus navigation
        Caret navigation (browse mode)
        Numpad navigator movement

Description of developer facing changes:

focusManager.py

    Inverted priorities 3 and 4 in getCurrentFocusCoordinates():
        If both system focus and navigator change, navigator wins.
        System focus only wins if navigator did not move.
Closes nvaccess#19268

After installing or updating NVDA, users sometimes experience issues that a Windows restart fixes. This PR adds a post-install dialog giving users clear options for what to do next.
Description of user facing changes

    After a successful installation or update, NVDA shows a dialog recommending a Windows restart.
        Restart Windows: Immediately restarts Windows.
        Start NVDA: Starts the newly installed copy without restarting (not shown when running elevated).
        Exit NVDA: Closes without starting NVDA or restarting Windows.
    If the Windows restart command fails, an error dialog informs the user to restart manually.
    Silent installs are unaffected.

Description of developer facing changes

    source/gui/installerGui.py:
        Added _restartWindows() — issues shutdown /r /t 0 via subprocess.run with CREATE_NO_WINDOW. Returns True if successful.
        Added _showPostInstallDialog(isUpdate, startAfterInstall) — shows the post-install MessageDialog with up to 3 buttons (CUSTOM_1, CUSTOM_2, CANCEL) and handles all follow-up actions.
        Modified doInstall() to call _showPostInstallDialog instead of the old gui.messageBox for non-silent installs.
    user_docs/en/userGuide.md: Added #RestartWindowsAfterInstall section; updated installation description.
    user_docs/en/changes.md: Added new-feature entry under 2026.2.
Fixes nvaccess#19634 

### Summary of the issue:
Windows throws errors when rapidly requesting a window handle on the
secure desktop.
This cause visual tearing and a crash of NVDA.

### Description of user facing changes:

Avoid crash and tearing of controls

### Description of developer facing changes:

Add custom handling of changing settings categories for secure mode.

### Description of development approach:
This pull request introduces a debounced category change mechanism in
the `NVDASettingsDialog` to improve stability and user experience,
particularly when running on a secure desktop.

* Added a debounce mechanism (50ms delay) for handling category changes
in `NVDASettingsDialog` when running on a secure desktop, using a timer
to prevent rapid or duplicate category switches. This helps avoid
potential issues with UI responsiveness or event handling in secure
desktop environments.
[[1]](diffhunk://#diff-6486e3db41b2272c03b84758b460cc4269d5ca218874391f58633f5d9b3968b1R6131-R6133)
[[2]](diffhunk://#diff-6486e3db41b2272c03b84758b460cc4269d5ca218874391f58633f5d9b3968b1L6193-R6234)
* Introduced the use of `isRunningOnSecureDesktop` from `utils.security`
to determine when to apply the debounce logic.
* Added type annotations to the `onCategoryChange` method and new
internal variables for better code clarity and maintainability.
[[1]](diffhunk://#diff-6486e3db41b2272c03b84758b460cc4269d5ca218874391f58633f5d9b3968b1L748-R749)
[[2]](diffhunk://#diff-6486e3db41b2272c03b84758b460cc4269d5ca218874391f58633f5d9b3968b1R6131-R6133)
* Ensured proper cleanup of the debounce timer and related state in the
`Destroy` method to prevent resource leaks.

An alternative approach with error suppression was tried, but visual
tearing still occurred.
https://github.com/nvaccess/nvda/compare/try-gui-crash-2?expand=1

### Testing strategy:
Tested STR in nvaccess#19634 

### Known issues with pull request:

Other instances may exist of rapidly requesting a window handle.
Should this be reported to wxWidgets or microsoft?
Should we create a generic monkey patch or something?
From basic investigating, the only real way to cause this could be
through updating controls in the settings dialog, or the config profiles
dialog.
Summary of the issue:

A deprecation message recommended to use gui.messageDialog.MessageDialog but the gui.message module does not exist.
Description of user facing changes:

The deprecation message will now mention gui.message.MessageDialog.
Description of developer facing changes:

Fixed both the deprecation message and docstrings mentioning the non-existing gui.messageDialog module.
This pull request updates translations to languages being tracked from
Crowdin.

Co-authored-by: GitHub Actions <github-actions@github.com>
Merged translations from Crowdin
Spawned from nvaccess#19740 

### Summary of the issue:
It was hard to track all the different places language codes are
normalized in NVDA.

### Description of developer facing changes:


This pull request standardizes language code formatting across the NVDA
codebase by introducing and using the `toXmlLang` and `toNvdaLang`
utility functions from `speechXml`. This ensures consistent handling of
language codes (e.g., converting between underscores and hyphens) when
interacting with speech synthesis engines and related components.


### Description of development approach:
Replaced manual string manipulation for language codes (such as
`replace("_", "-")` or `replace("-", "_")`) with the use of `toXmlLang`
and `toNvdaLang` utility functions in `speech.py`, `_espeak.py`,
`espeak.py`, and `oneCore.py` to ensure consistent formatting for speech
engine interoperability.
This pull request refactors type annotations and import statements in
`source/gui/settingsDialogs.py` to use modern Python type hinting syntax
and improve import organization. The changes primarily involve replacing
`typing` module type hints with built-in generic types, as well as
reordering some import statements for clarity.
seanbudd and others added 22 commits April 22, 2026 14:10
Co-authored-by: Peng-An Chen <andy72039@gmail.com>
Link to issue number:

Closes nvaccess#19949
Summary of the issue:

The issues readme says security issues shouldn't be reported via github, but we accept github advisories. We should specify not to use GitHub issues.

It is unclear what materials should be reported to the translators mailing list.
Description of user facing changes:

This pull request updates the issue reporting guidelines in the projectDocs/issues/readme.md file to clarify where to report translation-related issues and to provide more detailed instructions for contributors.

Documentation updates:

    Clarified that security issues should not be reported via GitHub issues, but through the security policy.
    Expanded guidance on translation-related issues, specifying that problems with NVDA interface text, User Guide and Changes content, and locale-specific gestures, symbols, and character descriptions should be reported to the NVDA Translators list.
Summary of the issue:

nvda would log the config at info level when a profile upgrade fails. Config should only ever be logged at debug level
Description of user facing changes:

none
Description of developer facing changes:

safer logging
Description of development approach:

    Added a new static method _shouldLogConfigAtStartup to encapsulate the logic for determining whether to log configuration details at startup, improving code readability and maintainability.
    Updated _loadConfig to use the new helper method when logging information when failing to upgrade a profile
…ries (nvaccess#19966)

Closes nvaccess#19465
Summary of the issue:

Secrets stored in NVDA config are often unintentionally logged in debug mode by NVDA
Description of user facing changes:

logging will attempt to redact secrets when the developer decides to sanitise risky log messages.
Added a new log level: secrets, to disable redactions for required debug logging.
Added a warning whenever selecting a log level below info.
Description of developer facing changes:

A new redactSecrets parameter for logging, which searches for and replaces secrets in the log message.
Description of development approach:

Use Yelp/detect-secrets

This pull request introduces secret redaction support in logging, ensuring that sensitive information is masked in log outputs when requested.
A new log level is added so you can view unredacted logs if needed.

Secret Redaction in Logging

    Added a redactSecrets parameter to the Logger._log method in logHandler.py that, when enabled, uses the detect-secrets library to scan and mask detected secrets in log messages.
    Updated logging calls in source/config/__init__.py to use redactSecrets=True when logging potentially sensitive configuration data.
    Updated the developer documentation to describe the new redactSecrets parameter and recommend its use for sensitive data.

Dependency and Packaging Support

    Added detect-secrets as a dependency in pyproject.toml and ensured all relevant submodules are included in frozen builds for dynamic plugin loading
    Include multiprocessing in bundle - needed for import, seems to functionally work?
…` collection. (nvaccess#19998)

Summary of the issue:

The NVDAObjects.UIA.UIATextInfo._controlFieldUIACachedPropertyIDs collection contains duplicate elements.
Description of user facing changes:

None
Description of developer facing changes:

None
Description of development approach:

Remove duplicate elements.
This pull request updates translations to languages being tracked from
Crowdin.

Co-authored-by: GitHub Actions <github-actions@github.com>
Fixes nvaccess#19711
Summary of the issue:

The magnifier could freeze after a _ctypes.COMError (RPC_E_DISCONNECTED) raised by the UIA API (Notepad RichEditD2DPT).

The exception was not caught in focusManager.py, causing the magnifier timer loop to stop permanently while the user continued navigating normally.
Description of user facing changes:

    Magnifier no longer freezes on COM/UIA disconnection.
    Timer loop is protected and always reschedules.
    After 3 consecutive errors, automatic recovery is attempted.
    Fullscreen magnifier reinitializes the Magnification API if needed.
    Clean stop with feedback if recovery fails.

Description of developer facing changes:

focusManager.py

    Broadened except (...) → except Exception
    Added debug logging.

magnifier.py

    Wrapped _updateMagnifier() in try/except Exception
    Added _consecutiveErrors counter.
    Added _attemptRecovery() base method.

fullscreenMagnifier.py

    Broadened exception handling.
    Protected mouse move calls.
    Added recovery via MagUninitialize() → MagInitialize().

spotlightManager.py

    Wrapped magnification calls in _executeStep() to prevent animation breakage.

Description of development approach:

    Prevent unhandled COM exceptions.
    Protect the timer loop from breaking.
    Add controlled recovery after repeated failures.
    Ensure clean failure instead of silent freeze.
fixes nvaccess#19991
fixes nvaccess#19990
Summary of the issue:

The magnifier follow-mode behavior was inconsistent: disabling follow modes could still cause view movement, toggling follow settings could trigger an immediate jump, and “Toggle all follow settings” did not provide the expected disable/restore flow.
Description of user facing changes:

The magnifier view now remains stable when follow modes are toggled, stays frozen when all follow modes are disabled, and “Toggle all follow settings” now works as a true two-step action: disable all first, then restore the previous follow configuration.
Description of developer facing changes:

Focus tracking logic in the magnifier now preserves and reuses the last reported coordinates when no enabled follow source produces a new event, and follow-setting toggle commands no longer force an immediate focus refresh. The all-follow toggle state handling was updated to implement disable-all and restore semantics.
Description of development approach:

The fix was implemented by adjusting the focus source resolution flow to avoid fallback-driven movement, removing forced update calls from follow toggle commands, and aligning global follow-toggle state transitions with the intended UX behavior (disable all -> restore previous states).
Closes nvaccess#19624
Summary of the issue:

Magnifier does not match Windows Magnifier behavior. Attempting to "zoom in" with NVDA+shift+plus while magnifier is not running results in a warning rather than starting the magnifier.
Description of user facing changes:

NVDA+shift+plus can now start the magnifier if it wasn't previously running. Keyset continues to serve as a "zoom in" command once magnifier is running.
Description of developer facing changes:

None.
Description of development approach:

A check has been added to the zoom function in commands.py that will call toggleMagnifier() if the magnifier is not already active and the zoom direction is positive. Otherwise, zoom behaves as expected.
This pull request updates translations to languages being tracked from
Crowdin.

Co-authored-by: GitHub Actions <github-actions@github.com>
Summary of the issue:

On French fr-fr keyboard layout, the magnifier zoom out gesture NVDA+shift+_ does not exist: "" is on the "8" key and the name of the key is "8", not "".
Description of user facing changes:

NVDA+shift+) can be used as magnifier zoom out gesture. On fr-fr keyboard layout, it is located next to the zoom in gesture.

NVDA+shift+_ remains assigned, for other French keyboard layouts (fr-ca, fr-ch).

Both gestures work on fr-be layout.
### Summary of the issue:
crazy-max/ghaction-virustotal@v4 uses node 2020. This will [be retired
in
June](https://github.blog/changelog/2025-09-19-deprecation-of-node-20-on-github-actions-runners/).
crazy-max/ghaction-virustotal@v5.0.0 uses Node 2024 and is backwards
compatible.

### Description of user facing changes:
None

### Description of developer facing changes:
None

### Description of development approach:
Updated tag version

### Testing strategy:
CI

### Known issues with pull request:
None
…fied Chinese (nvaccess#20019)

PengKun, a contributor from the Chinese community, is planning extensive
changes to this dictionary. The attached files contain detailed logs and
the rationale for these changes, which are provided here for archival
purposes.
pre - nvaccess#19473
parts of nvaccess#19810
Summary of the issue:

nvaccess#19810 was still to big so I focused on types changes and some functions renaming to go accordingly.
All these changes are nescessary for futur magnifier implementations.
Description of user facing changes:

"default"s have been removed so it can be seen in the doc
Description of developer facing changes:

replaced MagnifierPosition with MagnifierParameters for better handling of size, place and filter of the magnifier.
added a MagnifierType to handle magnifiers different types.
Description of development approach:

This work was split out from PR nvaccess#19473 to make review and integration easier.
We first added the new structure: MagnifierParameters for size/position/filter, and MagnifierType for futur mode switching.
Summary of the issue:

actions/upload-artifact@v6 and actions/download-artifact@v7 use node 2020. This will be retired in June. actions/upload-artifact@v7.0.1 and actions/download-artifact@v8.0.1 use Node 2024 and are backwards compatible.
Co-authored-by: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com>
Co-authored-by: GitHub Actions <github-actions@github.com>
Co-authored-by: wencong <manchen_0528@outlook.com>
This pull request updates translations to languages being tracked from
Crowdin.

---------

Co-authored-by: GitHub Actions <github-actions@github.com>
Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com>
Fixes nvaccess#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.
…ss#20025)

fix nvaccess#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.
@CrazySteve0605 CrazySteve0605 requested a review from a team as a code owner May 1, 2026 16:26
@CrazySteve0605 CrazySteve0605 requested a review from seanbudd May 1, 2026 16:26
@CrazySteve0605 CrazySteve0605 changed the base branch from master to try-chineseWordSegmentation-staging May 1, 2026 16:34
@CrazySteve0605 CrazySteve0605 requested a review from a team as a code owner May 1, 2026 16:34
@CrazySteve0605 CrazySteve0605 requested review from Qchristensen and removed request for a team May 1, 2026 16:34
@seanbudd seanbudd merged commit 31c9585 into nvaccess:try-chineseWordSegmentation-staging May 3, 2026
32 of 37 checks passed
@github-actions github-actions Bot added this to the 2026.2 milestone May 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.