@@ -419,6 +419,85 @@ def _handleNVDAModuleCleanupBeforeGUIExit():
419419 brailleViewer .destroyBrailleViewer ()
420420
421421
422+ def _pollForForegroundHWND () -> int :
423+ """
424+ @note: The foreground window should usually be fetched on the first try,
425+ however it may take longer if Windows is taking a long time changing window focus.
426+ Times out after 20 seconds (MAX_WAIT_TIME_SECS).
427+ After timing out, NVDA will give up trying to start and exit.
428+ """
429+ import ui
430+ from utils .blockUntilConditionMet import blockUntilConditionMet
431+ import winUser
432+
433+ # winUser.getForegroundWindow may return NULL in certain circumstances,
434+ # such as when a window is losing activation.
435+ # This should not remain the case for an extended period of time.
436+ # If NVDA is taking longer than expected to fetch the foreground window, perform a warning.
437+ # We must wait a long time after this warning to
438+ # allow for braille / speech to be understood before exiting.
439+ # Unfortunately we cannot block with a dialog as NVDA cannot read dialogs yet.
440+ WARN_AFTER_SECS = 5
441+ MAX_WAIT_TIME_SECS = 20
442+
443+ success , foregroundHWND = blockUntilConditionMet (
444+ getValue = winUser .getForegroundWindow ,
445+ giveUpAfterSeconds = WARN_AFTER_SECS ,
446+ )
447+ if success :
448+ return foregroundHWND
449+ ui .message (_ (
450+ # Translators: Message when NVDA is having an issue starting up
451+ "NVDA is failing to fetch the foreground window. "
452+ "If this continues, NVDA will quit starting in %d seconds." % (MAX_WAIT_TIME_SECS - WARN_AFTER_SECS )
453+ ))
454+
455+ success , foregroundHWND = blockUntilConditionMet (
456+ getValue = winUser .getForegroundWindow ,
457+ giveUpAfterSeconds = MAX_WAIT_TIME_SECS - WARN_AFTER_SECS ,
458+ )
459+ if success :
460+ return foregroundHWND
461+ log .critical ("NVDA could not fetch the foreground window. Exiting NVDA." )
462+ # Raising exception here causes core.main to exit and NVDA to fail to start
463+ raise NVDANotInitializedError ("Could not fetch foreground window" )
464+
465+
466+ def _initializeObjectCaches ():
467+ """
468+ Caches the desktop object.
469+ This may make information from the desktop window available on the lock screen,
470+ however no known exploit is known for this.
471+ 2023.1 plans to ensure the desktopObject is available only when signed-in.
472+
473+ Also initializes other object caches to the foreground window.
474+ Previously the object that was cached was the desktopObject,
475+ however this may leak secure information to the lock screen.
476+ The foreground window is set as the object cache,
477+ as the foreground window would already be accessible on the lock screen (e.g. Magnifier).
478+ It also is more intuitive that NVDA focuses the foreground window,
479+ as opposed to the desktop object.
480+
481+ @note: The foreground window should usually be fetched on the first try,
482+ however it may take longer if Windows is taking a long time changing window focus.
483+ Times out after 20 seconds (MAX_WAIT_TIME_SECS in _pollForForegroundHWND).
484+ After timing out, NVDA will give up trying to start and exit.
485+ """
486+ import api
487+ import NVDAObjects
488+ import winUser
489+
490+ desktopObject = NVDAObjects .window .Window (windowHandle = winUser .getDesktopWindow ())
491+ api .setDesktopObject (desktopObject )
492+
493+ foregroundHWND = _pollForForegroundHWND ()
494+ foregroundObject = NVDAObjects .window .Window (windowHandle = foregroundHWND )
495+ api .setForegroundObject (foregroundObject )
496+ api .setFocusObject (foregroundObject )
497+ api .setNavigatorObject (foregroundObject )
498+ api .setMouseObject (foregroundObject )
499+
500+
422501def main ():
423502 """NVDA's core main loop.
424503 This initializes all modules such as audio, IAccessible, keyboard, mouse, and GUI.
@@ -667,14 +746,8 @@ def handlePowerStatusChange(self):
667746 log .debug ("Initializing garbageHandler" )
668747 garbageHandler .initialize ()
669748
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 )
749+ _initializeObjectCaches ()
750+
678751 import JABHandler
679752 log .debug ("initializing Java Access Bridge support" )
680753 try :
0 commit comments