Skip to content

Commit 267bb3f

Browse files
authored
Merge 0b305bc into 9823556
2 parents 9823556 + 0b305bc commit 267bb3f

20 files changed

Lines changed: 901 additions & 357 deletions

source/NVDAHelper.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
import api
2929
import globalVars
3030
from logHandler import log
31-
from utils.security import isWindowsLocked
31+
from utils.security import _isLockScreenModeActive
3232

3333
versionedLibPath = os.path.join(globalVars.appDir, 'lib')
3434
if os.environ.get('PROCESSOR_ARCHITEW6432') == 'ARM64':
@@ -455,7 +455,7 @@ def nvdaControllerInternal_installAddonPackageFromPath(addonPath):
455455
if globalVars.appArgs.secure:
456456
log.debugWarning("Unable to install add-on into secure copy of NVDA.")
457457
return
458-
if isWindowsLocked():
458+
if _isLockScreenModeActive():
459459
log.debugWarning("Unable to install add-on while Windows is locked.")
460460
return
461461
import wx
@@ -470,7 +470,7 @@ def nvdaControllerInternal_openConfigDirectory():
470470
if globalVars.appArgs.secure:
471471
log.debugWarning("Unable to open user config directory for secure copy of NVDA.")
472472
return
473-
if isWindowsLocked():
473+
if _isLockScreenModeActive():
474474
log.debugWarning("Unable to open user config directory while Windows is locked.")
475475
return
476476
import systemUtils

source/NVDAObjects/__init__.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,12 +30,13 @@
3030
TreeInterceptor,
3131
)
3232
import braille
33+
from utils.security import _isObjectBelowLockScreen
3334
import vision
3435
import globalPluginHandler
3536
import brailleInput
3637
import locationHelper
3738
import aria
38-
from winAPI.sessionTracking import isWindowsLocked
39+
from winAPI.sessionTracking import _isLockScreenModeActive
3940

4041

4142
class NVDAObjectTextInfo(textInfos.offsets.OffsetsTextInfo):
@@ -181,7 +182,7 @@ def _insertLockScreenObject(self, clsList: typing.List["NVDAObject"]) -> None:
181182
Inserts LockScreenObject to the start of the clsList if Windows is locked.
182183
"""
183184
from .lockscreen import LockScreenObject
184-
if isWindowsLocked():
185+
if _isLockScreenModeActive():
185186
# This must be resolved first to prevent object navigation outside of the lockscreen.
186187
clsList.insert(0, LockScreenObject)
187188

@@ -1433,3 +1434,11 @@ def getSelectedItemsCount(self,maxCount=2):
14331434
For performance, this method will only count up to the given maxCount number, and if there is one more above that, then sys.maxint is returned stating that many items are selected.
14341435
"""
14351436
return 0
1437+
1438+
#: Type definition for auto prop '_get_isBelowLockScreen'
1439+
isBelowLockScreen: bool
1440+
1441+
def _get_isBelowLockScreen(self) -> bool:
1442+
if not _isLockScreenModeActive():
1443+
return False
1444+
return _isObjectBelowLockScreen(self)

source/api.py

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -237,8 +237,23 @@ def setReviewPosition(
237237
@param isCaret: Whether the review position is changed due to caret following.
238238
@param isMouse: Whether the review position is changed due to mouse following.
239239
"""
240-
if _isSecureObjectWhileLockScreenActivated(reviewPosition.obj):
241-
return False
240+
reviewObj = reviewPosition.obj
241+
242+
if isinstance(reviewObj, treeInterceptorHandler.DocumentTreeInterceptor):
243+
# reviewPosition.obj can be a number of classes, e.g.
244+
# CursorManager, DocumentWithTableNavigation, EditableText.
245+
# We can only handle the NVDAObject case.
246+
reviewObj = reviewObj.rootNVDAObject
247+
248+
if isinstance(reviewObj, NVDAObjects.NVDAObject):
249+
# reviewPosition.obj can be a number of classes, e.g.
250+
# CursorManager, DocumentWithTableNavigation, EditableText.
251+
# We can only handle the NVDAObject case.
252+
if _isSecureObjectWhileLockScreenActivated(reviewObj):
253+
return False
254+
else:
255+
log.debug(f"Unhandled reviewObj type {type(reviewObj)} when checking security of reviewObj")
256+
242257
globalVars.reviewPosition=reviewPosition.copy()
243258
globalVars.reviewPositionObj=reviewPosition.obj
244259
if clearNavigatorObject: globalVars.navigatorObject=None

source/appModuleHandler.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -832,3 +832,28 @@ def getWmiProcessInfo(processId):
832832
except:
833833
raise LookupError("Couldn't get process information using WMI")
834834
raise LookupError("No such process")
835+
836+
837+
def _checkWindowsForAppModules():
838+
"""
839+
Updates the appModuleHandler with the process from all top level windows.
840+
Adds any missing processes.
841+
"""
842+
import winUser
843+
844+
# BOOL CALLBACK EnumWindowsProc _In_ HWND,_In_ LPARAM
845+
# HWND as a pointer creates confusion, treat as an int
846+
# http://makble.com/the-story-of-lpclong
847+
848+
@ctypes.WINFUNCTYPE(ctypes.c_bool, ctypes.c_int, ctypes.POINTER(ctypes.c_int))
849+
def _appModuleHandlerUpdate(
850+
hwnd: winUser.HWNDVal,
851+
_lParam: ctypes.wintypes.LPARAM
852+
) -> bool:
853+
processID, _threadID = winUser.getWindowThreadProcessID(hwnd)
854+
if processID not in runningTable:
855+
update(processID)
856+
return True
857+
858+
if not ctypes.windll.user32.EnumWindows(_appModuleHandlerUpdate, 0):
859+
log.error("Failed to refresh app modules")

source/appModules/lockapp.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,13 +21,13 @@
2121
from NVDAObjects.lockscreen import LockScreenObject
2222
from NVDAObjects.UIA import UIA
2323
from utils.security import getSafeScripts
24-
from winAPI.sessionTracking import isWindowsLocked
24+
from winAPI.sessionTracking import _isLockScreenModeActive
2525

2626
"""App module for the Windows 10 and 11 lock screen.
2727
2828
The lock screen allows other windows to be opened, so security related functions
2929
are done at a higher level than the lockapp app module.
30-
Refer to usages of `winAPI.sessionTracking.isWindowsLocked`.
30+
Refer to usages of `winAPI.sessionTracking._isLockScreenModeActive`.
3131
"""
3232

3333

@@ -60,11 +60,11 @@ def chooseNVDAObjectOverlayClasses(
6060
if isinstance(obj,UIA) and obj.role==controlTypes.Role.PANE and obj.UIAElement.cachedClassName=="LockAppContainer":
6161
clsList.insert(0,LockAppContainer)
6262

63-
if not isWindowsLocked():
63+
if not _isLockScreenModeActive():
6464
log.debugWarning(
6565
"LockApp is being initialized but NVDA does not expect Windows to be locked. "
6666
"DynamicNVDAObjectType may have failed to apply LockScreenObject. "
67-
"This means Windows session tracking has failed or NVDA is yet to receive lock event. "
67+
"This means session lock state tracking has failed. "
6868
)
6969
clsList.insert(0, LockScreenObject)
7070

@@ -83,7 +83,7 @@ def _inputCaptor(self, gesture: inputCore.InputGesture) -> bool:
8383
if not scriptShouldRun:
8484
log.error(
8585
"scriptHandler failed to block script when Windows is locked. "
86-
"This means Windows session tracking has failed. "
86+
"This means session lock state tracking has failed. "
8787
)
8888
return scriptShouldRun
8989

source/baseObject.py

Lines changed: 26 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,39 @@
11
# A part of NonVisual Desktop Access (NVDA)
2-
# Copyright (C) 2007-2020 NV Access Limited, Christopher Toth, Babbage B.V., Julien Cochuyt
2+
# Copyright (C) 2007-2022 NV Access Limited, Christopher Toth, Babbage B.V., Julien Cochuyt
33
# This file is covered by the GNU General Public License.
44
# See the file COPYING for more details.
55

66
"""Contains the base classes that many of NVDA's classes such as NVDAObjects, virtualBuffers, appModules, synthDrivers inherit from. These base classes provide such things as auto properties, and methods and properties for scripting and key binding.
77
"""
88

9+
from typing import (
10+
Any,
11+
Callable,
12+
Optional,
13+
Set,
14+
Union,
15+
)
916
import weakref
1017
import garbageHandler
1118
from logHandler import log
1219
from abc import ABCMeta, abstractproperty
1320

21+
GetterReturnT = Any
22+
GetterMethodT = Callable[["AutoPropertyObject"], GetterReturnT]
23+
24+
1425
class Getter(object):
1526

1627
def __init__(self,fget, abstract=False):
1728
self.fget=fget
1829
if abstract:
1930
self._abstract = self.__isabstractmethod__ = abstract
2031

21-
def __get__(self,instance,owner):
32+
def __get__(
33+
self,
34+
instance: Union[Any, None, "AutoPropertyObject"],
35+
owner,
36+
) -> Union[GetterReturnT, "Getter"]:
2237
if isinstance(self.fget, classmethod):
2338
return self.fget.__get__(instance, owner)()
2439
elif instance is None:
@@ -31,16 +46,22 @@ def setter(self,func):
3146
def deleter(self,func):
3247
return (abstractproperty if self._abstract else property)(fget=self.fget,fdel=func)
3348

49+
3450
class CachingGetter(Getter):
3551

36-
def __get__(self, instance, owner):
52+
def __get__(
53+
self,
54+
instance: Union[Any, None, "AutoPropertyObject"],
55+
owner,
56+
) -> Union[GetterReturnT, "CachingGetter"]:
3757
if isinstance(self.fget, classmethod):
3858
log.warning("Class properties do not support caching")
3959
return self.fget.__get__(instance, owner)()
4060
elif instance is None:
4161
return self
4262
return instance._getPropertyViaCache(self.fget)
4363

64+
4465
class AutoPropertyType(ABCMeta):
4566

4667
def __init__(self,name,bases,dict):
@@ -125,6 +146,7 @@ class AutoPropertyObject(garbageHandler.TrackedObject, metaclass=AutoPropertyTyp
125146
#: @type: bool
126147
cachePropertiesByDefault = False
127148

149+
_propertyCache: Set[GetterMethodT]
128150

129151
def __new__(cls, *args, **kwargs):
130152
self = super(AutoPropertyObject, cls).__new__(cls)
@@ -134,7 +156,7 @@ def __new__(cls, *args, **kwargs):
134156
self.__instances[self]=None
135157
return self
136158

137-
def _getPropertyViaCache(self,getterMethod=None):
159+
def _getPropertyViaCache(self, getterMethod: Optional[GetterMethodT] = None) -> GetterReturnT:
138160
if not getterMethod:
139161
raise ValueError("getterMethod is None")
140162
missing=False

source/brailleViewer/brailleViewerGui.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
import fonts
1818
import inputCore
1919
import gui.contextHelp
20-
from utils.security import isWindowsLocked, postSessionLockStateChanged
20+
from utils.security import _isLockScreenModeActive, postSessionLockStateChanged
2121

2222
BRAILLE_UNICODE_PATTERNS_START = 0x2800
2323
BRAILLE_SPACE_CHARACTER = chr(BRAILLE_UNICODE_PATTERNS_START)
@@ -398,7 +398,7 @@ def _createControls(self, sizer: wx.Sizer, parent: wx.Control) -> None:
398398
self._shouldShowOnStartupCheckBox.SetValue(config.conf["brailleViewer"]["showBrailleViewerAtStartup"])
399399
self._shouldShowOnStartupCheckBox.Bind(wx.EVT_CHECKBOX, self._onShouldShowOnStartupChanged)
400400
optionsSizer.Add(self._shouldShowOnStartupCheckBox)
401-
if isWindowsLocked():
401+
if _isLockScreenModeActive():
402402
self._shouldShowOnStartupCheckBox.Disable()
403403

404404
# Translators: The label for a setting in the braille viewer that controls
@@ -415,11 +415,11 @@ def _createControls(self, sizer: wx.Sizer, parent: wx.Control) -> None:
415415
sizer.Add(optionsSizer, flag=wx.EXPAND | wx.TOP, border=5)
416416

417417
def _onShouldShowOnStartupChanged(self, evt: wx.CommandEvent):
418-
if not isWindowsLocked():
418+
if not _isLockScreenModeActive():
419419
config.conf["brailleViewer"]["showBrailleViewerAtStartup"] = self._shouldShowOnStartupCheckBox.IsChecked()
420420

421421
def _onShouldHoverRouteToCellCheckBoxChanged(self, evt: wx.CommandEvent):
422-
if not isWindowsLocked():
422+
if not _isLockScreenModeActive():
423423
config.conf["brailleViewer"]["shouldHoverRouteToCell"] = self._shouldHoverRouteToCellCheckBox.IsChecked()
424424
self._updateMouseOverBinding(self._shouldHoverRouteToCellCheckBox.IsChecked())
425425

source/core.py

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -451,13 +451,13 @@ class _TrackNVDAInitialization:
451451
regardless of lock state.
452452
Security checks may cause the desktop object to not be set if NVDA starts on the lock screen.
453453
As such, during initialization, NVDA should behave as if Windows is unlocked,
454-
i.e. winAPI.sessionTracking.isWindowsLocked should return False.
454+
i.e. winAPI.sessionTracking._isLockScreenModeActive should return False.
455455
456456
TODO: move to NVDAState module
457457
"""
458458

459459
_isNVDAInitialized = False
460-
"""When False, isWindowsLocked is forced to return False.
460+
"""When False, _isLockScreenModeActive is forced to return False.
461461
"""
462462

463463
@staticmethod
@@ -601,7 +601,6 @@ def onEndSession(evt):
601601
wx.CallAfter(audioDucking.initialize)
602602

603603
from winAPI.messageWindow import WindowMessage
604-
from winAPI import sessionTracking
605604
import winUser
606605
# #3763: In wxPython 3, the class name of frame windows changed from wxWindowClassNR to wxWindowNR.
607606
# NVDA uses the main frame to check for and quit another instance of NVDA.
@@ -630,27 +629,12 @@ def __init__(self, windowName=None):
630629
self.orientationCoordsCache = (0,0)
631630
self.handlePowerStatusChange()
632631

633-
# Call must be paired with a call to sessionTracking.unregister
634-
if not sessionTracking.register(self.handle):
635-
import utils.security
636-
wx.CallAfter(utils.security.warnSessionLockStateUnknown)
637-
638-
def destroy(self):
639-
"""
640-
NVDA must unregister session tracking before destroying the message window.
641-
"""
642-
# Requires an active message window and a handle to unregister.
643-
sessionTracking.unregister(self.handle)
644-
super().destroy()
645-
646632
def windowProc(self, hwnd, msg, wParam, lParam):
647633
post_windowMessageReceipt.notify(msg=msg, wParam=wParam, lParam=lParam)
648634
if msg == WindowMessage.POWER_BROADCAST and wParam == self.PBT_APMPOWERSTATUSCHANGE:
649635
self.handlePowerStatusChange()
650636
elif msg == winUser.WM_DISPLAYCHANGE:
651637
self.handleScreenOrientationChange(lParam)
652-
elif msg == WindowMessage.WTS_SESSION_CHANGE:
653-
sessionTracking.handleSessionChange(sessionTracking.WindowsTrackedSession(wParam), lParam)
654638

655639
def handleScreenOrientationChange(self, lParam):
656640
# TODO: move to winAPI
@@ -809,7 +793,8 @@ def run(self):
809793
mouseHandler.pumpAll()
810794
braille.pumpAll()
811795
vision.pumpAll()
812-
except:
796+
sessionTracking.pumpAll()
797+
except Exception:
813798
log.exception("errors in this core pump cycle")
814799
baseObject.AutoPropertyObject.invalidateCaches()
815800
watchdog.asleep()
@@ -832,6 +817,9 @@ def run(self):
832817
log.debug("initializing updateCheck")
833818
updateCheck.initialize()
834819

820+
from winAPI import sessionTracking
821+
sessionTracking.initialize()
822+
835823
_TrackNVDAInitialization.markInitializationComplete()
836824

837825
log.info("NVDA initialized")

source/globalVars.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import typing
2121

2222
if typing.TYPE_CHECKING:
23+
import documentBase # noqa: F401 used for type checking only
2324
import NVDAObjects # noqa: F401 used for type checking only
2425

2526

@@ -70,7 +71,7 @@ class DefaultAppArgs(argparse.Namespace):
7071
mouseOldY=None
7172
navigatorObject: typing.Optional['NVDAObjects.NVDAObject'] = None
7273
reviewPosition=None
73-
reviewPositionObj=None
74+
reviewPositionObj: typing.Optional["documentBase.TextContainerObject"] = None
7475
lastProgressValue=0
7576
appArgs = DefaultAppArgs()
7677
unknownAppArgs: typing.List[str] = []

source/nvda.pyw

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -350,13 +350,20 @@ if mutex is None:
350350
sys.exit(1)
351351

352352

353-
if _isSecureDesktop():
353+
def _serviceDebugEnabled() -> bool:
354354
import winreg
355355
try:
356356
k = winreg.OpenKey(winreg.HKEY_LOCAL_MACHINE, r"SOFTWARE\NVDA")
357-
if not winreg.QueryValueEx(k, u"serviceDebug")[0]:
358-
globalVars.appArgs.secure = True
357+
if winreg.QueryValueEx(k, "serviceDebug")[0]:
358+
return True
359359
except WindowsError:
360+
# Expected state by default, serviceDebug parameter not set
361+
pass
362+
return False
363+
364+
365+
if _isSecureDesktop():
366+
if not _serviceDebugEnabled():
360367
globalVars.appArgs.secure = True
361368
globalVars.appArgs.changeScreenReaderFlag = False
362369
globalVars.appArgs.minimal = True

0 commit comments

Comments
 (0)