@@ -419,6 +419,78 @@ def _handleNVDAModuleCleanupBeforeGUIExit():
419419 brailleViewer .destroyBrailleViewer ()
420420
421421
422+ def _pollForForegroundHWND () -> int :
423+ import ui
424+ import winUser
425+
426+ foregroundHWND = winUser .getForegroundWindow ()
427+ _hasWarned = False
428+ WARN_AFTER_SECS = 5
429+ MAX_WAIT_TIME_SECS = 20
430+ POLL_INTERVAL_SECS = 0.1
431+ waitForForegroundHWND_startTime = time .time ()
432+
433+ while not foregroundHWND :
434+ # The foreground window can be NULL in certain circumstances,
435+ # such as when a window is losing activation.
436+ # This should not remain the case for an extended period of time.
437+
438+ _timeElapsed = time .time () - waitForForegroundHWND_startTime
439+ if (
440+ not _hasWarned
441+ and _timeElapsed > WARN_AFTER_SECS
442+ ):
443+ _hasWarned = True
444+ # Allow for braille / speech to be understood before exiting.
445+ # Unfortunately we cannot block with a dialog as NVDA cannot read dialogs yet.
446+ ui .message (_ (
447+ # Translators: Message when NVDA is having an issue starting up
448+ "NVDA is failing to fetch the foreground window. "
449+ "If this continues, NVDA will quit starting in %d seconds." % (MAX_WAIT_TIME_SECS - WARN_AFTER_SECS )
450+ ))
451+
452+ if _timeElapsed > MAX_WAIT_TIME_SECS :
453+ log .critical ("NVDA could not fetch the foreground window. Exiting NVDA." )
454+ # Raising exception here causes core.main to exit and NVDA to fail to start
455+ raise NVDANotInitializedError ("Could not fetch foreground window" )
456+
457+ log .debugWarning ("Foreground window not found, fetching again" )
458+ time .sleep (POLL_INTERVAL_SECS )
459+ foregroundHWND = winUser .getForegroundWindow ()
460+
461+ return foregroundHWND
462+
463+
464+ def _initializeObjectCaches ():
465+ """
466+ Caches the desktop object.
467+ This may make information from the desktop window available on the lock screen,
468+ however no known exploit is known for this.
469+ 2023.1 plans to ensure the desktopObject is available only when signed-in.
470+
471+ Also initializes other object caches to the foreground window.
472+ Previously the object that was cached was the desktopObject,
473+ however this may leak secure information to the lock screen.
474+ The foreground window is set as the object cache,
475+ as the foreground window would already be accessible on the lock screen (e.g. Magnifier).
476+ It also is more intuitive that NVDA focuses the foreground window,
477+ as opposed to the desktop object.
478+ """
479+ import api
480+ import NVDAObjects
481+ import winUser
482+
483+ desktopObject = NVDAObjects .window .Window (windowHandle = winUser .getDesktopWindow ())
484+ api .setDesktopObject (desktopObject )
485+
486+ foregroundHWND = _pollForForegroundHWND ()
487+ foregroundObject = NVDAObjects .window .Window (windowHandle = foregroundHWND )
488+ api .setForegroundObject (foregroundObject )
489+ api .setFocusObject (foregroundObject )
490+ api .setNavigatorObject (foregroundObject )
491+ api .setMouseObject (foregroundObject )
492+
493+
422494def main ():
423495 """NVDA's core main loop.
424496 This initializes all modules such as audio, IAccessible, keyboard, mouse, and GUI.
@@ -667,14 +739,8 @@ def handlePowerStatusChange(self):
667739 log .debug ("Initializing garbageHandler" )
668740 garbageHandler .initialize ()
669741
670- import api
671- import winUser
672- import NVDAObjects .window
673- desktopObject = NVDAObjects .window .Window (windowHandle = winUser .getDesktopWindow ())
674- api .setDesktopObject (desktopObject )
675- api .setFocusObject (desktopObject )
676- api .setNavigatorObject (desktopObject )
677- api .setMouseObject (desktopObject )
742+ _initializeObjectCaches ()
743+
678744 import JABHandler
679745 log .debug ("initializing Java Access Bridge support" )
680746 try :
0 commit comments